PyTorch的深度学习入门教程之构建神经网络


Posted in Python onJune 27, 2019

前言

本文参考PyTorch官网的教程,分为五个基本模块来介绍PyTorch。为了避免文章过长,这五个模块分别在五篇博文中介绍。

Part3:使用PyTorch构建一个神经网络

神经网络可以使用touch.nn来构建。nn依赖于autograd来定义模型,并且对其求导。一个nn.Module包含网络的层(layers),同时forward(input)可以返回output。

这是一个简单的前馈网络。它接受输入,然后一层一层向前传播,最后输出一个结果。

训练神经网络的典型步骤如下:

(1)  定义神经网络,该网络包含一些可以学习的参数(如权重)

(2)  在输入数据集上进行迭代

(3)  使用网络对输入数据进行处理

(4)  计算loss(输出值距离正确值有多远)

(5)  将梯度反向传播到网络参数中

(6)  更新网络的权重,使用简单的更新法则:weight = weight - learning_rate* gradient,即:新的权重=旧的权重-学习率*梯度值。

1 定义网络

我们先定义一个网络:

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


class Net(nn.Module):

  def __init__(self):
    super(Net, self).__init__()
    # 1 input image channel, 6 output channels, 5x5 square convolution
    # kernel
    self.conv1 = nn.Conv2d(1, 6, 5)
    self.conv2 = nn.Conv2d(6, 16, 5)
    # an affine operation: 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):
    # Max pooling over a (2, 2) window
    x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
    # If the size is a square you can only specify a single number
    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):
    size = x.size()[1:] # all dimensions except the batch dimension
    num_features = 1
    for s in size:
      num_features *= s
    return num_features


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 (400 ->120)

 (fc2): Linear (120 ->84)

 (fc3): Linear (84 ->10)

)

你只需要定义forward函数,那么backward函数(梯度在此函数中计算)就会利用autograd来自动定义。你可以在forward函数中使用Tensor的任何运算。

学习到的参数可以被net.parameters()返回。

params = list(net.parameters())
print(len(params))
print(params[0].size()) # conv1's .weight

预期输出:

10

torch.Size([6, 1, 5, 5])

前向计算的输入和输出都是autograd.Variable,注意,这个网络(LeNet)的输入尺寸是32*32。为了在MNIST数据集上使用这个网络,请把图像大小转变为32*32。

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

预期输出:

Variable containing:
-0.0796 0.0330 0.0103 0.0250 0.1153 -0.0136 0.0234 0.0881 0.0374 -0.0359
[torch.FloatTensor of size 1x10]

将梯度缓冲区归零,然后使用随机梯度值进行反向传播。

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

注意:torch.nn只支持mini-batches. 完整的torch.nn package只支持mini-batch形式的样本作为输入,并且不能只包含一个样本。例如,nn.Conv2d会采用一个4D的Tensor(nSamples* nChannels * Height * Width)。如果你有一个单样本,可以使用input.unsqueeze(0)来添加一个虚假的批量维度。

在继续之前,让我们回顾一下迄今为止所见过的所有类。

概述:

(1)  torch.Tensor——多维数组

(2)  autograd.Variable——包装了一个Tensor,并且记录了应用于其上的运算。与Tensor具有相同的API,同时增加了一些新东西例如backward()。并且有相对于该tensor的梯度值。

(3)  nn.Module——神经网络模块。封装参数的简便方式,对于参数向GPU移动,以及导出、加载等有帮助。

(4)  nn.Parameter——这是一种变量(Variable),当作为一个属性(attribute)分配到一个模块(Module)时,可以自动注册为一个参数(parameter)。

(5)  autograd.Function——执行自动求导运算的前向和反向定义。每一个Variable运算,创建至少一个单独的Function节点,该节点连接到创建了Variable并且编码了它的历史的函数身上。

2 损失函数(Loss Function)

损失函数采用输出值和目标值作为输入参数,来计算输出值距离目标值还有多大差距。在nn package中有很多种不同的损失函数,最简单的一个loss就是nn.MSELoss,它计算输出值和目标值之间的均方差。

例如:

output = net(input)
target = Variable(torch.arange(1, 11)) # a dummy target, for example
criterion = nn.MSELoss()

loss = criterion(output, target)
print(loss)

现在,从反向看loss,使用.grad_fn属性,你会看到一个计算graph如下:

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

当我们调用loss.backward(),整个的graph关于loss求导,graph中的所有Variables都会有他们自己的.grad变量。

为了理解,我们进行几个反向步骤。

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

预期输出:

<torch.autograd.function.MSELossBackwardobjectat0x7fb3c0dcf4f8>

<torch.autograd.function.AddmmBackwardobjectat0x7fb3c0dcf408>

