Pytorch|官方入门教程-学习笔记(二)-神经网络

背景介绍

Pytorch是torch的一个衍生品,在Python语言中可以替代numpy的一个强大的科学计算库。

Pytorch与TensorFlow的主要区别:

  • TensorFlow是基于静态计算图,需要先定义再运行,一次定义多次运行;
  • Pytorch基于动态计算图,在运行过程中进行定义,可以实现多次构建多次运行。

Pytorch官方文档传送门

神经网络

torch.nn是神经网络的模块化接口,nn构建于Autograd之上,可用来定义和运行神经网络。torch.nn.module是nn一个重要的类,既可以表示神经网络的某一层(layer),也可以表示一个包含很多层的神经网络。一般在使用中,可以继承nn.module,编写自己的网络层。

一个典型的神经网络训练过程包括以下几点:

  • 定义一个包含可训练参数(或权重)的神经网络;
  • 迭代整个输入;
  • 通过神经网络处理输入;
  • 计算损失(当前输出的准确程度);
  • 反向传播梯度到神经网络的参数;
  • 更新网络的参数;

定义网络

现以Lenet网络为示例,演示一个前馈神经网络的定义过程:
LeNet网络结构

该网络的代码描述分为三个部分:卷积->激活->池化。

import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        # nn.Module的子类函数必须在构造函数中执行父类的构造函数
        super(Net, self).__init__() # 等价于nn.Module.__init__(self)
        
        # 卷积层
        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):
        # 最大池化
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        x = x.view(x.size()[0], -1)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        
        return x
    
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, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)

网络的可训练参数可通过net.parameters()返回,net.named_parameters()可同时返回名称与参数:

param = list(net.parameters())
print(len(param))

for name, parameters in net.named_parameters():
    print(name, ':', parameters.size())

输出:

10
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])

对此的x尝试32*32的输入。由于torch.nn只支持mini-batches,一次输入必须以一个batch为单位。比如nn.Conv2d的输入需要4维数据,形如nSamples × nChannels × Height × Width,可将样本数设为1:

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

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

输出:

tensor([[-0.0379, 0.0291, -0.0321, 0.1000, -0.0400, -0.0975, -0.0263, 0.0553, 0.0381, -0.0784]], grad_fn=<AddmmBackward>)

损失函数

nn库实现了神经网络中的大多数损失函数。例如nn.MSELoss用来计算均方误差,nn.CrossEntropyLoss用来计算交叉熵损失。对上例中的x定义一个随机指定的目标向量:

output = net(input)
target = t.randn(10)
target = target.view(1, -1)
criterion = nn.MSELoss()

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

print(loss.grad_fn)
print(net.conv1.bias.grad)

输出:

tensor(1.0112, grad_fn=<MseLossBackward>)
<MseLossBackward object at 0x0000024DA94798D0>
tensor([-0.0333, -0.0038, -0.0306, 0.0085, 0.0234, -0.0376])

反向传播

如果对loss进行反向传播溯源,可观察到其计算图的序列如下:input -> conv2d -> relu -> maxpool2d -> conv2d -> relu -> maxpool2d -> view -> linear -> relu -> linear -> relu -> linear -> MSELoss -> loss,当调用loss.backward(),该图会自动生成并自动微分,也会自动计算图中parameters的导数,而且所有在图中requires_grad = True的张量也会让他们的grad张量累计梯度。

net.zero_grad() # 将net中所有可学习参数的梯度清零
print('反向传播之前conv1.bias的梯度')
print(net.conv1.bias.grad)

loss.backward()

print('反向传播之后conv1.bias的梯度')
print(net.conv1.bias.grad)

反向传播之前conv1.bias的梯度
tensor([0., 0., 0., 0., 0., 0.])
反向传播之后conv1.bias的梯度
tensor([ 0.0040, 0.0052, 0.0036, 0.0031, 0.0193, -0.0061])

优化器

反向传播计算完所有参数的梯度后,需要使用优化方法来更新网络的权重和参数。一般采用随机梯度下降(SGD):
weight = weight - learning_rate * gradient
torch.optim实现了神经网络中的绝大多数优化方法,例如SGD,Adam,RMSProp等。

import torch.optim as optim

# 新建一个优化器,指定要调整的参数和学习率
optimizer = optim.SGD(net.parameters(), lr = 0.01)

# 训练之前先进行梯度清零(等同于net.zreo_grad)
optimizer.zero_grad()

# 计算损失
output = net(input)
loss = criterion(output, target)

# 反向传播
loss.backward()

# 更新参数
optimizer.step()

print(net.conv1.bias.grad)

tensor([ 0.0018, 0.0017, 0.0028, 0.0059, 0.0082, -0.0086])

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

推荐阅读更多精彩内容