目录

Cifar-10及模型文件下载:

如果嫌自动下载太慢   :cifar-10下载

已多次训练的模型文件 73%(放置在.py同目录下)(第一种模型)

过拟合程度较低的模型文件70%(放置在.py同目录下)(第一种模型)

全部代码:

训练结果:

第一种模型:

第二种模型:

小结:


实验内容:

使用pytorch对cifar10进行分类。

代码流程:

  1. 定义网络
  2. CIFAR-10的下载及录入。
  3. 数据预处理
  4. 模型加载
  5. 训练模型
  6. 测试模型
  7. 绘制图像

Cifar-10及模型文件下载:

如果嫌自动下载太慢   :cifar-10下载

cifa-10解压后,将 cifar-10-batches-py放置在  .py 文件同目录下的  dataset 文件夹

Cifar-10及已训练模型(cnn.pth)放置位置如图:

                        

已多次训练的模型文件 73%(放置在.py同目录下)(第一种模型)

这个过拟合了,如果需要更高的准确率,可以尝试重新训练,

如果欠拟合,可以尝试更改模型,增加训练次数,重新训练旧有模型(推荐)等。

如果更改模型,旧有模型文件将无法使用(不过训练的挺快的。)

过拟合程度较低的模型文件70%(放置在.py同目录下)(第一种模型)

 已多次训练的模型文件 66%(放置在.py同目录下)(第二种模型)


全部代码:

8轮训练约6min

减少卷积层和全连接层能够更快的训练

看着挺密集,注释挺多的,应该好理解。

