飞浆PaddlePaddle-百度架构师手把手带你零基础实践深度学习——21日学习打卡(第一周第四日)

百度架构师手把手带你零基础实践深度学习——21日学习打卡(第一周第四日)
首先声明,不详细讲解代码部分,主要是针对课程的理解及对作业的分析。(要是有代码相关问题可以私信)

在这里插入图片描述
让我们回顾一下,昨天所讲的手写体识别这个案例,着重讲了这个案例的数据处理的部分,其中的重点包含了同步读取和异步读取的不同,在不同的场景下选择合适的方法,存在即合理,有的时候同步读取更加的有效果。

今天毕然老师讲解了这个案例里面的网络结构、损失函数及对算法的优化(选取合适的激活函数优化器或者是正则化参数)。我觉得这部分的重点在于交叉熵损失函数的代码实现,我们可以实际编写一下。最后对于算法的调优,今天这堂课讲接的都是基础的部分,估计毕然老师会在接下来的课程里面有更加深入的讲解。文章最后我将视频中留的作业代码卸载后面。

作业

  • 本着给大家解惑的想法,给出答案解析,大家放心,第一个满分一定是我这篇博文发出之前的哦~

在这里插入图片描述
1.数据类型不同,对数据的处理也不同。

2.测试集用于估计应用效果(没有在模型中应用过的数据,更贴近模型在真实场景应用的效果)(内容出处)。

