Pytorch基础-02-自动梯度

在PyTorch中提供了一种非常方便的方法,可以帮助我们实现对模 型中后向传播梯度的自动计算,避免了“重复造轮子”,这就是接下来要 重点介绍的torch.autograd包。通过使用 torch.autograd 包,可以使模型参 数自动计算在优化过程中需要用到的梯度值,在很大程度上帮助降低了 实现后向传播代码的复杂度。

  • 1. torch.autograd和Variable

torch.autograd包的主要功能是完成神经网络后向传播中的链式求 导,手动实现链式求导的代码会给我们带来很大的困扰,而 torch.autograd 包中丰富的类减少了这些不必要的麻烦。实现自动梯度功 能的过程大致为:先通过输入的Tensor数据类型的变量在神经网络的前 向传播过程中生成一张计算图,然后根据这个计算图和输出结果准确计 算出每个参数需要更新的梯度,并通过完成后向传播完成对参数的梯度 更新。

在实践中完成自动梯度需要用到torch.autograd包中的Variable类对 我们定义的Tensor数据类型变量进行封装,在封装后,计算图中的各个 节点就是一个Variable对象,这样才能应用自动梯度的功能。

如果已经按照如上方式完成了相关操作,则在选中了计算图中的某 个节点时,这个节点必定会是一个Variable对象,用X来代表我们选中的节点,那么X.data代表Tensor数据类型的变量,X.grad也是一个Variable对象,不过它表示的是X的梯度,在想访问梯度值时需要使用X.grad.data。

下面通过一个自动梯度的示例来看看如何使用 
torch.autograd.Variable类和torch.autograd包。

import torch
from torch.autograd import Variable

batch_n = 100
hidden_layer = 100
input_data = 1000
output_data = 10

# requires_grad = False表示进行自动梯度计算过程中不会保留梯度值
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)

w1 = Variable(torch.randn(input_data, hidden_layer), requires_grad=True)
w2 = Variable(torch.randn(hidden_layer, output_data), requires_grad=True)

epoch_n = 20
learning_rate = 1e-6

for epoch in range(epoch_n):
    y_pred = x.mm(w1).clamp(min=0).mm(w2)
    loss = (y_pred - y).pow(2).sum()
    # loss or loss.item() or loss.data
    print('Epoch:{},Loss:{}'.format(epoch, loss.data))

    loss.backward()

    w1.data -= learning_rate * w1.grad.data
    w2.data -= learning_rate * w2.grad.data

    w1.grad.data.zero_()
    w2.grad.data.zero_()

和之前的代码相比,当前的代码更简洁了,之前代码中的后向传播 计算部分变成了新代码中的 loss.backward(),这个函数的功能在于让模 型根据计算图自动计算每个节点的梯度值并根据需求进行保留,有了这 一步,我们的权重参数 w1.data和 w2.data就可以直接使用在自动梯度过 程中求得的梯度值w1.data.grad和w2.data.grad,并结合学习速率来对现 有的参数进行更新、优化了。在代码的最后还要将本次计算得到的各个 参数节点的梯度值通过grad.data.zero_()全部置零,如果不置零,则计算 的梯度值会被一直累加,这样就会影响到后续的计算。同样,在整个模 型的训练和优化过程中,每个循环都加入了打印loss值的操作,所以最 后会得到20个loss值的打印输出,输出的结果如下:

Epoch:0,Loss:42446340.0
Epoch:1,Loss:62124656.0
Epoch:2,Loss:212499536.
Epoch:3,Loss:613557184.
Epoch:4,Loss:316774848.
Epoch:5,Loss:8154250.5
Epoch:6,Loss:5126338.
Epoch:7,Loss:3525115.
Epoch:8,Loss:2591381.
Epoch:9,Loss:2009312.
Epoch:10,Loss:1627536.0
Epoch:11,Loss:1365516.
Epoch:12,Loss:1177440.375
Epoch:13,Loss:1036691.
Epoch:14,Loss:927293.625
Epoch:15,Loss:839377.
Epoch:16,Loss:766661.
Epoch:17,Loss:705069.9375
Epoch:18,Loss:651869.875
Epoch:19,Loss:605188.0625

  • 2. 自定义传播函数

其实除了可以采用自动梯度方法,我们还可以通过构建一个继承了torch.nn.Module的新类,来完成对前向传播函数和后向传播函数的重写。在这个新类中,我们使用forward作为前向传播函数的关键字,使用backward作为后向传播函数的关键字。下面介绍如何使用自定义传播函数的方法,来调整之前具备自动梯度功能的简易神经网络模型。整个代码如下:

import torch
from torch.autograd import Variable

batch_n = 100
hidden_layer = 100
input_data = 1000
output_data = 10


class Model(torch.nn.Module):
    def __init__(self):
        super(Model, self).__init__()

    def forward(self, input, w1, w2):
        x = torch.mm(input, w1)
        x = torch.clamp(x, min=0)
        x = torch.mm(x, w2)
        return x

    def backward(self):
        pass


model = Model()

# requires_grad = False表示进行自动梯度计算过程中不会保留梯度值
x = Variable(torch.randn(batch_n, input_data), requires_grad=False)
y = Variable(torch.randn(batch_n, output_data), requires_grad=False)

w1 = Variable(torch.randn(input_data, hidden_layer), requires_grad=True)
w2 = Variable(torch.randn(hidden_layer, output_data), requires_grad=True)

epoch_n = 20
learning_rate = 1e-6

for epoch in range(epoch_n):
    y_pred = model(x, w1, w2)

    loss = (y_pred - y).pow(2).sum()
    print('Epoch:{},Loss:{}'.format(epoch, loss))
    loss.backward()

    w1.data -= learning_rate * w1.grad.data
    w2.data -= learning_rate * w2.grad.data

    w1.grad.data.zero_()
    w2.grad.data.zero_()

其中通过 class Model(torch.nn.Module)完成了类继承的操作,之后分别是类的初始 化,以及forward函数和backward函数。forward函数实现了模型的前向 传播中的矩阵运算,backward实现了模型的后向传播中的自动梯度计 算,后向传播如果没有特别的需求,则在一般情况下不用进行调整。在 定义好类之后,我们就可以对其进行调用了。

在20次训练后,20个loss值的打印输出如下:

Epoch:0,Loss:50420576.0
Epoch:1,Loss:106698128.
Epoch:2,Loss:380107904.0
Epoch:3,Loss:688367040.0
Epoch:4,Loss:55686864.
Epoch:5,Loss:18643374.0
Epoch:6,Loss:10126001.
Epoch:7,Loss:6374650.0
Epoch:8,Loss:4365133.
Epoch:9,Loss:3169498.
Epoch:10,Loss:2409720.
Epoch:11,Loss:1904333.75
Epoch:12,Loss:1554992.
Epoch:13,Loss:1305658.
Epoch:14,Loss:1122339.75
Epoch:15,Loss:983649.125
Epoch:16,Loss:875711.
Epoch:17,Loss:789469.5
Epoch:18,Loss:718763.
Epoch:19,Loss:659620.625

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值