中文手写数字数据识别

news2024/11/25 4:38:43

实验环境

python=3.7
torch==1.13.1+cu117
torchaudio==0.13.1+cu117
torchvision==0.14.1

数据下载地址:Mnist中文手写数字数据集Python资源-CSDN文库

这些汉字包括:

零、一、二、三、四、五、六、七、八、九、十、百、千、万、亿
总共15个汉字,分别用0、1、2、3、4、5、6、7、8、9、10、100、1000、10000、100000000标记

使用方法

import pickle, numpy

with open("./chn_mnist", "rb") as f:
 data = pickle.load(f)
images = data["images"]
targets = data["targets"]

数据预处理

数据加载

将数据存入俩个变量,格式为numpy.ndarray

#修改自己的数据集路径
with open(r"D:\zr\data\chn_mnist\chn_mnist", "rb") as f:
    dataset = pickle.load(f)
images = dataset["images"]
targets = dataset["targets"]
统一标签值

100、1000、10000、100000000这四个标签分别用11、12、13、14表示

index = np.where(targets == 100)
targets[index] = 11
index = np.where(targets == 1000)
targets[index] = 12
index = np.where(targets == 10000)
targets[index] = 13
index = np.where(targets == 100000000)
targets[index] = 14

构建数据集

构建Dataset

使用torch.utils.data.DataLoader根据数据集生成一个可迭代的对象,用于模型训练前,需要构建自己的Dataset类

在定义自己的数据集时,需要继承Dataset类,并实现三个函数:initlen__和__getitem

init:实例化Dataset对象时运行,完成初始化工作
len:返回数据集的大小
getitem:根据索引返回一个样本(数据和标签)

import numpy as np
from torch.utils.data import Dataset
from PIL import Image

class MyDataset(Dataset):
    def __init__(self, data, targets, transform=None, target_transform=None):
        '''
        data 数据形状为(x,64,64) x张64*64图像数组
        targets 数据形状为(x) x个图像类别取值
        '''
        self.transform = transform
        self.target_transform = target_transform
        self.data = []
        self.targets = []
        #转换数据格式    
        targets = targets.astype(np.uint8)
        #标签集不做任何处理的情况下
        if target_transform is None:
            self.targets = targets
    	#我这里transform处理numpy数组图像会报错,需要将图像转为Image格式
        #遍历依次对每个图像转换
        for index in range(0, data.shape[0]):
            if self.transform:
                image = Image.fromarray(data[index])
                self.data.append(self.transform(image))
            if self.target_transform:
                self.targets.append(self.target_transform(targets))
    def __len__(self):
        return len(self.data)

    def __getitem__(self, index):
        return self.data[index], self.targets[index]

定义转换方法,对于图像数组,将每个像素点取值规范至0-1之间,均值为0.5

transform_data = transforms.Compose([
    	#确保所有图像都为(64,64),此处图像为标准数据,可以不用
   		torchvision.transforms.Resize((64, 64)),
    	#将PIL Image格式的数据转换为tensor格式,像素值大小缩放至区间[0., 1.]
    	transforms.ToTensor(),
    	#对输入进行标准化,传入均值(mean[1],…,mean[n])和标准差(std[1],…,std[n]),n与输入的维度相同
    	#对于三通道图像(mean=[0.5,0.5,0.5], std=[0.5,0.5,0.5])
    	transforms.Normalize(mean=[0.5], std=[0.5])])
transform_target = None

实例化Dataset类,此处将前14000张作为训练集,后1000张作为测试集

train_dataset = dataloader.MyDataset(images[:14000, :, :], targets[:14000], transform_data, transform_target)
test_dataset = dataloader.MyDataset(images[-1000:, :, :], targets[-1000:], transform_data, transform_target)
DataLoader加载数据集

DataLoader参数解释,通常填前三个参数即可

常用参数:

  • dataset (Dataset) :定义好的数据集
  • batch_size (int, optional):每次放入网络训练的批次大小,默认为1.
  • shuffle (bool, optional) :是否打乱数据的顺序,默认为False。一般训练集设置为True,测试集设置为False
  • num_workers (int, optional) :线程数,默认为0。在Windows下设置大于0的数可能会报错
  • drop_last (bool, optional) :是否丢弃最后一个批次的数据,默认为False

两个工具包,可配合DataLoader使用:

  • enumerate(iterable, start=0):输入是一个可迭代的对象和下标索引开始值;返回可迭代对象的下标索引和数据本身
  • tqdm(iterable):进度条可视化工具包

定义超参数

