PyTorch 入门-简单介绍

本篇博客的主要作用为用来记录自己的PyTorch学习过程,主要参考了简书用户”Zen_君”(传送门)的相关入门教程.

PyTorch的官网:http://pytorch.org/
PyTorch中文文档:http://pytorch-cn.readthedocs.io/zh/latest/

PyTorch的安装:https://www.jianshu.com/p/5ae644748f21

Tensor张量

其实我的理解中张量就是多维的向量.
其实标量,向量,矩阵它们三个也是张量,标量是零维的张量,向量是一维的张量,矩阵是二维的张量。
这里写图片描述
这张图真的很生动形象的描述了常用的这几个标量,一维向量,矩阵,张量之间的联系.
PyTorch中的数据全部构建在Tensor的基础上.
Tensor的最基本使用:

import torch ##引用torch包
#新建一个Tensor
x=torch.Tensor(2,3)#构建一个2x3的Tensor
y=torch.Tensor(2,3,4)#构建一个2x3x4的Tensor
#注意,即使不初始化Tensor,其依然有值!!
#Tensor的运算
#生成两个形状一致的随机Tensor
a=torch.rand(5,3)
b=torch.rand(5,3)
c=torch.Tensor(5,3)
c=a+b
c=torch.add(a,b)
torch.add(a,b,out=c)
b,add_(a)#把运算结果覆盖存储在b中
#把tensor转换为numpy矩阵
d=a.numpy()#a是Tensor,d是numpy array
e=torch.from_numpy(d)#d是numpy array,e是Tensor
##cuda相关
torch.cuda.is_available()  #看看是否支持cuda
x = x.cuda()
y = y.cuda()
x+y           #这里的x和y都是tensor,使用cuda函数以后,x和y的所有运算均会调用gpu来运算。

还有很多类似矩阵操作的基本操作,和原本python,numpy的操作基本一致,更多的操作请参考这里:http://pytorch.org/docs/master/torch.html

Autograd自动微分

autograd中使用到了Variable和Function两种数据类型,要进行autograd必须先将Tensor类型的数据打包成为Variable类型的数据.
这里写图片描述
Variable类型是Tensor类型的外包装,Variable类型变量的data属性存储着其中的Tensor类型的数据,grad属性存储着该变量的导数,creator属性记录该变量的创造者.
这里写图片描述
如图,假设我们有一个输入变量input(数据类型为Variable)input是用户输入的,所以其创造者creator为null值,input经过第一个数据操作operation1(比如加减乘除运算)得到output1变量(数据类型仍为Variable),这个过程中会自动生成一个function1的变量(数据类型为Function的一个实例),而output1的创造者就是这个function1。随后,output1再经过一个数据操作生成output2,这个过程也会生成另外一个实例function2,output2的创造者creator为function2。
在这个向前传播的过程中,function1和function2记录了数据input的所有操作历史,当output2运行其backward函数时,会使得function2和function1自动反向计算input的导数值并存储在grad属性中。
creator为null的变量才能被返回导数,比如input,若把整个操作流看成是一张图(Graph),那么像input这种creator为null的被称之为图的叶子(graph leaf)。而creator非null的变量比如output1和output2,是不能被返回导数的,它们的grad均为0。所以只有叶子节点才能被autograd。

from torch.autograd import Variable
import torch
x = Variable(torch.ones(2), requires_grad = True) #vairable是tensor的一个外包装
z=4*x*x
y.backward()   #backward()函数表示backprop
x.grad    #返回y关于x的梯度向量

构造一个简单的CNN

这里以LeNet为例:
这里写图片描述
直接上代码!基本看备注就能看懂

#coding=utf-8
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
import torch
import torchvision
import torchvision.transforms as transforms
import torch.optim as optim
###########处理数据集开始#########################
# The output of torchvision datasets are PILImage images of range [0, 1].
# We transform them to Tensors of normalized range [-1, 1]
transform=transforms.Compose([transforms.ToTensor(),
                              transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                             ])

#训练集,将相对目录./data下的cifar-10-batches-py文件夹中的全部数据(50000张图片作为训练数据)加载到内存中,若download为True时,会自动从网上下载数据并解压
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=False, transform=transform)

#将训练集的50000张图片划分成12500份,每份4张图,用于mini-batch输入。shffule=True在表示不同批次的数据遍历时,打乱顺序。num_workers=2表示使用两个子进程来加载数据
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, 
                                          shuffle=True, num_workers=2)

#测试集,将相对目录./data下的cifar-10-batches-py文件夹中的全部数据(10000张图片作为测试数据)加载到内存中,若download为True时,会自动从网上下载数据并解压
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=False, transform=transform)

