還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

機器之心發表於2020-08-11

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

這劑解藥就是VisualDL 2.0——飛槳視覺化分析工具全面改版升級,幫眾位開發者們從 「煉丹萌新」 變身「太上老君」

懷疑我們自吹自擂?那就讓我們一起看看 VisualDL 到底是啥?先上圖為證!

VisualDL 2.0 是什麼?

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

看到這裡,有些小夥伴可能已經大概知道 VisualDL 是什麼了,不知道的同學請繼續往下看,反正花花綠綠的,至少比 log 看著養眼多了! 

具體來說,VisualDL 是飛槳團隊為廣大深度學習開發者訂製的功能完備的視覺化分析工具,可以幫助深度學習開發者瞭解訓練過程中模型引數的變化趨勢、 網路層對資料特徵的提取情況、網路結構應該如何調整、精度與召回是否達到了理想的平衡等,從而實現有方向性的錯誤排查,實現高效的模型調優。

其實,VisualDL 1.0 早在 2017 年就推出了,隨著飛槳開源深度學習框架歷經 3 年深入產業實踐的不斷打磨,VisualDL 本次也完成了 2.0 版本的全新蛻變!相較 VisualDL 1.0,新版本的 API 設計更加簡潔易用、與框架銜接更為順暢、功能更豐富,介面設計也全面進行了升級,致力為老使用者帶來全新體驗,為新使用者帶來使用上的驚喜

VisualDL 2.0 能做什麼?

VisualDL 2.0 共有五大視覺化功能,下面我們來逐一講解。

標量(Scalar) 

標量可以透過圖表的形式展示 Loss、Accuracy、Learning Rate 等引數指標在訓練過程中的變化趨勢,幫助開發者瞭解其是否朝著理想的方向最佳化,便於發現異常情況,及時排查並修復問題;另外,透過對比多組實驗的訓練引數,開發者們能深入探究引數對模型效果的影響,加速模型的調優。

實現程式碼如下:

add_scalar(tag, value, step, walltime=None)

資料樣本分析(Sample) 

資料樣本分析可以在多種深度學習任務中發揮重要作用。例如在計算機視覺任務中,該功能不僅可以檢視每個訓練批次中的指定的樣本圖片,也可以展示影像資料的在訓練過程中間階段的提取特徵情況,便於開發者們觀察圖片資料在訓練過程中的狀態,進而深入瞭解訓練過程及效果。

實現程式碼如下:

add_image(tag, img, step, walltime=None)

語音識別或合成任務中,資料樣本分析功能可以幫助開發者實時獲取訓練過程中的音訊資料,評估語音識別或合成的效果,挑選最優的訓練模型。

實現程式碼如下:

add_audio(tag, audio_array, step, sample_rate)

模型結構(Graph)

模型結構功能支援一鍵視覺化模型網路結構。開發者們可檢視模型屬性、節點資訊、節點輸入輸出等,並支援節點搜尋功能,協助開發者們快速分析模型結構並瞭解資料流向。

當前支援如下兩種操作方式:

  • 模型檔案拖拽上傳

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

  • 在命令列加入引數 --model 並指定模型檔案路徑(非資料夾路徑),執行命令後即可啟動:

visualdl --model ./log/model --port 8080

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

直方圖(Histogram) 

直方圖可以展示 Tensor(weight、bias、gradient 等)資料在訓練過程中的變化趨勢,深入瞭解模型各層效果,幫助開發者精準調整模型結構

實現程式碼如下:

add_histogram(tag, values, step, walltime=None, buckets=10)

PR 曲線(PR Curve)

PR 曲線可以展示每一分類在不同閾值下的精度(Precision)- 召回率(Recall)曲線,幫助開發者權衡模型精度和召回率之間的平衡,設定最佳閾值。精度是指正樣本的數量除以所有被選中樣本的數量,而召回率是指所有正樣本中被推理正確的比例,由此可見精度越高,召回率越高,我們的模型就越好。但是很多情況下,魚和熊掌不可兼得,無法同時保證精度和召回率都是最高,此時需要透過 PR 曲線,權衡精度與召回率,確定最佳閾值。

實現程式碼如下:

add_pr_curve(tag, labels, predictions, step=None, num_thresholds=10)

為了便於大家更好的瞭解 VisualDL,我們結合一個簡單的實際模型例子來更直觀的看下這幾個功能。真的是很簡單的例子——那就是深度學習中的「Hello World」,手寫數字識別!

VisualDL 2.0 怎麼用?

假設在一個風和日麗的早晨,作為深度學習愛好者的你,想要建立一個簡單的 LeNet 模型進行手寫數字識別,在辛苦完成模型搭建後,進入模型訓練時,卻看到了如下一幕:

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