# 定义超参数
#每次进入模型的图像数量
batch_size = 32
#学习率
learning_rate = 0.001
#总的迭代次数
num_epochs = 50

加载

#shuffle=True表示打乱数据
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size)

模型构建

CNN

自定义卷积模块,对于不同数据集,修改输入图像通道数和输出的分类数量即可

import torch
import torch.nn as nn


class SelfCnn(nn.Module):
    def __init__(self):
        super(SelfCnn, self).__init__()
        self.features = nn.Sequential(
            # Block 1
            nn.Conv2d(1, 32, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(32, 64, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # (32,32,64)
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # (16,16,64)
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # (8,8,64)

        )
        self.classifier = nn.Sequential(
            nn.Linear(8 * 8 * 64, 256),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(256, 256),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(256, 15)  # 输出层,二分类任务
        )

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, 1)  # 展开特征图
        x = self.classifier(x)
        return x

加载模型

model=SelfCnn()
VGG16

VGG16由于模型参数量太大,自己从0训练不大能行,需要加载pytorch的预训练模型

#pretrained = True代表加载预训练数据
vgg16_ture = torchvision.models.vgg16(pretrained = True)

VGG16默认的输入图像数据为(224,224,3),输出为(1,1,1000) 我们的数据输入为(64,64,1),目标输出为(1,1,15),因此需要对模型进行修改结构

#增加一层线性变化,将1000类变为15类
vgg16_ture.classifier.append(nn.Linear(1000,15))
#全连接层修改,原来为(7*7*512),将(224/32=)7换为(64/32=)2即可
vgg16_ture.classifier[0]=nn.Linear(2*2*512,4096)
#输入的三通道改为单通道1
vgg16_ture.features[0]=nn.Conv2d(1, 64, kernel_size=3, padding=1)
vgg16_ture.avgpool=nn.AdaptiveAvgPool2d((2,2))
model=vgg16_ture
ResNet50

ResNet50同样需要加载预训练模型

#pretrained = True代表加载预训练数据
resnet50 = torchvision.models.resnet50(pretrained=True)

ResNet50默认输入为三通道图像,将其修改为单通道,以及全连接层输出分类修改

#输入的三通道改为单通道1
resnet50.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3)
#将输出分类改为15
resnet50.fc = (nn.Linear(2048, 15))
model=resnet50

模型训练

选择模型以及训练环境

#有gpu则使用gpu
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
#选择使用的模型,model=vgg16_ture,model=SelfCnn()
#加载已经训练过的模型: model=torch.load(r'D:\zr\projects\utils\chn_mnist_resnet50.pth')
model=resnet50
#将模型置于device
model.to(device)

定义损失函数和优化器

#多分类任务使用这个损失
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), momentum=0.9, lr=learning_rate)

定义绘图方法,本例绘制俩附图像

def plt_img(plt_data):
    # 创建数据点
    plt.clf()
    x = plt_data.get('Epoch')
    train_acc = plt_data.get('train_acc')
    train_loss = plt_data.get('train_loss')
    test_acc = plt_data.get('test_acc')
    test_loss = plt_data.get('test_loss')
    # 绘制曲线
    plt.plot(x, train_acc, label='train_acc')
    plt.plot(x, test_acc, label='test_acc')
    plt.plot(x, train_loss, label='train_loss')
    plt.plot(x, test_loss, label='test_loss')
    plt.legend(title='Accuracy And Loss')  # 添加图例标题
    plt.xlabel('epoch')
    # plt.ylabel('rate')
    plt.savefig(f'resnet50_{num_epochs}_{batch_size}_{learning_rate}_1.png')
    # 显示图形
def plt_acc_loss(plt_data):
    plt.clf()
    _, axes = plt.subplots(2, 1)
    x = plt_data.get('Epoch')
    train_acc = plt_data.get('train_acc')
    train_loss = plt_data.get('train_loss')
    test_acc = plt_data.get('test_acc')
    test_loss = plt_data.get('test_loss')
    axes[0].plot(x, train_acc, label='train_acc')
    axes[0].plot(x, test_acc, label='test_acc')
    axes[0].legend(title='Accuracy')  # 添加图例标题
    axes[0].set_xlabel('epoch')
    # axes[0].set_ylabel('rate')
    axes[1].plot(x, train_loss, label='train_loss')
    axes[1].plot(x, test_loss, label='test_loss')
    axes[1].legend(title='Loss')
    axes[1].set_xlabel('epoch')
    # axes[1].set_ylabel('rate')
    # 防止标签被遮挡
    plt.tight_layout()
    plt.savefig(f'resnet50_{num_epochs}_{batch_size}_{learning_rate}_2.png')

