定义模型参数

模型的构建加了一层隐藏层

  1. import torch
  2. import d2lzh
  3. # 数据初始化与之前相同
  4. batch_size = 256
  5. train_iter, test_iter = d2lzh.load_data_fashion_mnist(batch_size)
  6. num_inputs, num_outputs, num_hiddens = 784, 10, 256
  7. W1 = torch.normal(mean=0, std=0.01, size=[num_inputs, num_hiddens], dtype=torch.float, requires_grad=True)
  8. b1 = torch.zeros(num_hiddens, dtype=torch.float)
  9. W2 = torch.normal(mean=0, std=0.01, size=[num_hiddens, num_outputs], dtype=torch.float, requires_grad=True)
  10. b2 = torch.zeros(num_outputs, dtype=torch.float)

定义激活函数

使用relu函数作为激活函数。在torch.max()函数中,other表明待比较的张量。因此,relu函数

  1. def relu(x):
  2. return torch.max(x, other=torch.tensor(0.0))
  3. # 对张量中每个元素都做relu激活操作
  4. print(relu(torch.tensor([1.0, -1.0])))
  5. 结果:
  6. tensor([1., 0.])

定义模型及损失函数

torch.matmul是tensor的乘法,输入可以是高维的。当输入是都是二维时,就是普通的矩阵乘法,和tensor.mm函数用法相同。
具体用法参见:torch.matmul()用法介绍

同softmax回归一样,我们通过view函数将每张原始图像改成长度为num_inputs的向量。

其实就是从输入层到隐藏层,再到输出层的计算

  1. def net(x):
  2. x = x.view((-1, num_inputs))
  3. h = relu(torch.matmul(x, W1) + b1)
  4. return torch.matmul(h, W2) + b2
  5. loss = torch.nn.CrossEntropyLoss()

训练模型

设置超参数迭代周期数为5,学习率为100.0

原书的mxnet中的SoftmaxCrossEntropyLoss在反向传播的时候相对于沿batch维求和了,而PyTorch默认的是求平均,所以用PyTorch计算得到的loss比mxnet小很多(大概是maxnet计算得到的1/batch_size这个量级),所以反向传播得到的梯度也小很多,所以为了得到差不多的学习效果,我们把学习率调得成原书的约batch_size倍,原书的学习率为0.5,这里设置成100.0。(之所以这么大,应该是因为d2lzh_pytorch里面的sgd函数在更新的时候除以了batch_size,其实PyTorch在计算loss的时候已经除过一次了,sgd这里应该不用除了)

他讲的这段话看看之前线性回归从零开始实现的笔记就能知道是什么意思。不用他的sgd函数就不用这么大的学习率了。

完整代码:

  1. import torch
  2. import d2lzh
  3. batch_size = 256
  4. train_iter, test_iter = d2lzh.load_data_fashion_mnist(batch_size)
  5. num_inputs, num_outputs, num_hiddens = 784, 10, 256
  6. W1 = torch.normal(mean=0, std=0.01, size=[num_inputs, num_hiddens], dtype=torch.float, requires_grad=True)
  7. b1 = torch.zeros(num_hiddens, dtype=torch.float, requires_grad=True)
  8. W2 = torch.normal(mean=0, std=0.01, size=[num_hiddens, num_outputs], dtype=torch.float, requires_grad=True)
  9. b2 = torch.zeros(num_outputs, dtype=torch.float, requires_grad=True)
  10. params = [W1, b1, W2, b2]
  11. def relu(x):
  12. return torch.max(x, other=torch.tensor(0.0))
  13. def net(x):
  14. x = x.view((-1, num_inputs))
  15. h = relu(torch.matmul(x, W1) + b1)
  16. return torch.matmul(h, W2) + b2
  17. loss = torch.nn.CrossEntropyLoss()
  18. num_epochs, lr = 5, 100.0
  19. d2lzh.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)

小结

  • 可以通过手动定义模型及其参数来实现简单的多层感知机。
  • 当多层感知机的层数较多时,本节的实现方法会显得较烦琐,例如在定义模型参数的时候。