• 多层感知机的从零开始实现——2020.2.24


    其他博客:

    多层感知机概述:https://www.cnblogs.com/somedayLi/p/12313804.html
    多层感知机简洁实现:https:////www.cnblogs.com/somedayLi/p/12359420.html

    下⾯实现⼀个多层感知机。⾸先导⼊实现所需的包或模块。

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

    1. 获取和读取数据:

    这⾥继续使⽤Fashion-MNIST数据集。我们将使⽤多层感知机对图像进⾏分类。

    # 1.获取和读取数据
    batch_size = 256
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
    

    2. 定义模型参数

    Fashion-MNIST数据集中图像形状为(28 imes 28),类别数为 10 。本节中我们依然使⽤⻓度为 (28 imes 28 = 784) 的向量表示每⼀张图像。因此,输⼊个数为784,输出个数为10。实验中,我们设超参数隐藏单元个数为256。

    # 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)
    

    3. 定义激活函数

    使⽤基础的 max 函数来实现ReLU,⽽⾮直接调⽤ relu 函数。

    # 3 定义激活函数
    def relu(x):
        return torch.max(input=x, other=torch.tensor(0.0))
    

    4. 定义模型

    同softmax回归⼀样,我们通过 view 函数将每张原始图像改成⻓度为 num_inputs 的向量。然后实现概述中的多层感知机的计算表达式。

    # 4 定义模型
    def net(x):
        x = x.view((-1, num_inputs))
        H = relu(torch.matmul(x,w1) + b1)
        return torch.matmul(H, w2) + b2
    

    5. 定义损失函数

    为了得到更好的数值稳定性,我们直接使⽤PyTorch提供的包括softmax运算和交叉熵损失计算的函数。

    # 5 定义损失函数
    loss = torch.nn.CrossEntropyLoss()
    

    6. 训练模型

    训练多层感知机的步骤和3.6节中训练softmax回归的步骤没什么区别。我们直接调⽤ d2lzh_pytorch 包中的 train_ch3 函数,它的实现已经在3.6节⾥介绍过。我们在这⾥设超参数迭代周期数为5,学习率为100.0。

    注:由于原书的mxnet中的 SoftmaxCrossEntropyLoss 在反向传播的时候相对于沿batch维求和了,⽽PyTorch默认的是求平均,所以⽤PyTorch计算得到的loss⽐mxnet⼩很多(⼤概是maxnet计算得到的1/batch_size这个量级),所以反向传播得到的梯度也⼩很多,所以为了得到差不多的学习效果,我们把学习率调得成原书的约batch_size倍,原书的学习率为0.5,这⾥设置成100.0。(之所以这么⼤,应该是因为d2lzh_pytorch⾥⾯的sgd函数在更新的时候除以了batch_size,其实PyTorch在计算loss的时候已经除过⼀次了,sgd这⾥应该不⽤除了)

    # 6 训练模型
    num_epochs, lr = 5, 100.0
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)
    

    这一步稍稍费时一点,花了大概1min左右。
    运行结果:

    epoch 1, loss 0.0031, train acc 0.713, test acc 0.815
    epoch 2, loss 0.0019, train acc 0.826, test acc 0.817
    epoch 3, loss 0.0017, train acc 0.843, test acc 0.754
    epoch 4, loss 0.0015, train acc 0.857, test acc 0.799
    epoch 5, loss 0.0014, train acc 0.866, test acc 0.860
    

    从上述结果中,即可看出不同损失函数下的准确率的变化,随着训练周期越长,损失函数值减小、准确率更高。
    对第6步训练模型稍作修改,输出运行时间。修改后的代码:

    # 6 训练模型
    import time
    num_epochs, lr = 5, 100.0
    start = time.time()
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, batch_size, params, lr)
    print(time.time() - start)
    

    第二次运行训练模型训练结果:

    epoch 1, loss 0.0014, train acc 0.870, test acc 0.860
    epoch 2, loss 0.0013, train acc 0.876, test acc 0.833
    epoch 3, loss 0.0013, train acc 0.880, test acc 0.841
    epoch 4, loss 0.0012, train acc 0.885, test acc 0.844
    epoch 5, loss 0.0012, train acc 0.887, test acc 0.841
    132.66817021369934
    

    第三次运行结果

    epoch 1, loss 0.0012, train acc 0.890, test acc 0.872
    epoch 2, loss 0.0011, train acc 0.894, test acc 0.808
    epoch 3, loss 0.0011, train acc 0.894, test acc 0.870
    epoch 4, loss 0.0011, train acc 0.897, test acc 0.869
    epoch 5, loss 0.0010, train acc 0.900, test acc 0.873
    118.6175651550293
    

    我做了一个尝试,将学习周期设为10、20,继续运行:

    • 将学习周期设为10,运行结果:
    epoch 1, loss 0.0010, train acc 0.901, test acc 0.876
    epoch 2, loss 0.0010, train acc 0.904, test acc 0.857
    epoch 3, loss 0.0010, train acc 0.906, test acc 0.854
    epoch 4, loss 0.0010, train acc 0.907, test acc 0.862
    epoch 5, loss 0.0010, train acc 0.909, test acc 0.826
    epoch 6, loss 0.0009, train acc 0.911, test acc 0.865
    epoch 7, loss 0.0009, train acc 0.912, test acc 0.884
    epoch 8, loss 0.0009, train acc 0.914, test acc 0.884
    epoch 9, loss 0.0009, train acc 0.916, test acc 0.881
    epoch 10, loss 0.0009, train acc 0.916, test acc 0.856
    234.6531686782837
    
    • 将学习周期设为20,运行结果:
    epoch 1, loss 0.0009, train acc 0.917, test acc 0.871
    epoch 2, loss 0.0009, train acc 0.918, test acc 0.875
    epoch 3, loss 0.0008, train acc 0.922, test acc 0.867
    epoch 4, loss 0.0008, train acc 0.923, test acc 0.873
    epoch 5, loss 0.0008, train acc 0.924, test acc 0.885
    epoch 6, loss 0.0008, train acc 0.925, test acc 0.886
    epoch 7, loss 0.0008, train acc 0.926, test acc 0.885
    epoch 8, loss 0.0008, train acc 0.926, test acc 0.883
    epoch 9, loss 0.0008, train acc 0.929, test acc 0.893
    epoch 10, loss 0.0007, train acc 0.929, test acc 0.872
    epoch 11, loss 0.0007, train acc 0.930, test acc 0.871
    epoch 12, loss 0.0007, train acc 0.932, test acc 0.882
    epoch 13, loss 0.0007, train acc 0.933, test acc 0.887
    epoch 14, loss 0.0007, train acc 0.934, test acc 0.867
    epoch 15, loss 0.0007, train acc 0.935, test acc 0.885
    epoch 16, loss 0.0007, train acc 0.936, test acc 0.885
    epoch 17, loss 0.0007, train acc 0.937, test acc 0.880
    epoch 18, loss 0.0007, train acc 0.937, test acc 0.854
    epoch 19, loss 0.0007, train acc 0.939, test acc 0.893
    epoch 20, loss 0.0006, train acc 0.939, test acc 0.886
    490.9914619922638
    

    不过,这样训练下去,因为是全连接层,也很可能导致过拟合,关于防止过拟合,在后续的博客中将持续更新。

  • 相关阅读:
    js将页面上取得的元素坐标转换为电脑屏幕坐标
    一个例子形象的理解协程和线程的区别
    为什么有的人把代码写的如此复杂?
    都说Dapper性能好,突然就遇到个坑,还是个性能问题
    springgateway基于数据库 + nacos 的动态路由
    k8s配置deployment的 liveness 和 readiness 探针 若
    UML设计图5部署图 若
    UML设计图1用例图 若
    UML设计图6序列图 若
    UML设计图2数据流图 若
  • 原文地址:https://www.cnblogs.com/somedayLi/p/12359167.html
Copyright © 2020-2023  润新知