开始训练,每次epoch结束都会对模型进行评估,保存准确率最高的模型,同时记录每次的准确率以及loss

max_acc = 0.0
plt_data = {
    'Epoch': [],
    'train_acc': [],
    'train_loss': [],
    'test_acc': [],
    'test_loss': [],

}
for epoch in range(num_epochs):
    plt_data.get('Epoch').append(epoch + 1)
    model.eval()
    torch.no_grad()
    correct = 0.0
    total = 0.0
    loss_ = 0.0
    #测试模型
    loop = tqdm(enumerate(test_loader), total=len(test_loader))
    for i, (images, labels) in loop:
        images = images.to(device)
        labels = labels.to(device)
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss_ += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        acc = correct / total
        loop.set_description(f'Epoch Test [{epoch + 1}/{num_epochs}]')
        loop.set_postfix(loss=loss_/(i+1), acc=acc)
    if epoch == 0:
        print('原有模型在测试集表现如下:')
    acc = correct / total
    loss_ = loss_ / len(test_loader)
    plt_data.get('test_acc').append(acc)
    plt_data.get('test_loss').append(loss_)
    print(f"Accuracy on test images: {acc * 100}% , Loss  {loss_}")
    if acc > max_acc:
        max_acc = acc
        torch.save(model, 'chn_mnist_resnet50.pth')
        print('The model has been saved as chn_mnist_resnet50.pth')
    correct = 0.0
    total = 0.0
    loss_ = 0.0
    time.sleep(0.1)
    #训练
    loop = tqdm(enumerate(train_loader), total=len(train_loader))
    for i, (images, labels) in loop:
        images = images.to(device)
        labels = labels.to(device)
        # 前向传播
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss_ += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        acc = correct / total
        # 反向传播和优化,测试集时不要要
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        loop.set_description(f'Epoch Train [{epoch + 1}/{num_epochs}]')
        loop.set_postfix(loss=loss_/(i+1), acc=acc)
    acc = correct / total
    loss_ = loss_ / len(train_loader)
    plt_data.get('train_acc').append(acc)
    plt_data.get('train_loss').append(loss_)
    print(f"Accuracy on train images: {acc * 100}% , Loss  {loss_}")
    time.sleep(0.1)
    #绘图
    plt_img(plt_data)
	plt_acc_loss(plt_data)

结果分析

