PyTorch: 动态控制流程 + 权重共享

译者:@yongjay13@speedmancs

校对者:@bringtree

为了展示PyTorch的动态图的强大, 我们实现了一个非常奇异的模型: 一个全连接的ReLU激活的神经网络, 每次前向计算时都随机选一个1到4之间的数字n, 然后接下来就有n层隐藏层, 每个隐藏层的连接权重共享.

  1. import random
  2. import torch
  3. from torch.autograd import Variable
  4. class DynamicNet(torch.nn.Module):
  5. def __init__(self, D_in, H, D_out):
  6. """
  7. 在构造函数中,我们构造了三个nn.Linear实例,我们将在正向传递中使用它们.
  8. """
  9. super(DynamicNet, self).__init__()
  10. self.input_linear = torch.nn.Linear(D_in, H)
  11. self.middle_linear = torch.nn.Linear(H, H)
  12. self.output_linear = torch.nn.Linear(H, D_out)
  13. def forward(self, x):
  14. """
  15. 对于模型的正向通道,我们随机选择0,1,2或3,
  16. 并重复使用多次计算隐藏层表示的middle_linear模块.
  17. 由于每个正向通道都会生成一个动态计算图,因此在定义模型的正向通道时,
  18. 我们可以使用普通的Python控制流操作符(如循环或条件语句).
  19. 在这里我们也看到,定义计算图时多次重复使用相同模块是完全安全的.
  20. 这是Lua Torch的一大改进,每个模块只能使用一次.
  21. """
  22. h_relu = self.input_linear(x).clamp(min=0)
  23. for _ in range(random.randint(0, 3)):
  24. h_relu = self.middle_linear(h_relu).clamp(min=0)
  25. y_pred = self.output_linear(h_relu)
  26. return y_pred
  27. # N 批量大小; D_in是输入尺寸;
  28. # H是隐藏尺寸; D_out是输出尺寸.
  29. N, D_in, H, D_out = 64, 1000, 100, 10
  30. # 创建随机张量来保存输入和输出,并将它们包装在变量中.
  31. x = Variable(torch.randn(N, D_in))
  32. y = Variable(torch.randn(N, D_out), requires_grad=False)
  33. # 通过实例化上面定义的类来构建我们的模型
  34. model = DynamicNet(D_in, H, D_out)
  35. # 构建我们的损失函数和优化器.
  36. # 用随机梯度下降训练这个奇怪的模型非常困难,所以我们使用动量
  37. criterion = torch.nn.MSELoss(size_average=False)
  38. optimizer = torch.optim.SGD(model.parameters(), lr=1e-4, momentum=0.9)
  39. for t in range(500):
  40. # 正向传递:通过将x传递给模型来计算预测的y
  41. y_pred = model(x)
  42. # 计算和打印损失
  43. loss = criterion(y_pred, y)
  44. print(t, loss.data[0])
  45. # 零梯度执行反向传递并更新权重.
  46. optimizer.zero_grad()
  47. loss.backward()
  48. optimizer.step()