zoukankan      html  css  js  c++  java
  • 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.
  • 相关阅读:
    C字符串和C++中string的区别 &&&&C++中int型与string型互相转换
    UML的类图关系分为: 关联、聚合/组合、依赖、泛化(继承)
    STL map详细用法和make_pair函数
    字符串旋转(str.find()---KMP)
    层次遍历二叉树
    图像特征提取三大法宝:HOG特征,LBP特征,Haar特征
    位运算---整数间的转化
    最大公倍数
    单链表的实现
    jsp下Kindeditor环境搭建
  • 原文地址:https://www.cnblogs.com/aluomengmengda/p/13856114.html
Copyright © 2011-2022 走看看