import torchvision as tv  # 专门用来处理图像的库
from torchvision import transforms  # transforms用来对图片进行变换
from torchvision.transforms import ToPILImage
import os  # 用于加载旧模型使用
import torch
import torch.nn as nn  # 神经网络基本工具箱
import torch.nn.functional as fun
import numpy as np
import matplotlib.pyplot as plt  # 绘图模块,能绘制 2D 图表# 定义卷积神经网络==========================================================
class ConvNet(nn.Module):  # 类 ConvNet 继承自 nn.Moduledef __init__(self):  # 构造方法# 下式等价于nn.Module.__init__.(self)super(ConvNet, self).__init__()  # 调用父类构造方法# 使用了三个卷积层,四个全连接层# RGB 3*32*32# 卷积层===========================================================self.conv1 = nn.Conv2d(3, 15, 3)  # 输入3通道,输出15通道,卷积核为3*3self.conv2 = nn.Conv2d(15, 75, 4)  # 输入15通道,输出75通道,卷积核为4*4self.conv3 = nn.Conv2d(75, 375, 3)  # 输入75通道,输出375通道,卷积核为3*3# 全连接层=========================================================self.fc1 = nn.Linear(1500, 400)  # 输入2000,输出400self.fc2 = nn.Linear(400, 120)  # 输入400,输出120self.fc3 = nn.Linear(120, 84)  # 输入120,输出84self.fc4 = nn.Linear(84, 10)  # 输入 84,输出 10(分10类)def forward(self, x):# 最大池化步长为2x = fun.max_pool2d(fun.relu(self.conv1(x)), 2)  # 3*32*32  -> 150*30*30  -> 15*15*15x = fun.max_pool2d(fun.relu(self.conv2(x)), 2)  # 15*15*15 -> 75*12*12  -> 75*6*6x = fun.max_pool2d(fun.relu(self.conv3(x)), 2)  # 75*6*6   -> 375*4*4   -> 375*2*2x = x.view(x.size()[0], -1)  # 将375*2*2的tensor打平成1维,(卷积变为全连接)1500x = fun.relu(self.fc1(x))  # 全连接层 1500 -> 400x = fun.relu(self.fc2(x))  # 全连接层 400 -> 120x = fun.relu(self.fc3(x))  # 全连接层 120 -> 84x = self.fc4(x)  # 全连接层 84  -> 10return x# ==========================================================================================================
# 数据预处理
transform = transforms.Compose([transforms.ToTensor(),  # 将图片类型由 PIL Image 转化成tensor类型。转换时会自动归一化transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  # 对图像进行标准化(均值变为0,标准差变为1)# 下载数据集==========================================
print("开始导入数据集==============================================")
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 下载(download) cifar-10 后放到项目中的 dataset 文件夹(root)并分为训练集,测试集,(train)并做预处理(transform)
train_start = tv.datasets.CIFAR10(root="./dataset", train=True, download=True, transform=transform)  # 训练集
test_set = tv.datasets.CIFAR10(root="./dataset", train=False, download=True, transform=transform)  # 测试集
print('训练及图像有:', len(train_start), '张。\n测试集图像有:', len(test_set), '张。')
# 打包数据集 python将多个数据打包处理,能够加快训练速度
batch_size = 4
# 将测试集和训练集每 4个 进行打包,并打乱训练集(shuffle)
train_set = torch.utils.data.DataLoader(train_start, batch_size=batch_size, shuffle=True)  # 训练集
test_set = torch.utils.data.DataLoader(test_set, batch_size=batch_size, shuffle=False)  # 测试集# 设置卷积神经网络和训练参数=================================
print("正在加载卷积神经网络=========================================")
# 如果设备 GPU 能被调用,则转到 GPU 加快运算,否则使用CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = ConvNet().to(device)  # 初始化模型
print(device)
print('可使用GPU加速' if (torch.cuda.is_available()) else '无法开启GPU加速')
learning_rate = 0.001  # 学习率
criterion = nn.CrossEntropyLoss()  # 交叉熵损失函数
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)  # 优化器:随机梯度下降算法
loop = 8  # 循环次数
print("学习率为", learning_rate, "\n训练次数为:", loop)# 模型加载==========================================
i = 0  # 绘图用
seat = './cnn.pth'  # 保存位置(名称)
if os.path.exists(seat):  # 如果检测到  seat  文件print("检测到模型文件,是否加载已训练模型(Y\\N):")shuru = input()if shuru == 'Y' or shuru == 'y':model.load_state_dict(torch.load(seat))print("已加载已训练模型")print("是否继续训练(Y\\N):")shuru = input()  # 加载模型用户决定是否训练else:print("未加载已训练模型")shuru = 'Y'  # 不加载模型直接训练
else:print("未检测到旧模型文件")shuru = 'Y'  # 不加载模型直接训练# 开始训练==========================================
if shuru == 'Y' or shuru == 'y':print("开始训练===================================================")print("训练结果会自动保存")lentrain = len(train_set)process = []for epoch in range(loop):  # 训练 loop 次running_loss = 0.0  # 训练误差# 下面这个作用是每轮打乱一次,没什么大用处,不想要可以删去train_set = torch.utils.data.DataLoader(train_start, batch_size=batch_size, shuffle=True)  # 训练集# enumerate() 函数:用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标。for i, (images, labels) in enumerate(train_set, 0):# 转到GPU或CPU上进行运算images = images.to(device)labels = labels.to(device)outputs = model(images)  # 正向传播loss = criterion(outputs, labels)  # 计算batch(四个一打包)误差optimizer.zero_grad()  # 梯度清零loss.backward()  # 反向传播optimizer.step()  # 更新参数# 打印loss信息running_loss += loss.item()  # 2000个batch的误差和if i % 2000 == 1999:  # 每2000个batch打印一次训练状态print("第%2d/%2d 轮循环,%6d/%6d 组,误差为:%.4f"% (epoch + 1, loop, i + 1, lentrain, running_loss / 2000))process.append(running_loss)running_loss = 0.0  # 误差归零# 绘制训练过程i = i + 1plt.figure(i)plt.plot(list(range(len(process))), process, 'g:', label='loss')plt.legend(loc='lower right')  # 显示上面的labelplt.xlabel('time')  # x_labelplt.ylabel('loss')  # y_labelplt.title('loss about time')  # 标题# 模型保存==========================================print("保存模型至%s======================================" % seat)torch.save(model.state_dict(), seat)print("保存完毕")# 模型测试==========================================
print("开始测试===================================================")
#  在训练集上测试====================================
correct = 0  # 预测正确图片数
total = 0  # 总图片数
for images, labels in train_set:images = images.to(device)labels = labels.to(device)outputs = model(images)# 返回得分最高的索引(一组 4 个)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum()
print("训练集中的准确率为:%d %%" % (100 * correct / total))
#  在测试集上测试====================================
correct = 0  # 预测正确图片数
total = 0  # 总图片数
for images, labels in test_set:images = images.to(device)labels = labels.to(device)outputs = model(images)# 返回得分最高的索引(一组 4 个)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum()
print("测试集中的准确率为:%d %%" % (100 * correct / total))
# 输出在测试集上一组(4个)的数据和预测结果===================
dataiter = iter(test_set)  # 生成测试集的可迭代对象
images, labels = dataiter.next()  # 得到一组数据
# 绘图====================
i = i + 1
plt.figure(i)
npimg = (tv.utils.make_grid(images / 2 + 0.5)).numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
print("实际标签:", " ".join("%08s" % classes[labels[j]] for j in range(4)))
show = ToPILImage()  # 把tensor转为image
images = images.to(device)
labels = labels.to(device)
outputs = model(images)  # 计算图片在每个类别上的分数
# 返回得分最高的索引
_, predicted = torch.max(outputs.data, 1)  # 第一个数是具体值,不需要
# 一组 4 张图,所以找每行的最大值
print("预测结果:", " ".join("%08s" % classes[predicted[j]] for j in range(4)))
plt.show()  # 显示=========

训练结果:

3层卷积层和池化层,4层全连接层。最大池化层步长为2。

第一种模型:

代码如下:

8轮训练约 6 分钟训练集测试集正确率可达50+%

如果你的时间比较多,可以不打包(把打包数改为1)也能提升准确率

如果loss图像不再呈下降趋势,可以减少学习率,继续训练。(注意过拟合)

# 定义卷积神经网络==========================================================
class ConvNet(nn.Module):  # 类 ConvNet 继承自 nn.Moduledef __init__(self):  # 构造方法# 下式等价于nn.Module.__init__.(self)super(ConvNet, self).__init__()  # 调用父类构造方法# 使用了三个卷积层,四个全连接层# RGB 3*32*32# 卷积层===========================================================self.conv1 = nn.Conv2d(3, 15, 3)  # 输入3通道,输出15通道,卷积核为3*3self.conv2 = nn.Conv2d(15, 75, 4)  # 输入15通道,输出75通道,卷积核为4*4self.conv3 = nn.Conv2d(75, 375, 3)  # 输入75通道,输出375通道,卷积核为3*3# 全连接层=========================================================self.fc1 = nn.Linear(1500, 400)  # 输入2000,输出400self.fc2 = nn.Linear(400, 120)  # 输入400,输出120self.fc3 = nn.Linear(120, 84)  # 输入120,输出84self.fc4 = nn.Linear(84, 10)  # 输入 84,输出 10(分10类)def forward(self, x):# 最大池化步长为2x = fun.max_pool2d(fun.relu(self.conv1(x)), 2)  # 3*32*32  -> 150*30*30  -> 15*15*15x = fun.max_pool2d(fun.relu(self.conv2(x)), 2)  # 15*15*15 -> 75*12*12  -> 75*6*6x = fun.max_pool2d(fun.relu(self.conv3(x)), 2)  # 75*6*6   -> 375*4*4   -> 375*2*2x = x.view(x.size()[0], -1)  # 将375*2*2的tensor打平成1维,(卷积变为全连接)1500x = fun.relu(self.fc1(x))  # 全连接层 1500 -> 400x = fun.relu(self.fc2(x))  # 全连接层 400 -> 120x = fun.relu(self.fc3(x))  # 全连接层 120 -> 84x = self.fc4(x)  # 全连接层 84  -> 10return x

训练过程:

开始导入数据集==============================================
Files already downloaded and verified
Files already downloaded and verified
训练及图像有: 50000 张。
测试集图像有: 10000 张。
正在加载卷积神经网络=========================================
cuda
可使用GPU加速
学习率为 0.001
训练次数为: 8
检测到模型文件,是否加载已训练模型(Y\N):
n
未加载已训练模型
开始训练===================================================
训练结果会自动保存
第 1/ 8 轮循环,  2000/ 12500 组,误差为:2.3039
第 1/ 8 轮循环,  4000/ 12500 组,误差为:2.3028
第 1/ 8 轮循环,  6000/ 12500 组,误差为:2.3023
第 1/ 8 轮循环,  8000/ 12500 组,误差为:2.3013
第 1/ 8 轮循环, 10000/ 12500 组,误差为:2.3012
第 1/ 8 轮循环, 12000/ 12500 组,误差为:2.3006
第 2/ 8 轮循环,  2000/ 12500 组,误差为:2.2995
第 2/ 8 轮循环,  4000/ 12500 组,误差为:2.2990
第 2/ 8 轮循环,  6000/ 12500 组,误差为:2.2972
第 2/ 8 轮循环,  8000/ 12500 组,误差为:2.2952
第 2/ 8 轮循环, 10000/ 12500 组,误差为:2.2919
第 2/ 8 轮循环, 12000/ 12500 组,误差为:2.2852
第 3/ 8 轮循环,  2000/ 12500 组,误差为:2.2652
第 3/ 8 轮循环,  4000/ 12500 组,误差为:2.2210
第 3/ 8 轮循环,  6000/ 12500 组,误差为:2.1317
第 3/ 8 轮循环,  8000/ 12500 组,误差为:2.0523
第 3/ 8 轮循环, 10000/ 12500 组,误差为:2.0022
第 3/ 8 轮循环, 12000/ 12500 组,误差为:1.9558
第 4/ 8 轮循环,  2000/ 12500 组,误差为:1.9096
第 4/ 8 轮循环,  4000/ 12500 组,误差为:1.8596
第 4/ 8 轮循环,  6000/ 12500 组,误差为:1.8319
第 4/ 8 轮循环,  8000/ 12500 组,误差为:1.8148
第 4/ 8 轮循环, 10000/ 12500 组,误差为:1.7812
第 4/ 8 轮循环, 12000/ 12500 组,误差为:1.7598
第 5/ 8 轮循环,  2000/ 12500 组,误差为:1.7161
第 5/ 8 轮循环,  4000/ 12500 组,误差为:1.6853
第 5/ 8 轮循环,  6000/ 12500 组,误差为:1.6911
第 5/ 8 轮循环,  8000/ 12500 组,误差为:1.6542
第 5/ 8 轮循环, 10000/ 12500 组,误差为:1.6195
第 5/ 8 轮循环, 12000/ 12500 组,误差为:1.6182
第 6/ 8 轮循环,  2000/ 12500 组,误差为:1.5706
第 6/ 8 轮循环,  4000/ 12500 组,误差为:1.5715
第 6/ 8 轮循环,  6000/ 12500 组,误差为:1.5304
第 6/ 8 轮循环,  8000/ 12500 组,误差为:1.5078
第 6/ 8 轮循环, 10000/ 12500 组,误差为:1.5062
第 6/ 8 轮循环, 12000/ 12500 组,误差为:1.4785
第 7/ 8 轮循环,  2000/ 12500 组,误差为:1.4556
第 7/ 8 轮循环,  4000/ 12500 组,误差为:1.4451
第 7/ 8 轮循环,  6000/ 12500 组,误差为:1.4233
第 7/ 8 轮循环,  8000/ 12500 组,误差为:1.3809
第 7/ 8 轮循环, 10000/ 12500 组,误差为:1.3972
第 7/ 8 轮循环, 12000/ 12500 组,误差为:1.3602
第 8/ 8 轮循环,  2000/ 12500 组,误差为:1.3418
第 8/ 8 轮循环,  4000/ 12500 组,误差为:1.3309
第 8/ 8 轮循环,  6000/ 12500 组,误差为:1.2963
第 8/ 8 轮循环,  8000/ 12500 组,误差为:1.3022
第 8/ 8 轮循环, 10000/ 12500 组,误差为:1.2693
第 8/ 8 轮循环, 12000/ 12500 组,误差为:1.2843
保存模型至./cnn.pth======================================
保存完毕
开始测试===================================================
训练集中的准确率为:55 %
测试集中的准确率为:54 %
实际标签:      cat     ship     ship    plane
预测结果:      cat     ship     ship     ship

第二种模型:

如果用以下卷积神经网络,8轮训练约 6分钟,可达50+%

class ConvNet(nn.Module):def __init__(self):super(ConvNet, self).__init__()self.conv1 = nn.Conv2d(3, 6, 5)self.pool = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(6, 16, 5)self.fc1 = nn.Linear(16 * 5 * 5, 120)self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x):x = self.pool(F.relu(self.conv1(x)))x = self.pool(F.relu(self.conv2(x)))x = x.view(-1, 16 * 5 * 5)x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x)return x

