前言

本文将基于MINIST数据集,建立一个多层感知机完成图像分类任务。和本系列之前的博文一样,首先采用“造轮子”的方法从头开始实现,最后用pytorch的高级API封装实现。值得注意的是,训练过程和模型评价的函数由d2l包给出,d2l包并不具有普适性。本文采用的代码如下:

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模块。

    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 可能会导致过拟合,即模型在训练数据上表现很好,但在新数据上表现不佳。

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

    定义待优化参数和初始化参数

    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]

    定义模型

    定义激活函数

    def relu(x):
        return torch.max(x,torch.zeros_like(x))

    定义学习模型

    def net(x):
        x = x.reshape(-1, num_inputs)
        h = relu(x@W1 + b1)
        return (h@W2 + b2)

    定义损失函数

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

    定义优化手段

    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的简洁实现

    import torch
    from torch import nn
    from d2l import torch as d2l
    
    # 定义神经网络模型
    net = nn.Sequential(
        nn.Flatten(),           # 将输入的图像展平为向量
        nn.Linear(784, 256),    # 全连接层,输入维度为784,输出维度为256
        nn.ReLU(),              # 激活函数ReLU
        nn.Linear(256, 10)      # 全连接层,输入维度为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库中的训练函数进行模型训练
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)