你心裡一沉,這精度怎麼抖得那麼厲害啊。訓練中哪裡出現問題了呢?到底誰是「兇手」?可是連問題出在哪都不知道,模型最佳化和修復更是無從下手。這時你想起幾日前偶然發現的深度學習視覺化分析工具——VisualDL,心中頓時升起希望,因為在訓練之前,已經把下面的程式碼新增到訓練指令碼中了。

#使用VisualDL的第一步是在訓練指令碼中新增如下程式碼建立日誌檔案,用於記錄訓練中產生的資料。
from visualdl import LogWriter
log_writer = LogWriter("./paddle_lenet_log")

# 使用標量(Scalar)記錄Loss、Accuracy引數,用於觀察其變化趨勢
writer.add_scalar(tag="train/loss", step=step, value=cost)
writer.add_scalar(tag="train/acc", step=step, value=accuracy)

# 使用資料樣本分析功能記錄每批次第一張資料,用於檢視影像資料
img = np.reshape(batch[0][0], [28, 28, 1]) * 255
writer.add_image(tag="train/input", step=step, img=img)

# 使用直方圖功能記錄所有引數,用於檢視weight、bias在訓練步數中的分佈變化
for param in params:
     values = fluid.global_scope().find_var(param).get_tensor()
     writer.add_histogram(tag='train/{}'.format(param), step=step, values=values)

# 記錄PR曲線檢視不同閾值下的精度和召回率
labels = np.array(batch)[:, 1]
for i in range(10):
label_i = np.array(labels == i, dtype='int32')
prediction_i = pred[:, i]
writer.add_pr_curve(tag='train/class_{}_pr_curve'.format(i),
                            labels=label_i,
                            predictions=prediction_i,
                            step=step,
                            num_thresholds=20)
# 使用save_inference_model儲存模型結構至“./model”目錄,便於訓練後使用模型結構(Graph)功能檢視模型網路結構
fluid.io.save_inference_model(dirname='./model', feeded_var_names=['img'],target_vars=[predictions], executor=exe)

接下來就執行下面的命令來開始奇幻的破案(調優)之旅吧!

visualdl--logdir ./paddle_lenet_log --port 8080

執行命令後,即可得到這樣一個網址 http://localhost:8080/,開啟瀏覽器輸入這個網址即可檢視究竟發生了什麼。首先來看看案發現場。。

1. 點選 「標量資料」 頁籤檢視模型的 Loss 和 Accuracy 整體變化趨勢,也就是把剛才的日誌資訊透過圖形直觀的展示出來。這部分對應的程式碼如下所示:

writer.add_scalar(tag="train/loss", step=step, value=cost)
writer.add_scalar(tag="train/acc", step=step, value=accuracy)

一眼望去,這哪是 Loss 和 Accuracy 的變化曲線啊,這明顯是心率不齊啊,讓人有打 120 叫救護車的衝動了!

顯而易見,Accuracy 一直在 10% 左右徘徊,Loss 一直無法下降,由此我們開始逐個檢視問題出在哪個環節。首先看看模型結構的實際樣子,是否是結構設計出了問題。

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

2. 點選 「網路結構」 頁籤,將儲存在 「./model」 目錄下的模型檔案拖進頁面即可看到模型的結構。

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

透過觀察模型結構、節點屬性、模型屬性、資料流向,我們們可以直觀的發現整體結構是符合預期的,也就是說模型網路本身是清白的,那麼是否是模型 「吃進」 的資料有問題呢? 

3. 點選 「樣本資料」 檢視訓練中的樣本資料。這部分對應的程式碼如下所示:

# 使用資料樣本分析功能記錄每批次第一張資料,用於檢視影像資料
img = np.reshape(batch[0][0], [28, 28, 1]) * 255
writer.add_image(tag="train/input", step=step, img=img)

透過檢視每批次資料的第一張圖片,發現輸入資料也是沒有問題的。那麼我們們再來「回放錄影」,看看每一時間步的引數變化情況吧。

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

4. 點選 「直方圖」 頁籤,檢視訓練過程中每一時間步權重和偏差的變化情況,就如同回放整個訓練過程的監控錄影一樣,讓訓練過程中引數變化不正常的問題無所遁形!這部分對應的程式碼如下所示:

for param in params:
         values = fluid.global_scope().find_var(param).get_tensor()
         writer.add_histogram(tag='train/{}'.format(param), step=step, 
values=values)

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

透過檢視後發現,每一層的權重和偏差的變化正常。由此證明不是特定層的初始引數配置出現問題,排除了模型結構、資料樣本、每層網路引數配置後,還剩下超引數的配置,因此決定嘗試不同的學習率(0.001,0.03,0.05,0.08,0.1),並透過 VisualDL 的多實驗對比功能,來觀察學習率對模型訓練效果的影響情況。