以下结果均在总训练次数(Epoch)=100,学习率(learn_rate_=0.001,批样本数量(Batch Size)=32的情况下

CNN

测试表现

训练集准确率为:99.99%,测试集准确率为 88.5%,模型存在过拟合

VGG16

可见模型正在Epoch =10左右的时候就基本收敛完成

测试表现

训练集准确率为:99.92%,测试集准确率为 99.5%,模型良好且泛化能力强

ResNet50

可见模型正在Epoch =10之前的时候就基本收敛完成,相较于VGG,resnet50的收敛速度更快

测试表现

训练集准确率为:100%,测试集准确率为 96.8%,模型良好但存在过拟合

源代码

dataloader.py
import numpy as np
from torch.utils.data import Dataset
from PIL import Image


class MyDataset(Dataset):
    def __init__(self, data, targets, transform=None, target_transform=None):
        self.transform = transform
        self.target_transform = target_transform
        self.data = []
        self.targets = []
        targets = targets.astype(np.uint8)
        if target_transform is None:
            self.targets = targets
        for index in range(0, data.shape[0]):
            if self.transform:
                image = Image.fromarray(data[index])
                self.data.append(self.transform(image))
            if self.target_transform:
                self.targets.append(self.target_transform(targets))
    def __len__(self):
        return len(self.data)

    def __getitem__(self, index):
        return self.data[index], self.targets[index]
selfnet_cnn.py
import torch
import torch.nn as nn


class SelfCnn(nn.Module):
    def __init__(self):
        super(SelfCnn, self).__init__()
        self.features = nn.Sequential(
            # Block 1
            nn.Conv2d(1, 32, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(32, 64, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # (32,32,64)
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # (16,16,64)
            nn.Conv2d(64, 64, kernel_size=3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=2, stride=2),  # (8,8,64)

        )
        self.classifier = nn.Sequential(
            nn.Linear(8 * 8 * 64, 256),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(256, 256),
            nn.ReLU(inplace=True),
            nn.Dropout(),
            nn.Linear(256, 15)  # 输出层,二分类任务
        )

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, 1)  # 展开特征图
        x = self.classifier(x)
        return x
train_self_cnn.py
import pickle
import time
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from torch import nn
from torch.utils.data import DataLoader
import dataloader
import torch
import torchvision
import torchvision.transforms as transforms
from tqdm import tqdm
import os

from selfnet_cnn import SelfCnn

os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# 定义数据转换
transform_data = transforms.Compose([
    torchvision.transforms.Resize((64, 64)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5], std=[0.5])
])
transform_target = None
with open(r"D:\zr\data\chn_mnist\chn_mnist", "rb") as f:
    dataset = pickle.load(f)
images = dataset["images"]
targets = dataset["targets"]
index = np.where(targets == 100)
targets[index] = 11
index = np.where(targets == 1000)
targets[index] = 12
index = np.where(targets == 10000)
targets[index] = 13
index = np.where(targets == 100000000)
targets[index] = 14

train_dataset = dataloader.MyDataset(images[:14000, :, :], targets[:14000], transform_data, transform_target)
test_dataset = dataloader.MyDataset(images[-1000:, :, :], targets[-1000:], transform_data, transform_target)

# 定义超参数
batch_size = 32
learning_rate = 0.001
num_epochs = 100
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size)


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model=SelfCnn()
# model = torch.load(r'D:\zr\projects\utils\chn_mnist_resnet50.pth', map_location=device)
model.to(device)
# 定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), momentum=0.9, lr=learning_rate)
def plt_img(plt_data):
    # 创建数据点
    plt.clf()
    x = plt_data.get('Epoch')
    train_acc = plt_data.get('train_acc')
    train_loss = plt_data.get('train_loss')
    test_acc = plt_data.get('test_acc')
    test_loss = plt_data.get('test_loss')
    # 绘制曲线
    plt.plot(x, train_acc, label='train_acc')
    plt.plot(x, test_acc, label='test_acc')
    plt.plot(x, train_loss, label='train_loss')
    plt.plot(x, test_loss, label='test_loss')
    plt.legend(title='Accuracy And Loss')  # 添加图例标题
    plt.xlabel('epoch')
    # plt.ylabel('rate')
    plt.savefig(f'selfCnn_{num_epochs}_{batch_size}_{learning_rate}_1.png')
    # 显示图形
def plt_acc_loss(plt_data):
    plt.clf()
    _, axes = plt.subplots(2, 1)
    x = plt_data.get('Epoch')
    train_acc = plt_data.get('train_acc')
    train_loss = plt_data.get('train_loss')
    test_acc = plt_data.get('test_acc')
    test_loss = plt_data.get('test_loss')
    axes[0].plot(x, train_acc, label='train_acc')
    axes[0].plot(x, test_acc, label='test_acc')
    axes[0].legend(title='Accuracy')  # 添加图例标题
    axes[0].set_xlabel('epoch')
    # axes[0].set_ylabel('rate')
    axes[1].plot(x, train_loss, label='train_loss')
    axes[1].plot(x, test_loss, label='test_loss')
    axes[1].legend(title='Loss')
    axes[1].set_xlabel('epoch')
    # axes[1].set_ylabel('rate')
    # 防止标签被遮挡
    plt.tight_layout()
    plt.savefig(f'selfCnn_{num_epochs}_{batch_size}_{learning_rate}_2.png')
# 训练模型
max_acc = 0.0
plt_data = {
    'Epoch': [],
    'train_acc': [],
    'train_loss': [],
    'test_acc': [],
    'test_loss': [],

}

for epoch in range(num_epochs):
    plt_data.get('Epoch').append(epoch + 1)
    model.eval()
    torch.no_grad()
    correct = 0.0
    total = 0.0
    loss_ = 0.0
    loop = tqdm(enumerate(test_loader), total=len(test_loader))
    for i, (images, labels) in loop:
        images = images.to(device)
        labels = labels.to(device)
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss_ += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        acc = correct / total
        loop.set_description(f'Epoch Test [{epoch + 1}/{num_epochs}]')
        loop.set_postfix(loss=loss_/(i+1), acc=acc)
    if epoch == 0:
        print('原有模型在测试集表现如下:')
    acc = correct / total
    loss_ = loss_ / len(test_loader)
    plt_data.get('test_acc').append(acc)
    plt_data.get('test_loss').append(loss_)
    print(f"Accuracy on test images: {acc * 100}% , Loss:  {loss_}")
    if acc > max_acc:
        max_acc = acc
        torch.save(model, 'chn_mnist_selfCnn.pth')
        print('The model has been saved as chn_mnist_selfCnn.pth')
    correct = 0.0
    total = 0.0
    loss_ = 0.0
    time.sleep(0.1)
    loop = tqdm(enumerate(train_loader), total=len(train_loader))
    for i, (images, labels) in loop:
        images = images.to(device)
        labels = labels.to(device)
        # 前向传播
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss_ += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        acc = correct / total
        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        loop.set_description(f'Epoch Train [{epoch + 1}/{num_epochs}]')
        loop.set_postfix(loss=loss_/(i+1), acc=acc)
    acc = correct / total
    loss_ = loss_ / len(train_loader)
    plt_data.get('train_acc').append(acc)
    plt_data.get('train_loss').append(loss_)
    print(f"Accuracy on train images: {acc * 100}% , Loss:  {loss_}")
    time.sleep(0.1)
    plt_img(plt_data)
    plt_acc_loss(plt_data)
