简单训练模型加入autograd实现自动梯度计算

前言

今天的训练模型将在昨天的训练模型基础上做出改进,通过Pytorch中的autograd包替代后向传播中的手动链式求导,实现自动梯度功能。
(昨天的后向传播部分写的非常简略,主要是里面有个.t()函数一直查不出来是干啥用的……感觉自己理解的也非常模糊,只知道是在求偏导数……幸好有autograd可以掩盖我的无知……)

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import torch

from torch.autograd import Variable
batch_n = 100
hidden_layer = 100
input_data = 1000
output_data = 10

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()
print("Epoch:{}, Loss:{:.4f}".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_()

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Epoch:0, Loss:46125084.0000
Epoch:1, Loss:97735776.0000
Epoch:2, Loss:353886400.0000
Epoch:3, Loss:681477440.0000
Epoch:4, Loss:70418120.0000
Epoch:5, Loss:19572480.0000
Epoch:6, Loss:10264789.0000
Epoch:7, Loss:6297184.5000
Epoch:8, Loss:4209952.5000
Epoch:9, Loss:2988804.0000
Epoch:10, Loss:2225728.0000
Epoch:11, Loss:1726369.1250
Epoch:12, Loss:1387307.2500
Epoch:13, Loss:1149427.6250
Epoch:14, Loss:977541.5625
Epoch:15, Loss:849593.3125
Epoch:16, Loss:751535.7500
Epoch:17, Loss:674315.6875
Epoch:18, Loss:611959.5625
Epoch:19, Loss:560407.1250

由于在定义输入层和输出层时使用的是randn随即正态分布函数,运行结果会有很大不同,我挑了一组比较明显的结果。

代码分析

torch.grad包u实现自动梯度的过程大致为先通过定义的Tensor类型数据变量在前向传播中生成计算图,然后根据计算图和输出结果计算出每个参数需要更新的梯度,并通过后向传播完成对参数的梯度更新。
开头需要导入torch.grad包中的Variable类从而对Tensor数据类型变量进行封装。在计算图中,每个节点都应该是Variable类型的对象,这样才能应用自动梯度的功能。
requires_grad一看名字就知道,决定了Variable类型是否需要计算梯度,w1、w2是权重参数,所以为True。
.backward()函数根据我们自己设置的需求求出梯度值并保留,再结合学习速率对权重参数进行更新,最后通过.zero_()函数对grad.data进行置零,否则梯度值会一直累加,影响后边儿计算。