训练过程:

开始导入数据集==============================================
Files already downloaded and verified
Files already downloaded and verified
训练及图像有: 50000 张。
测试集图像有: 10000 张。
正在加载卷积神经网络=========================================
cuda
可使用GPU加速
学习率为 0.001
训练次数为: 8
未检测到旧模型文件
开始训练===================================================
训练结果会自动保存
第 1/ 8 轮循环,  2000/ 12500 组,误差为:2.3037
第 1/ 8 轮循环,  4000/ 12500 组,误差为:2.3005
第 1/ 8 轮循环,  6000/ 12500 组,误差为:2.2982
第 1/ 8 轮循环,  8000/ 12500 组,误差为:2.2896
第 1/ 8 轮循环, 10000/ 12500 组,误差为:2.2701
第 1/ 8 轮循环, 12000/ 12500 组,误差为:2.2173
第 2/ 8 轮循环,  2000/ 12500 组,误差为:2.1186
第 2/ 8 轮循环,  4000/ 12500 组,误差为:2.0516
第 2/ 8 轮循环,  6000/ 12500 组,误差为:1.9952
第 2/ 8 轮循环,  8000/ 12500 组,误差为:1.9494
第 2/ 8 轮循环, 10000/ 12500 组,误差为:1.8899
第 2/ 8 轮循环, 12000/ 12500 组,误差为:1.8465
第 3/ 8 轮循环,  2000/ 12500 组,误差为:1.7775
第 3/ 8 轮循环,  4000/ 12500 组,误差为:1.7656
第 3/ 8 轮循环,  6000/ 12500 组,误差为:1.6979
第 3/ 8 轮循环,  8000/ 12500 组,误差为:1.6662
第 3/ 8 轮循环, 10000/ 12500 组,误差为:1.6437
第 3/ 8 轮循环, 12000/ 12500 组,误差为:1.6254
第 4/ 8 轮循环,  2000/ 12500 组,误差为:1.5787
第 4/ 8 轮循环,  4000/ 12500 组,误差为:1.5767
第 4/ 8 轮循环,  6000/ 12500 组,误差为:1.5592
第 4/ 8 轮循环,  8000/ 12500 组,误差为:1.5478
第 4/ 8 轮循环, 10000/ 12500 组,误差为:1.5125
第 4/ 8 轮循环, 12000/ 12500 组,误差为:1.5148
第 5/ 8 轮循环,  2000/ 12500 组,误差为:1.4820
第 5/ 8 轮循环,  4000/ 12500 组,误差为:1.4918
第 5/ 8 轮循环,  6000/ 12500 组,误差为:1.4665
第 5/ 8 轮循环,  8000/ 12500 组,误差为:1.4551
第 5/ 8 轮循环, 10000/ 12500 组,误差为:1.4489
第 5/ 8 轮循环, 12000/ 12500 组,误差为:1.4568
第 6/ 8 轮循环,  2000/ 12500 组,误差为:1.4287
第 6/ 8 轮循环,  4000/ 12500 组,误差为:1.4117
第 6/ 8 轮循环,  6000/ 12500 组,误差为:1.4024
第 6/ 8 轮循环,  8000/ 12500 组,误差为:1.3971
第 6/ 8 轮循环, 10000/ 12500 组,误差为:1.4009
第 6/ 8 轮循环, 12000/ 12500 组,误差为:1.3575
第 7/ 8 轮循环,  2000/ 12500 组,误差为:1.3744
第 7/ 8 轮循环,  4000/ 12500 组,误差为:1.3572
第 7/ 8 轮循环,  6000/ 12500 组,误差为:1.3516
第 7/ 8 轮循环,  8000/ 12500 组,误差为:1.3301
第 7/ 8 轮循环, 10000/ 12500 组,误差为:1.3229
第 7/ 8 轮循环, 12000/ 12500 组,误差为:1.3346
第 8/ 8 轮循环,  2000/ 12500 组,误差为:1.3087
第 8/ 8 轮循环,  4000/ 12500 组,误差为:1.2906
第 8/ 8 轮循环,  6000/ 12500 组,误差为:1.3167
第 8/ 8 轮循环,  8000/ 12500 组,误差为:1.2887
第 8/ 8 轮循环, 10000/ 12500 组,误差为:1.3085
第 8/ 8 轮循环, 12000/ 12500 组,误差为:1.2699
保存模型至./cnn.pth======================================
保存完毕
开始测试===================================================
训练集中的准确率为:53 %
测试集中的准确率为:52 %
实际标签:      cat     ship     ship    plane
预测结果:      cat      car      car     ship

