PyTorch与Python、Numpy等最大的区别在于自动求导机制,这种机制为神经网络训练过程中的梯度计算而特别设计。在PyTorch中,Autograd是所有神经网络的核心内容,为Tensor所有操作提供自动求导方法。
下面应用一个例子来理解Autograd机制的强大之处。
手动实现线性回归
线性回归是机器学习的入门知识,应用十分广泛。线性回归应用数理统计中的回归分析来确定两种或两种以上变量间相互依赖的定量关系,其表达形式为y = wx+b+e,其中误差e服从均值为0的正态分布。
利用随机梯度下降法更新参数w和b来最小化损失函数,最终学得w和b的数值。
import torch as t
import torch.optim as optim
import matplotlib.pyplot as plt
#########################################################
# 生成待拟合数据
#########################################################
def get_fake_data(batch_size=8):
'''
产生随机数据: y=x*2+3 '''
x = t.randn(batch_size, 1) * 20
y = x * 2 + 3
return x, y
# 产生x,y数据
x, y = get_fake_data()
# 显示原始点
# plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())
# plt.show()
#########################################################
# 线性回归
#########################################################
# 随机初始化参数
w = t.rand(1, 1)
b = t.zeros(1, 1)
# 学习率
lr = 0.001
# 训练集样本总数
batch_size = 8
for i in range(1000):
# forward部分
y_pred = x.mm(w) + b.expand_as(y)
error = y_pred - y
# 损失函数与终止条件
loss = error ** 2 / batch_size # 均方误差
loss = loss.sum()
print('loss is ', loss.numpy())
if loss < 0.01:
print(w.squeeze().numpy(), b.squeeze().numpy())
break
# backward部分
dw = x.t().mm(error) / batch_size
db = error.sum()
# 显示拟合线
# plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())
# plt.plot(x.squeeze().numpy(), (w*x + b).squeeze().numpy())
# plt.show()
利用Autograd实现线性回归
用Autograd实现的线性回归最大的不同点就在于利用Autograd不需要手动计算梯度,可以自动微分。需要注意的是在更新参数后要记得把梯度清零。
import torch as t
import torch.optim as optim
import matplotlib.pyplot as plt
#########################################################
# 生成待拟合数据
#########################################################
def get_fake_data(batch_size=8):
'''
产生随机数据: y=x*2+3 '''
x = t.randn(batch_size, 1) * 20
y = x * 2 + 3
return x, y
# 产生x,y数据
x, y = get_fake_data()
# 显示原始点
# plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())
# plt.show()
#########################################################
# 线性回归
#########################################################
# 随机初始化参数
w = t.rand(1, 1, requires_grad=True)
b = t.zeros(1, 1, requires_grad=True)
# 学习率
lr = 0.001
# 训练集样本总数
batch_size = 8
for i in range(3000):
# forward部分
y_pred = x.mm(w) + b.expand_as(y)
error = y_pred - y
# 损失函数与终止条件
loss = error ** 2 / batch_size # 均方误差
loss = loss.sum()
print('loss is ', loss.item())
if loss.item() < 0.05:
print(w.item(), b.item())
break
# backward部分(自动计算梯度)
loss.backward()
# 更新参数
w.requires_grad = False
b.requires_grad = False
w.sub_(lr * w.grad.data)
b.sub_(lr * b.grad.data)
w.requires_grad = True
b.requires_grad = True
# 梯度清零
w.grad.data.zero_()
b.grad.data.zero_()
# 显示拟合线
# plt.scatter(x.squeeze().numpy(), y.squeeze().numpy())
# plt.plot(x.squeeze().numpy(), (w.item()*x + b.item()).squeeze().numpy())
# plt.show()