不再被大量超參數及模型表現淹沒!使用MLFlow進行實驗管理

Posted by MingLun Allen Wu on Wednesday, May 27, 2020

前言

在訓練模型時,常需要使用不同的:

  1. 超參數 (Learning Rate、Epoch、Batch_size…)
  2. 資料配置 (資料欄位、資料前處理方式的不同)
  3. 模型架構 (Ex: 使用特定層數的Layer進行Fine-tune)

我原先是透過 Notion.so 的表格來簡單紀錄:

然而每次模型訓練完成後,手動將結果填到表格上會遇到兩個心態上的掙扎:

  1. 號稱在做人工智慧,居然還要手動將資料 Key 到表格中 xD
  2. 回顧結果時,都會擔心有沒有因為恍神而紀錄錯誤

這些不同的組合將會產生大量的模型及指標,對這些資料進行妥善的管理,能夠節省許多心力,可以很方便的整理出超參數間的 Pattern,也較不會因為個人疏忽而漏記某些數據。


重點摘要

本篇筆記的重點 :

  1. 在產生多種超參數的組合時,使用 itertools 套件來取代多層迴圈,讓程式碼的執行能更簡潔。
  2. 使用 MLFlowtracking 功能取代原先的手動紀錄,協助管理:
    • 訓練前的參數配置
    • 訓練過程的資訊
    • 訓練後的各項指標

原先在做實驗時,如果有下列兩種參數選項:

max_depth = [1,2,3,4,5]
min_leaf = [1,2,3]

早期我會透過兩個迴圈來進行實驗,然後把 結果 print 出來 (或是寫到 CSV 檔)

for a_max_depth in max_depth:
    for a_min_leaf in min_leaf:
        model = SomeModel(a_max_depth, a_min_leaf)
        # 下面進行訓練及驗證
        # .....
        # .....
        # .....
        print("Max Depth: {} | Min Leaf: {} | Acc: {}".format(a_max_depth, a_min_leaf, acc))

當參數種類過多時,會需要過多層迴圈來進行參數組合。

而使用 print 方式列印模型結果,對於模型表現的管理相當不方便。

透過MLFlow Tracking 管理後,可以透過 UI 介面得到下圖結果:

此介面統整了所有的指標及超參數,所有實驗過程都一目了然。

除此之外,還能針對特定項目進行篩選 (例如我想找所有 testing accuracy > 0.75 的訓練)。


使用 itertools 簡化多層迴圈

有多個超參數,需要比較各項組合時,常見的做法是使用巢狀迴圈:

param_a = [1,2,3,4,5]
param_b = [1,2,3]
param_c = [1, 0.5, 0.25, 0]

for a in param_a:
    for b in param_b:
        for c in param_c:
            # 實際訓練的程式碼
            doSomething(a, b, c)

當參數的種類有很多時,需要使用相當多層的巢狀迴圈,使用 itertools 可以得到較為簡潔的程式碼:

import itertools 

param_a = [1,2,3,4,5]
param_b = [1,2,3]
param_c = [1, 0.5, 0.25, 0]

# 透過 itertools.product 產生所有的變數組合
all_combinations = list(itertools.product(param_a, param_b, param_c))

print(all_combinations)
# [(1,1,1), (1,1,0.5), (1,1,0.25), (1,1,0),......,(5,3,0.25), (5,3,0)]

for (a,b,c) in all_combinations:
    # 實際訓練的程式碼
    doSomething(a,b,c)

Introduction to MLFlow

MLFlow是一個 Open Source 的平台,主要用來管理 Machine Learning 相關的流程,優勢在與「深度學習的框架」是獨立的,不論使用哪一種深度學習框架( TensorflowPytorch ),都能很方便地與 MLFlow 進行整合。

MLFlow 可以分為四項獨立的功能:

1. MLFlow Tracking

2. MLFlow Projects

3. MLFlow Models

4. Model Registry

各項功能是各自獨立的,你可以單獨使用其中一項功能,也能組合使用,本篇筆記將使用 MLFlow Tracking 的功能來進行訓練指標的管理。