<AccumulateGradobjectat0x7fb3c0db79e8>

3 反向传播(Backprop)

可以使用loss.backward()进行误差反向传播。你需要清除已经存在的梯度值,否则梯度将会积累到现有的梯度上。

现在,我们调用loss.backward(),看一看conv1的bias 梯度在backward之前和之后的值。

net.zero_grad()   # zeroes the gradient buffers of all parameters

print('conv1.bias.grad before backward')
print(net.conv1.bias.grad)

loss.backward()

print('conv1.bias.grad after backward')
print(net.conv1.bias.grad)

4 更新权重

实践当中最简单的更新法则就是随机梯度下降法( StochasticGradient Descent (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等。为了实现此功能,有一个package叫做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()  # zero the gradient buffers
output = net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()  # Does the update

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python基础教程之类class定义使用方法
Feb 20 Python
最基础的Python的socket编程入门教程
Apr 23 Python
详解Python3中的Sequence type的使用
Aug 01 Python
python多进程共享变量
Apr 06 Python
Python Tkinter实现简易计算器功能
Jan 30 Python
Python实现加载及解析properties配置文件的方法
Mar 29 Python
在unittest中使用 logging 模块记录测试数据的方法
Nov 30 Python
对python中类的继承与方法重写介绍
Jan 20 Python
python 同时读取多个文件的例子
Jul 16 Python
tensorflow将图片保存为tfrecord和tfrecord的读取方式
Feb 17 Python
Python线程协作threading.Condition实现过程解析
Mar 12 Python
keras实现基于孪生网络的图片相似度计算方式
Jun 11 Python
PyTorch的深度学习入门之PyTorch安装和配置
Jun 27 #Python
解决pycharm remote deployment 配置的问题
Jun 27 #Python
python turtle库画一个方格和圆实例
Jun 27 #Python
Python实现的对一个数进行因式分解操作示例
Jun 27 #Python
python pytest进阶之xunit fixture详解
Jun 27 #Python
Python批量查询关键词微信指数实例方法
Jun 27 #Python
Django框架orM与自定义SQL语句混合事务控制操作
Jun 27 #Python
You might like
php生成随机数或者字符串的代码
2008/09/05 PHP
判断是否为指定长度内字符串的php函数
2010/02/16 PHP
Codeigniter框架的更新事务(transaction)BUG及解决方法
2014/07/25 PHP
ThinkPHP入口文件设置及相关注意事项分析
2014/12/05 PHP
分享10段PHP常用代码
2015/11/11 PHP
Ajax实现对静态页面的文章访问统计功能示例
2016/10/10 PHP
jquery $.ajax入门应用二
2008/11/19 Javascript
JavaScript NodeTree导航栏(菜单项JSON类型/自制)
2013/02/01 Javascript
jQuery检查事件是否触发的方法
2015/06/26 Javascript
谈谈JavaScript中function多重理解
2015/08/28 Javascript
AngularJS之依赖注入模拟实现
2016/08/19 Javascript
详解利用exif.js解决ios手机上传竖拍照片旋转90度问题
2016/11/04 Javascript
js手机号4位显示空格,银行卡每4位显示空格效果
2017/03/23 Javascript
使用bootstraptable插件实现表格记录的查询、分页、排序操作
2017/08/06 Javascript
基于webpack 实用配置方法总结
2017/09/28 Javascript
详解angularjs跨页面传参遇到的一些问题
2018/11/01 Javascript
基于JS实现web端录音与播放功能
2019/04/17 Javascript
[05:17]DOTA2誓师:今天我们在这里 明天TI4等我!
2014/03/26 DOTA
pycharm 主题theme设置调整仿sublime的方法
2018/05/23 Python
在python中pandas读文件,有中文字符的方法
2018/12/12 Python
selenium python 实现基本自动化测试的示例代码
2019/02/25 Python
Python range、enumerate和zip函数用法详解
2019/09/11 Python
Python基于WordCloud制作词云图
2019/11/29 Python
python实现同一局域网下传输图片
2020/03/20 Python
Python按照list dict key进行排序过程解析
2020/04/04 Python
python中怎么表示空值
2020/06/19 Python
pandas to_excel 添加颜色操作
2020/07/14 Python
python 高阶函数简单介绍
2021/02/19 Python
canvas线条的属性详解
2018/03/27 HTML / CSS
淘宝客服专员岗位职责
2014/04/11 职场文书
党的群众路线教育实践活动宣传标语口号
2014/06/06 职场文书
篮球赛口号
2014/06/18 职场文书
教室标语大全
2014/06/21 职场文书
校运动会广播稿300字
2014/10/07 职场文书
情感电台广播稿
2015/08/18 职场文书
2016年五一劳动节专题校园广播稿
2015/12/17 职场文书