Pytorch 神经网络 3

神经网络(以下简称NN)主要用的包是torch.nn
nn基于autograd,定义模型并微分。一个nn.Module模块包含着forward(input)方法,返回output

Convnet

上图是一个简单的前馈网络,从输入一层层向前,算出输出。
典型的训练步骤是:

  1. 定义NN结构,包括哪些要学习的参数(或权重)
  2. 迭代计算数据库作为输入
  3. 将输入传播到整个网络
  4. 计算损失函数
  5. 损失反传
  6. 调整参数,weight = weight - learning_rate * gradient

定义网络

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.view调整大小
        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函数,Pytorch会自动求得backward函数,使用autograd可自动计算梯度后传。
可学习的参数可用net.parameters()返回。

params = list(net.parameters())
print(len(params))
print(params[0].size())
10
torch.Size([6, 1, 5, 5])

下面输入一个autograd.Variable变量,输出也是这个类型。

input = Variable(torch.randn(1, 1, 32, 32))
out = net(input)
print out
Variable containing:
 0.0449 -0.0996  0.0021 -0.0830  0.0022 -0.0132 -0.1068  0.1161 -0.0166  0.0630
[torch.FloatTensor of size 1x10]

将梯度缓冲区置零,反传随机梯度:

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

注1: 这里手动清零是必须的,因为调用.backwardVariable.grad会自动累积,即Variable.grad=Variable.grad+new_grad

注2:torch.nn 仅支持一个mini-batch, 整个torch.nn包仅仅支持那些一个mini-batch的输入, 而单独的样本是不行的.
举例,nn.Conv2d 须输入一个4维Tensor,形状为nSamples x nChannels x Height x Width.
如果是单独的样本,使用input.unsqueeze(0)去增加batch的伪维度。

我们稍微回顾一下用到的函数和方法。

  • torch.Tensor - 多维度的数组
  • autograd.Variable - *封装一个Tensor,并记录其所有的操作历史。与Tensor有相同的接口,并多一个backward()。 它保留了对tensor的梯度。
  • nn.Module - 神经网络模块。可便捷地整合参数, 并由其他模块辅助进入GPU加速, 输出, 输入, 等等.
  • nn.Parameter - 一种自动注册为参数的变量,作为属性分配给模块。
  • autograd.Function -实现前传与后传操作autograd operation的定义。每个变量操作创造至少一个Function节点,链接创造变量的函数,记录操作历史*.
    到目前为止,我们
  • 定义了一个神经网络
  • 处理了输入并调用后传操作
    还余下:
  • 计算损失
  • 更新网络权重

损失函数

nn 包里有许多损失函数类型,最简单的是均方差nn.MSEloss

>>> output = net(input)
>>> target = Variable(torch.range(1, 10))  # a dummy target, for example
__main__:1: UserWarning: torch.range is deprecated in favor of torch.arange and will be removed in 0.3. Note that arange generates values in [start; end), not [start; end].
>>> criterion = nn.MSELoss()
>>> loss = criterion(output, target)
>>> print(loss)
Variable containing:
 37.8372
[torch.FloatTensor of size 1]
>>> output = net(input)
>>> target = Variable(torch.range(1, 10))  # a dummy target, for example
>>> criterion = nn.MSELoss()
>>> loss = criterion(output, target)
>>> print(loss)
Variable containing:
 37.8372
[torch.FloatTensor of size 1]

如果去看loss.creator属性,会看到计算图就像这样:

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

当我们调用loss.backward()时,就会调用Loss对整张计算图的导数,变量会计算梯度.grad

print loss.grad_fn
print loss.grad_fn.next_functions[0][0]
print loss.grad_fn.next_functions[0][0].next_functions[0][0]
print loss.grad_fn
print loss.grad_fn.next_functions[0][0]
print loss.grad_fn.next_functions[0][0].next_functions[0][0]

网络反传

调用loss.backward()之前须清理已有的梯度。

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
conv1.bias.grad before backward
Variable containing:
 0
 0
 0
 0
 0
 0
[torch.FloatTensor of size 6]

conv1.bias.grad after backward
Variable containing:
1.00000e-02 *
 -2.3452
  8.7239
 -5.3345
 -6.5685
 -2.3857
  5.7952
[torch.FloatTensor of size 6]

更新权重

根据最简单的更新原则随机梯度下降(SGD):
weight = weight - learning_rate * gradient
实现:

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

不过,我们也许希望用更高级的方法,比如Nesterov-SGD,Adam,RMSProp,等等。为了达到这些要求,我们调用torch.optim包:

import torch.optim as optim
optimizer = optim.SGD(net.parameters(), lr=0.01)
optimizer.zero_grad()
output=net(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容