目录
1、model.py文件 (预训练的模型)
2、train.py文件(会产生训练好的.th文件)
3、predict.py文件(预测文件)
4、结果展示:
1、model.py文件 (预训练的模型)
import torch.nn as nn
import torch.nn.functional as F
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
# RGB图像; 这里用了16个卷积核;卷积核的尺寸为5x5的
self.conv1 = nn.Conv2d(3, 16, 5) # 输入的是RBG图片,所以in_channel为3; out_channels=卷积核个数;kernel_size:5x5的
self.pool1 = nn.MaxPool2d(2, 2) # kernal_size:2x2 stride:2
self.conv2 = nn.Conv2d(16, 32, 5) # 这里使用32个卷积核;kernal_size:5x5
self.pool2 = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(32*5*5, 120) # 全连接层的输入,是一个一维向量,所以我们要把输入的特征向量展平。
# 将得到的self.poolx(x) 的output(32,5,5)展开; 图片上给的全连接层是120
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10) # 这里的10,是需要根据训练集修改的
def forward(self, x): # 正向传播
# Pytorch Tensor的通道排序:[channel,height,width]
'''
卷积后的尺寸大小计算:
N = (W-F+2P)/S + 1
其中,默认的padding:0 stride:1
①输入图片大小:WxW
②Filter大小 FxF (卷积核大小)
③步长S
④padding的像素数P
'''
x = F.relu(self.conv1(x)) # 输入特征图为32x32大小的RGB图片; input(3,32,32) output(16,28,28)
x = self.pool1(x) # 经过最大下采样会将图片的高度和宽度:缩小为原来的一半 output(16,14,14) 池化层,只改变特征矩阵的高和宽;
x = F.relu(self.conv2(x)) # output(32, 10, 10) 因为第二个卷积层的卷积核大小是32个,这里就是32
x = self.pool2(x) # 经过最大下采样会将图片的高度和宽度:缩小为原来的一半output(32, 5, 5)
x = x.view(-1, 32*5*5) # x.view() 将其展开成一维向量,-1表示第一个维度batch需要自动推理
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
return x
# 测试下
# import torch
# input1 = torch.rand([32,3,32,32])
# model = LeNet()
# print(model)
# output = model(input1)
2、train.py文件(会产生训练好的.th文件)
import matplotlib.pyplot as plt
import numpy as np
import torch.utils.data
import torchvision
from torch import nn, optim
from torchvision import transforms
from pilipala_pytorch.pytorch_learning.Test1_pytorch_demo.model import LeNet
# 1、下载数据集
# 图形预处理 ;其中transforms.Compose()是用来组合多个图像转换操作的,使得这些操作可以顺序地应用于图像。
transform = transforms.Compose(
[transforms.ToTensor(), # 将PIL图像或ndarray转换为torch.Tensor,并将像素值的范围从[0,255]缩放到[0.0, 1.0]
transforms.Normalize((0.5, 0.5, 0.5),(0.5, 0.5, 0.5))] # 对图像进行标准化;标准化通常用于使模型的训练更加稳定。
)
# 50000张训练图片
train_ds = torchvision.datasets.CIFAR10('data',
train=True,
transform=transform,
download=False)
# 10000张测试图片
test_ds = torchvision.datasets.CIFAR10('data',
train=False,
transform=transform,
download=False)
# 2、加载数据集
train_dl = torch.utils.data.DataLoader(train_ds, batch_size=36, shuffle=True, num_workers=0) # shuffle数据是否是随机提取的,一般设置为True
test_dl = torch.utils.data.DataLoader(test_ds, batch_size=10000, shuffle=True, num_workers=0)
test_image,test_label = next(iter(test_dl)) # 将test_dl 转换为一个可迭代的迭代器,通过next()方法获取数据
classes = ('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')
'''
标准化处理:output = (input - 0.5) / 0.5
反标准化处理: input = output * 0.5 + 0.5 = output / 2 + 0.5
'''
# 测试下展示图片
# def imshow(img):
# img = img / 2 + 0.5 # unnormalize 反标准化处理
# npimg = img.numpy()
# plt.imshow(np.transpose(npimg, (1,2,0)))
# plt.show()
#
# # 打印标签
# print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
# imshow(torchvision.utils.make_grid(test_image))
# 实例化网络模型
net = LeNet()
# 定义相关参数
loss_function = nn.CrossEntropyLoss() # 定义损失函数
optimizer = optim.Adam(net.parameters(), lr=0.001) # 定义优化器, 这里使用的是Adam优化器
# 训练过程
for epoch in range(5): # 定义循环,将训练集迭代多少轮
running_loss = 0.0 # 叠加,训练过程中的损失
for step,data in enumerate(train_dl,start=0): # 遍历训练集样本
inputs, labels = data # 获取图像及其对应的标签
optimizer.zero_grad() # 将历史梯度清零;如果不清除历史梯度,就会对计算的历史梯度进行累加
outputs = net(inputs) # 将输入的图片输入到网络,进行正向传播
loss = loss_function(outputs, labels) # outputs网络预测的值, labels真实标签
loss.backward()
optimizer.step()
running_loss += loss.item()
if step % 500 == 499:
with torch.no_grad(): # with 是一个上下文管理器
outputs = net(test_image) # [batch,10]
predict_y = torch.max(outputs, dim=1)[1] # 网络预测最大的那个
accuracy = (predict_y == test_label).sum().item() / test_label.size(0) # 得到的是tensor (predict_y == test_label).sum() 要通过item()拿到数值
print("[%d, %5d] train_loss: %.3f test_accuracy:%.3f" % (epoch + 1, step + 1, running_loss / 500, accuracy))
running_loss = 0.0
print('Finished Training')
save_path = './Lenet.pth' # 保存模型
torch.save(net.state_dict(), save_path) # net.state_dict() 模型字典;save_path 模型路径
测试下展示图片:
运行下,train.py文件,看下正确率、损失率:
3、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()
net.load_state_dict(torch.load('Lenet.pth')) # 加载train里面的训练好 产生的模型。
im = Image.open('2.jpg') # 载入准备好的图片
im = transform(im) # 如果要将图片放入网络,进行正向传播,就得转换下格式 得到的结果为:[C,H,W]
im = torch.unsqueeze(im, dim=0) # 增加一个维度;得到 [N,C,H,W],从而模拟一个批量大小为1的输入。
with torch.no_grad(): # 不需要计算损失梯度
outputs = net(im)
predict = torch.max(outputs, dim=1)[1].data.numpy() # outputs是一个张量;torch.max()用于找到张量在指定维度上的最大值;
# torch.max()函数返回两个张量,一个包含最大值,另一个包含最大值的作用。
# .data()属性用于从变量中提取底层的张量数据。直接使用.data()已经被认为是不安全的,推荐使用.detach()
# .numpy() 表示将pytorch转换成numpy数组,从而使用numpy库的各种功能来操作数据。
print(classes[int(predict)])
# predict = torch.softmax(outputs,dim=1) # 可以返回概率
# print(predict)
4、结果展示:
返回结果:预测是猫的概率为 86%。