翻译: 4.2. 从零开始实现多层感知器MLP pytorch

现在我们已经在数学上描述了多层感知器 (MLP),让我们尝试自己实现一个。为了与我们之前通过 softmax 回归(第 3.6 节)获得的结果进行比较,我们将继续使用 Fashion-MNIST 图像分类数据集(第 3.5 节)。

import torch
from torch import nn
from d2l import torch as d2l

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

4.2.1。初始化模型参数

回想一下,Fashion-MNIST 包含 10 个类,并且每个图像都包含一个28 x 28 = 784灰度像素值网格。同样,我们现在将忽略像素之间的空间结构,因此我们可以将其视为具有 784 个输入特征和 10 个类别的简单分类数据集。首先,我们将实现一个具有一个隐藏层和 256 个隐藏单元的 MLP。请注意,我们可以将这两个量都视为超参数。通常,我们选择以 2 的幂为单位的层宽度,由于内存在硬件中的分配和寻址方式,这往往具有计算效率。

同样,我们将用几个张量来表示我们的参数。请注意, 对于每一层,我们必须跟踪一个权重矩阵和一个偏置向量。与往常一样,我们为这些参数的损失梯度分配内存。

num_inputs, num_outputs, num_hiddens = 784, 10, 256

W1 = nn.Parameter(torch.randn(
    num_inputs, num_hiddens, requires_grad=True) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad=True))
W2 = nn.Parameter(torch.randn(
    num_hiddens, num_outputs, requires_grad=True) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))

params = [W1, b1, W2, b2]

4.2.2. 激活函数

为了确保我们知道一切是如何工作的,我们将使用最大函数自己实现 ReLU 激活,而不是直接调用内置relu函数。

def relu(X):
    a = torch.zeros_like(X)
    return torch.max(X, a)

4.2.3 模型 Model

因为我们不考虑空间结构,所以我们将reshape每个二维图像转换为长度为 的平面向量num_inputs。最后,我们只用几行代码来实现我们的模型。

def net(X):
    X = X.reshape((-1, num_inputs))
    H = relu(X@W1 + b1)  # Here '@' stands for matrix multiplication
    return (H@W2 + b2)

4.2.4. 损失函数

为了确保数值稳定性,并且因为我们已经从头开始实现了 softmax 函数(第 3.6 节),我们利用来自高级 API 的集成函数来计算 softmax 和交叉熵损失。回想一下我们之前在第 3.7.2 节中对这些复杂性的讨论 。我们鼓励感兴趣的读者检查损失函数的源代码,以加深他们对实现细节的了解。

loss = nn.CrossEntropyLoss(reduction='none')

4.2.5 训练

幸运的是,MLP 的训练循环与 softmax 回归完全相同。再次利用该d2l包,我们调用该 train_ch3函数(参见第 3.6 节),将 epoch 数设置为 10,将学习率设置为 0.1。

num_epochs, lr = 10, 0.1
updater = torch.optim.SGD(params, lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)

在这里插入图片描述
为了评估学习模型,我们将其应用于一些测试数据。

d2l.predict_ch3(net, test_iter)

在这里插入图片描述

4.2.6 概括

  • 我们看到实现一个简单的 MLP 很容易,即使手动完成也是如此。

  • 然而,对于大量的层,从头开始实现 MLP 仍然会变得混乱(例如,命名和跟踪我们模型的参数)。

4.2.7。练习

    1. 更改超参数的值num_hiddens并查看此超参数如何影响您的结果。确定这个超参数的最佳值,保持所有其他参数不变。

原始值num_inputs, num_outputs, num_hiddens = 784, 10, 256
在这里插入图片描述

num_hiddens变小了,速度变快了,损失函数会变大一点,也就是结果变差了
改为num_hiddens = 56num_inputs, num_outputs, num_hiddens = 784, 10, 56
在这里插入图片描述

变大点num_inputs, num_outputs, num_hiddens = 784, 10, 2560
num_hiddens变大了,速度变慢了,损失函数会变小一点,也就是结果变好了一点
在这里插入图片描述

    1. 尝试添加一个额外的隐藏层,看看它如何影响结果。
      加了一个隐藏层 128,初始化参数需要变
num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 128

W1 = nn.Parameter(torch.randn(
    num_inputs, num_hiddens1, requires_grad=True) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens1, requires_grad=True))
W2 = nn.Parameter(torch.randn(
    num_hiddens1, num_hiddens2, requires_grad=True) * 0.01)
b2 = nn.Parameter(torch.zeros(num_hiddens2, requires_grad=True))
W3 = nn.Parameter(torch.randn(
    num_hiddens2, num_outputs, requires_grad=True) * 0.01)
b3 = nn.Parameter(torch.zeros(num_outputs, requires_grad=True))

params = [W1, b1, W2, b2, W3, b3]

对应的model函数也需要变

def net(X):
    X = X.reshape((-1, num_inputs))
    H = relu(X@W1 + b1)  # Here '@' stands for matrix multiplication
    H2 = relu(H@W2 + b2)
    return (H2@W3 + b3)

在这里插入图片描述
结果变化不大,但是acc 准确度初始值的时候变小了。

    1. 改变学习率如何改变你的结果?修复模型架构和其他超参数(包括 epoch 数),什么学习率可以给你最好的结果?

参考基线 num_epochs, lr = 10, 0.1
在这里插入图片描述
增加 epoch num_epochs, lr = 100, 0.1, 速度明显变慢,准确度上升
在这里插入图片描述
减少epoch num_epochs, lr = 5, 0.1, 速度边框,test rate也没变化多少
在这里插入图片描述

    1. 通过联合优化所有超参数(学习率、时期数、隐藏层数、每层隐藏单元数),您可以获得的最佳结果是什么?
      在这里插入图片描述

Test Rate大约在85%

    1. 描述为什么处理多个超参数更具挑战性。
      因为计算量,指数型增加。
      If we have multiple hyperparameters, so mix-and-match of all the parameters will create an exponential amount of parameters to optimize.
    1. 对于构建多个超参数的搜索,您能想到的最聪明的策略是什么?

Grid search can be a good way to go about it. Increase the value exponentially. Maybe try binary search. The idea is to not go linearly but in order of log.

参考

https://d2l.ai/chapter_multilayer-perceptrons/mlp-scratch.html

猜你喜欢

转载自blog.csdn.net/zgpeace/article/details/123948810