1 环境配置
python 3.6.10
pytorch 1.3.1
torchvision 0.4.1
Pillow 5.2.0
numpy 1.18.1
2 说明
2.1)关于数据一般情况下处理图像、文本、音频和视频数据时,可以使用标准的Python包来加载数据到一个numpy数组中 然后把这个数组转换torch.*Tensor ?图像可以使用 Pillow, OpenCV ?音频可以使用 scipy, librosa ?文本可以使用原始Python和Cython来加载,或者使用 NLTK或 SpaCy 处理eg1:特别的,对于图像任务,我们创建了一个包 torchvision,它包含了处理一些基本图像数据集的方法。这些数据集包括 Imagenet、CIFAR10、MNIST 等。除了数据加载以外,torchvision 还包含了图像转换器: torchvision.datasets和 torch.utils.data.DataLoader。 eg2:PyTorch Tensor的通道排序:[batch,channel,height,width]2.2)改进神经网络提高图像分类的准确率---》动model 1)使用多层小卷积核 3*3 2)使用BN
3 LeNet结构
4 model.py
import torch.nn as nn
import torch.nn.functional as F# 定义一个类,继承父类,实现两个方法
class LeNet(nn.Module):# 【1】初始化函数,实现在搭建网络过程中,需要所使用的一些网络层结构def __init__(self):super(LeNet, self).__init__()self.conv1 = nn.Conv2d(3, 16, 5) # 输入特征层深度,卷积核的个数,卷积核的大小5*5# self.batch1 = nn.BatchNorm2d(16)self.pool1 = nn.MaxPool2d(2, 2)self.conv2 = nn.Conv2d(16, 32, 5)# self.batch1 = nn.BatchNorm2d(16)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)
# 输出是根据训练集进行修改的,cifar10是只有10个类别的分类任务# 【2】在此过程中来实现正向传播的过程
# x 是输入的数据,它是Tensor[batch,channel,height,width]def forward(self, x):x = F.relu(self.conv1(x)) # 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)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)
5 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# Compose 将图像的预处理方法打包成一个整体
transform = transforms.Compose([transforms.ToTensor(), # 把PIL Image/ numpy.ndarray 转换成tensortransforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])# 50000张训练图片;torchvision.datasets里面有很多数据集可以供我们下载使用。
# cifar数据集的下载, 下载位置当前目录的data文件下, train为真的时候导入cifar10的训练样本
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,# TRUE就是可以下载,transform对图像进行预处理的函数download=False, transform=transform)# 此函数是将刚刚的训练集导入,分成一个批次一个批次,每一批随机拿出36张图进行训练
trainloader = torch.utils.data.DataLoader(trainset, batch_size=36,# 是否要将数据集打乱,载入数据的线程数shuffle=True, num_workers=0)# 10000张测试图片
testset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)# batch_size=10000 一次性全部拿出来,来计算测试集的准确率
testloader = torch.utils.data.DataLoader(testset, batch_size=10000,shuffle=True, num_workers=0)# 将testloader转换成可迭代的迭代器,它的next方法能获取到测试图片,和图片对应的标签
test_data_iter = iter(testloader)
test_image, test_label = test_data_iter.next()classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')# def imshow(img):
# img = img / 2 + 0.5 # 反标准化
# npimg = img.numpy() # 将图片转化为原来的numpy格式
# plt.imshow(np.transpose(npimg, (1,2,0))) # 转化为原始的shape格式
# plt.show()
#
#
# # print labels
# print(' '.join('%5s' % classes[test_label[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)# optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) 使用带动量的随机梯度下降
# # Adam 参数betas=(0.9, 0.99)
# #optimizer = torch.optim.Adam(net.parameters(), lr=0.001, betas=(0.9, 0.98))for epoch in range(20): # loop over the dataset multiple times;训练集迭代多少次# 累加训练过程中的损失running_loss = 0.0# 通过这个循环来遍历训练集的样本,不仅能返回每一批的训练数据data,还会返回每一批data对应的步数for step, data in enumerate(trainloader, start=0):# get the inputs; data is a list of [inputs, labels]# 输入的图像,对应的标签inputs, labels = data# zero the parameter gradients# 历史损失梯度清零,每次计算一个batch都要调用一次# 如果不清楚历史梯度,就会对计算的历史梯度进行累加(通过这个特性可以变相的实现一个很大的batch数值训练)optimizer.zero_grad()# ------------------------------------# forward + backward + optimizeoutputs = net(inputs)loss = loss_function(outputs, labels)# ------------------------------------# 把loss进行反向传播,optimizer.step()对参数进行更新loss.backward()optimizer.step()# print statisticsrunning_loss += loss.item()if step % 500 == 499: # print every 500 mini-batches# with是一个上下文管理器,在接下来的计算过程中,在测试集中不要计算每个节点的误差梯度# 在预测过程中,要加上这个函数,下面管理范围内都不会计算误差梯度with torch.no_grad():# 把测试集传入--(正向传播)-》得到结果outputs = net(test_image) # [batch, 10]# 输出是10个标签的能量。 一个类别的能量越大,神经网络越认为它是这个类别。所以让我们得到最高能量的标签。# 寻找输出的最大的index位置,即网络预测最大可能属于哪个类# _, predicted = torch.max(outputs, 1)--》每行选择一个最大值--》得到预测的标签类别predict_y = torch.max(outputs, dim=1)[1]# 维度是1上寻找最大值accuracy = (predict_y == test_label).sum().item() / test_label.size(0)# (predict_y == test_label).sum()预测正确的个数,这是tensor---》想要获得数值.item();# test_label.size(0) 是10000个测试样本数目# 训练迭代到第几轮,某一轮的第几步,500步的平均误差,测试样本的准确率print('[%d, %5d] train_loss: %.3f test_accuracy: %.3f' %(epoch + 1, step + 1, running_loss / 500, accuracy))running_loss = 0.0print('Finished Training')# 通过这个函数将网络中所有的参数保存,位置在save_path中
save_path = './Lenet.pth'
torch.save(net.state_dict(), save_path)
6.predict.py
import torch
import torchvision.transforms as transforms
from PIL import Image
from model import LeNettransform = transforms.Compose([transforms.Resize((32, 32)), # 图片大小不一,所以需要resizetransforms.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'))# 通过from PIL import Image此模块来载入图像
im = Image.open('2.jpg') # [H,W,C]--->需要转换成tensor
im = transform(im) # [C, H, W]# 对数据加一个新的维度,dim=0 在最前面加
im = torch.unsqueeze(im, dim=0) # [N, C, H, W]with torch.no_grad():outputs = net(im)predict = torch.max(outputs, dim=1)[1].data.numpy()
print(classes[int(predict)])# predict = torch.softmax(outputs,dim=1)
# print(predict)
# 这会得到一个概率分布
7.数据集
cifar10