iT邦幫忙

2021 iThome 鐵人賽

DAY 13
0
AI & Data

手寫中文字之影像辨識系列 第 13

【第13天】訓練模型-優化器(Optimizer)

  • 分享至 

  • xImage
  •  

摘要

  1. 優化器演算法比較

    1.1 淺談優化器演算法

    1.2 設計實驗

    1.3 函數設定

    1.4 紀錄學習曲線與訓練時間

  2. 常見的5種優化器與模型訓練效果

    2.1 Adam + ReduceLROnPlateau

    2.2 Adagrad

    2.3 RMSprop

    2.4 Nadam

    2.5 SGD

  3. 模型準確度驗證

  4. 優化器比較表


內容

  1. 優化器演算法比較

    1.1 優化器演算法

    • 簡介

      • 用途:在反向傳播的過程中,指引損失函數的參數至合適的方向,希望找到全局最小值(Global minima)。
      • 常見的優化標的:梯度方向、動量與學習率。
      • 如何選擇優化器:優化器的收斂速度與資料集規模關聯有限,先以小資料集進行優化器演算法測試,再套用到大資料集微調,能提高選擇優化器的效率。
    • 不同優化器的收斂軌跡

      圖片來自於:https://lonepatient.top/2018/09/25/Cyclical_Learning_Rate

    1.2 設計實驗

    • 選擇預訓練模型:

      • 選擇參數較少,且準確率不錯的DenseNet121,進行遷移學習,節省模型訓練時間。
    • 挑選資料集:

      • 考量手寫中文字資料集樣本多,訓練時間過長。故選擇以現有的健身器材圖檔進行實驗。
      • 5種健身器材:臥推架、龍門架、划船機、啞鈴、拉背機。
      • 每種健身器材樣本數:train / test / vali資料集 → 1202 / 240 / 100張

    1.3 重要函數設定

    • Callbacks
    # -------------------------2.設置callbacks-------------------------
    # 設定earlystop條件
    estop = EarlyStopping(monitor='val_loss', patience=5, mode='min', verbose=1)
    
    # 設定模型儲存條件
    checkpoint = ModelCheckpoint('Densenet121_Adam_checkpoint.h5', verbose=1,
                              monitor='val_loss', save_best_only=True,
                              mode='min')   
    
    • 資料集
    # -----------------------------3.設置資料集--------------------------------
    # 設定ImageDataGenerator參數(路徑、批量、圖片尺寸)
    train_dir = './workout/train/'
    valid_dir = './workout/val/'
    test_dir = './workout/test/'
    batch_size = 32
    target_size = (80, 80)
    
    # 設定批量生成器
    train_datagen = ImageDataGenerator(rescale=1./255, 
                                       rotation_range=20,
                                       width_shift_range=0.2,
                                       height_shift_range=0.2,
                                       shear_range=0.2, 
                                       zoom_range=0.5,
                                       fill_mode="nearest")
    
    val_datagen = ImageDataGenerator(rescale=1./255)
    
    test_datagen = ImageDataGenerator(rescale=1./255)
    
    # 讀取資料集+批量生成器,產生每epoch訓練樣本
    train_generator = train_datagen.flow_from_directory(train_dir,
                                          target_size=target_size,
                                          batch_size=batch_size)
    
    valid_generator = val_datagen.flow_from_directory(valid_dir,
                                          target_size=target_size,
                                          batch_size=batch_size)
    
    test_generator = test_datagen.flow_from_directory(test_dir,
                                          target_size=target_size,
                                          batch_size=batch_size,
                                          shuffle=False)
    

    1.4 紀錄學習曲線與訓練時間

    • 紀錄學習曲線
    # 畫出acc學習曲線
    acc = history.history['accuracy']
    epochs = range(1, len(acc) + 1)
    val_acc = history.history['val_accuracy']
    plt.plot(epochs, acc, 'b', label='Training acc')
    plt.plot(epochs, val_acc, 'r', label='Validation acc')
    plt.title('Training and validation accuracy')
    plt.legend(loc='lower right')
    plt.grid()
    # 儲存acc學習曲線
    plt.savefig('./acc.png')
    plt.show()
    
    # 畫出loss學習曲線
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    plt.plot(epochs, loss, 'b', label='Training loss')
    plt.plot(epochs, val_loss, 'r', label='Validation loss')
    plt.title('Training and validation loss')
    plt.legend(loc='upper right')
    plt.grid()
    # 儲存loss學習曲線
    plt.savefig('loss.png')
    plt.show()
    
    • 紀錄模型訓練時間
    import time
    
    # 計算建立模型的時間(起點)
    start = time.time()
    
    # ---------------------------1.客製化模型-------------------------------
    
    #  --------------------------2.設置callbacks---------------------------
    
    # ---------------------------3.設置訓練集-------------------------------
    
    # ---------------------------4.開始訓練模型-----------------------------
    history = model.fit_generator(train_generator,
                    epochs=8, verbose=1,
                    steps_per_epoch=train_generator.samples//batch_size,
                    validation_data=valid_generator,
                    validation_steps=valid_generator.samples//batch_size,
                    callbacks=[checkpoint, estop, reduce_lr])
    
    # 計算建立模型的時間(終點)
    end = time.time()
    spend = end - start
    hour = spend // 3600
    minu = (spend - 3600 * hour) // 60
    sec = int(spend - 3600 * hour - 60 * minu)
    print(f'一共花費了{hour}小時{minu}分鐘{sec}秒')
    
  2. 常見的5種優化器與訓練效果

    2.1 Adam + ReduceLROnPlateau

    • 程式碼
    # --------------------------1.客製化模型-------------------------------
    # 載入keras模型(更換輸出類別數)
    model = DenseNet121(include_top=False,
                  weights='imagenet',
                  input_tensor=Input(shape=(80, 80, 3))
                  )
    
    # 定義輸出層
    x = model.output
    x = GlobalAveragePooling2D()(x)
    predictions = Dense(5, activation='softmax')(x)
    model = Model(inputs=model.input, outputs=predictions)
    
    # 編譯模型
    model.compile(optimizer=Adam(lr=1e-4),
               loss='categorical_crossentropy',
               metrics=['accuracy'])
    
    # --------------------------2.設置callbacks---------------------------
    # 另外新增lr降低條件
    reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.5,
                               patience=3, mode='min', verbose=1,
                               min_lr=1e-5)
    
    # --------------------------4.開始訓練模型-----------------------------   
    # 訓練模型時,以Callbacks監控,呼叫reduce_lr調整Learning Rate值
    history = model.fit_generator(train_generator,
                       epochs=30, verbose=1,
                       steps_per_epoch=train_generator.samples//batch_size,
                       validation_data=valid_generator,
                       validation_steps=valid_generator.samples//batch_size,
                       callbacks=[checkpoint, estop, reduce_lr])
    
    • 學習曲線

    2.2 Adagrad

    • 程式碼
    # --------------------------1.客製化模型-------------------------------
    # 載入keras模型(更換輸出類別數)
    model = DenseNet121(include_top=False,
                  weights='imagenet',
                  input_tensor=Input(shape=(80, 80, 3))
                  )
    
    # 定義輸出層
    x = model.output
    x = GlobalAveragePooling2D()(x)
    predictions = Dense(5, activation='softmax')(x)
    model = Model(inputs=model.input, outputs=predictions)
    
    # 編譯模型
    model.compile(optimizer=Adagrad(lr=0.01, epsilon=None, decay=0.0),
               loss='categorical_crossentropy',
               metrics=['accuracy']) 
    
    • 學習曲線

    2.3 RMSprop

    • 程式碼
    # --------------------------1.客製化模型-------------------------------
    # 載入keras模型(更換輸出類別數)
    model = DenseNet121(include_top=False,
                  weights='imagenet',
                  input_tensor=Input(shape=(80, 80, 3))
                  )
    
    # 定義輸出層
    x = model.output
    x = GlobalAveragePooling2D()(x)
    predictions = Dense(5, activation='softmax')(x)
    model = Model(inputs=model.input, outputs=predictions)
    
    # 編譯模型
    model.compile(optimizer=RMSprop(lr=0.001, rho=0.9, decay=0.0),
               loss='categorical_crossentropy',
               metrics=['accuracy']) 
    
    • 學習曲線

    2.4 Nadam

    • 程式碼
    # --------------------------1.客製化模型-------------------------------
    # 載入keras模型(更換輸出類別數)
    model = DenseNet121(include_top=False,
                  weights='imagenet',
                  input_tensor=Input(shape=(80, 80, 3))
                  )
    
    # 定義輸出層
    x = model.output
    x = GlobalAveragePooling2D()(x)
    predictions = Dense(5, activation='softmax')(x)
    model = Model(inputs=model.input, outputs=predictions)
    
    # 編譯模型
    model.compile(optimizer=Nadam(lr=0.002, beta_1=0.9, 
                                  beta_2=0.999, schedule_decay=0.004),
               loss='categorical_crossentropy',
               metrics=['accuracy']) 
    
    • 學習曲線

    2.5 SGD

    • 程式碼
    # --------------------------1.客製化模型-------------------------------
    # 載入keras模型(更換輸出類別數)
    model = DenseNet121(include_top=False,
                  weights='imagenet',
                  input_tensor=Input(shape=(80, 80, 3))
                  )
    
    # 定義輸出層
    x = model.output
    x = GlobalAveragePooling2D()(x)
    predictions = Dense(5, activation='softmax')(x)
    model = Model(inputs=model.input, outputs=predictions)
    
    # 編譯模型
    model.compile(optimizer=SGD(lr=0.01, momentum=0.0, decay=0.0, nesterov=False),
               loss='categorical_crossentropy',
               metrics=['accuracy']) 
    
    • 學習曲線
  3. 模型準確度驗證:vali資料夾(每個類別100張圖檔)。

    3.1 程式碼

    # 以vali資料夾驗證模型準確度
    test_loss, test_acc = model.evaluate_generator(test_generator,
                                steps=test_generator.samples//batch_size,
                                verbose=1)
    print('test acc:', test_acc)
    print('test loss:', test_loss)
    

    3.2 結果

    • Adam + ReduceLROnPlateau

    • Adagrad

    • RMSprop

    • Nadam

    • SGD

  4. 優化器比較表


小結

  1. 參考上述比較表,訓練模型時,我們會優先嘗試「Adam + ReduceLROnPlateau、Adagrad、SGD」三種優化器。
  2. 下一章,目標是:「簡單介紹Xception模型,並分享手寫中文字模型訓練成果」。

讓我們繼續看下去...


參考資料

  1. Keras Optimizers
  2. 優化器

上一篇
【第12天】訓練模型-Learning Rate
下一篇
【第14天】訓練模型-Xception
系列文
手寫中文字之影像辨識31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言