中文手写数字数据识别

实验环境

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, numpywith 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 Imageclass MyDataset(Dataset):def __init__(self, data, targets, transform=None, target_transform=None):'''data 数据形状为(x,64,64) x张64*64图像数组targets 数据形状为(x) x个图像类别取值'''self.transform = transformself.target_transform = target_transformself.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 nnclass SelfCnn(nn.Module):def __init__(self):super(SelfCnn, self).__init__()self.features = nn.Sequential(# Block 1nn.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.0total = 0.0loss_ = 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 / totalloop.set_description(f'Epoch Test [{epoch + 1}/{num_epochs}]')loop.set_postfix(loss=loss_/(i+1), acc=acc)if epoch == 0:print('原有模型在测试集表现如下:')acc = correct / totalloss_ = 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 = acctorch.save(model, 'chn_mnist_resnet50.pth')print('The model has been saved as chn_mnist_resnet50.pth')correct = 0.0total = 0.0loss_ = 0.0time.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 / totalloss_ = 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 Imageclass MyDataset(Dataset):def __init__(self, data, targets, transform=None, target_transform=None):self.transform = transformself.target_transform = target_transformself.data = []self.targets = []targets = targets.astype(np.uint8)if target_transform is None:self.targets = targetsfor 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 nnclass SelfCnn(nn.Module):def __init__(self):super(SelfCnn, self).__init__()self.features = nn.Sequential(# Block 1nn.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 osfrom selfnet_cnn import SelfCnnos.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] = 14train_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.0total = 0.0loss_ = 0.0loop = 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 / totalloop.set_description(f'Epoch Test [{epoch + 1}/{num_epochs}]')loop.set_postfix(loss=loss_/(i+1), acc=acc)if epoch == 0:print('原有模型在测试集表现如下:')acc = correct / totalloss_ = 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 = acctorch.save(model, 'chn_mnist_selfCnn.pth')print('The model has been saved as chn_mnist_selfCnn.pth')correct = 0.0total = 0.0loss_ = 0.0time.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 / totalloss_ = 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] = 14train_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.0total = 0.0loss_ = 0.0loop = 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 / totalloop.set_description(f'Epoch Test [{epoch + 1}/{num_epochs}]')loop.set_postfix(loss=loss_/(i+1), acc=acc)if epoch == 0:print('原有模型在测试集表现如下:')acc = correct / totalloss_ = 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 = acctorch.save(model, 'chn_mnist_vgg16.pth')print('The model has been saved as chn_mnist_vgg16.pth')correct = 0.0total = 0.0loss_ = 0.0time.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 / totalloss_ = 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] = 14train_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.0total = 0.0loss_ = 0.0loop = 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 / totalloop.set_description(f'Epoch Test [{epoch + 1}/{num_epochs}]')loop.set_postfix(loss=loss_/(i+1), acc=acc)if epoch == 0:print('原有模型在测试集表现如下:')acc = correct / totalloss_ = 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 = acctorch.save(model, 'chn_mnist_resnet50.pth')print('The model has been saved as chn_mnist_resnet50.pth')correct = 0.0total = 0.0loss_ = 0.0time.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 / totalloss_ = 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.mzph.cn/news/199256.shtml

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

相关文章

浅谈ArrayBuffer、Blob和File、FileReader

ArrayBuffer、Blob和File都是JavaScript中处理二进制数据的对象。 ArrayBuffer 用于表示一个通用的、固定长度的原始二进制数据缓冲区。它不能直接操作缓冲区中的数据,而需要通过一个类型化数组TypedArray(如Int8Array、Uint8Array等)或者一…

linux 中crontab 定时任务计划创建时间文件夹示例

1.创建一个sh脚本 /usr/bin/mkdir 是mkdir命令的路径 /usr/bin/chmod 是chmod命令的路径 2.编辑定时任务 crontab -e

爆款开放式耳机哪一款性价比最高?3款热门机型推荐,小白速看

随着生活水平的提升,越来越多的人对蓝牙耳机的需求不再局限于简单的音乐欣赏。他们对耳机的要求越来越高,包括音质表现、舒适度、环境感知等方面也有极大的期待,正是因为这样,开放式耳机应运而生。 身为一个数码测评小博主&#x…

C++ 12.5作业

以下是一个简单的比喻,将多态概念与生活中的实际情况相联系: 比喻:动物园的讲解员和动物表演 想象一下你去了一家动物园,看到了许多不同种类的动物,如狮子、大象、猴子等。现在,动物园里有一位讲解员&…

音乐律动效果

先上图 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>音乐律动效果</title><style>* {margin: 0;padding: 0;}li {list-style: none;}.container .img {width: 200px;height: 200…

Git介绍与安装使用

目录 1.Git初识 1.1提出问题 1.2如何解决--版本控制器 1.3注意事项 2.Git安装 2.1Linux-centos安装 2.2Linux-ubuntu安装 2.3Windows安装 3.Git基本操作 3.1创建Git本地仓库 3.2配置Git 4.认识⼯作区、暂存区、版本库 1.Git初识 1.1提出问题 不知道你工作或学习时…

VBA技术资料MF92:将多个Excel表插入Word文档的不同位置

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。我的教程一共九套&#xff0c;分为初级、中级、高级三大部分。是对VBA的系统讲解&#xff0c;从简单的入门&#xff0c;到…

从零开始,轻松实现Python接口自动化测试(基于PyCharm)

1.接口清单整理 &#xff08;1&#xff09;请求&#xff1a; 请求URL请求方法请求参数请求报文 &#xff08;2&#xff09;响应 状态码响应数据 2.用例设计 &#xff08;1&#xff09;单接口测试用例 模板&#xff1a;id、模块、接口名称、请求URL、用例名称、请求方法、…

解决typescript报错:找不到名称xxx

现象&#xff1a; 原因&#xff1a;在同时导入默认导出和命名导出时&#xff0c;默认导出必须放在命名导出之前 下面的就是原始文件&#xff1a; 默认导出指&#xff1a; export default导出类型&#xff0c; import时无需大括号 命名导出指&#xff1a; 仅有export关键字…

优化汽车产业用户营运:精细化策略

近年来随着互联网时代新技术浪潮的冲击&#xff0c;商业社会中各种原生边界不断被打破&#xff0c;新的消费需求、新的商业模式、新的竞争挑战层出不穷。各行业往往面临重重困境与迷思&#xff0c;学会如何精细化运营用户显得尤为重要。立即阅读阅文&#xff0c;详细了解其中用…

手动创建spring bean并注入

文章目录 前言一、jar包中,相同class不同类加载器加载的时候是同一个class嘛&#xff1f;二、利用ConfigurableListableBeanFactory手动注册bean注册bean,并自动注入依赖bean根据类型获取注入的bean,两个bean是一个吗? 三、同一份字节码,class隔离,bean隔离总结 前言 注入一个…

python打包exe,打包好后,启动exe报错找不到paddleocr

目录 1、安装pyinstaller 2、生成脚本文件的.spce文件 3、资源文件配置 4、生成exe文件 5、使用了paddleocr启动exe后报错 6、配置.spce文件 7、重新生成exe文件 8、关于图片找不到的问题 参考&#xff1a;PaddleOCR打包exe--Pyinstaller_paddleocr 打包exe_mjiansun的博…

JS初步了解this

什么是环境对象&#xff1f; 环境对象&#xff1a;指的是函数内部特殊的变量this&#xff0c;它代表着当前函数运行时所处的环境 作用&#xff1a;弄清楚this的指向&#xff0c;可以让我们代码更简洁 在普通函数中&#xff1a; // 每个函数里面都有this 普通函数的this指向wind…

面试多线程八股文十问十答第三期

面试多线程八股文十问十答第三期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1.介绍一下自旋锁 重量级锁竞争时&#xff0c;尝试获取锁的线程不会立即阻塞&…

高效合并技巧:视频合并,保证质量,提升剪辑效率

在视频制作过程中&#xff0c;视频剪辑和合并是常见的操作步骤。不过这些步骤往往需要耗费大量的时间和精力。那要如何提高效率呢&#xff1f;下面讲解一些高效合并技巧&#xff0c;引用云炫AI智剪快速整合视频&#xff0c;随机合并视频&#xff0c;保证质量&#xff0c;并提升…

【Linux--进程】

目录 一、基本概念1.1描述进程-PCB1.2task_struct中内容分类 二、了解进程2.1查看进程2.2通过系统调用获取进程标识符 三、fork创建进程3.1fork()函数3.2写时拷贝 四、进程的状态4.1操作系统学科里的进程状态&#xff08;运行、阻塞、挂起&#xff09;4.具体的Linux状态是如何维…

xampp环境安装

XAMPP是完全免费且易于安装的Apache发行版&#xff0c;其中包含Apache、MariaDB、PHP和Perl。 类似XAMPP的服务器套件还有很多&#xff0c;我用过的还有UPUPW&#xff0c;它们都极大的简化了开发环境的配置。 下载链接Download XAMPP 我选的最新的 一路next就安装好了。 访问…

百度曾出价 8500 万挖“AI 教父”被拒;GPT-3.5 图灵测试中败给上世纪 AI丨 RTE 开发者日报 Vol.99

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

创建 Python Docker 镜像的完整指南

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Python和Docker是两个极其流行的技术&#xff0c;结合它们可以创建强大的应用程序。Docker允许将应用程序及其依赖项打包到一个独立的容器中&#xff0c;而Python则提供了丰富的库和工具来开发应用程序。本文将提…

2023年12月5日作业:多态

题目&#xff1a; 代码&#xff1a; #include <iostream>using namespace std;class Animals { private:string name; public:Animals(){}Animals(string name):name(name){}virtual void perform() 0;void show(){cout << "这个动物是" << name…