pytorch入门(二)

初步了解torch.nn

pytorch的神经网络层利用torch.nn实现,我们通过一个例子来熟悉其前向传播、反向传播的链路。

首先,我们给出要优化的函数——它是一个包含2000个样本的正弦函数:

import math
# Create Tensors to hold input and outputs.
x = torch.linspace(-math.pi, math.pi, 2000)
y = torch.sin(x)

我们用一个包含三个神经元的线性输入层去逼近真实的y,输出层是一个神经元,Flatten是继承自torch.flatten方法的,它表示将数据展成一维(与真实y维度对应):

torch.nn.Flatten(start_dim=0, end_dim=1)  
p = torch.tensor([1, 2, 3])
xx = x.unsqueeze(-1).pow(p) # tensor (x, x^2, x^3)

model = torch.nn.Sequential(
           torch.nn.Linear(3, 1),
           torch.nn.Flatten(0, 1)
)

定义损失函数,利用梯度下降法去优化参数:

#定义损失函数
loss_fn = torch.nn.MSELoss(reduction='sum')

learning_rate = 1e-6

for t in range(2000):

    y_pred = model(xx)
    loss = loss_fn(y_pred, y)
    if t % 100 == 0:
        print(t, loss.item())

    # Zero the gradients before running the backward pass.
    model.zero_grad()
    loss.backward()
    with torch.no_grad(): #停止对从跟踪历史中的requires_grad=True的张量自动求导 
        for param in model.parameters():
            param -= learning_rate * param.grad

model.parameters()可以获取神经网络层所有参数,这里一共4个参数,三个神经元对应的系数项w以及输出一个神经元对应的偏移项b。在第一讲的时候我们说过,pytorch计算梯度是累加的,所以下一次迭代执行反向传播前,需要执行梯度清零操作——moel.zero_grad()。然后,上面代码就剩下最后的torch.no_grad()要理解,要理解这个,首先要知道pytorch的原地操作符——in-place operation。

pytorch的原地操作符是指改变一个tensor的值的时候,不经过复制操作,而是直接在原来的内存上改变它的值,比如带下划线后缀的操作,“+=”操作:

x.add_(y)
x += 1
x *= 2

而pytorch规定有两种情况不能使用原地操作符:

  • 对于requires_grad=True的叶子张量

  • 求梯度阶段用到的张量

举个例子,下面对张量w的归一化会报错:

第二种情况就是上面的例子:

param -= learning_rate * param.grad

这里对模型参数进行原地操作符,它在计算w1后会更新w1,再次计算w2是会使用更新后w1的值,这显然就不对了。所以,为了避免这种情况,就要使用torch.no_grad()来停止对张量即刻更新,等待程序跳出with torch.no_grad()后再更新。

我们来看看模型的结果:

优化器torch.optim

上面的优化是执行了常规的梯度下降,梯度下降还有很多变种,pytorch也封装了各种优化器,直接调用就行。

传送门:梯度下降法

继续上一节的例子,我们来看看pytorch如何利用优化器完成整个训练过程:

learning_rate = 1e-3

optimizer = torch.optim.RMSprop(model.parameters(), lr=learning_rate)
for t in range(2000):
    # Forward pass: compute predicted y by passing x to the model.
    y_pred = model(xx)

    # Compute and print loss.
    loss = loss_fn(y_pred, y)
    if t % 500 == 0:
        print(t, loss.item())

    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

这里使用RMSprop梯度下降法,用torch.optim传入模型参数、学习率即可;然后执行代码optimizer.step() 进行参数更新

nn.Module

类似与keras,pytorch实现神经网络的高级API是模块torch.nn.Module,我们通过一个稍微复杂的案例来理解它的过程:

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
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

随便定义一些样本,通过优化器来训练模型:

input = torch.randn(1, 1, 32, 32)
target = torch.randn(10) # a dummy target, for example
target = target.view(1, -1) # make it the same shape as output


net = Net()
criterion = nn.MSELoss()
optimizer = optim.SGD(net.parameters(), lr=0.01)


for t in range(20):
    
    output = net(input)
    loss = criterion(output, target)
    print(t,loss.item())
    optimizer.zero_grad() # zero the gradient buffers
    loss.backward()
    optimizer.step() # Does the update

参考资料:

https://pytorch.org/tutorials/beginner/pytorch_with_examples.html#pytorch-nn

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

整得咔咔响

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值