5. 啟動多實驗對比功能非常的簡單,只需要在訓練指令碼中參考如下程式碼實現同一個目錄下記錄多份不同學習率的訓練日誌檔案,並啟動相應訓練即可。接著啟動 VisualDL,就會得到多組實驗記錄對比圖了。

#建立日誌檔案,儲存當lr=0.001時訓練結果
log_writer = LogWriter("paddle_lenet_log/lr0.001")
#建立日誌檔案,儲存當lr=0.03時訓練結果
log_writer = LogWriter("paddle_lenet_log/lr0.03")
#建立日誌檔案,儲存當lr=0.05時訓練結果
log_writer = LogWriter("paddle_lenet_log/lr0.05")
#建立日誌檔案,儲存當lr=0.08時訓練結果
log_writer = LogWriter("paddle_lenet_log/lr0.08")
#建立日誌檔案,儲存當lr=0.1時訓練結果
log_writer = LogWriter("paddle_lenet_log/lr0.1")

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

你終於發現了問題所在了,原來是學習率設定的過大了,導致 Loss 無法下降收斂,根據 「標量資料」 展示的效果,當學習率為 0.001 時(深藍色線條),Loss 呈現優美的下降趨勢且後續漸漸收斂,Accuracy 呈現逐漸上升並趨於平穩,因此你將學習率設定為 0.001,使得模型呈現最佳效果。

但是你還不滿足於現狀,想要選擇一個最佳閾值,使得模型的精準度和召回率都達到最優,於是又開始使用 「PR 曲線」 功能。

6. 點選 「PR 曲線」 頁籤,權衡精確度與召回間的關係,確定最佳閾值。這部分對應的程式碼如下所示:

labels = np.array(batch)[:, 1]
for i in range(10):
label_i = np.array(labels == i, dtype='int32')
prediction_i = pred[:, i]
writer.add_pr_curve(tag='train/class_{}_pr_curve'.format(i),
                            labels=label_i,
                            predictions=prediction_i,
                            step=step,
                            num_thresholds=20)

還在「黑盒煉丹」? 教你如何實現一行程式碼透視煉丹過程

以上圖為例,該圖是手寫數字識別任務中類別 7 對應的 PR 曲線,從圖中可以看出,當閾值為 0.10、0.15 或 0.20 時,準確率和召回率同時達到最高值,因此選擇上述中的任意閾值,模型都可達到最佳效果。

最終,在 VisualDL 的幫助下,你確定了模型閾值為 0.15,學習率為 0.001,至此,一個效果理想的手寫數字識別模型搭建完成。

如需檢視完整應用案例程式碼,請參考:

  • https://aistudio.baidu.com/aistudio/projectdetail/622772 

如需檢視較複雜的應用案例 -- 眼疾識別,請參考:

  • https://aistudio.baidu.com/aistudio/projectdetail/502834

寫在最後

看到這裡,相信大家已經對 VisualDL 2.0 有了一個比較全面的瞭解,也發現它是真的又有用,又好用吧?然而這還不夠,飛槳團隊還為它增加了諸多軟實力:

  • 高相容:全面支援飛槳、ONNX、Caffe 等市面主流模型結構視覺化,廣泛支援各類使用者實現視覺化分析。

  • 生態支援全面:與飛槳的多個套件、工具元件以及 AI 學習和實訓社群 AI Studio 全面打通,為開發者們在飛槳生態系統中提供最佳使用體驗。

在未來,VisualDL 將會持續加入新的功能元件,致力於為開發者們提供簡單易用、功能豐富、效能強大的視覺化分析工具,助力模型的最佳化過程。

小夥伴們是不是已經破迫不及待想要親自上手嘗試了呢?歡迎登入 VisualDL 2.0 官網檢視功能示例,GitHub 上也提供了詳細的使用指南,大家可以踴躍嘗試!想要與其他使用 VisualDL 的小夥伴們交流心得麼?請加入 VisualDL 官方 QQ 群:1045783368,提出使用中遇到的問題與對於視覺化的其他需求,同時還有機會與深度學習高手們面對面過招!

如果您加入飛槳官方 QQ 群,您將遇上大批志同道合的深度學習同學。官方 QQ 群:1108045677。

如果您想詳細瞭解更多飛槳的相關內容,請參閱以下文件。

  • 飛槳官網地址:https://www.paddlepaddle.org.cn

  • VisualDL 官網地址:https://www.paddlepaddle.org.cn/paddle/visualdl

飛槳 VisualDL 專案地址:

  • GitHub:https://github.com/PaddlePaddle/VisualDL

  • Gitee: https://gitee.com/paddlepaddle/VisualDL 

飛槳開源框架專案地址:

  • GitHub: https://github.com/PaddlePaddle/Paddle 

  • Gitee:  https://gitee.com/paddlepaddle/Paddle 

相關文章