PyTorch-->image classification(图像分类)

使用深度学习框架的流程:

模型定义(包括损失函数的选择)-> 数据处理和加载 -> 训练(可能包含训练过程可视化)-> 测试

以下是根据官方教程的练手,其中卷积神经网络的部分会单独开一篇去写原理,目前俺还不太懂,哈哈哈哈!冲鸭!!!

  1 # 使用torchvision来加载并归一化CIFAR10数据集
  2 
  3 import torch
  4 import torchvision  # 保存了一些数据集
  5 import torchvision.transforms as transforms  # 进行数据预处理
  6 import torch.nn as nn
  7 import torch.nn.functional as F
  8 import torch.optim as optim
  9 
 10 from torch.autograd import Variable
 11 
 12 
 13 # 定义网络一般继承torch.nn.Module创建新子类
 14 class Net(nn.Module):
 15 
 16     def __init__(self):
 17         super(Net, self).__init__()
 18         # 1 input image channel, 6 output channels, 5*5 square conwolution
 19         # kernel
 20         # 添加卷积层
 21         self.conv1 = nn.Conv2d(3, 6, 5)  # 定义一个输入深度为3,输出为6,卷积核大小为 5*5 的 conv1 变量
 22         self.pool = nn.MaxPool2d(2, 2)  # 最大池化层
 23         self.conv2 = nn.Conv2d(6, 16, 5)  # 输入通道数为6 输出通道数为16
 24         # an affine operation: y = Wx + b
 25         # 3个全连接层
 26         self.fc1 = nn.Linear(16 * 5 * 5, 120)
 27         self.fc2 = nn.Linear(120, 84)
 28         self.fc3 = nn.Linear(84, 10)  # 最终属于10类中的一个
 29 
 30     # 定义前向传播的方法:即定义了使用给定的层和函数计算输出的方式
 31     def forward(self, x):
 32         # 定义forward()函数:可以在此函数中使用任何Tensor操作
 33         # backward()函数被autograd自动定义
 34         # Max pooling over a (2,2) window
 35         # 输入x -> conv1 -> relu -> 2*2窗口的最大池化
 36         # x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
 37         # If the size is a square you can only specify a single number
 38         # x = F.max_pool2d(F.relu(self.conv2(x)), 2)
 39         # view 函数将张量x变形成一维向量形式,总特征数不变,为全连接层做准备
 40         # 为什么这里只关心列数不关心行数呢,因为马上就要进入全连接层了,而全连接层说白了就是矩阵乘法!
 41         #  第一个全连接层的首参数是16*5*5,所以要保证能够相乘,在矩阵乘法之前就要把x调到正确的size
 42         x = self.pool(F.relu(self.conv1(x)))
 43         x = self.pool(F.relu(self.conv2(x)))
 44         x = x.view(-1, 16 * 5 * 5)
 45         x = F.relu(self.fc1(x))
 46         x = F.relu(self.fc2(x))
 47         x = self.fc3(x)
 48         return x
 49 
 50 
 51 # torch.nn中大多数layer在torch.nn.funtional中都有一个与之对应的函数。
 52 # 二者的区别在于:
 53 # torch.nn.Module中实现layer的都是一个特殊的类,都是以class xx来定义的, 会自动提取可学习的参数
 54 # 而 nn.functional中的函数,更像是纯函数,由def function( )定义,只进行简单的数学运算。
 55 # 即二者的区别是functional中的函数是一个确定的不变的运算公式,输入数据产生输出就ok,
 56 # 而深度学习中会有很多权重是在不断更新的,不可能每进行一次forward就用新的权重重新来定义一遍函数来进行计算,所以说就会采用类的方式,以确保能在参数发生变化时仍能使用我们之前定好的运算步骤。
 57 # 从这个分析就可以看出什么时候应该用nn.Module中的layer了:
 58 #   如果模型有可学习的参数,最好使用nn.Module对应的相关layer,否则二者都可以使用,没有什么区别。
 59 # 比如此例中的Relu其实没有可学习的参数,只是进行一个运算而已,所以使用的就是functional中的relu函数,
 60 # 而卷积层和全连接层都有可学习的参数,所以用的是nn.Module中的类。
 61 # 不具备可学习参数的层,将它们用函数代替,这样可以不用放在构造函数中进行初始化。
 62 
 63 
 64 # torchvision dataset 输出范围:[0,1]的PILImage,首先需要归一化为[-1,1]的Tensors
 65 # define a transform :可以将多个变换组合在一起,此处为组合了totensor & normalize
 66 transform = transforms.Compose(
 67     [transforms.ToTensor(),
 68      transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  # first RGB三个通道上的均值 second RGB三个通道上的标准差 用于对RGB图像归一化
 69 # define a trainset,加载后使用上面定义的transform进行变换 (存放位置 为True代表创建的是训练集 为True代表需要从网上下载 使用的变换)
 70 trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
 71 # 后面会通过loader将数据传入网络
 72 # 组合数据集和采样器 在数据集上提供单进程或多进程的迭代器(数据的来源 每批次进入的数据数量 为True代表打乱数据顺序 默认为0代表在主进程中加载,此处为2代表选用用来加载数据的子进程个数)
 73 #                                                              有些时候使用固定RAM(通过pin_memory)加速RAM到GPU的传输
 74 trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)
 75 # define a testset
 76 testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
 77 
 78 testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=2)
 79 # 类别需要给定
 80 classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
 81 
 82 # show some examples
 83 import matplotlib.pyplot as plt
 84 import numpy as np
 85 
 86 
 87 # functions to show an image
 88 
 89 def imshow(img):
 90     img = img / 2 + 0.5
 91     npimg = img.numpy()
 92     plt.imshow(np.transpose(npimg, (1, 2, 0)))
 93     plt.show()
 94 
 95 
 96 if __name__ == '__main__':
 97     # get some random training images
 98     dataiter = iter(trainloader)
 99     images, labels = dataiter.next()
