PyTorch学习笔记(三) ---- 神经网络

转载请注明作者和出处: http://blog.csdn.net/john_bh/


PyTorch搭建神经网络可以通过 torch.nn 包来构建。一个 nn.Module 包括层和一个方法 forward(input) 它会返回输出(output)。例如,看一下数字图片识别的网络:

在这里插入图片描述
这是一个简单的前馈神经网络,它接收输入,让输入一个接着一个的通过一些层,最后给出输出。

一个典型的神经网络训练过程包括以下几点:
1.定义一个包含可训练参数的神经网络
2.迭代整个输入
3.通过神经网络处理输入
4.计算损失(loss)
5.反向传播梯度到神经网络的参数
6.更新网络的参数,典型的用一个简单的更新方法:weight = weight - learning_rate *gradient

1.定义神经网络

# -*- coding:utf-8 -*-
import torch
import torch.nn as nn
import torch.nn.functional as F

# 1.定义神经网络

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__() #对继承自父类的属性进行初始化
        
        self.conv1 = nn.Conv2d(1,6,5) # 1 input image channel, 6 output channels, 5x5 square convolution
        self.conv2 = nn.Conv2d(6,16,5)
        
        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)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)),2)  # If the size is a square you can only specify a single number
        x =x.view(-1,self.num_flat_features(x))#view函数将张量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:]
        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(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() 返回
params=list(net.parameters())
print(len(params))
print(params[0].size())

输出:

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

2.迭代整个输入

随机生成一个 32x32 的输入。注意:期望的输入维度是 32x32 。为了使用这个网络在 MNIST 数据及上,你需要把数据集中的图片维度修改为 32x32。

# -*- coding:utf-8 -*-
import torch
import torch.nn as nn
import torch.nn.functional as F

# 1.定义神经网络

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__() #对继承自父类的属性进行初始化
        
        self.conv1 = nn.Conv2d(1,6,5) # 1 input image channel, 6 output channels, 5x5 square convolution
        self.conv2 = nn.Conv2d(6,16,5)
        
        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)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)),2)  # If the size is a square you can only specify a single number
        x =x.view(-1,self.num_flat_features(x))#view函数将张量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:]
        num_features=1
        for s in size:
            num_features *=s
        
        return num_features
    
net=Net()
#2.迭代整个输入
input = torch.randn(1, 1, 32, 32)
out = net(input)
print(out)

输出:

tensor([[-0.0142, -0.1713, -0.0990, 0.0307, 0.2069, -0.0126, 0.1045, 0.0479,
0.0644, -0.1227]], grad_fn=)

3.通过神经网络处理输入

# -*- coding:utf-8 -*-
import torch
import torch.nn as nn
import torch.nn.functional as F

# 1.定义神经网络

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__() #对继承自父类的属性进行初始化
        
        self.conv1 = nn.Conv2d(1,6,5) # 1 input image channel, 6 output channels, 5x5 square convolution
        self.conv2 = nn.Conv2d(6,16,5)
        
        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)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)),2)  # If the size is a square you can only specify a single number
        x =x.view(-1,self.num_flat_features(x))#view函数将张量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:]
        num_features=1
        for s in size:
            num_features *=s
        
        return num_features
    
net=Net()
#2.迭代整个输入
input = torch.randn(1, 1, 32, 32)
out = net(input)

#3.通过神经网络处理输入
#把所有参数梯度缓存器置零,用随机的梯度来反向传播
net.zero_grad()
out.backward(torch.randn(1,10))

4.计算损失(loss)

一个损失函数需要一对输入:模型输出和目标,然后计算一个值来评估输出距离目标有多远。有一些不同的损失函数在 nn 包中。一个简单的损失函数就是 nn.MSELoss ,这计算了均方误差。

例如:

# -*- coding:utf-8 -*-
import torch
import torch.nn as nn
import torch.nn.functional as F

# 1.定义神经网络

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__() #对继承自父类的属性进行初始化
        
        self.conv1 = nn.Conv2d(1,6,5) # 1 input image channel, 6 output channels, 5x5 square convolution
        self.conv2 = nn.Conv2d(6,16,5)
        
        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)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)),2)  # If the size is a square you can only specify a single number
        x =x.view(-1,self.num_flat_features(x))#view函数将张量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:]
        num_features=1
        for s in size:
            num_features *=s
        
        return num_features
    
