文章目录
- 1、pytorch安装
- 2、Lenet简介
- 3、代码
- Conv2d和_MaxPoolNd参数介绍
- model.py
- train.py
- predict.py
1、pytorch安装
2、Lenet简介
Lenet网络结构:卷积-下采样层-卷积-下采样层-全连接层-全连接层-全连接层
Lenet网络:pytorch tensor的通道顺序:[batch,channel,height,width]
batch:每一批的数量
channel:通道的数量,对于彩色图片有RGB三个通道,channel=3
3、代码
Conv2d和_MaxPoolNd参数介绍
- pytorch通过Conv2d定义卷积层
Conv2d各个参数(Pycharm中通过Ctrl+单击查看)
def __init__(
self,
in_channels: int, # 输入特征矩阵的深度
out_channels: int, # 使用卷积核的个数
kernel_size: _size_2_t, # 卷积核大小
stride: _size_2_t = 1, # 步距,默认=1
padding: _size_2_t = 0, #在四周补0处理,默认=0
dilation: _size_2_t = 1,
groups: int = 1,
bias: bool = True, # 偏执,默认使用
padding_mode: str = 'zeros' # TODO: refine this type
):
- pytorch通过MaxPool2d定义下采样层
MaxPool2d继承了父类_MaxPoolNd
_MaxPoolNd各个参数
def __init__(self, kernel_size: _size_any_t, stride: Optional[_size_any_t] = None,
padding: _size_any_t = 0, dilation: _size_any_t = 1,
return_indices: bool = False, ceil_mode: bool = False) -> None:
super(_MaxPoolNd, self).__init__()
self.kernel_size = kernel_size # kernel_size池化和大小
self.stride = stride or kernel_size # 步距,未指定步距就与池化和大小一致
self.padding = padding
self.dilation = dilation
self.return_indices = return_indices
self.ceil_mode = ceil_mode
model.py
import torch.nn as nn
import torch.nn.functional as F
class LeNet(nn.Module):
# 初始化函数 搭建所需要的网络层结构
def __init__(self):
super(LeNet, self).__init__()
# 第一个卷积层conv1
# Conv2d第一个参数=3代表输入特征层的深度(RGB3个通道)
# Conv2d第二个参数=16表示使用的卷积核的个数=16
# Conv2d第三个参数=5表示卷积核的尺寸是5*5
self.conv1 = nn.Conv2d(3, 16, 5)
# 第一个下采样层pool1
# 池化和大小为2*2,步距=2
self.pool1 = nn.MaxPool2d(2, 2)
# 第二个卷积层
self.conv2 = nn.Conv2d(16, 32, 5)
# 第二个下采样层pool1
# 池化和大小为2*2,步距=2
self.pool2 = nn.MaxPool2d(2, 2)
# 开始全连接层
# 全连接层输入为一维向量
self.fc1 = nn.Linear(32*5*5, 120) # 第一个全连接层
self.fc2 = nn.Linear(120, 84) # 第二个全连接层
# 输出根据训练集来选择,本例具有10个分类类别,选择10
self.fc3 = nn.Linear(84, 10) # 第三个全连接层
# 正向传播过程
def forward(self, x):
# 第一个卷积层
# input(3, 32, 32) output(16, 28, 28)
# 根据公式N=(W-F+2*P)/S+1计算经卷积之后的矩阵尺寸大小
# 已知输入特征的高和宽W=32,卷积核的大小F=5,padding默认P=0,stride=1
# 故N=(32-5)/1+1=28,且使用的卷积核的个数=16,故output(16, 28, 28)
x = F.relu(self.conv1(x))
# 第一个下采样层
# 经过池化和之后,高度和宽度缩小为原来一半28/2,深度不变
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)
# 开始和全连接层拼接
# .view展成一维的,-1是因为LeNet的tensor第一维的参数是batch,自动推理
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)
# 由于在计算损失交叉熵的过程中已经实现了更加高效的softmax方法,因此不需要添加softmax层了
return x
# 测试
# import torch
# input1 = torch.rand([32, 3, 32, 32])
# model =LeNet()
# print(model)
# output = model(input1)
train.py
import numpy as np
import torch
import torchvision
import torch.nn as nn
from model import LeNet
import torch.optim as optim
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
def main():
transform = transforms.Compose(# Compose将所使用的预处理方法(ToTensor()和Normalize)打包成一个整体
[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_set导入进来,并分成一个批次一个批次的,shuffle是否将数据集打乱
train_loader = torch.utils.data.DataLoader(train_set, batch_size=36,
shuffle=True, num_workers=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) #num_workers在Windows下只能=0
# 将val_loader转化成可迭代的迭代器
val_data_iter = iter(val_loader)
val_image, val_label = val_data_iter.next() # 使用next获取图像以及图像的标签值,获取全部图像10000张
# 导入标签
classes = ('plane', 'car', 'bird', 'cat',
'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
# 简单查看测试集中的4张图片,需要把val_loader的batch_size改成=4
# 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() # 实例化模型
# 定义损失函数,CrossEntropyLoss已经包含了softmax函数了
loss_function = nn.CrossEntropyLoss()
# 使用Adam优化器,第一个参数为需要训练的参数,此例为LeNet的所有参数;学习率lr=0.001
optimizer = optim.Adam(net.parameters(), lr=0.001)
# 训练集迭代5次
for epoch in range(5): # loop over the dataset multiple times
running_loss = 0.0 # 累加损失
# 遍历训练集样本
# 使用enumerate函数,不仅会返回每一批的data,还对返回相应的索引,start=0从0开始
for step, data in enumerate(train_loader, start=0):
# get the inputs; data is a list of [inputs, labels]
# 将得到的数据分为inputs和对应的标签labels
inputs, labels = data
# zero the parameter gradients
# 将历史损失梯度函数清零,帮助实现很大的batch训练
optimizer.zero_grad()
# forward + backward + optimize
# 将所有图片inputs输入到网络中进行正向传播
outputs = net(inputs)
# 计算损失,outputs是网络预测值,labels是对应的真实标签
loss = loss_function(outputs, labels)
# 将loss进行反向传播
loss.backward()
# 通过优化器的函数进行参数更新
optimizer.step()
# print statistics打印
running_loss += loss.item()
# 每训练500次打印一次
if step % 500 == 499: # print every 500 mini-batches
with torch.no_grad(): # 在接下来的计算中不计算每个节点的误差损失梯度,避免占用更多的算力
outputs = net(val_image) # [batch, 10]正向传播
# 寻找输出的最大的index 由于第0个维度对应的是batch,故选择dim=1,从10个类别中寻找最大
predict_y = torch.max(outputs, dim=1)[1] # [1]表示只需index值既可,不需要知道具体值
# 判断预测的label和实际的label是否相等
# 通过sum求和预测对了多少样本(此时得到的是Tensor)
# 通过.item()拿到对应的数值,再除训练样本的个数
accuracy = (predict_y == val_label).sum().item() / val_label.size(0)
# epoch训练迭代的轮数,在某一轮的多少步,训练过程中累加的误差/500得到平均误差,测试样本的准确率
print('[%d, %5d] train_loss: %.3f test_accuracy: %.3f' %
(epoch + 1, step + 1, running_loss / 500, accuracy))
# 将损失误差清零开始下一轮500步的迭代
running_loss = 0.0
print('Finished Training')
save_path = './Lenet.pth'
torch.save(net.state_dict(), save_path)# 模型的参数进行保存
if __name__ == '__main__':
main()
predict.py
import torch
import torchvision.transforms as transforms
from PIL import Image
from model import LeNet
transform = transforms.Compose(
[transforms.Resize((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() # 实例化LeNet
net.load_state_dict(torch.load('Lenet.pth')) # 载入训练生成的权重文件
# 载入图像
im = Image.open('1.jpg')
im = transform(im) # [C, H, W]预处理成pytorch能处理的tensor格式
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()#取到最大的index,赋值给predict
predict = torch.softmax(outputs,dim=1) # 对第一个维度进行处理,第0维为batch
print(predict)
#print(classes[int(predict)]) # 将index传入classes
目录结构