这种模型因为卷积核大,参数少,收敛速度快,不容易过拟合。


小结:

以下观点基于个人理解,同真实情况或许有出入,欢迎各位在评论区指正。

关于学习率,训练时,我们可以前几次设置一个较大的学习率,如0.05,加快模型收敛,随着训练的进行,如看到误差不在下降,或者 loss about time 呈现锯齿状,可以逐渐减少学习率。

关于卷积神经网络各层的设置,如果层数多,各层又比较大,参数就会比较多,训练时,开始的收敛速度会比较满,也会容易欠拟合,如果卷积核大,层数少,参数少,训练的会比较快,但是可能会欠拟合。

关于卷积核的大小,可以将卷积核理解为“视界”相当于一次看到的大小,小的话可能会“盲人摸象”,只会看到某个图片的局部特征,不容易在测试集上得到高准确率,卷积核大的话,可能会“眼花缭乱”不容易抓到重点,影响训练速度和准确性的提高。

关于卷积层和全连接层,我个人理解是,卷积层主要用来提取特征,类似人的眼睛,来“扫视”图片,获得信息,而全连接层类似于大脑神经网络,用来对获得的信息做处理及分类。所以,全连接层的某些性质类似神经网络,比如宽而浅的网络可能比较擅长记忆,却不擅长概括,泛化能力差,提升同样效果需要增加的宽度远远超过需要增加的深度。