示範案例 - 傳統方式

我們舉一個實際例子來說明傳統方式與 MLFlow 的差別:

  • 使用 sklearnDecisionTreeClassifier 來進行分類任務
  • Training Set 跟 Testing Set 透過 Numpy 來隨機產生。
  • 此項任務的超參數有兩項: (不知道是什麼意思也無所謂,反正就是我們想要監控的超參數)
    1. max_depth : 決定決策樹的深度。
    2. min_leaf : 決定樹的葉節點容納個數。
import pandas as pd
import numpy as np
import mlflow
from sklearn.tree import DecisionTreeClassifier
import itertools

# 隨機產生資料
train_x = np.random.rand(500, 3)
train_y = np.random.choice(a=[False,True], size=(500,), p=[0.5,0.5])

test_x = np.random.rand(100, 3)
test_y = np.random.choice(a=[False,True], size=(100,), p=[0.5,0.5])

# 候選的超參數
max_depth = [1,2,3,4,5]
min_leaf = [1,2,3]

# 使用 itertools 產生所有超參數的組合
all_combination = list(itertools.product(max_depth, min_leaf))

for a_max_depth, a_min_leaf in all_combination:
    # 使用特定參數組合訓練模型
    model = DecisionTreeClassifier(max_depth=a_max_depth, min_samples_leaf=a_min_leaf)
    model.fit(train_x, train_y)
    
    # 驗證模型結果 (將結果以print方式呈現)
    train_pred = model.predict(train_x)
    train_acc = sum(train_pred==train_y) / train_y.shape[0]
    print("Max Depth:{} | Min Leaf:{} | Training Accuracy:{}".format(a_max_depth, a_min_leaf, train_acc))
    
    test_pred = model.predict(test_x)
    test_acc = sum(test_pred==test_y) / test_y.shape[0]
    print("Max Depth:{} | Min Leaf:{} | Testing Accuracy:{}".format(a_max_depth, a_min_leaf, test_acc))

使用 MLFlow Tracking進行管理

安裝

透過 pip 可以快速安裝

pip install mlflow

基本語法使用

與上一小節同樣的情境,但此次使用 MLFlow Tracking 功能進行管理,有以下幾個重點:

  • 使用 MLFlow 的功能時,需要將寫入指令放置在 with mlflow.start_run(): 的範圍中,常用的寫入指令包含:

    • mlflow.log_param("參數名稱", "參數值"): 寫入特定參數的值。
    • mlflow.log_metric("指標名稱", "指標值"): 寫入特定指標的值。
    import mlflow
    
    with mlflow.start_run(): # 所有的mlflow寫入指令必須放置在 mlflow.start_run 範圍中. 
        mlflow.log_param("batch_size", 16) # 寫入超參數
        mlflow.log_param("learning_rate", 2e-5)
        # ... 驗證程式碼 
        # ...
        # ...
        mlflow.log_metric("train_acc", train_acc) # 寫入指標
    
  • 我們可以將 with mlflow.start_run() 視為一次「嘗試」,所以在此範圍內:

    • 參數只能被設定一次。(你無法先設定 batch_size=4 接著又設定 batch_size=8,這並不合邏輯)
    • 指標可以重複被更新. (例如 training loss 就會根據訓練的 Step 持續更動),可以在寫入時加入 step 參數來紀錄變動的過程:
    import mlflow
    
    with mlflow.start_run():
        # 參數只能被寫入一次
        mlflow.log_param("batch_size",4) #ok
        mlflow.log_param("learning_rate", 2e-5) #ok
        mlflow.log_param("batch_size", 8) # 會噴錯,因為參數在一個 `start_run()`中只能紀錄一次.
    
        for step in range(50000):
            mlflow.log_metric("training_loss", loss, step=step) # metric 是可以持續被更新的.
    

    使用 step參數紀錄後,可以在 tracking UI 看到該指標的變化:

看到這裏,發現 MLFlow 的優點了嗎? 其實只是使用 MLFlow 套件的 method 進行寫入,就能達到 Tracking 的效果,跟使用什麼樣的深度學習框架完全無關。 你可以透過 MLFlow 很方便的「監控你有興趣的指標」。

