Pytorch学习(一)一些基础认识

相关教程文档

Pytorch官方教程传送门
PyTorch中文文档传送门
参考博文Zen_君的简书

Tensor张量

对Tensor的认识

其实标量,向量,矩阵它们三个也是张量,标量是零维的张量,向量是一维的张量,矩阵是二维的张量。
张量就是按照任意维排列的一堆数字的推广。如图所示,矩阵不过是三维张量下的一个二维切面,向量是一条有方向的线。要找到三维张量下的一个标量,需要三个维度的坐标来定位。除此之外,张量还可以是四维的、五维的、。。。等等
在这里插入图片描述
比如定义一个三维的张量,输出为4个2×3矩阵,符合预期。

y=torch.Tensor(4,2,3) #构造一个4x2x3的张量,没初始化
y
(0 ,.,.) =
1.00000e-29 *

0.0000  2.5244  0.0000

2.5244  0.0000  0.0000

(1 ,.,.) =

1.00000e-29 *

0.0000  0.0000  0.0000

0.0000  0.0000  0.0000

(2 ,.,.) =

1.00000e-29 *

0.0000  0.0000  0.0000

0.0000  0.0000  0.0000

(3 ,.,.) =

1.00000e-29 *

0.0000  0.0000  0.0000

2.5244  0.0000  2.5244

[torch.FloatTensor of size 4x2x3]

作者:Zen_君
链接:https://www.jianshu.com/p/5ae644748f21

Tensor的常用基本操作

初始化张量

import torch ##引用torch包
#新建一个Tensor
x=torch.Tensor(2,3)#构建一个2x3的Tensor
y=torch.Tensor(2,3,4)#构建一个2x3x4的Tensor
#注意,即使不初始化Tensor,其依然有值!!

Tensor的部分截取

x[:,1]#]截取第2列的所有元素

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)#第三种加法#把运算结果存储在c上
b,add_(a)#把运算结果覆盖存储在b中#第四种加法

tensor与numpy矩阵的相互转化

#注意转换前后的变量是共用一块内存,a发生变化,b也会发生变化
d=a.numpy()#a是Tensor,d是numpy array
e=torch.from_numpy(d)#d是numpy array,e是Tensor

cuda相关

##cuda相关
torch.cuda.is_available()  #看看是否支持cuda
x = x.cuda()
y = y.cuda()
x+y           #这里的x和y都是tensor,使用cuda函数以后,x和y的所有运算均会调用gpu来运算。

还有更多操作见
torch文档

Autograd自动微分

对Autograd的认识

假如我们有一个向量x=(1,1)当成input,经过一系列运算得到了output变量y,然后我求y关于x的微分,注意y的值和y关于x微分的值相等,笔算如下图所示:
在这里插入图片描述
若使用Pytorch,会帮我们自动求解

from torch.autograd import Variable
import torch
#要进行autograd必需先将tensor数据包成Variable。
x = Variable(torch.ones(2), requires_grad = True) #vairable是tensor的一个外包装
z=4*x*x
y=z.norm()
y

Variable containing:
5.6569
[torch.FloatTensor of size 1]
我们可以看到y的值与我们上图计算的结果一致。

>>>y.backward()   #backward()函数表示backprop
>>>x.grad    #返回y关于x的梯度向量
Variable containing:
5.6569
5.6569
[torch.FloatTensor of size 2]

我们可以看到x.grad也与我们上图计算结果一致。
作者:Zen_君
链接:https://www.jianshu.com/p/cbce2dd60120

需要注意:autograd是专门为了BP算法设计的,所以这autograd只对输出值为标量的有用,因为损失函数的输出是一个标量。如果y是一个向量,那么backward()函数就会失效。

Autograd的内部机理

autograd中使用到了Variable和Function两种数据类型,要进行autograd必须先将Tensor类型的数据打包成为Variable类型的数据,Varibale和tensor基本一致,所区别在于多了下面几个属性。
在这里插入图片描述
variable是tensor的外包装,variable类型变量的data属性存储着tensor数据,grad属性存储关于该变量的导数,creator是代表该变量的创造者。

variable和function它们是彼此不分开的,如图所示
在这里插入图片描述
如图,假设我们有一个输入变量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。

简单的神经网络CNN

对神经网络CNN的简单认识

卷积神经网络CNN
在这里插入图片描述
上图即可看出,其实每一层网络所做的就是 y=W×X+b,只不过W的维数由X和输出维书决定,比如X是10维向量,想要输出的维数,也就是中间层的神经元个数为20,那么W的维数就是20x10,b的维数就是20x1,这样输出的y的维数就为20。
中间层的维数可以自己设计,而最后一层输出的维数就是你的分类数目,比如MNIST数据集是10个数字的分类,那么最后输出层的神经元就为10。

定义网络

torch.nn只接受mini-batch的输入,也就是说我们输入的时候是必须是好几张图片同时输入。例如:nn. Conv2d 允许输入4维的Tensor:n个样本 x n个色彩频道 x 高度 x 宽度
以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):
        #复制并使用Net的父类的初始化方法,即先运行nn.Module的初始化函数
        super(Net, self).__init__()
        # 定义conv1函数的是图像卷积函数:输入为图像(3个频道,即彩色图),输出为6张特征图, 卷积核为5x5正方形
        self.conv1 = nn.Conv2d(3, 6, 5) 
        self.pool  = nn.MaxPool2d(2,2) # 定义2d的MaxPooling层
        # 定义conv2函数的是图像卷积函数:输入为6张特征图,输出为16张特征图, 卷积核为5x5正方形
        self.conv2 = nn.Conv2d(6, 16, 5)
        # 定义fc1(fullconnect)全连接函数1为线性函数:y = Wx + b,并将16*5*5个节点连接到120个节点上。
        self.fc1   = nn.Linear(16*5*5, 120)
        #定义fc2(fullconnect)全连接函数2为线性函数:y = Wx + b,并将120个节点连接到84个节点上。
        self.fc2   = nn.Linear(120, 84)
        #定义fc3(fullconnect)全连接函数3为线性函数:y = Wx + b,并将84个节点连接到10个节点上。
        self.fc3   = nn.Linear(84, 10)
#定义该神经网络的向前传播函数,该函数必须定义,一旦定义成功,向后传播函数也会自动生成(autograd)
    def forward(self, x):
    	#输入x经过卷积conv1之后,经过激活函数ReLU,使用2x2的窗口进行最大池化Max pooling,然后更新到x。
        x = self.pool(F.relu(self.conv1(x)))
        #输入x经过卷积conv2之后,经过激活函数ReLU,使用2x2的窗口进行最大池化Max pooling,然后更新到x。
        x = self.pool(F.relu(self.conv2(x)))
        #view函数将张量x变形成一维的向量形式,总特征数并不改变,为接下来的全连接作准备。
        x = x.view(-1, 16*5*5)
        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
        #把input数据从tensor转为variable
        inputs, labels = Variable(inputs), Variable(labels)  

        # 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值
        #loss本身为Variable类型,所以要使用data获取其Tensor,因为其为标量,所以取0
        running_loss += loss.data[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
    #outputs.data是一个4x10张量,将每一行的最大的那一列的值和序号各自组成一个一维张量返回,第一个是值的张量,第二个是序号的张量。
    _, predicted = torch.max(outputs.data, 1)  
    total += labels.size(0)
    #两个一维张量逐行对比,相同的行记为1,不同的行记为0,再利用sum(),求总和,得到相同的个数。
    correct += (predicted == labels).sum()   

print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))
#############测试过程结束##################
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值