关于GPU加速,GPU加速最好还是整一个,没有GPU加速,一开始训练CPU占用100%都要训练十几分钟,甚至几十分钟,GPU加速一开,别看GPU占用率没有多少,CPU占用直接下降至20%训练速度也能提升一倍以上,绝对是个好东西。

关于已训练模型的保存和读取,如果你真的很有时间,电脑也很好,电脑费也不贵的话,你可以尝试每训练一轮就测试一下,并把当前模型保存,再一轮训练完后进行比对,如果过拟合了(测试集准确率下降)就回档一下,重新训练,记着设置最大回档此处,别停不下来了。

关于提高准确性的思路,总结以上,可以由大到小设置不同卷积核大小,加深和拓宽全连接层深度(加深比拓宽效果好),设置动态学习率,以及时常根据测试集准确率决定是否回档,执行数据增强。

其他问题:

关于打开绘图窗口而不等待plt.show()返回继续运行代码,本来打算通过多线程解决的,但是发现在主线程之外使用plt.show()可能会失效,不太稳定,于是只能在末尾统一显示。

关于程序中的 i ,本来是用来程序中标记窗口的,但是因为训练时也有一个 i 用来读取了序号,并控制着训练过程的统计及显示。所以显示的窗口名称是 12500 之类的大数字,不过,不影响运行,实在觉着膈应,改个变量名就行。

版本v1.2 加了点没用的回溯操作和变化学习率