train_vgg16.py
import pickle
import time
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from torch import nn
from torch.utils.data import DataLoader
import dataloader
import torch
import torchvision
import torchvision.transforms as transforms
from tqdm import tqdm
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# 定义数据转换
transform_data = transforms.Compose([
    torchvision.transforms.Resize((64, 64)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5], std=[0.5])
])
transform_target = None
with open(r"D:\zr\data\chn_mnist\chn_mnist", "rb") as f:
    dataset = pickle.load(f)
images = dataset["images"]
targets = dataset["targets"]
index = np.where(targets == 100)
targets[index] = 11
index = np.where(targets == 1000)
targets[index] = 12
index = np.where(targets == 10000)
targets[index] = 13
index = np.where(targets == 100000000)
targets[index] = 14

train_dataset = dataloader.MyDataset(images[:14000, :, :], targets[:14000], transform_data, transform_target)
test_dataset = dataloader.MyDataset(images[-1000:, :, :], targets[-1000:], transform_data, transform_target)

# 定义超参数
batch_size = 32
learning_rate = 0.001
num_epochs = 50
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size)


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

vgg16_ture = torchvision.models.vgg16(pretrained = True)
vgg16_ture.classifier.append(nn.Linear(1000,15))
vgg16_ture.classifier[0]=nn.Linear(2*2*512,4096)
vgg16_ture.features[0]=nn.Conv2d(1, 64, kernel_size=3, padding=1)
vgg16_ture.avgpool=nn.AdaptiveAvgPool2d((2,2))
model=vgg16_ture
# model = torch.load(r'D:\zr\projects\utils\chn_mnist_resnet50.pth', map_location=device)
model.to(device)
# 定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), momentum=0.9, lr=learning_rate)
def plt_img(plt_data):
    # 创建数据点
    plt.clf()
    x = plt_data.get('Epoch')
    train_acc = plt_data.get('train_acc')
    train_loss = plt_data.get('train_loss')
    test_acc = plt_data.get('test_acc')
    test_loss = plt_data.get('test_loss')
    # 绘制曲线
    plt.plot(x, train_acc, label='train_acc')
    plt.plot(x, test_acc, label='test_acc')
    plt.plot(x, train_loss, label='train_loss')
    plt.plot(x, test_loss, label='test_loss')
    plt.legend(title='Accuracy And Loss')  # 添加图例标题
    plt.xlabel('epoch')
    # plt.ylabel('rate')
    plt.savefig(f'vgg16_{num_epochs}_{batch_size}_{learning_rate}_1.png')
    # 显示图形
def plt_acc_loss(plt_data):
    plt.clf()
    _, axes = plt.subplots(2, 1)
    x = plt_data.get('Epoch')
    train_acc = plt_data.get('train_acc')
    train_loss = plt_data.get('train_loss')
    test_acc = plt_data.get('test_acc')
    test_loss = plt_data.get('test_loss')
    axes[0].plot(x, train_acc, label='train_acc')
    axes[0].plot(x, test_acc, label='test_acc')
    axes[0].legend(title='Accuracy')  # 添加图例标题
    axes[0].set_xlabel('epoch')
    # axes[0].set_ylabel('rate')
    axes[1].plot(x, train_loss, label='train_loss')
    axes[1].plot(x, test_loss, label='test_loss')
    axes[1].legend(title='Loss')
    axes[1].set_xlabel('epoch')
    # axes[1].set_ylabel('rate')
    # 防止标签被遮挡
    plt.tight_layout()
    plt.savefig(f'vgg16_{num_epochs}_{batch_size}_{learning_rate}_2.png')
# 训练模型
max_acc = 0.0
plt_data = {
    'Epoch': [],
    'train_acc': [],
    'train_loss': [],
    'test_acc': [],
    'test_loss': [],

}

