前言
本文将基于MINIST数据集,建立一个多层感知机完成图像分类任务。和本系列之前的博文一样,首先采用“造轮子”的方法从头开始实现,最后用pytorch的高级API封装实现。值得注意的是,训练过程和模型评价的函数由d2l包给出,d2l包并不具有普适性。本文采用的代码如下:
1
| d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs,trainer)
|
事实上,我们从该函数的参数可以窥见完成深度学习的基本要素:
深度学习的基本要素
数据采集(train_iter, test_iter):获取和规范数据,划分为训练集、验证集和测试集。
模型定义(net):包括模型的层数和每层进行的运算(激活函数),神经元和神经元之间的联系;最重要的是输入层和输出层的定义(一般使用nn.Sequential()进行连续定义)。
损失函数(loss):描述输出层数据(或进一步变换)和真实数据的误差。
优化方法(trainer, num_epochs):包括降低损失的手段(如梯度下降法)、需要优化的参数、以及参数变化幅度(学习率)。num_epochs则定义了重复训练的次数。
多层感知机的从头实现
导包
我们使用torch实现多层感知机。从torch包中导入nn模块。
1 2 3
| import torch from torch import nn from d2l import torch as d2l
|
数据采集
使用d2l已经封装好的数据采集函数,定义每个batch的大小为256。
这里还需要记录一下:深度学习对训练集划分为不同的batch,batch的获得是随机的,初始化的参数经过batch优化后得到新的参数,继而进入下一个batch运算。通过所有batch运算完最后得到本轮epoch训练的参数。本轮epoch训练的参数继续进入下一个epoch。
epoch 的概念是为了让模型在整个训练数据集上得到充分的学习,以便提高模型的性能和泛化能力。增加 epoch 的数量可以使模型更好地适应训练数据,但过多的 Epoch 可能会导致过拟合,即模型在训练数据上表现很好,但在新数据上表现不佳。
1 2
| batch_size = 256 train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
|
定义待优化参数和初始化参数
1 2 3 4 5 6
| num_inputs, num_outputs, num_hiddens = 784, 10, 256 W1 = nn.Parameter(torch.randn(num_inputs, num_hiddens, requires_grad = True)) b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad = True)) W2 = nn.Parameter(torch.randn(num_hiddens, num_outputs, requires_grad = True)) b2 = nn.Parameter(torch.zeros(num_outputs,requires_grad = True)) params = [W1, b1, W2, b2]
|
定义模型
定义激活函数
1 2
| def relu(x): return torch.max(x,torch.zeros_like(x))
|
定义学习模型
1 2 3 4
| def net(x): x = x.reshape(-1, num_inputs) h = relu(x@W1 + b1) return (h@W2 + b2)
|
定义损失函数
1
| loss = nn.CrossEntropyLoss(reduction = 'none')
|
定义优化手段
1 2 3 4
| num_epochs = 10 lr = 0.1 updater = torch.optim.SGD(params, lr = lr) d2l.train_ch3(net, train_iter, test_iter,loss, num_epochs, updater)
|
基于PyTorch高级API的简洁实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import torch from torch import nn from d2l import torch as d2l
net = nn.Sequential( nn.Flatten(), nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 10) )
def init_weights(m): if type(m) == nn.Linear: nn.init.normal_(m.weight, std=0.01) net.apply(init_weights)
batch_size = 256 lr = 0.1 num_epochs = 10
loss = nn.CrossEntropyLoss(reduction="none")
trainer = torch.optim.SGD(net.parameters(), lr=lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
|