『PyTorch』第四弹_通过LeNet初识pytorch神经网络_上

总结一下相关概念:

  • torch.Tensor - 一个近似多维数组的数据结构
  • autograd.Variable - 改变Tensor并且记录下来操作的历史记录。和Tensor拥有相同的API,以及backward()的一些API。同时包含着和张量相关的梯度
  • nn.Module - 神经网络模块,便捷的数据封装,能够将运算移往GPU,还包括一些输入输出的东西
  • nn.Parameter - 一种变量(Variable),当将任何值赋予Module时自动注册为一个参数
  • autograd.Function - 实现了使用自动求导方法的前馈和后馈的定义。每个Variable的操作都会生成至少一个独立的Function节点,与生成了Variable的函数相连之后记录下操作历史

导入库:

# Author : Hellcat
# Time   : 2018/2/10

import torch as t
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.autograd import Variable

torch.nn:网络层

torch.nn.functional:激活函数、池化函数归于此模块

pytorch中的网络层是class,而tensorflow

print(t.nn.Conv2d)

<class 'torch.nn.modules.conv.Conv2d'>

print(tf.nn.conv2d)

<function conv2d at 0x000001A33CC44510>

网络主体:

net网络要使用class并继承父类才行,因而有一些自带的方法

net.parameters():返回全部的参数值,迭代器

net.named_parameters():返回参数名称和值,迭代器

net.参数名:就是参数变量,Variable,可以直接查看data和grad等等

class Net(nn.Module):
    def __init__(self):
        # nn.Module子类的函数必须在构造函数中执行父类的构造函数
        # 等价于nn.Model.__init__(self)
        super(Net,self).__init__()

        # 输入1通道,输出6通道,卷积核5*5
        self.conv1 = nn.Conv2d(1, 6, 5)
        # 定义卷积层:输入6张特征图,输出16张特征图,卷积核5x5
        self.conv2 = nn.Conv2d(6,16,5)
        # 定义全连接层:线性连接(y = Wx + b),16*5*5个节点连接到120个节点上
        self.fc1 = nn.Linear(16*5*5,120)
        # 定义全连接层:线性连接(y = Wx + b),120个节点连接到84个节点上
        self.fc2 = nn.Linear(120,84)
        # 定义全连接层:线性连接(y = Wx + b),84个节点连接到10个节点上
        self.fc3 = nn.Linear(84,10)

    # 定义向前传播函数,并自动生成向后传播函数(autograd)
    def forward(self,x):
        # 输入x->conv1->relu->2x2窗口的最大池化->更新到x
        x = F.max_pool2d(F.relu(self.conv1(x)),(2,2))
        # 输入x->conv2->relu->2x2窗口的最大池化->更新到x
        x = F.max_pool2d(F.relu(self.conv2(x)),2)
        # view函数将张量x变形成一维向量形式,总特征数不变,为全连接层做准备
        x = x.view(x.size()[0], -1)
        # 输入x->fc1->relu,更新到x
        x = F.relu(self.fc1(x))
        # 输入x->fc2->relu,更新到x
        x = F.relu(self.fc2(x))
        # 输入x->fc3,更新到x
        x = self.fc3(x)
        return x


if __name__ == "__main__":

    net = Net()

展示网络参数:

# #########查看参数#########
    print(net)
    """
    Net(
    (conv1): Conv2d (1, 6, kernel_size=(5, 5), stride=(1, 1))
    (conv2): Conv2d (6, 16, kernel_size=(5, 5), stride=(1, 1))
    (fc1): Linear(in_features=400, out_features=120)
    (fc2): Linear(in_features=120, out_features=84)
    (fc3): Linear(in_features=84, out_features=10)
    )
    """

    # 返回参数值:顺序和下面的named一致
    params = list(net.parameters())
    print(len(params))
    """
    10
    """

    # net.named_parameters(): ((参数名称,参数属性),……)
    for name, parameters in net.named_parameters():
        print(name, ":", parameters.size())
        """
        conv1.weight : torch.Size([6, 1, 5, 5])
        conv1.bias : torch.Size([6])
        conv2.weight : torch.Size([16, 6, 5, 5])
        conv2.bias : torch.Size([16])
        fc1.weight : torch.Size([120, 400])
        fc1.bias : torch.Size([120])
        fc2.weight : torch.Size([84, 120])
        fc2.bias : torch.Size([84])
        fc3.weight : torch.Size([10, 84])
        fc3.bias : torch.Size([10])
        """

模拟单次向前&向后传播:

# #########网络传播过程模拟#########
    # 输入如果没有batch数,则少一维度,Tensor,unsqueeze()可以为张量扩维
    input_ = Variable(t.randn(1, 1, 32, 32))
    out = net(input_)
    print(out.size())
    """
    torch.Size([1, 10])
    """
    # net.zero_grad()
    # 输出值为10个标量(一个向量),所以需要指定每个标量梯度的权重
    # out.backward(t.ones(1,10))

注意: torch.nn 只接受小批量的数据

整个torch.nn包只接受那种小批量样本的数据,而非单个样本。 例如,nn.Conv2d能够结构一个四维的TensornSamples x nChannels x Height x Width。

如果你拿的是单个样本,使用input.unsqueeze(0)来加一个假维度就可以了

维度是[batch,channel,height,width]。

Loss函数构建

 # #########Loss设计#########
    target = Variable(t.arange(0,10))
    # Loss需要先实例化,然后是callable的实例
    loss_fn = nn.MSELoss()  # 均方误差
    loss = loss_fn(out, target)
    print(loss)

    net.zero_grad()
    print("反向传播之前:", net.conv1.bias.grad)
    loss.backward()
    print("反向传播之后:", net.conv1.bias.grad)

反向传播之前: None

反向传播之后: Variable containing:

        -0.1330

        -0.0888

        -0.0101

        -0.0186

         0.0462

        0.0317

       [torch.FloatTensor of size 6]

优化器构建

# #########优化器设计#########
    print(net.parameters())
    """
    <generator object Module.parameters at 0x0000021B525BE888>
    """
    # 初始化优化器
    optimizer = optim.SGD(net.parameters(), lr=0.01)

    optimizer.zero_grad()  # 效果等同net.zero_grad()

    output = net(input_)
    loss = loss_fn(output, target)

    loss.backward()
    print("反向传播之前:", net.conv1.bias.data)
    optimizer.step()
    print("反向传播之后:", net.conv1.bias.data)

反向传播之前:

    -0.1702

     0.1192

     0.1349

    0.1307

    -0.0141

    -0.0558

  [torch.FloatTensor of size 6]

反向传播之后:

    -0.1689

    0.1201

     0.1350

     0.1309

    -0.0146

    -0.0561

  [torch.FloatTensor of size 6]