#将测试集的10000张图片划分成2500份,每份4张图,用于mini-batch输入。
testloader = torch.utils.data.DataLoader(testset, batch_size=4, 
                                          shuffle=False, num_workers=2)
classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
###########处理数据集结束#########################
###########定义网络开始#########################
class Net(nn.Module):
#定义net的初始化函数,这个函数定义了该神经网络的基本结构
        def __init__(self):
        super(Net, self).__init__()#复制并使用Net的父类的初始化方法,即先运行nn.Module的初始化函数
        self.conv1 = nn.Conv2d(3, 6, 5) # 定义conv1函数的是图像卷积函数:输入为图像(3个频道,即彩色图),输出为6张特征图, 卷积核为5x5正方形
        self.pool  = nn.MaxPool2d(2,2) # 定义2d的MaxPooling层,
        self.conv2 = nn.Conv2d(6, 16, 5)# 定义conv2函数的是图像卷积函数:输入为6张特征图,输出为16张特征图, 卷积核为5x5正方形
        self.fc1   = nn.Linear(16*5*5, 120)# 定义fc1(fullconnect)全连接函数1为线性函数:y = Wx + b,并将16*5*5个节点连接到120个节点上。
        self.fc2   = nn.Linear(120, 84)#定义fc2(fullconnect)全连接函数2为线性函数:y = Wx + b,并将120个节点连接到84个节点上。
        self.fc3   = nn.Linear(84, 10)#定义fc3(fullconnect)全连接函数3为线性函数:y = Wx + b,并将84个节点连接到10个节点上。
#定义该神经网络的向前传播函数,该函数必须定义,一旦定义成功,向后传播函数也会自动生成(autograd)
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))#输入x经过卷积conv1之后,经过激活函数ReLU,使用2x2的窗口进行最大池化Max pooling,然后更新到x。
        x = self.pool(F.relu(self.conv2(x)))#输入x经过卷积conv2之后,经过激活函数ReLU,使用2x2的窗口进行最大池化Max pooling,然后更新到x。
        x = x.view(-1, 16*5*5)#view函数将张量x变形成一维的向量形式,总特征数并不改变,为接下来的全连接作准备。
        x = F.relu(self.fc1(x))#输入x经过全连接1,再经过ReLU激活函数,然后更新x
        x = F.relu(self.fc2(x))#输入x经过全连接2,再经过ReLU激活函数,然后更新x
        x = self.fc3(x)#输入x经过全连接3,然后更新x
        return x
###########定义网络结束#########################
#新建一个之前定义的网路
net = Net()
#################查看需要训练的网络参数的相关信息开始############
print net
params = list(net.parameters())

k=0
for i in params:
    l =1
    print "该层的结构:"+str(list(i.size()))
    for j in i.size():
        l *= j
    print "参数和:"+str(l)
    k = k+l

print "总参数和:"+ str(k)
#################查看需要训练的网络参数的相关信息结束############
#######关于loss function 开始################
criterion = nn.CrossEntropyLoss() #叉熵损失函数
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)  #使用SGD(随机梯度下降)优化,学习率为0.001,动量为0.9
#######关于loss function 结束################
###############训练过程开始##########################
for epoch in range(2): # 遍历数据集两次

    running_loss = 0.0
    #enumerate(sequence, [start=0]),i序号,data是数据
    for i, data in enumerate(trainloader, 0): 
        # get the inputs
        inputs, labels = data   #data的结构是:[4x3x32x32的张量,长度4的张量]

        # wrap them in Variable
        inputs, labels = Variable(inputs), Variable(labels)  #把input数据从tensor转为variable

        # zero the parameter gradients
        optimizer.zero_grad() #将参数的grad值初始化为0

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels) #将output和labels使用叉熵计算损失
        loss.backward() #反向传播
        optimizer.step() #用SGD更新参数

        # 每2000批数据打印一次平均loss值
        running_loss += loss.data[0]  #loss本身为Variable类型,所以要使用data获取其Tensor,因为其为标量,所以取0
        if i % 2000 == 1999: # 每2000批打印一次
            print('[%d, %5d] loss: %.3f' % (epoch+1, i+1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')
#############训练过程结束##################
#############测试过程开始##################
correct = 0
total = 0
for data in testloader:
    images, labels = data
    outputs = net(Variable(images))
    #print outputs.data
    _, predicted = torch.max(outputs.data, 1)  #outputs.data是一个4x10张量,将每一行的最大的那一列的值和序号各自组成一个一维张量返回,第一个是值的张量,第二个是序号的张量。
    total += labels.size(0)
    correct += (predicted == labels).sum()   #两个一维张量逐行对比,相同的行记为1,不同的行记为0,再利用sum(),求总和,得到相同的个数。

print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))
#############测试过程结束##################

猜你喜欢

转载自blog.csdn.net/tuzixini/article/details/78937162