for epoch in range(num_epochs):
    plt_data.get('Epoch').append(epoch + 1)
    model.eval()
    torch.no_grad()
    correct = 0.0
    total = 0.0
    loss_ = 0.0
    loop = tqdm(enumerate(test_loader), total=len(test_loader))
    for i, (images, labels) in loop:
        images = images.to(device)
        labels = labels.to(device)
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss_ += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        acc = correct / total
        loop.set_description(f'Epoch Test [{epoch + 1}/{num_epochs}]')
        loop.set_postfix(loss=loss_/(i+1), acc=acc)
    if epoch == 0:
        print('原有模型在测试集表现如下:')
    acc = correct / total
    loss_ = loss_ / len(test_loader)
    plt_data.get('test_acc').append(acc)
    plt_data.get('test_loss').append(loss_)
    print(f"Accuracy on test images: {acc * 100}% , Loss:  {loss_}")
    if acc > max_acc:
        max_acc = acc
        torch.save(model, 'chn_mnist_vgg16.pth')
        print('The model has been saved as chn_mnist_vgg16.pth')
    correct = 0.0
    total = 0.0
    loss_ = 0.0
    time.sleep(0.1)
    loop = tqdm(enumerate(train_loader), total=len(train_loader))
    for i, (images, labels) in loop:
        images = images.to(device)
        labels = labels.to(device)
        # 前向传播
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss_ += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        acc = correct / total
        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        loop.set_description(f'Epoch Train [{epoch + 1}/{num_epochs}]')
        loop.set_postfix(loss=loss_/(i+1), acc=acc)
    acc = correct / total
    loss_ = loss_ / len(train_loader)
    plt_data.get('train_acc').append(acc)
    plt_data.get('train_loss').append(loss_)
    print(f"Accuracy on train images: {acc * 100}% , Loss:  {loss_}")
    time.sleep(0.1)
    plt_img(plt_data)
    plt_acc_loss(plt_data)
train_resnet50.py
import pickle
import time
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from torch import nn
from torch.utils.data import DataLoader
import dataloader
import torch
import torchvision
import torchvision.transforms as transforms
from tqdm import tqdm
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"
# 定义数据转换
transform_data = transforms.Compose([
    torchvision.transforms.Resize((64, 64)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5], std=[0.5])
])
transform_target = None
with open(r"D:\zr\data\chn_mnist\chn_mnist", "rb") as f:
    dataset = pickle.load(f)
images = dataset["images"]
targets = dataset["targets"]
index = np.where(targets == 100)
targets[index] = 11
index = np.where(targets == 1000)
targets[index] = 12
index = np.where(targets == 10000)
targets[index] = 13
index = np.where(targets == 100000000)
targets[index] = 14

train_dataset = dataloader.MyDataset(images[:14000, :, :], targets[:14000], transform_data, transform_target)
test_dataset = dataloader.MyDataset(images[-1000:, :, :], targets[-1000:], transform_data, transform_target)

# 定义超参数
batch_size = 32
learning_rate = 0.001
num_epochs = 50
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size)


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

resnet50 = torchvision.models.resnet50(pretrained=True)
# print(resnet50)
resnet50.conv1 = nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3)
resnet50.fc = (nn.Linear(2048, 15))
# resnet50.add_module('add',nn.Linear(1000,15))
model=resnet50
# model = torch.load(r'D:\zr\projects\utils\chn_mnist_resnet50.pth', map_location=device)
model.to(device)
# 定义损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), momentum=0.9, lr=learning_rate)
def plt_img(plt_data):
    # 创建数据点
    plt.clf()
    x = plt_data.get('Epoch')
    train_acc = plt_data.get('train_acc')
    train_loss = plt_data.get('train_loss')
    test_acc = plt_data.get('test_acc')
    test_loss = plt_data.get('test_loss')
    # 绘制曲线
    plt.plot(x, train_acc, label='train_acc')
    plt.plot(x, test_acc, label='test_acc')
    plt.plot(x, train_loss, label='train_loss')
    plt.plot(x, test_loss, label='test_loss')
    plt.legend(title='Accuracy And Loss')  # 添加图例标题
    plt.xlabel('epoch')
    # plt.ylabel('rate')
    plt.savefig(f'resnet50_{num_epochs}_{batch_size}_{learning_rate}_1.png')
    # 显示图形
