翻译: 4.2. 从零开始实现多层感知器MLP pytorch
Posted AI架构师易筋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了翻译: 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。练习
-
- 更改超参数的值num_hiddens并查看此超参数如何影响您的结果。确定这个超参数的最佳值,保持所有其他参数不变。
原始值num_inputs, num_outputs, num_hiddens = 784, 10, 256
num_hiddens变小了,速度变快了,损失函数会变大一点,也就是结果变差了
改为num_hiddens = 56
, num_inputs, num_outputs, num_hiddens = 784, 10, 56
变大点num_inputs, num_outputs, num_hiddens = 784, 10, 2560
num_hiddens变大了,速度变慢了,损失函数会变小一点,也就是结果变好了一点
-
- 尝试添加一个额外的隐藏层,看看它如何影响结果。
加了一个隐藏层 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 准确度初始值的时候变小了。
-
- 改变学习率如何改变你的结果?修复模型架构和其他超参数(包括 epoch 数),什么学习率可以给你最好的结果?
参考基线 num_epochs, lr = 10, 0.1
增加 epoch num_epochs, lr = 100, 0.1
, 速度明显变慢,准确度上升
减少epoch num_epochs, lr = 5, 0.1
, 速度边框,test rate也没变化多少
-
- 通过联合优化所有超参数(学习率、时期数、隐藏层数、每层隐藏单元数),您可以获得的最佳结果是什么?
- 通过联合优化所有超参数(学习率、时期数、隐藏层数、每层隐藏单元数),您可以获得的最佳结果是什么?
Test Rate大约在85%
-
- 描述为什么处理多个超参数更具挑战性。
因为计算量,指数型增加。
If we have multiple hyperparameters, so mix-and-match of all the parameters will create an exponential amount of parameters to optimize.
- 描述为什么处理多个超参数更具挑战性。
-
- 对于构建多个超参数的搜索,您能想到的最聪明的策略是什么?
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
以上是关于翻译: 4.2. 从零开始实现多层感知器MLP pytorch的主要内容,如果未能解决你的问题,请参考以下文章
翻译: 4.1 多层感知器MLP Multilayer Perceptrons pytorch