3.通常需要自己编写适合当前任务的数据处理程序,一般涉及如下五个环节:(内容出处

  • 读入数据
  • 划分数据集
  • 生成批次数据
  • 训练样本集乱序
  • 校验数据有效性

在这里插入图片描述

4.在手写数字识别任务中,仅改动三行代码,就可以将在现有模型的损失函数替换成交叉熵(cross_entropy)。(内容出处

  • 在读取数据部分,将标签的类型设置成int,体现它是一个标签而不是实数值(飞桨默认将标签处理成“int64”)。
  • 在网络定义部分,将输出层改成“输出十个标签的概率”的模式。
  • 在训练过程部分,将损失函数从均方误差换成交叉熵。

5.卷积=conv,池化层=pool,二维=2D(对应API文档链接

代码

  • 我们看一下通过调节学习率,来优化模型,通过loss值来体现,loss值越小模型越好
  • 在这里加载的就是下载下来的本地数据,因为上一篇文章是直接从api读取的,所以今天就换种方式。本地下载,提取码:ild8
# 加载相关库
import os
import random
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, Linear
import numpy as np
from PIL import Image

import gzip
import json

# 定义数据集读取器
def load_data(mode='train'):

    # 读取数据文件
    datafile = './work/mnist.json.gz'
    print('loading mnist dataset from {} ......'.format(datafile))
    data = json.load(gzip.open(datafile))
    # 读取数据集中的训练集,验证集和测试集
    train_set, val_set, eval_set = data

    # 数据集相关参数,图片高度IMG_ROWS, 图片宽度IMG_COLS
    IMG_ROWS = 28
    IMG_COLS = 28
    # 根据输入mode参数决定使用训练集,验证集还是测试
    if mode == 'train':
        imgs = train_set[0]
        labels = train_set[1]
    elif mode == 'valid':
        imgs = val_set[0]
        labels = val_set[1]
    elif mode == 'eval':
        imgs = eval_set[0]
        labels = eval_set[1]
    # 获得所有图像的数量
    imgs_length = len(imgs)
    # 验证图像数量和标签数量是否一致
    assert len(imgs) == len(labels), \
          "length of train_imgs({}) should be the same as train_labels({})".format(
                  len(imgs), len(labels))

    index_list = list(range(imgs_length))

    # 读入数据时用到的batchsize
    BATCHSIZE = 100

    # 定义数据生成器
    def data_generator():
        # 训练模式下,打乱训练数据
        if mode == 'train':
            random.shuffle(index_list)
        imgs_list = []
        labels_list = []
        # 按照索引读取数据
        for i in index_list:
            # 读取图像和标签,转换其尺寸和类型
            img = np.reshape(imgs[i], [1, IMG_ROWS, IMG_COLS]).astype('float32')
            label = np.reshape(labels[i], [1]).astype('int64')
            imgs_list.append(img) 
            labels_list.append(label)
            # 如果当前数据缓存达到了batch size,就返回一个批次数据
            if len(imgs_list) == BATCHSIZE:
                yield np.array(imgs_list), np.array(labels_list)
                # 清空数据缓存列表
                imgs_list = []
                labels_list = []

        # 如果剩余数据的数目小于BATCHSIZE,
        # 则剩余数据一起构成一个大小为len(imgs_list)的mini-batch
        if len(imgs_list) > 0:
            yield np.array(imgs_list), np.array(labels_list)

    return data_generator


# 定义模型结构
class MNIST(fluid.dygraph.Layer):
     def __init__(self):
         super(MNIST, self).__init__()
         
         # 定义一个卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
         self.conv1 = Conv2D(num_channels=1, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义一个池化层,池化核为2,步长为2,使用最大池化方式
         self.pool1 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
         # 定义一个卷积层,输出通道20,卷积核大小为5,步长为1,padding为2,使用relu激活函数
         self.conv2 = Conv2D(num_channels=20, num_filters=20, filter_size=5, stride=1, padding=2, act='relu')
         # 定义一个池化层,池化核为2,步长为2,使用最大池化方式
         self.pool2 = Pool2D(pool_size=2, pool_stride=2, pool_type='max')
         # 定义一个全连接层,输出节点数为10 
         self.fc = Linear(input_dim=980, output_dim=10, act='softmax')
    # 定义网络的前向计算过程
     def forward(self, inputs):
         x = self.conv1(inputs)
         x = self.pool1(x)
         x = self.conv2(x)
         x = self.pool2(x)
         x = fluid.layers.reshape(x, [x.shape[0], -1])
         x = self.fc(x)
         return x

#仅优化算法的设置有所差别
with fluid.dygraph.guard():
    model = MNIST()
    model.train()
    #调用加载数据的函数
    train_loader = load_data('train')
    
    #设置不同初始学习率
    
    for learning_rate in np.arange(0.001,0.1,0.008):
        print("-----------------------------learning_rate={:0.3}----------------------------".format(learning_rate))
        optimizer = fluid.optimizer.SGDOptimizer(learning_rate=learning_rate, parameter_list=model.parameters())
        # optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.001, parameter_list=model.parameters())
        # optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.1, parameter_list=model.parameters())
    
        EPOCH_NUM = 5
        for epoch_id in range(EPOCH_NUM):
            for batch_id, data in enumerate(train_loader()):
                #准备数据,变得更加简洁
                image_data, label_data = data
                image = fluid.dygraph.to_variable(image_data)
                label = fluid.dygraph.to_variable(label_data)
            
                #前向计算的过程
                predict = model(image)
            
                #计算损失,取一个批次样本损失的平均值
                loss = fluid.layers.cross_entropy(predict, label)
                avg_loss = fluid.layers.mean(loss)
            
                #每训练了200批次的数据,打印下当前Loss的情况
                if batch_id % 200 == 0:
                    print("epoch: {}, batch: {}, loss is: {}".format(epoch_id, batch_id, avg_loss.numpy()))
            
                #后向传播,更新参数的过程
                avg_loss.backward()
                optimizer.minimize(avg_loss)
                model.clear_gradients()
	print(----------------------------------"完成!"------------------------------------------)

输出结果:

-----------------------------learning_rate=0.001----------------------------
epoch: 0, batch: 0, loss is: [2.6776578]
epoch: 0, batch: 200, loss is: [1.7148232]
...
epoch: 4, batch: 0, loss is: [0.29852232]
...
epoch: 4, batch: 400, loss is: [0.02747598]
-----------------------------learning_rate=0.089----------------------------
epoch: 0, batch: 0, loss is: [0.00082897]
epoch: 0, batch: 200, loss is: [0.00915111]
...
epoch: 4, batch: 200, loss is: [0.00126368]
epoch: 4, batch: 400, loss is: [0.00580785]
-----------------------------learning_rate=0.097----------------------------
epoch: 0, batch: 0, loss is: [0.01506544]
epoch: 0, batch: 200, loss is: [0.00326346]
...
epoch: 4, batch: 0, loss is: [0.00186367]
epoch: 4, batch: 200, loss is: [0.00140749]
epoch: 4, batch: 400, loss is: [0.01802499]
------------------------------------完成!-----------------------------------

太多了,大部分省略,显而易见,在这个模型中,通过调高学习率,对模型进行调优。

  • 下面我们改变优化器(选择不同的优化算法训练模型),观察训练时间和损失变化的情况及模型好坏。
  • 代码太多了,相同的部分我就不写了,就把各个优化器代码写出来,到时候改一下就行,看着方便,但是结果我都写出来
optimizer = fluid.optimizer.SGDOptimizer(learning_rate=0.01, parameter_list=model.parameters())
optimizer = fluid.optimizer.MomentumOptimizer(learning_rate=0.01, momentum=0.9, parameter_list=model.parameters())
optimizer = fluid.optimizer.AdagradOptimizer(learning_rate=0.01, parameter_list=model.parameters())
optimizer = fluid.optimizer.AdamOptimizer(learning_rate=0.01, parameter_list=model.parameters())
#SGD: 随机梯度下降算法,每次训练少量数据,抽样偏差导致参数收敛过程中震荡。
#Momentum: 引入物理“动量”的概念,累积速度,减少震荡,使参数更新的方向更稳定。
#AdaGrad: 根据不同参数距离最优解的远近,动态调整学习率。学习率逐渐下降,依据各参数变化大小调整学习率。
#Adam: 由于动量和自适应学习率两个优化思路是正交的,因此可以将两个思路结合起来,这就是当前广泛应用的算法。

各个优化器的运行结果:

SGD:
epoch: 0, batch: 0, loss is: [2.352339]
epoch: 0, batch: 200, loss is: [0.5131626]
epoch: 0, batch: 400, loss is: [0.39667332]
epoch: 1, batch: 0, loss is: [0.32583618]
epoch: 1, batch: 200, loss is: [0.26180467]
epoch: 1, batch: 400, loss is: [0.1095606]
epoch: 2, batch: 0, loss is: [0.15181603]
epoch: 2, batch: 200, loss is: [0.21409091]
epoch: 2, batch: 400, loss is: [0.10645081]
epoch: 3, batch: 0, loss is: [0.10574649]
epoch: 3, batch: 200, loss is: [0.07654014]
epoch: 3, batch: 400, loss is: [0.06573325]
epoch: 4, batch: 0, loss is: [0.09977328]
epoch: 4, batch: 200, loss is: [0.18264307]
epoch: 4, batch: 400, loss is: [0.17275396]
Momentum:
epoch: 0, batch: 0, loss is: [2.6172771]
epoch: 0, batch: 200, loss is: [0.13799015]
epoch: 0, batch: 400, loss is: [0.10121547]
epoch: 1, batch: 0, loss is: [0.03110733]
epoch: 1, batch: 200, loss is: [0.01395287]
epoch: 1, batch: 400, loss is: [0.02664336]
epoch: 2, batch: 0, loss is: [0.14613625]
epoch: 2, batch: 200, loss is: [0.02807039]
epoch: 2, batch: 400, loss is: [0.0291254]
epoch: 3, batch: 0, loss is: [0.01481789]
epoch: 3, batch: 200, loss is: [0.05487074]
epoch: 3, batch: 400, loss is: [0.0469206]
epoch: 4, batch: 0, loss is: [0.02150199]
epoch: 4, batch: 200, loss is: [0.01105433]
epoch: 4, batch: 400, loss is: [0.05675033]
Adagrad:
epoch: 0, batch: 0, loss is: [2.4442697]
epoch: 0, batch: 200, loss is: [0.11416334]
epoch: 0, batch: 400, loss is: [0.08026418]
epoch: 1, batch: 0, loss is: [0.05991463]
epoch: 1, batch: 200, loss is: [0.0653023]
epoch: 1, batch: 400, loss is: [0.06509476]
epoch: 2, batch: 0, loss is: [0.08109752]
epoch: 2, batch: 200, loss is: [0.08389792]
epoch: 2, batch: 400, loss is: [0.08805]
epoch: 3, batch: 0, loss is: [0.04903215]
epoch: 3, batch: 200, loss is: [0.02047388]
epoch: 3, batch: 400, loss is: [0.04319945]
epoch: 4, batch: 0, loss is: [0.0190237]
epoch: 4, batch: 200, loss is: [0.00539449]
epoch: 4, batch: 400, loss is: [0.02614666]
Adam:
epoch: 0, batch: 0, loss is: [3.062758]
epoch: 0, batch: 200, loss is: [0.12846503]
epoch: 0, batch: 400, loss is: [0.05115846]
epoch: 1, batch: 0, loss is: [0.12037631]
epoch: 1, batch: 200, loss is: [0.0200488]
epoch: 1, batch: 400, loss is: [0.06120364]
epoch: 2, batch: 0, loss is: [0.08290919]
epoch: 2, batch: 200, loss is: [0.01771411]
epoch: 2, batch: 400, loss is: [0.04155124]
epoch: 3, batch: 0, loss is: [0.00240592]
epoch: 3, batch: 200, loss is: [0.02146371]
epoch: 3, batch: 400, loss is: [0.07598638]
epoch: 4, batch: 0, loss is: [0.0187786]
epoch: 4, batch: 200, loss is: [0.01773342]
epoch: 4, batch: 400, loss is: [0.05995531]

哪个优化器好用就让大家来看喽~
有什么不对或者可以改进的地方请评论
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zhu_rui/article/details/108012710