zoukankan      html  css  js  c++  java
  • 寒假学习日报(八)

      昨天提到过过拟合与欠拟合的概念,今天主要学习了如何抑制过拟合,首先看一下如何判断过拟合:

      代码测试:

    #先看一下什么是过拟合
    import tensorflow as tf
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    (train_image, train_label), (test_image, test_label) = tf.keras.datasets.fashion_mnist.load_data()
    train_image = train_image/255
    test_image = test_image/255
    #转化独热编码
    train_label_onehot = tf.keras.utils.to_categorical(train_label)
    test_label_onehot = tf.keras.utils.to_categorical(test_label)
    #增加层
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Flatten(input_shape=(28,28)))
    model.add(tf.keras.layers.Dense(128, activation='relu'))
    model.add(tf.keras.layers.Dense(128, activation='relu'))
    model.add(tf.keras.layers.Dense(128, activation='relu'))
    model.add(tf.keras.layers.Dense(10, activation='softmax'))
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
    #训练时使用history记录训练情况,并使用validation_data来调用test_image和test_label_onehot来验证正确率情况
    history = model.fit(train_image, train_label_onehot,
                        epochs=10, 
                        validation_data=(test_image, test_label_onehot))

    这里直接剪一下最后一次训练的结果:

    #看一下history都显示什么
    history.history.keys()

    #用折线图表示loss和val_loss损失率,判断是否发生过拟合
    plt.plot(history.epoch, history.history.get('loss'), label='loss')
    plt.plot(history.epoch, history.history.get('val_loss'), label='val_loss')
    plt.legend()
    #由于从8开始,loss一直下降,而val_loss却反而开始上升,证明发生了过拟合

    #用折线图表示acc和val_acc正确率,判断是否发生过拟合
    plt.plot(history.epoch, history.history.get('acc'), label='acc')
    plt.plot(history.epoch, history.history.get('val_acc'), label='val_acc')
    plt.legend()
    #在test数据集上的正确率val_acc与acc差距很大,证明发生了过拟合
    
    #总结:
    ##过拟合:训练数据上得分很高,测试数据上得分相对比较低
    ##欠拟合:训练数据上得分比较低,测试数据上得分相对比较低

       在判断出这个训练模型存在过拟合现象之后,我们要想办法去抑制它,下面介绍抑制过拟合的方法。

    Dropout抑制过拟合

           实现原理:添加dropout层,在该层中会人为设置随机丢弃掉一些单元。图示如下:

    由于是随机丢弃的一些隐藏单元,这次建立模型和下一次训练结果使用的是不同的树,而在预测的时候使用的是全部的隐藏单元。

    Dropout抑制过拟合的原因:

    (1)使用dropout层就像是取平均值一样,假如使用相同的训练数据训练5次,就像是训练了5次不同的神经网络,一般得到5个不同的结果,这时可以选择取均值或者多数取胜策略。

    (2)减少神经元之间复杂的共适应关系:dropout每次是随机丢弃神经元的,导致两个神经元不一定每次都在一个dropout网络层中出现,这样权值的更新不再依赖于有固定关系的隐含节点(神经元)的共同作用,阻止某些特征仅仅在其他特征下才有的情况。

      只是了解概念还不够,咱们再拿代码来测试一下:

    #抑制过拟合:插入dropout层
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Flatten(input_shape=(28,28)))
    model.add(tf.keras.layers.Dense(128, activation='relu'))
    #Dropout参数rate:丢弃比率,取值范围是0-1,设置0.5证明每次随机丢弃50%的神经元
    model.add(tf.keras.layers.Dropout(0.5))
    model.add(tf.keras.layers.Dense(128, activation='relu'))
    model.add(tf.keras.layers.Dropout(0.5))
    model.add(tf.keras.layers.Dense(128, activation='relu'))
    model.add(tf.keras.layers.Dropout(0.5))
    model.add(tf.keras.layers.Dense(10, activation='softmax'))
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
    #再训练一下,还是使用history保存一下模型
    history = model.fit(train_image, train_label_onehot,
                        epochs=10, 
                        validation_data=(test_image, test_label_onehot))

    依然是剪最后一次的训练结果:

     再用图表示一下:

    #添加dropout层后正确率情况
    plt.plot(history.epoch, history.history.get('acc'), label='acc')
    plt.plot(history.epoch, history.history.get('val_acc'), label='val_acc')
    plt.legend()

    #添加dropout层后损失率情况
    plt.plot(history.epoch, history.history.get('loss'), label='loss')
    plt.plot(history.epoch, history.history.get('val_loss'), label='val_loss')
    plt.legend()

     可以看到效果已经得到了很大的改善。

    除了Dropout以外,还有其他方法,如增加训练数据,但我们使用的fashion mnist数据已经是下载好的了,再添加也不太现实,因此才用减少网络容量的方法:

    #抑制过拟合2:减少网络容量
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.Flatten(input_shape=(28,28)))
    #原隐藏单元数设置是128,这里改成32
    model.add(tf.keras.layers.Dense(32, activation='relu'))
    model.add(tf.keras.layers.Dense(10, activation='softmax'))
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc'])
    ###此外还有正则化的方法,Dense方法参数中kernel_regularizer可设置,默认为None。
    ###正则化本质是控制网络规模
    
    #再训练
    history = model.fit(train_image, train_label_onehot,
                        epochs=10, 
                        validation_data=(test_image, test_label_onehot))

    #减小网络容量后正确率情况
    plt.plot(history.epoch, history.history.get('acc'), label='acc')
    plt.plot(history.epoch, history.history.get('val_acc'), label='val_acc')
    plt.legend()
    #训练次数不够,epoch次数再多一些效果更好

    #减小网络容量后损失率情况
    plt.plot(history.epoch, history.history.get('loss'), label='loss')
    plt.plot(history.epoch, history.history.get('val_loss'), label='val_loss')
    plt.legend()
    #训练次数不够,epoch次数再多一些效果更好

    在了解过拟合以及抑制方法之后,我们可以总结一下参数选择原则:

    首先开发一个过拟合模型(添加更多层;让每层更大;训练更多轮次),然后去抑制过拟合(dropout;正则化;图像增强;而抑制过拟合的最好办法是增加训练数据),之后再次调节超参数(学习速率;隐藏层单元数;训练轮次),调参的时候要注意交叉验证。

     构建网络的总原则:保证神经网络容量足够拟合数据!(增大网络容量直到过拟合=>采取措施抑制过拟合=>继续增大网络容量直到过拟合)

      以上是今天学习的关于过拟合的全部内容,此外今天还了解了函数式api的使用概念,这里涉及到的一些操作会在明天的日报中做一个总结。

  • 相关阅读:
    Regular Expression Basic
    Getting http address from text file by awk script
    日报、周报,项目进度汇报有意义吗?
    目不转睛地盯着电脑屏幕,认真找Bug的你
    这组朋友圈,得罪了半个互联网圈!
    2021年,让你看透世界的8个底层逻辑
    再见,胡阿姨!再见,共享单车!
    @所有人,2021新年快乐,每个人都了不起!
    为了实现而工程,大道至简第五章读后感
    Java第四次上课博文动手动脑
  • 原文地址:https://www.cnblogs.com/20183711PYD/p/14289816.html
Copyright © 2011-2022 走看看