Pytorch 安装
进入官网:: Pytorch.官网链接.
选择系统的版本、按装的方式,生成相应的安装代码命令。
示例:pip 安装
生成的安装命令:
pip3 install torch==1.8.1+cu102 torchvision==0.9.1+cu102 torchaudio===0.8.1 -f https://download.pytorch.org/whl/torch_stable.html
在电脑端打开终端:(cmd打开窗口)
输入复制生成的指令:
conda 方式安装
生成的安装命令:
conda install pytorch torchvision torchaudio cudatoolkit=10.2 -c pytorch
在电脑端打开终端:(cmd打开窗口)
在官网上可找到:训练一个分类器
: 官方网页链接.
LeNet 的网络架构:
包含三个.py文件
① model.py文件
# model.py
import torch.nn as nn
import torch.nn.functional as F
class LeNet(nn.Module): # 定义一个类,继承自nn.Module
def __init__(self): # 定义从初始化函数
super(LeNet, self).__init__() # super()继承父类的构造函数,就是调用基类的构造函数
self.conv1 = nn.Conv2d(3, 16, 5) # 参数依次为:通道数,卷积核个数,卷积核的尺寸
self.pool1 = nn.MaxPool2d(2, 2) # 第一下采样层采用的最大特征采样
self.conv2 = nn.Conv2d(16, 32, 5)
self.pool2 = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(32*5*5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10)
def forward(self, x):
x = F.relu(self.conv1(x)) # input(3, 32, 32) output(16, 28, 28) # 16就是卷积核的个数,28 按照公式 (32-5+2*0)/ 1 + 1 = 28
x = self.pool1(x) # output(16, 14, 14)
x = F.relu(self.conv2(x)) # output(32, 10, 10)
x = self.pool2(x) # output(32, 5, 5)
x = x.view(-1, 32*5*5) # output(32*5*5)
x = F.relu(self.fc1(x)) # output(120)
x = F.relu(self.fc2(x)) # output(84)
x = self.fc3(x) # output(10)
return x
# # 添加调试代码 可以查看卷积过程的变量数据变化
# import torch
# input1 = torch.rand([32, 3, 32, 32])
# model = LeNet()
# print(model)
# output = model(input1)
② train.py 文件
# train.py
import torch
import torchvision
import torch.nn as nn
from model import LeNet
import torch.optim as optim
import torchvision.transforms as transforms
# 如果想看加载数据集图片效果,需要导入的库
import numpy as np
import matplotlib.pyplot as plt
def main():
transform = transforms.Compose(
[transforms.ToTensor(), # 数据张量化
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) # 数据标准化
# # 50000张训练图片
# # 第一次使用时要将download设置为True才会自动去下载数据集
train_set = torchvision.datasets.CIFAR10(root='./data', train=True,
download=False, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=36, # 分批次进行 训练: 每一次随机拿出36张图片进行训练
shuffle=True, num_workers=0) # shuffle 是否将数据集打乱 num_workers 理解为载入数据的线程数,Linux下可以为非零参数,Windows下为0
# # 10000张验证图片
# # 第一次使用时要将download设置为True才会自动去下载数据集
val_set = torchvision.datasets.CIFAR10(root='./data', train=False,
download=False, transform=transform) # 在导入图片的时候进行了处理
val_loader = torch.utils.data.DataLoader(val_set, batch_size=10000,
shuffle=False, num_workers=0)
val_data_iter = iter(val_loader) # 设置迭代器
val_image, val_label = val_data_iter.next()
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# # 利用官方的代码加载查看数据集
# # functions to show an image
# def imshow(img):
# img = img / 2 + 0.5 # unnormalize 反标准化
# npimg = img.numpy()
# plt.imshow(np.transpose(npimg, (1, 2, 0)))
# plt.show()
# # print labels
# print(' '.join('%5s' % classes[val_label[j]] for j in range(4)))
# # show images
# imshow(torchvision.utils.make_grid(val_image))
net = LeNet() # 实例化网络
loss_function = nn.CrossEntropyLoss() # 定义损失函数,其中已经包含了 logSoftmax 和 NLLLose 函数
optimizer = optim.Adam(net.parameters(), lr=0.001) # 传入训练的参数 , 学习率
# 训练过程
for epoch in range(5): # loop over the dataset multiple times 将训练集迭代5次
running_loss = 0.0 # 累加训练过程中的损失
for step, data in enumerate(train_loader, start=0): # 循环遍历训练集样本
# get the inputs; data is a list of [inputs, labels]
inputs, labels = data
# zero the parameter gradients
optimizer.zero_grad() # 清除历史梯度,如果不清除掉历史梯度,就会对计算的历史梯度进行累加(通过这个特性你可以变相的实现一个很大batch数值的训练)
# forward + backward + optimize
outputs = net(inputs) # 图片输入网络,得到输出
loss = loss_function(outputs, labels) # 通过损失函数计算损失 outputs 对应网络预测的值, labels 对应输入图片的真实标签
loss.backward() # 将得到的损失进行反向传播
optimizer.step() # 通过优化器函数进行参数的更新
# print statistics
running_loss += loss.item() # 累加损失变量
if step % 500 == 499: # print every 500 mini-batches
with torch.no_grad(): # with是一个上下文管理器,相对重要 /作用:在接下来的计算中,不会去计算每个节点的误差损失梯度 节省算力/内存资源
outputs = net(val_image) # [batch, 10] # 正向传播
predict_y = torch.max(outputs, dim=1)[1] # 网络预测最可能是哪个类别 ---> 找到对应的下标索引
accuracy = torch.eq(predict_y, val_label).sum().item() / val_label.size(0) # 预测的标签类别与真实标签类别进行比较 相同的返回1/true,不同的返回0/false
# 且求和得到本次预测过程中,准确预测的样本比例 ,最终结果形式是 张量
print('[%d, %5d] train_loss: %.3f test_accuracy: %.3f' %
(epoch + 1, step + 1, running_loss / 500, accuracy)) # 打印出 迭代次数,某次迭代具体的哪一步,每500步的平均训练误差,测试样本的准确率
running_loss = 0.0 # 将训练误差归零,进行下500步的迭代过程
print('Finished Training')
# 保存模型
save_path = './Lenet.pth'
torch.save(net.state_dict(), save_path)
if __name__ == '__main__':
main()
③ predict.py 文件
预测代码: predict.py 文件
# predict.py
import torch
import torchvision.transforms as transforms
from PIL import Image
from model import LeNet
# def main():
transform = transforms.Compose(
[transforms.Resize((32, 32)), # 测试图片转换为 32 * 32 大小
transforms.ToTensor(), # 张量化处理
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) # 标准化处理
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
net = LeNet()
net.load_state_dict(torch.load('Lenet.pth'))
im = Image.open('text.jpg')
im = transform(im) # 预处理之后的图片通道[C, H, W] # pytorch tensor 的通道排序是[batch, channel, height, width]
im = torch.unsqueeze(im, dim=0) # [N, C, H, W] # 使用函数,增加一个维度batch
with torch.no_grad():
outputs = net(im)
predict = torch.max(outputs, dim=1)[1].data.numpy()
# predict = torch.softmax(outputs, dim=1) # 显示张量的测试结果(每一个分类对应的测试概率)
# print(predict)
print(classes[int(predict)])
# if __name__ == '__main__':
# main()
model.py文件的解析
在编辑器中打开:
查看内置函数的详细定义
点击内置函数,按住Ctrl,点击鼠标右键,可以进入内置函数的详细定义
如查看: init() 初始化函数的定义:
另外,函数定义也可以在pytorch 的官网文档中查找说明:
如:Conv2d
pytorch 的官方文档使用
神经网络卷积与池化过程代码解析
神经网络第一层卷积和池化
具体数据计算:
16就是卷积核的个数,28 按照公式 (32-5+2*0)/ 1 + 1 = 28
这里w=32, F = 5, P = 0, S=1,
注意:这里的代码中 卷积参数 batch 没有 表示出来(一次输入多少张图片)
经过第一层的池化,把特征矩阵降维到原来的一半,卷积深度不变
神经网络的第二层卷积和池化
第二个下采样层与 第一个相同,用 22 ,步距为2 的池化核 ,将特征维度再次缩减为原来的一半。得到深度为32,55的特征矩阵。
全连接层
接下来是全连接层。将得到的特征矩阵进行矩阵的展平,成为一个一维向量
网络节点参数:
先理解一点:通常,一般无法分析计算人工神经网络中每层使用的层数或节点数,以解决特定的实际预测建模问题。
每层中的层数和节点数是必须指定的模型超参数。
你可能是第一个尝试使用神经网络解决自己的特定问题的人。在你之前没有人解决过它。
需要使用系统的实验来发现对特定数据集最有效的方法。
注意这里传入的最后一个参数: 10
官网中的数据集是:CIFAR10,一共是分了10个类别
正向传播过程
定义函数:
def forward(self, x): # x 代表输入的数据
x = F.relu(self.conv1(x)) # input(3, 32, 32) output(16, 28, 28) # 16就是卷积核的个数,28 按照公式 (32-5+2*0)/ 1 + 1 = 28
x = self.pool1(x) # output(16, 14, 14)
x = F.relu(self.conv2(x)) # output(32, 10, 10)
x = self.pool2(x) # output(32, 5, 5)
x = x.view(-1, 32*5*5) # output(32*5*5)
x = F.relu(self.fc1(x)) # output(120)
x = F.relu(self.fc2(x)) # output(84)
x = self.fc3(x) # output(10)
return x
具体数据含义:
x 代表输入的数据
· F.relu()是激活函数
· F.view()函数将得到的特征矩阵展开为一维向量, -1 代表第一个 维度(batch),32×5×5是展平特征向量后的节点个数
self.fc1(x) 表示全连接层作用之后,将得到的一维向量分别通过下面的全连接1层以及激活函数的处理;全连接2层以及激活函数的处理,最终通过全连接层3得到最终的输出。
train.py文件解析
下载数据:
更改train.py文件进行训练数据集的下载,可以先将全部代码注释掉,只留下下载的代码运行:
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
# 50000张训练图片
# 第一次使用时要将download设置为True才会自动去下载数据集
train_set = torchvision.datasets.CIFAR10(root='./data', train=True,
download=True, transform=transform)
下载完以后,记得再把True 改为 False
下载的时候可以查看使用的具体函数定义:
张量化函数 : transforms.ToTensor()
ctrl + 鼠标右击查看(有兴趣深入的,其他函数同理可以自己看)
内置函数说明
标准化函数 : transforms.Normalize()
同时: Pytorch 官网储备有很多其他的数据集可以下载
可以 通过 torchvision.datasets.() 查看:
以上述相同的方式下载。
利用官方的代码加载查看数据集
相比官方的代码,修改了部分变量名 ,修改了batch_size的大小 10000 & 4
# functions to show an image
# 需要手动添加导入的库
# import numpy as np
# import matplotlib.pyplot as plt
def imshow(img):
img = img / 2 + 0.5 # unnormalize 反标准化
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
# print labels
print(' '.join('%5s' % classes[val_label[j]] for j in range(4)))
# show images
imshow(torchvision.utils.make_grid(val_image))
数据集图片 显示效果:随机载入4张图片
实例化网络
定义损失函数
loss_function = nn.CrossEntropyLoss() # 定义损失函数,其中已经包含了 logSoftmax 和 NLLLose 函数
定义优化器
optimizer = optim.Adam(net.parameters(), lr=0.001) # 传入训练的参数 , 学习率
为什么每计算一个batch, 就要调用以一次optimizer.zero_grad() 函数:
optimizer.zero_grad() 梯度清零函数
函数作用:清除历史梯度,如果不清除掉历史梯度,就会对计算的历史梯度进行累加
(通过这个特性你可以变相的实现一个很大batch数值的训练)
补充理解:
目前,我们在训练神经网络模型时,一般采用批梯度训练,大量实验表明,超参数batch size会影响模型收敛速度(训练时间)和模型效果。
通常,batch size越小,模型的收敛速度越慢;batch size越大,模型收敛速度越快,性能一般也会好一些。但是受限于设备的显存,我们不可能一直增大batch size。所以,大多数情况下,在一个batch中先累加多个mini_batch计算的梯度,再对这个梯度进行反向传播。
就是将整个dataset分成多个batch,分别将每个batch分成多个mini_batch,将每个mini_batch喂给神经网络,计算loss,计算梯度,并将梯度保存下来,先不进行反向传播。再对一个batch中的所有mini_batch得到的梯度进行累加,并进行反向传播。等同于将一个batch喂给神经网络,计算loss,计算梯度,再进行反向传播。这样就可以根据显存大小,实现任何batch_size 大小的批梯度训练。
batch_size 的范围是 [1, len(dataset)]。
如果你有更多的显存,就把mini_batch_size 设大一点,显存不足则将mini_batch_size设小一点。这个思想在 Tensorflow 和 Pytorch 中的都有体现
with torch.no_grad():
with是一个上下文管理器,这个函数相对比较重要 ,作用:在这个函数接下来的计算中,不会去计算每个节点的误差损失梯度 ,可以 节省算力/减少内存资源的占用。
在测试,预测环节都应当使用这个函数。
训练结果
保存训练模型权重文件 Lenet.pth 文件
这里的训练结果并没有进行学习率的调整,而且考虑到该网络提出时间在1998年,所以,精确度还是相对不错的。
predect.py文件解析
另外找张10个类别中的图片,通过predect.py文件加载训练好的模型进行测试,就可以得到预测的结果和准确率。
text.jpg
不同形式的显示结果:
softmax() 函数返回的是测试的概率
涉及的内容:
pytorch的安装
LeNet网络结构
通过pytorch搭建LeNet网络模型
卷积层、池化层、全连接层的代码构建,定义了损失函数、优化器、正向传播过程等
下载,显示了 pytorch官方CIFAR10数据集并导入网络模型
进行了网络训练,并将训练好的模型进行保存,通过预测的脚本进行训练模型效果预测
本文并未使用GPU加速进行训练,而且官方给出了使用GPU加速的指导说明:
或者多线程GPU训练:
GPU 加速训练是必须掌握的技能,后续会补上更新的训练代码。
文章
https://blog.csdn.net/lxy_2011/article/details/98209706
https://blog.csdn.net/weixin_41560402/article/details/106930463
https://blog.csdn.net/Kefenggewu_/article/details/108294039
视频:
https://www.bilibili.com/video/BV187411T7Ye