《动手学深度学习+PyTorch》3.9多层感知机(MLP)从零开始实现 学习笔记


前言

我们已经学习了包括线性回归和softmax回归在内的单层神经网络。然而深度学习主要关注多层模型。本次,我们将完成一个简单的多层感知机(multilayer perceptron,MLP)。


一、引入库

import torch
import numpy as np
import sys
sys.path.append("..")
import d2lzh_pytorch as d2l

二、步骤

1.读取数据

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

读取训练集和测试集

2.参数设置

num_inputs, num_outputs, num_hiddens = 784, 10, 256

W1 = torch.tensor(np.random.normal(0, 0.01, (num_inputs, num_hiddens)), dtype=torch.float)
b1 = torch.zeros(num_hiddens, dtype=torch.float)
W2 = torch.tensor(np.random.normal(0, 0.01, (num_hiddens, num_outputs)), dtype=torch.float)
b2 = torch.zeros(num_outputs, dtype=torch.float)

params =[W1, b1, W2, b2]
for param in params:
    param.requires_grad_(requires_grad=True)

2.激活函数

def relu(X):
    return torch.max(input=X, other=torch.tensor(0.0))

def net(X):
    X =X.view((-1, num_inputs))
    H = relu(torch.matmul(X, W1) + b1)
    return torch.matmul(H, W2) + b2

torch.max(input=X, other=torch.tensor(0.0))

函数中other参数的意义可以通过一段测试代码来理解:

python import torch import numpy as np import sys
sys.path.append("..") import d2lzh_pytorch as d2l

def relu(X):
    return torch.max(input=X, other=torch.tensor(0.0))

X = torch.tensor(np.random.normal(0, 0.01, (2, 2)), dtype=torch.float)
Y = relu(X)

print(X, '\n'  , Y) 

输出为一下情况:

python tensor([[-0.0035,  0.0065],
        [-0.0013,  0.0013]])   tensor([[0.0000, 0.0065],
        [0.0000, 0.0013]]) 

可以发现定义的rule函数实现了激活函数应有的功能,其中other参数的意义应该是给定一个tensor,在输入tensor X中,若对应位置比给定的other tensor小,则将值替换为改other tensor的值,否则不变的意思。

torch.matmul(X, W1)t

orch.matmul()是tensor的乘法,输入可以是高维的。
当输入是都是二维时,就是普通的矩阵乘法,和tensor.mm()函数用法相同。

3.损失函数

loss = torch.nn.CrossEntropyLoss()

该函数的详细理解见:交叉熵损失函数详细理解

4.训练模型

书中的代码:

num_epochs, lr = 5, 100.0
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)

我没可以发现lr=100.0,前面学习线性拟合时说过学习率不应过大,为什么此处lr这么大?
如果我们强行把学习率改为lr=0.1则会出现:

epoch 1, loss 0.0090, train acc 0.139, test acc 0.163
epoch 2, loss 0.0090, train acc 0.190, test acc 0.210
epoch 3, loss 0.0090, train acc 0.237, test acc 0.251
epoch 4, loss 0.0089, train acc 0.284, test acc 0.293
epoch 5, loss 0.0089, train acc 0.320, test acc 0.324

可以看到,模型经过训练之后的准确率很低,所以强行修改学习率不可取。

我们找到sgd()的定义:

def sgd(params, lr, batch_size):
    # 为了和原书保持一致,这里除以了batch_size,但是应该是不用除的,因为一般用PyTorch计算loss时就
    # 默认已经沿batch维求了平均了。
    for param in params:
        param.data -= lr * param.grad / batch_size # 注意这里更改param时用的param.data

我们知道sgd()的定义是保存在书中提供的d2lzh_pytorch的包中,并非PyTorch官方提供,定义注释中说明PyTorch官方给出的loss计算函数已经沿batch维求了平均了,而为了和原书保持一致,这里除以了batch_size,但是应该是不用除的。
因为我们的模型使用了PyTorch官方的torch.nn.CrossEntropyLoss()已经沿batch维求了平均,所以在sgd中就不再需要除以batch_size

sgd函数最开始定义在《动手学深度学习+PyTorch》3.2线性回归的从零开始实现
学习笔记
中,在那篇博客里面,损失函数和参数回传的sgd()函数要么都是d2lzh_pytorch包中的,要么都是PyTorch官方的,都只除了一遍batch_size,所以就没有出现问题,但是在本文中,损失函数是官方,训练模型d2l.train_ch3()中用到的sgd()d2lzh_pytorch包的,所以就出现了这个问题。

所以我们把sgd()中除以batch_size注释掉,训练模型的代码变为:

num_epochs, lr = 5, 0.2
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)

输出:

epoch 1, loss 0.0034, train acc 0.690, test acc 0.786
epoch 2, loss 0.0020, train acc 0.814, test acc 0.783
epoch 3, loss 0.0018, train acc 0.837, test acc 0.805
epoch 4, loss 0.0017, train acc 0.849, test acc 0.824
epoch 5, loss 0.0016, train acc 0.858, test acc 0.847

可以看出准确率还是可以的,


总结

《动手学深度学习+PyTorch》3.9多层感知机(MLP)从零开始实现 学习笔记

猜你喜欢

转载自blog.csdn.net/qq_27839923/article/details/122552687