zoukankan      html  css  js  c++  java
  • Neural Networks

    神经网络能够使用torch.nn包构建神经网络。

    现在你已经对autogard有了初步的了解,nn基于autograd来定义模型并进行微分。一个nn.Module包含层,和一个forward(input)方法并返回output。

    以如下分类数字图片的网络所示:

    这是一个简单的前馈网络。它接受输入,经过一层接着一层的神经网络层,最终得到输出。

    一个神经网络典型的训练流程如下:

    • 定义拥有可学习的参数的神经网络
    • 迭代数据集作为输入
    • 经过网络处理输入
    • 计算损失(离正确输出的距离)
    • 反向传播梯度到网络参数
    • 更新网络的权重,比如简单的更新规则:weight=weight-learning_rate*gradient

    定义网络

    让我们定义这个网络:  

    import torch.nn as nn
    import torch.nn.functional as F
    class Net(nn.Module):
        def __init__(self):
            super(Net,self).__init__()
            # 一个输入图片通道,六个输出通道,5*5的卷积核
            self.conv1=nn.Conv2d(1,6,5)
            self.conv2=nn.Conv2d(6,16,5)
            # 一个仿射操作:y=wx+b
            self.fc1=nn.Linear(16*5*5,120)
            self.fc2=nn.Linear(120,84)
            self.fc3=nn.Linear(84,10)
    
        def forward(self,x):
            # 2*2窗口的最大赤化
            x=F.max_pool2d(F.relu(self.conv1(x)),(2,2))
            # 如果是一个方块就只需要指定一个长度
            x=F.max_pool2d(F.relu(self.conv2(x)),2)
            x=x.view(-1,self.num_flat_features(x))
            x=F.relu(self.fc1(x))
            x=F.relu(self.fc2(x))
            x=self.fc3(x)
            return x
    
        def num_flat_features(self,x):
         #第一个尺寸是batch size size
    =x.size()[1:] print(size) num_features=1 for s in size: num_features*=s return num_features net=Net() print(net)
    out:
    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, bias=True)
      (fc2): Linear(in_features=120, out_features=84, bias=True)
      (fc3): Linear(in_features=84, out_features=10, bias=True)
    )

    你只需要定义forward函数,backward函数(计算梯度的地方)是自动定义的。你能够在forward中使用任意的tensor运算。

    模型可学习的参数将通过net.parameters()返回

    params=list(net.parameters())
    print(len(params))
    print(params[0].size())

    out:
    10
    torch.Size([6, 1, 5, 5])

    让我们试一下随机的32*32输入,注意:这个网络(LeNet)期望的输入尺寸是32*32。为了在MNIST数据集上使用这个网络,请将数据集的图片调整到32*32。

    input=torch.randn(1,1,32,32)
    out=net(input)
    print(out)

    out:
    tensor([[ 0.0355, -0.0294, -0.0025, -0.0743, -0.0168, -0.0202, -0.0558,
    0.0803, -0.0162, -0.1153]])

    将所有参数的梯度缓冲变为0并使用随机梯度进行后向传播:

    net.zero_grad()
    out.backward(torch.randn(1,10))

    !注意:

    torch.nn只支持最小批。整个torch.nn包只支持输入的样本是一个最小批,而不是一个单一样本.

    举例来说,nn.Conv2d将会接收4维的Tensor,nSamples*nChannels*Heights*Width.

    如果你有一个单一样本,可以使用input.unsqueeze(0)来增加一个虚假的批维度。

    在进行进一步处理前,让我们简要重复目前为止出现的类。

    扼要重述:

    • torch.Tensor- 一个支持自动求导操作比如backward()的多维数组。同时保留关于tensor的梯度.
    • nn.Module- 神经网络模型。简易的封装参数的方法,帮助将它们转移到GPU上,导出加载等等.
    • nn.Parameters - 一类Tensor,在作为Module属性指定时会自动注册为一个parameter.
    • autograd.Function- 自动求导操作前向与后向的实现。每个tensor操作,至少创建一个Functional节点,它连接到创建Tensor的函数并编码它的历史

    在这一节,我们包含了:

    • 定义一个神经网络
    • 处理输入并调用后向传播

    还剩下:

    • 计算损失
    • 更新网络的权重

    损失函数:

     损失函数接收对(输出,目标)作为输入,计算一个值估计输出与目标之间的距离。

    nn包下有一些不同的损失函数。一个简单的损失是nn.MSELoss,它计算的是输入与输出之间的均方误差。

    比如:

    output=net(input)
    target=torch.randn(10)
    target=target.view(1,-1)
    criterion=nn.MSELoss()
    
    loss=criterion(output,target)
    print(loss)
    out:
    tensor(1.1941)

    现在,如果你如果按照loss的反向传播方向,使用.grad_fn属性,你将会看到一个计算图如下所示:

    input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d
          -> view -> linear -> relu -> linear -> relu -> linear
          -> MSELoss
          -> loss

    所以,当你调用loss.backward(),整个图关于损失求导,并且图中所有requires_grad=True的tensor将会有它们的.grad属性。Tensor的梯度是累加的。

    为了说明这一点,我们跟踪backward的部分步骤:

    print(loss.grad_fn)  #MSELoss
    print(loss.grad_fn.next_functions[0][0]) #Linear
    print(loss.grad_fn.next_functions[0][0].next_functions[0][0]) # ReLU
    out:
    <MseLossBackward object at 0x0000020E2E1289B0>
    <AddmmBackward object at 0x0000020E2BF48048>
    <ExpandBackward object at 0x0000020E2BF48048>

    Backprop

    为了反向传播error,我们需要做的就是loss.backward()。你需要清除现有的梯度,否则梯度将会累计到现有梯度上。

     现在我们会调用loss.backward(),观察调用backward前后conv1层偏差的梯度。

    net.zero_grad()
    
    print('conv1.bias.grad before backward')
    print(net.conv1.bias.grad)
    loss.backward()
    print('conv1.bias.grad after backward')
    print(net.conv1.bias.grad)

    out:
    conv1.bias.grad before backward
    None # 上一个版本将会是一个为0的向量
    conv1.bias.grad after backward
    tensor(1.00000e-03 *
    [ 4.0788, 1.9541, 5.8585, -2.3754, 2.3815, 1.3351])

     现在我们知道了如何使用loss函数

    稍后阅读:

    神经网络包包含各种模型和loss函数,它们组成了深度神经网络的构建区块。完整的文档在这里。http://pytorch.org/docs/nn

     剩下来需要学习的是:

    • 更新网络的权重

    更新权重

    实际中使用的最简单更新规则是随机梯度下降(SGD):

    weight=weight-learning_rate*gradient

     我们能够使用简单的python代码实现:

    learning_rate=0.01
    for f in net.parameters():
        f.data.sub_(f.grad.data*learning_rate)

    然而,当我们使用神经网络,你想要使用各种不同的更新规则比如SGD,Nesterov-SGD,Adam,RMSProp等。为了做到这一点,我们建立了一个小的包torch.optim实现了这些方法。使用它非常简单。

    import torch.optim as optim
    
    #create your optimizer
    optimizer =optim.SGD(net.parameters(),lr=0.01)
    
    # in your training loop
    optimizer.zero_grad()
    output=net(input)
    loss=criterion(output,target)
    loss.backward()
    optimizer.step()

    !注意:

     手动使用optimizer.zero_grad()来将梯度缓冲变为0。这在Backprop章节进行了解释,因为梯度是累加的。

  • 相关阅读:
    SAP分析云及协同计划
    使用SSH命令行远程登录运行在CloudFoundry上的应用
    如何远程调试部署在CloudFoundry平台上的nodejs应用
    Apache httpclient的execute方法调试
    如何用Java代码在SAP Marketing Cloud里创建contact数据
    nodejs request module里的json参数的一个坑
    如何在调用Marketing Cloud contact创建API时增加对扩展字段的支持
    Efim and Strange Grade
    Vitya in the Countryside
    Anatoly and Cockroaches
  • 原文地址:https://www.cnblogs.com/Thinker-pcw/p/9635572.html
Copyright © 2011-2022 走看看