net=Net()
#2.迭代整个输入
input = torch.randn(1, 1, 32, 32)
out = net(input)

# 4.计算损失值
# 一个损失函数需要一对输入:模型输出和目标,然后计算一个值来评估输出距离目标有多远。有一些不同的损失函数在 nn 包中。
# 一个简单的损失函数就是 nn.MSELoss ,这计算了均方误差。
target=torch.randn(10)
target=target.view(1,-1)
criterion=nn.MSELoss()

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

输出:

tensor(1.2788, grad_fn=<MseLossBackward>)

现在,如果你跟随损失到反向传播路径,可以使用它的 .grad_fn 属性,你将会看到一个这样的计算图:

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

所以,当我们调用 loss.backward(),整个图都会微分,而且所有的在图中的requires_grad=True 的张量将会让他们的 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

输出:

<MseLossBackward object at 0x0000023E639F6400>
<AddmmBackward object at 0x0000023E639F6400>
<AccumulateGrad object at 0x0000023E637EF978>

5.反向传播梯度到神经网络的参数

为了实现反向传播损失,我们所有需要做的事情仅仅是使用 loss.backward()。你需要清空现存的梯度,要不然梯度将会和现存的梯度累计到一起。

现在我们调用 loss.backward() ,然后看一下 con1 的偏置项在反向传播之前和之后的变化。

# -*- coding:utf-8 -*-

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

# 1.定义神经网络

class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__() #对继承自父类的属性进行初始化
        
        self.conv1 = nn.Conv2d(1,6,5) # 1 input image channel, 6 output channels, 5x5 square convolution
        self.conv2 = nn.Conv2d(6,16,5)
        
        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)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)),2)  # If the size is a square you can only specify a single number
        x =x.view(-1,self.num_flat_features(x))#view函数将张量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:]
        num_features=1
        for s in size:
            num_features *=s
        
        return num_features
    
net=Net()
#2.迭代整个输入
input = torch.randn(1, 1, 32, 32)
out = net(input)
out.backward(torch.randn(1,10))
out=net(input)

target=torch.randn(10)
target=target.view(1,-1)
criterion=nn.MSELoss()

loss=criterion(out,target)
# print(loss)

# 5.反向传播梯度到神经网络的参数
# 为了实现反向传播损失,我们所有需要做的事情仅仅是使用 loss.backward()。你需要清空现存的梯度,要不然梯度将会和现存的梯度累计到一起。
# 现在我们调用 loss.backward() ,然后看一下 con1 的偏置项在反向传播之前和之后的变化。
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 tensor([0., 0., 0., 0., 0., 0.])
conv1.bias.grad after backward tensor([ 9.7322e-03, -6.5905e-05,
2.7879e-03, -2.1420e-03, 2.8334e-03,
1.1446e-02])

6.更新网络的参数

更新神经网络参数:最简单的更新规则就是随机梯度下降

weight = weight - learning_rate * gradient

在神经网络中,可以使用torch.optim 调用常用的方法: SGD, Nesterov-SGD, Adam, RMSProp等

# -*- coding:utf-8 -*-

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

# 1.定义神经网络
class Net(nn.Module):
    def __init__(self):
        super(Net,self).__init__() #对继承自父类的属性进行初始化
        
        self.conv1 = nn.Conv2d(1,6,5) # 1 input image channel, 6 output channels, 5x5 square convolution
        self.conv2 = nn.Conv2d(6,16,5)
        
        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)) # Max pooling over a (2, 2) window
        x = F.max_pool2d(F.relu(self.conv2(x)),2)  # If the size is a square you can only specify a single number
        x =x.view(-1,self.num_flat_features(x))#view函数将张量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:]
        num_features=1
        for s in size:
            num_features *=s
        
        return num_features
    
net=Net()
#2.迭代整个输入
input = torch.randn(1, 1, 32, 32)
target=torch.randn(10)
target=target.view(1,-1)

criterion=nn.MSELoss()
net.zero_grad() #清空现存的梯度

#6.使用优化函数,更新神经网络参数
optimizer=optim.SGD(net.parameters(),lr=0.01)
optimizer.zero_grad()# zero the gradient buffers

output=net(input) #网络处理输入
loss=criterion(output,target) #计算losss
loss.backward() #调用反向传播

optimizer.step() # Does the update
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值