import torchvision as tv  # 专门用来处理图像的库
from torchvision import transforms  # transforms用来对图片进行变换
import os  # 用于加载旧模型使用
import torch
import torch.nn as nn  # 神经网络基本工具箱
import torch.nn.functional as fun
import matplotlib.pyplot as plt  # 绘图模块,能绘制 2D 图表# 定义卷积神经网络==========================================================
class ConvNet(nn.Module):  # 类 ConvNet 继承自 nn.Moduledef __init__(self):  # 构造方法# 下式等价于nn.Module.__init__.(self)super(ConvNet, self).__init__()  # 调用父类构造方法# 使用了三个卷积层,四个全连接层# RGB 3*32*32# 卷积层===========================================================self.conv1 = nn.Conv2d(3, 15, 3)  # 输入3通道,输出15通道,卷积核为3*3self.conv2 = nn.Conv2d(15, 75, 4)  # 输入15通道,输出75通道,卷积核为4*4self.conv3 = nn.Conv2d(75, 375, 3)  # 输入75通道,输出375通道,卷积核为3*3# 全连接层=========================================================self.fc1 = nn.Linear(1500, 400)  # 输入2000,输出400self.fc2 = nn.Linear(400, 120)  # 输入400,输出120self.fc3 = nn.Linear(120, 84)  # 输入120,输出84self.fc4 = nn.Linear(84, 10)  # 输入 84,输出 10(分10类)def forward(self, x):# 最大池化步长为2x = fun.max_pool2d(fun.relu(self.conv1(x)), 2)  # 3*32*32  -> 150*30*30  -> 15*15*15x = fun.max_pool2d(fun.relu(self.conv2(x)), 2)  # 15*15*15 -> 75*12*12  -> 75*6*6x = fun.max_pool2d(fun.relu(self.conv3(x)), 2)  # 75*6*6   -> 375*4*4   -> 375*2*2x = x.view(x.size()[0], -1)  # 将375*2*2的tensor打平成1维,(卷积变为全连接)1500x = fun.relu(self.fc1(x))  # 全连接层 1500 -> 400x = fun.relu(self.fc2(x))  # 全连接层 400 -> 120x = fun.relu(self.fc3(x))  # 全连接层 120 -> 84x = self.fc4(x)  # 全连接层 84  -> 10return x# ==========================================================================================================
# 数据预处理
transform = transforms.Compose([transforms.ToTensor(),  # 将图片类型由 PIL Image 转化成tensor类型。转换时会自动归一化transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  # 对图像进行标准化(均值变为0,标准差变为1)# 下载数据集==========================================
print("开始导入数据集==============================================")
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 下载(download) cifar-10 后放到项目中的 dataset 文件夹(root)并分为训练集,测试集,(train)并做预处理(transform)
train_start = tv.datasets.CIFAR10(root="./dataset", train=True, download=True, transform=transform)  # 训练集
test_set = tv.datasets.CIFAR10(root="./dataset", train=False, download=True, transform=transform)  # 测试集
print('训练及图像有:', len(train_start), '张。\n测试集图像有:', len(test_set), '张。')
# 打包数据集 python将多个数据打包处理,能够加快训练速度
batch_size = 4
# 将测试集和训练集每 4个 进行打包,并打乱训练集(shuffle)
train_set = torch.utils.data.DataLoader(train_start, batch_size=batch_size, shuffle=True)  # 训练集
test_set = torch.utils.data.DataLoader(test_set, batch_size=batch_size, shuffle=False)  # 测试集
print("已将将数据集%2d 个打包为一组,加快训练速度" % batch_size)# 设置卷积神经网络和训练参数=================================
print("正在加载卷积神经网络=========================================")
# 如果设备 GPU 能被调用,则转到 GPU 加快运算,否则使用CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = ConvNet().to(device)  # 初始化模型
print(device)
print('可使用GPU加速' if (torch.cuda.is_available()) else '无法开启GPU加速')
criterion = nn.CrossEntropyLoss()  # 交叉熵损失函数# 模型加载==========================================
seat = './cnn.pth'  # 保存位置(名称)
if os.path.exists(seat):  # 如果检测到  seat  文件print("检测到模型文件,是否加载已训练模型(Y\\N):")shuru = input()if shuru == 'Y' or shuru == 'y':model.load_state_dict(torch.load(seat))print("已加载已训练模型")else:print("未加载已训练模型")
else:print("未检测到旧模型文件")# 训练开始==========================================
loop_MAX = 20  # 外循环次数(测试)
loop = 5  # 内循环次数(训练)
print("训练次数为:", loop * loop_MAX)
print("每过 %d 轮执行自动测试以及模型保存" % loop)
print("开始训练===================================================")
Training_accuracy = []  # 记录训练集正确率
Test_accuracy = []  # 记录测试集正确率
process = []  # 记录训练时误差
Test_dot = []  # 记录回溯的点
Test_data = []  # 记录回溯点的值
Test_MAX = 0  # 记录测试集正确率,用于回溯
i = 0  # 函数内使用,提前定义
lentrain = len(train_set)
learning_rate = 0.001  # 基础学习率
print("基础学习率为:", learning_rate)
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)  # 优化器:随机梯度下降算法
for j in range(loop_MAX):  # j 测试轮数if j == int(loop_MAX / 4):learning_rate = 0.0005print("更改学习率为:", learning_rate)optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)  # 优化器:随机梯度下降算法if j == int(loop_MAX / 2):learning_rate = 0.0001print("更改学习率为:", learning_rate)optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)  # 优化器:随机梯度下降算法if j == int(loop_MAX * 3 / 4):learning_rate = 0.0005print("更改学习率为:", learning_rate)optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)  # 优化器:随机梯度下降算法for epoch in range(loop):  # 训练 loop 次  epoch 当前轮训练次数running_loss = 0.0  # 训练误差# 下面这个作用是每轮打乱一次,没什么大用处,不想要可以删去train_set = torch.utils.data.DataLoader(train_start, batch_size=batch_size, shuffle=True)  # 训练集# enumerate() 函数:用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标。for i, (images, labels) in enumerate(train_set, 0):# 转到GPU或CPU上进行运算images = images.to(device)labels = labels.to(device)outputs = model(images)  # 正向传播loss = criterion(outputs, labels)  # 计算batch(四个一打包)误差optimizer.zero_grad()  # 梯度清零loss.backward()  # 反向传播optimizer.step()  # 更新参数# 打印loss信息running_loss += loss.item()  # batch的误差和print("第%2d/%2d 轮循环,%6d/%6d 组,误差为:%.4f"% (epoch + 1, loop, i + 1, lentrain, running_loss / i))process.append(running_loss)running_loss = 0.0  # 误差归零# 模型测试==========================================print("开始第%2d次测试===================================================" % j + 1)#  在训练集上测试====================================correct = 0  # 预测正确图片数total = 0  # 总图片数ii = 0for images, labels in train_set:if ii > int(i / 10):  # 训练集太多了,挑一点测试breakii = ii + 1images = images.to(device)labels = labels.to(device)outputs = model(images)# 返回得分最高的索引(一组 4 个)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum()print("第%d轮训练集上的准确率为:%3d %%" % ((j + 1) * loop, 100 * correct / total), end=' ')Training_accuracy.append(100 * correct / total)#  在测试集上测试====================================correct = 0  # 预测正确图片数total = 0  # 总图片数for images, labels in test_set:images = images.to(device)labels = labels.to(device)outputs = model(images)# 返回得分最高的索引(一组 4 个)_, predicted = torch.max(outputs.data, 1)total += labels.size(0)correct += (predicted == labels).sum()total = 100 * correct / totalprint("\t测试集上的准确率为:%3d %%" % total)Test_accuracy.append(total)# 防止过拟合的回溯操作===============================================if Test_MAX > total:  # 正确率减小,准备回溯model.load_state_dict(torch.load(seat))  # 读取上一次测试的模型来回溯print("正确率降低,进行回溯")Test_dot.append(j)  # 记录回溯点Test_data.append(total)  # 记录正确率,便于绘图else:Test_MAX = total  # 更改最大正确率# 模型保存==========================================torch.save(model.state_dict(), seat)print("已保存模型至%s" % seat)# 绘制训练过程===========================================================
# 从GPU中拿出来才能用来画图
Training_accuracy = torch.tensor(Training_accuracy, device='cpu')
Test_accuracy = torch.tensor(Test_accuracy, device='cpu')
Test_dot = torch.tensor(Test_dot, device='cpu')
Test_data = torch.tensor(Test_data, device='cpu')
plt.figure(1)  # =======================================
plt.plot(list(range(len(process))), process, label='loss')
plt.legend(loc='lower right')  # 显示上面的label
plt.xlabel('time')  # x_label
plt.ylabel('loss')  # y_label
plt.title('loss about time')  # 标题
plt.figure(2)  # =======================================
plt.plot(list(range(len(Training_accuracy))), Training_accuracy, label='Train_set')
plt.plot(list(range(len(Test_accuracy))), Test_accuracy, label='Test_set')
plt.scatter(Test_dot, Test_data, c='r', alpha=0.8, label='Backtracking point')
plt.legend(loc='lower right')  # 显示上面的label
plt.xlabel('time')  # x_label
plt.ylabel('loss')  # y_label
plt.title('Training_accuracy and Test_accuracy')  # 标题
plt.show()  # 显示========================================================

Cifar-10 卷积神经网络 的python实现(绘图,自动下载,模型存取,图片显示,GPU加速)相关推荐

  1. 卷积神经网络算法python实现_自动色彩均衡(ACE)快速算法python实现

    自动色彩均衡(ACE)快速算法 ACE算法源自retinex算法,可以调整图像的对比度,实现人眼色彩恒常性和亮度恒常性,通过差分来计算目标点与周围像素点的相对明暗关系来校正最终像素值,有很好的增强效果 ...

  2. 深度学习教程(10) | 卷积神经网络解读(吴恩达·完整版)

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/35 本文地址:http://www.showmeai.tech/article-det ...

  3. python狗图像识别_TensorFlow卷积神经网络之使用训练好的模型识别猫狗图片

    本文是Python通过TensorFlow卷积神经网络实现猫狗识别的姊妹篇,是加载上一篇训练好的模型,进行猫狗识别 本文逻辑: 我从网上下载了十几张猫和狗的图片,用于检验我们训练好的模型. 处理我们下 ...

  4. 深度学习之 10 卷积神经网络2

    本文是接着上一篇深度学习之 10 卷积神经网络1_水w的博客-CSDN博客 目录 1 出现原因 2 一般结构框架 (1)一般结构框架:卷积层 --利用卷积核提取特征 卷积核的本质: 总结 特征图可视化 ...

  5. 实用卷积神经网络 运用python pdf_解析卷积神经网络—深度学习实践手册 中文pdf高清版...

    解析卷积神经网络-深度学习实践手册从实用角度着重解析了深度学习中的一类神经网络模型--卷积神经网络,向读者剖析了卷积神经网络的基本部件与工作机理,更重要的是系统性的介绍了深度卷积神经网络在实践应用方面 ...

  6. 医学图像处理医学图像处理-卷积神经网络卷积神经网络_基于深度卷积神经网络的刀具磨损量自动提取方法...

    ⬆点击上方蓝色字体,关注<工具技术>官方微信~ 数控加工实质上是刀具和毛坯的相互运动,包含众多的不可控因素,在工件成型的过程中,刀具不可避免发生磨损.为了提高加工效率,实际加工中一般采用高 ...

  7. 卷积神经网络matlab_基于卷积神经网络的遥感图像养殖区自动划分

    基于卷积神经网络的遥感图像养殖区自动划分 摘要:卷积神经网络是目前计算机视觉领域广泛应用的模型.我们在传统卷积神经网络的基础上,替换了全连接层,借助高分辨率图像,对海水养殖区进行识别和标记,最终实现了 ...

  8. python 通达信自动下载收盘和财务数据

    python 通达信自动下载收盘和财务数据,自动启动通达信,鼠标自动操作: 通达信直接从官网下载免费版,可下载财务数据. 自动识别屏幕尺寸(目前为1440x900.1920x1080.1366*768 ...

  9. mac用python爬虫下载图片_使用Python爬虫实现自动下载图片

    python爬虫支持模块多.代码简洁.开发效率高 ,是我们进行网络爬虫可以选取的好工具.对于一个个的爬取下载,势必会消耗我们大量的时间,使用Python爬虫就可以解决这个问题,即可以实现自动下载.本文 ...

  10. python web微信应用(五) 自动下载接收的图片/语音/视频/普通文件

    文章目录 前言 一.webwx 模块介绍 二.自动下载接收的图片/语音/视频/普通文件到本地 前言 本篇文章作为系列第五篇文章,将实现自动下载接收到的图片.语音.视频.普通文件的功能: 系列其它文章请 ...

最新文章

  1. linux下的主要目录
  2. 4412 GPIO读 和 ioremap控制GPIO寄存器
  3. stm32 窗口看门狗学习(一)
  4. 代码改动和配置文件相分离
  5. Linux下编译安装Apache httpd 2.4
  6. 刚刚发现的 xaml里面颜色的定义方式
  7. html三列布局和两列布局,CSS 常见两列布局、三列布局
  8. Zookeeper概念介绍
  9. VRRP实现AC双机备份原理详解与配置实例
  10. 2018-2019-2 20165206《网络对抗技术》Exp1 PC平台逆向破解
  11. 求n的阶乘【VB代码实现】
  12. unity移动平台阴影解决方案
  13. 【教程】无需下载任何软件,使win10任务栏完全透明!
  14. 使用 Visio 绘制卷积示意图
  15. element-ui走马灯使用心得
  16. 解决AS3.5在oppo系统更新后无法打包apk问题
  17. 「MacTeX 小笔记」LaTeX 学习资料推荐篇
  18. Oracle 数据库中的 时间 时区
  19. python打开paint并画一个圆
  20. 机器视觉VS计算机视觉

热门文章

  1. 密信国密浏览器:推动SM2国密算法和国密SSL证书应用
  2. android 11(R)预装APP到data/app目录
  3. Android ListView item信息显示不全
  4. Spring boot 集成rocketMQ 官方文档
  5. OSChina 周二乱弹 —— 10月份结婚,媳妇要出去锻炼下自己
  6. 关于Eclipse中突然冒出一个configure build path的提示
  7. 分析Java堆:内存溢出的原因
  8. android刺激战场不卡机型,835不是安卓高端机? 刺激战场: 不是
  9. 论文解读:DCSpell:A Detector-Corrector Framework for Chinese Spelling Error Correction
  10. 修改jdk环境变量后,在cmd中看版本没有变化