100 
101     # # show
102     # imshow(torchvision.utils.make_grid(images))
103     # # print labes
104     # print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
105 
106     net = Net()
107 
108     # use a Classification Cross-Entropy 分类交叉熵 loss(损失函数) and SGD 动量 with momentum(优化器)
109     # 想把模型搬到GPU上跑,要在定义优化器之前完成.cuda()这一步 因为在将网络参数传递给优化器之前,将它们传输到适当的设备是很重要的,否则优化器将无法以正确的方式跟踪它们
110     criterion = nn.CrossEntropyLoss()
111     optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
112 
113     # loop over the dataset multiple times 将数据集循环传给net & momentum
114     # 下面进行两次训练
115     for epoch in range(2):
116 
117         running_loss = 0.0  # 方便对损失函数的值进行输出
118         # enumerate() 既获得索引也获得数据
119         for i, data in enumerate(trainloader, 0):
120             # get the inputs
121             inputs, labels = data  # 从enumerate返回的data 包含数据和标签信息
122             # inputs, labels = Variable(inputs),Variable(labels) 将数据转换成Variable
123             # don't forget!!!
124             optimizer.zero_grad()
125 
126             # forward + backward + optimize
127             outputs = net(inputs)
128             loss = criterion(outputs, labels)
129             loss.backward()
130             # 在定义网络时定义了前向传播函数,但是并没有定义反向传播函数,深度学习是需要反向传播求导的,
131             # Pytorch其实利用的是Autograd模块来进行自动求导,反向传播。
132             # Autograd中最核心的类就是Variable了,它封装了Tensor,并几乎支持所有Tensor的操作,这里可以参考官方给的详细解释:
133             # http: // pytorch.org / tutorials / beginner / blitz / autograd_tutorial.html  # sphx-glr-beginner-blitz-autograd-tutorial-py
134             # 以上链接详细讲述了variable究竟是怎么能够实现自动求导的,怎么用它来实现反向传播的。
135             # 这里涉及到计算图的相关概念
136             # 总结:要计算各个variable的梯度,只需调用根节点的backward方法,Autograd就会自动沿着整个计算图进行反向计算
137             # 而在此例子中,根节点就是loss,所以程序中的loss.backward()
138             # 代码就是在实现反向传播,自动计算所有的梯度。
139             optimizer.step()  # 执行完反向传播之后,更新优化器参数,以便进行下一轮训练
140 
141             # print statistics
142             running_loss += loss.item()
143             # print every 2000 mini-batches
144             if i % 2000 == 1999:
145                 print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000))
146                 running_loss = 0.0
147 
148     print('Finished!!!')
149 
150     # save the model
151     PATH = './cifar_net.pth'
152     torch.save(net.state_dict(), PATH)
153 
154     # test the network on the test data
155 
156     dataiter = iter(testloader)
157     images, labels = dataiter.next()  # 根据设置应该是四张图片
158 
159     # print images
160     imshow(torchvision.utils.make_grid(images))
161     print('Ground_Truth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
162 
163     net_1 = Net()
164 
165     net_1.load_state_dict(torch.load(PATH))
166     outputs = net_1(images)
167     _, predited = torch.max(outputs, 1)  # 会返回两个值,但是对第一个不感兴趣
168     # .max() 返回输入Tensor中每行的最大值,并转换成指定的dim(维度)
169     # 指的 the dimension to reduce!并不是在the dimension上去返回最大值。
170     # 理解为:返回最大的索引,即预测出的类别
171     print('Predicted: ', ' '.join('%5s' % classes[predited[j]] for j in range(4)))
172 
173     # performs on the whole dataset
174 
175     correct = 0
176     total = 0
177 
178     with torch.no_grad():
179         for data in testloader:
180             images, labels = data
181             outputs = net_1(images)
182             _, predited = torch.max(outputs.data, 1)
183             total += labels.size(0)
184             correct += (predited == labels).sum().item()
185 
186     print('Accuracy of the network on the 10000 test images: %d %%' % (
187             100 * (correct / total)))
188 
189     # performs on different classes
190     class_correct = list(0. for i in range(10))
191     class_total = list(0. for i in range(10))
192     with torch.no_grad():
193         for data in testloader:
194             images, labels = data
195             outputs = net_1(images)
196             _, predited = torch.max(outputs, 1)
197             c = (predited == labels).squeeze()
198             for i in range(4):  # 每个batch有4个图片!
199                 label = labels[i]
200                 class_correct[label] += c[i].item()
201                 class_total[label] += 1
202 
203     for i in range(10):
204         print('Accuracy of %5s : %2d %%' % (classes[i],
205                                             100 * (class_correct[i] / class_total[i])))
206 
207     # run the neural network on the GPU
208     device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
209     print(device)
210 
211     net.to(device)
212     inputs, labels = data[0].to(device), data[0].to(device)
To see I can not see, to know I do not know.
原文地址:https://www.cnblogs.com/aluomengmengda/p/13856114.html