原文:LEARNING PYTORCH WITH EXAMPLES
作者:Justin Johnson
翻译:Jerry
时间:2019-01-22
PyTorch: Tensors
Numpy是一个很好的框架,但是它不能利用GPU来加速数值计算。对于现在的深度网络而言,GPU通常能提供50倍或更高的提速,所以很不幸的是,Numpy对深度学习来说是不够的。
这里我们介绍PyTorch中最基础的概念:Tensor。它与numpy array是同一个东西:一个Tensor是一个n维数组,PyTorch为操作Tensor提供了很多函数。Tensor能在后台持续跟踪计算图和梯度,并且它对科学计算来说也是一个通用的工具。
与numpy不同,PyTorch的Tensor可以利用GPU来甲酸数值计算。要在GPU上使用Tensor,只需要将其转换成一个新的数据类型。
这里我们使用PyTorch的Tensor来实现一个两层网络以匹配随机数据。与numpy一样,这里我们需要自己实现神经网络的前向传播和反向传播:
dtype = torch.float
device = torch.device("cpu")
# device = torch.device("cuda:0") # 这行代码将使得PyTorch运行在GPU上
# N 是 batch size; D_in 是 输入层节点数;
# H 是 隐藏层节点数; D_out 是 输出层节点数.
N, D_in, H, D_out = 64, 1000, 100, 10
# 随机生成输入和输出
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)
# 随机初始化权重
w1 = torch.randn(D_in, H, device=device, dtype=dtype)
w2 = torch.randn(H, D_out, device=device, dtype=dtype)
learning_rate = 1e-6
for t in range(500):
# 前向传播:计算神经网络的预测值
h = x.mm(w1)
h_relu = h.clamp(min=0)
y_pred = h_relu.mm(w2)
# 计算、显示损失值
loss = (y_pred - y).pow(2).sum().item()
print(t, loss)
# 反向传播:计算w1和w2的梯度
grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_relu.t().mm(grad_y_pred)
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h < 0] = 0
grad_w1 = x.t().mm(grad_h)
# 使用梯度更新权重
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
Autograd
PyTorch: Tensors and autograd
在上面的例子中,我们手动实现了神经网络的前向传播和反向传播。在一个小网络(例如上面的2层网络)中实现反向传播还不算太难,但是对于一个大型复杂网络而言,这是一件非常棘手的事情。
值得庆幸的是,我们可以使用自动微分算法来实现神经网络中的反向传播。PyTorch中的autograd包正好提供了这个功能。当使用autogra的时候,神经网络的前向传播定义了计算图,图中的节点是Tensor,边是一个从输入Tensor产生输出Tensor的函数。通过计算图进行反向传播可以很容易得到梯度。
这听起来很复杂,其实它在使用的时候非常简单。每一个Tensor都代表着计算图中的一个节点,那些设置了x.requires_grad=True
的Tensorx
,可以通过x.grad
来得到x
在当前值下的梯度。
这里我们使用PyTorch的Tensor和autograd来实现我们的两层网络,现在我们不再需要手动实现反向传播了:
dtype = torch.float
device = torch.device("cpu")
# device = torch.device("cuda:0") # 这行代码将使得PyTorch运行在GPU上
# N 是 batch size; D_in 是 输入层节点数;
# H 是 隐藏层节点数; D_out 是 输出层节点数.
N, D_in, H, D_out = 64, 1000, 100, 10
# 随机生成输入和输出
# 设置requires_grad=False表示
# 在反向传播中不需要计算梯度
x = torch.randn(N, D_in, device=device, dtype=dtype)
y = torch.randn(N, D_out, device=device, dtype=dtype)
# 随机初始化权重
# 设置requires_grad=True表示
# 在反向传播中需要计算其梯度
w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True)
w2 = torch.randn(H, D_out, device=device, dtype