4.2 多层感知机的从零开始实现

发布时间 2023-06-29 12:08:20作者: Ann-

本节实现一个单隐藏层的,具有256个隐藏单元的多层感知机,并且隐藏层使用ralu函数激活。注意,我们通常选择2的若干次幂作为层的隐藏单元数,因为内存在硬件中的分配和寻址方式,这么做往往可以在计算上更高效。

1. 参数初始化

我们用几个张量来表示我们的参数。 注意,对于每一层我们都要记录一个权重矩阵和一个偏置向量。

num_inputs, num_outputs, num_hiddens = 784, 10, 256

#这个nn.Parameter就是声明变量是一个神经网络参数,不加也没关系
#torch.randn()创建均值为0,方差为1的标准正态分布张量,参数为张量的形状,这里是形状为(num_inputs,num_hiddens)(第一课pytorch数据处理有过)
#这里randn产生的随机数乘上0.01,如果外面不加一个nn.Parameter包起来的话会报错,说什么不能优化非叶子的tensor:can't optimize a non-leaf Tensor
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]

2. 定义激活函数relu

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

3. 定义模型

记得我们从数据集中拿到的X是1*28*28的,而我们目前不考虑其空间结构,要将其作为一个784的向量输入。

def net(X):
    X = X.reshape((-1, num_inputs))
    H = relu(X@W1 + b1)  # 这里“@”代表矩阵乘法
    return (H@W2 + b2)

4. 定义损失函数

由于之前已经实现过交叉熵损失了,我们这里直接使用torch.nn自带的交叉熵损失函数:

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

5. 训练

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)