現在我們嘗試將剛剛的示範情境,透過 MLFlow進行管理:

import pandas as pd
import numpy as np
import mlflow
from sklearn.tree import DecisionTreeClassifier
import itertools

# 隨機產生資料
train_x = np.random.rand(500, 3)
train_y = np.random.choice(a=[False,True], size=(500,), p=[0.5,0.5])

test_x = np.random.rand(100, 3)
test_y = np.random.choice(a=[False,True], size=(100,), p=[0.5,0.5])

# 候選的超參數
max_depth = [1,2,3,4,5]
min_leaf = [1,2,3]

# 使用 itertools 產生所有超參數的組合
all_combination = list(itertools.product(max_depth, min_leaf))

for a_max_depth, a_min_leaf in all_combination:
    with mlflow.start_run(): # 新增的程式碼
        mlflow.log_param("max_depth", a_max_depth) # 新增的程式碼
        mlflow.log_param("min_leaf", a_min_leaf) # 新增的程式碼
        model = DecisionTreeClassifier(max_depth=a_max_depth, min_samples_leaf=a_min_leaf)
        model.fit(train_x, train_y)

        train_pred = model.predict(train_x)
        train_acc = sum(train_pred==train_y) / train_y.shape[0]
        mlflow.log_metric("train_acc",train_acc) # 新增的程式碼

        test_pred = model.predict(test_x)
        test_acc = sum(test_pred==test_y) / test_y.shape[0]
        mlflow.log_metric("test_acc", test_acc) # 新增的程式碼

只需要加入五行程式碼,就能在接下來的章節中透過 MLFlow UI 進行視覺化的管理,整合十分方便!


啟動 UI (Dashboard)

當你在 python script 中執行 MLFlow 寫入功能後,預設會在當前資料夾產生 mlruns 資料夾,你所寫入的資訊會儲存在其中。 你可以透過下列指令啟動 MLFlow UI:

cd "Your project folder"
mlflow ui # 啟動 mlflow tracking dashboard

執行成功後, MLFLow UI預設會在 127.0.0.1:5000 執行,進入後就能看到剛剛寫入的指標一目了然的以表格形式呈現:

除了呈現清楚外,還能進行 filter,例如我想要 「min_leaf = 3」且 「test_acc > 0.44」的結果:

或者是選定幾種不同的嘗試進行 compare ,內建有幾種簡單的圖表能讓你進行初步的視覺化:

這些基本功能對於管理、比較大量的模型很有幫助,能夠針對自己的需求篩選出所需要的參數設置、甚至是透過基本的視覺化來找到一些特別的 Pattern。


後記

這篇筆記的目的是希望能達到兩個目的:

  1. 更有效率的組合各種超參數
  2. 使用 MLFlow Tracking 來進行模型的管理

在進行資料分析相關任務時,找尋最佳模型這個階段,程式碼的架構其實不會有太大的變動,只是某些「超參數」會有調整。 過去只知道使用Git來管理程式碼,卻疏忽「超參數」跟「模型」的管理也是相當重要的,畢竟這些變動的超參數只佔程式碼的一小部分,卻影響了我們真正在乎的結果。

我認為使用這種管理模型及超參數的工具是有必要的,能夠省下許多整理結果、解讀結果的時間。很希望當時研究所時期在做論文實驗時能看到這種工具的介紹,所以寫下了這則筆記。

當然,MLFlow Tracking 的功能遠遠不止這則筆記所提到的,我正開始將其整合進我個人的工作習慣中,也持續在摸索怎麼更有效率的使用它,不過希望透過這則筆記能讓你稍微了解有這種類型的工具在協助管理模型,甚至能真的幫助到你~

接下來會再慢慢摸索 MLFlow的其他功能,希望能分享更多的功能! 附上 MLFlow 的官方網站~

MLFlow 官方網站連結

如果有任何經驗上的分享交流,請直接聯絡我吧!我很期待! 下次見!



See Also