def plt_acc_loss(plt_data):
    plt.clf()
    _, axes = plt.subplots(2, 1)
    x = plt_data.get('Epoch')
    train_acc = plt_data.get('train_acc')
    train_loss = plt_data.get('train_loss')
    test_acc = plt_data.get('test_acc')
    test_loss = plt_data.get('test_loss')
    axes[0].plot(x, train_acc, label='train_acc')
    axes[0].plot(x, test_acc, label='test_acc')
    axes[0].legend(title='Accuracy')  # 添加图例标题
    axes[0].set_xlabel('epoch')
    # axes[0].set_ylabel('rate')
    axes[1].plot(x, train_loss, label='train_loss')
    axes[1].plot(x, test_loss, label='test_loss')
    axes[1].legend(title='Loss')
    axes[1].set_xlabel('epoch')
    # axes[1].set_ylabel('rate')
    # 防止标签被遮挡
    plt.tight_layout()
    plt.savefig(f'resnet50_{num_epochs}_{batch_size}_{learning_rate}_2.png')
# 训练模型
max_acc = 0.0
plt_data = {
    'Epoch': [],
    'train_acc': [],
    'train_loss': [],
    'test_acc': [],
    'test_loss': [],

}

for epoch in range(num_epochs):
    plt_data.get('Epoch').append(epoch + 1)
    model.eval()
    torch.no_grad()
    correct = 0.0
    total = 0.0
    loss_ = 0.0
    loop = tqdm(enumerate(test_loader), total=len(test_loader))
    for i, (images, labels) in loop:
        images = images.to(device)
        labels = labels.to(device)
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss_ += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        acc = correct / total
        loop.set_description(f'Epoch Test [{epoch + 1}/{num_epochs}]')
        loop.set_postfix(loss=loss_/(i+1), acc=acc)
    if epoch == 0:
        print('原有模型在测试集表现如下:')
    acc = correct / total
    loss_ = loss_ / len(test_loader)
    plt_data.get('test_acc').append(acc)
    plt_data.get('test_loss').append(loss_)
    print(f"Accuracy on test images: {acc * 100}% , Loss:  {loss_}")
    if acc > max_acc:
        max_acc = acc
        torch.save(model, 'chn_mnist_resnet50.pth')
        print('The model has been saved as chn_mnist_resnet50.pth')
    correct = 0.0
    total = 0.0
    loss_ = 0.0
    time.sleep(0.1)
    loop = tqdm(enumerate(train_loader), total=len(train_loader))
    for i, (images, labels) in loop:
        images = images.to(device)
        labels = labels.to(device)
        # 前向传播
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss_ += loss.item()
        _, predicted = torch.max(outputs, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()
        acc = correct / total
        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        loop.set_description(f'Epoch Train [{epoch + 1}/{num_epochs}]')
        loop.set_postfix(loss=loss_/(i+1), acc=acc)
    acc = correct / total
    loss_ = loss_ / len(train_loader)
    plt_data.get('train_acc').append(acc)
    plt_data.get('train_loss').append(loss_)
    print(f"Accuracy on train images: {acc * 100}% , Loss:  {loss_}")
    time.sleep(0.1)
    plt_img(plt_data)
    plt_acc_loss(plt_data)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1287821.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS学习--了解基本工程目录

1.工程级目录 工程的目录结构如下: 其中详细如下: AppScope中存放应用全局所需要的资源文件。entry是应用的主模块,存放HarmonyOS应用的代码、资源等。oh_modules是工程的依赖包,存放工程依赖的源文件。build-profile.json5是工…

Scrapy爬虫数据存储为JSON文件的解决方案

什么是JSON文件 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人们阅读和编写,同时也易于机器解析和生成。它基于JavaScript Spark语言的一个子集,但独立于Smashing语言,因此在许多中…

C语言每日一题(46)整数转罗马数字

力扣网12 整数转罗马数字 题目描述 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D …

Get职场新知识:做分析,用大数据分析工具

为什么企业每天累积那么多的数据,也做数据分析,但最后决策还是靠经验?很大程度上是因为这些数据都被以不同的指标和存储方式放在各自的系统中,这就导致了数据的分析口径和标准不一致,无法在同一个分析软件上做综合分析…

nodejs微信小程序+python+PHP在线购票系统的设计与实现-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性:…

Vue自定义hook函数

hook 本质是一个函数,可以把 setup 函数中使用的 Composition API 进行封装。 hook 类似于 Vue2 中的 mixin 混合。 自定义 hook 的优势:复用代码,让 setup 中的逻辑更加清晰易懂。 自定义hook函数: 1、在 src 目录下创建 hooks…

codeforces 题目 Chtholly‘s request

目录 题目: 题目描述: 思路: AC代码: 题目: 题目描述: zcy数:(形如:11,1221,103301) ①是回文数 ②数位个数是偶数 给你两个整数 k…

flask项目的基本配置

1. 目录结构 2. 入口文件app.py from manger import create_app, db from flask_migrate import Migrate from manger import models# 传入settings参数,开发版本“develop”,线上版本“product” app create_app(develop)# 数据库设置 migrate Migra…

Git 分支合并时 Merge, Rebase, Squash 的使用场景

前言 Git 的分支设计大大提升了并行开发的能力,但相应的,也就要解决如何进行分支合并。毕竟分久必合,最终还是要把大家的工作合并起来,进行统一发布的。在合并时,通常有三种操作: Merge commitsRebaseSqu…

vivado时序方法检查2

TIMING-4 &#xff1a; 时钟树上的基准时钟重新定义无效 时钟树上的时钟重新定义无效。基准时钟 <clock_name> 是在时钟 <clock_name> 下游定义的 &#xff0c; 并覆盖其插入延迟和/ 或波形定义。 描述 基准时钟必须在时钟树的源时钟上定义。例如 &#xff0…

计网Lesson7 - 超网与路由概述

文章目录 一、构造超网1 概念解析2 路由聚合判断网段 3 实例演示几个配置问题&#xff1a;传输过程中的若干问题包的问题传输时丢包的问题 4 判断是子网还是超网 二、路由概述1. 路由的作用2. 多个网段进行联络3. 数据包的传输 一、构造超网 1 概念解析 与划分子网相反&#…

行云海CMS SQL注入漏洞复现

0x01 产品简介 行云海cms是完全开源的一套CMS内容管理系统,简洁,易用,安全,稳定,免费。 0x02 漏洞概述 行云海cms中ThinkPHP在处理order by排序时可利用key构造SQL语句进行注入,LtController.class.php中发现传入了orderby未进行过滤导致sql注入。攻击者除了可以利用 SQL 注入…

mysql原理--重新认识MySQL,字符集,比较规则

1.MySQL请求处理 1.1.查询缓存 MySQL 服务器程序处理查询请求时&#xff0c;会把刚刚处理过的查询请求和结果缓存起来&#xff0c;如果下一次有一模一样的请求过来&#xff0c;直接从缓存中查找结果就好了&#xff0c;就不用再傻呵呵的去底层的表中查找了。这个查询缓存可以在不…

Qnx boot workflow

S820A QNX Hypervisor Software User Guide 80-CF838-1 Rev. Img 生成脚本: target/hypervisor/host/create_images.sh tools/build/image-builder.sh The QVM config file for the guest is instantiated within the host rootfs build file, located at root/target/hyp…

【QT】QComboBox和QPlainTextEdit基本介绍和应用示例

目录 1.QComboBox 1.1 QComboBox概述 1.2 QComboBox信号 1.3 QComboBox常用功能 1.4 QComboBox添加简单项 1.6 QComboBox列表项的访问 2.QPlainTextEdit 2.1 QPlainTextEdit概述 2.2 QPlainTextEdit的基本属性 2.3 QPlainTextEdit的公共函数 2.4 QPlainTextEdit的公…

设计模式篇之创建型模式

目录 前言一、简单工厂模式二、工厂方法模式总结 前言 最近开始整理Java设计模式&#xff0c;本篇主要分享设计模式中的创建型模式&#xff0c;并给出demo代码&#xff0c;适合初中级开发学习。分享书籍《大话设计模式》&#xff0c;分享GitHub学习设计模式仓库。 一、简单工厂…

集成开发环境PyCharm的使用【侯小啾python基础领航计划 系列(三)】

集成开发环境 PyCharm 的使用【侯小啾python基础领航计划 系列(三)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…

2.环境变量及接口关联

一、环境变量以及全局变量 操作流程 1.点击environment 2.点击environment右侧号&#xff0c;新增环境变量 3.在变量中输入变量名以及变量值 4.回到collection页面&#xff0c;修改变量环境 5.在collection中通过{{变量名}}调用变量 变量定义 环境变量&#xff1a;环境变量…

Vue实现简单用户登录页面

&#x1f4d1;前言 本文主要是【Vue】——Vue实现简单用户登录页面的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日…

内部文件上传以及渲染-接口API

文件上传 地址http://172.16.0.118:8090/api/pm/base/affix/upload请求类型POSTContent-Type:text/plain;charsetutf-8参数 prjData {"prjId":"", "jobId":"3031b2c8-c809-4110-8e88-22c80a9c1ec0721aca89-96a1-4346-9b6e-022331d221d1Nec…