*本篇文章基於 PaddlePaddle 0.13.0、Python 2.7
前言¶
VisualDL是一個面向深度學習任務設計的可視化工具,包含了scalar、參數分佈、模型結構、圖像可視化等功能。可以這樣說:“所見即所得”。我們可以藉助VisualDL來觀察我們訓練的情況,方便我們對訓練的模型進行分析,改善模型的收斂情況。
之前我們使用的paddle.v2.plot接口,也可以觀察訓練的情況,但是隻是支持CSOT的折線圖而已。而VisualDL可以支持一下這個功能:
scalar,趨勢圖,可用於訓練測試誤差的展示

image, 圖片的可視化,可用於卷積層或者其他參數的圖形化展示

histogram, 用於參數分佈及變化趨勢的展示

graph,用於訓練模型結構的可視化

以上的圖像來自VisualDL的Github
既然那麼方便,那麼我們就來嘗試一下吧。VisualDL底層採用C++編寫,但是它在提供C++ SDK的同時,也支持Python SDK,我們主要是使用Python的SDK。順便說一下,VisualDL除了支持PaddlePaddle,之外,還支持pytorch, mxnet在內的大部分主流DNN平臺。
VisualDL的安裝¶
本章只講述在Ubuntu系統上的安裝和使用,Mac的操作應該也差不多。
使用pip安裝¶
使用pip安裝非常簡單,只要一條命令就夠了,如下:
pip install --upgrade visualdl
測試一下是否安裝成功了,運行一個例子下載日誌文件:
# 在當前位置下載一個日誌
vdl_create_scratch_log
# 如果提示命令不存在,那就使用下面這條命令
vdl_scratch.py
然後再輸入,啓動VisualDL並加載這個日誌信息:
visualdl --logdir ./scratch_log --port 8080
這裏說明一下,visualDL的參數:
host設定IPport設定端口model_pb指定 ONNX 格式的模型文件,這木方我們還沒要用到
注意: 如果是報以下的錯誤,那是因爲protobuf版本過低的原因。
root@test:/home/test/VisualDL# visualdl --logdir ./scratch_log --port 8080
Traceback (most recent call last):
File "/usr/local/bin/visualdl", line 29, in <module>
import visualdl.server.graph as vdl_graph
File "/usr/local/lib/python2.7/dist-packages/visualdl/server/graph.py", line 23, in <module>
from . import onnx
File "/usr/local/lib/python2.7/dist-packages/visualdl/server/onnx/__init__.py", line 8, in <module>
from .onnx_pb2 import ModelProto
File "/usr/local/lib/python2.7/dist-packages/visualdl/server/onnx/onnx_pb2.py", line 213, in <module>
options=None, file=DESCRIPTOR),
TypeError: __init__() got an unexpected keyword argument 'file'
protobuf的版本要不小於3.5.0,如何小於這個版本可以使用以下命令升級:
pip install protobuf -U
然後在瀏覽器上輸入:
http://127.0.0.1:8080
即可看到一個可視化的界面,如下:

使用源碼安裝¶
如果讀者出於各種情況,使用pip安裝不能滿足需求,那可以考慮使用源碼安裝VisualDL,操作如下:
首先要安裝依賴庫:
# 安裝npm
apt install npm
# 安裝node
apt install nodejs-legacy
# 安裝cmake
apt install cmake
# 安裝unzip
apt install unzip
然後在GitHub上clone最新的源碼並打開:
git clone https://github.com/PaddlePaddle/VisualDL.git
cd VisualDL
之後是編譯生成whl安裝包:
python setup.py bdist_wheel
生成whl安裝包之後,就可以使用pip命令安裝這個安裝包了,*號對應的是visualdl版本號,讀者要根據實際情況來安裝:
pip install --upgrade dist/visualdl-*.whl
安裝完成之後,同樣可以使用在上一部分的使用pip安裝的測試方法測試安裝是否成功。
簡單使用VisualDL¶
我們編寫下面這一小段的代碼來學習VisualDL的使用,代碼如下:
# coding=utf-8
# 導入VisualDL的包
from visualdl import LogWriter
# 創建一個LogWriter,第一個參數是指定存放數據的路徑,
# 第二個參數是指定多少次寫操作執行一次內存到磁盤的數據持久化
logw = LogWriter("./random_log", sync_cycle=10000)
# 創建訓練和測試的scalar圖,
# mode是標註線條的名稱,
# scalar標註的是指定這個組件的tag
with logw.mode('train') as logger:
scalar0 = logger.scalar("scratch/scalar")
with logw.mode('test') as logger:
scalar1 = logger.scalar("scratch/scalar")
# 讀取數據
for step in range(1000):
scalar0.add_record(step, step * 1. / 1000)
scalar1.add_record(step, 1. - step * 1. / 1000)
運行Python代碼之後,在終端上輸入,從上面的代碼可以看到我們定義的路徑是./random_log:
visualDL --logdir ./random_log --port 8080
然後在瀏覽器上輸入:
http://127.0.0.1:8080
然後就可以看到剛纔編寫Python代碼生成的圖像了:

經過這個例子,讀者對VisualDL有了進一步的瞭解了,那麼在接下來的我們就在實際的PaddlePaddle例子中使用我們的VisualDL。
在PaddlePaddle使用VisualDL¶
定義VisualDL組件¶
創建三個組件:scalar,image,histogram,並指定存放日誌的路徑
# 創建VisualDL,並指定當前該項目的VisualDL的路徑
logdir = "../data/tmp"
logwriter = LogWriter(logdir, sync_cycle=10)
# 創建loss的趨勢圖
with logwriter.mode("train") as writer:
loss_scalar = writer.scalar("loss")
# 創建acc的趨勢圖
with logwriter.mode("train") as writer:
acc_scalar = writer.scalar("acc")
# 定義沒多少次重新輸出一遍
num_samples = 4
# 創建卷積層和輸出圖像的圖形化展示
with logwriter.mode("train") as writer:
conv_image = writer.image("conv_image", num_samples, 1)
input_image = writer.image("input_image", num_samples, 1)
# 創建可視化的訓練模型結構
with logwriter.mode("train") as writer:
param1_histgram = writer.histogram("param1", 100)
編寫PaddlePaddle代碼¶
然後創建PaddlePaddle代碼,我們使用的是PaddlePaddle的Fluid版本,如果對Fluid版本不熟悉的話,可以閱讀筆者的上一篇文章新版本Fluid的使用,瞭解Fluid版本之後再繼續閱讀下面的代碼,如果讀者已經很熟悉Fluid版本的使用了,那就往下看。
定義data和label,代碼如下:
# 定義圖像的類別數量
class_dim = 10
# 定義圖像的通道數和大小
image_shape = [3, 32, 32]
# 定義輸入數據大小,指定圖像的形狀,數據類型是浮點型
image = fluid.layers.data(name='image', shape=image_shape, dtype='float32')
# 定義標籤,類型是整型
label = fluid.layers.data(name='label', shape=[1], dtype='int64')
然後是獲取分類器,這裏跟上一篇有點不一樣,這裏還要提供第一層卷積,這是在訓練的時候要使用到,使用它來獲得卷積層的輸出。
# 獲取神經網絡
net, conv1 = vgg16_bn_drop(image)
# 獲取全連接輸出,獲得分類器
predict = fluid.layers.fc(
input=net,
size=class_dim,
act='softmax',
param_attr=ParamAttr(name="param1", initializer=NormalInitializer()))
之後獲取損失函數和batch_acc,在這些之後才能定義優化方法。
# 獲取損失函數
cost = fluid.layers.cross_entropy(input=predict, label=label)
# 定義平均損失函數
avg_cost = fluid.layers.mean(x=cost)
# 每個batch計算的時候能取到當前batch裏面樣本的個數,從而來求平均的準確率
batch_size = fluid.layers.create_tensor(dtype='int64')
print batch_size
batch_acc = fluid.layers.accuracy(input=predict, label=label, total=batch_size)
# 定義優化方法
optimizer = fluid.optimizer.Momentum(
learning_rate=learning_rate,
momentum=0.9,
regularization=fluid.regularizer.L2Decay(5 * 1e-5))
opts = optimizer.minimize(avg_cost)
然後就開始創建調試器,並讓其初始化。
# 是否使用GPU
place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace()
# 創建調試器
exe = fluid.Executor(place)
# 初始化調試器
exe.run(fluid.default_startup_program())
在訓練之前,還有獲取訓的數據,這裏沒有使用到測試,所以就沒有獲取測試的數據。
# 獲取訓練數據
train_reader = paddle.batch(
paddle.dataset.cifar.train10(), batch_size=BATCH_SIZE)
# 指定數據和label的對於關係
feeder = fluid.DataFeeder(place=place, feed_list=[image, label])
這裏多了一步,這是爲了讓調試器在訓練的時候也輸出參數的分佈和變化趨勢。
step = 0
sample_num = 0
start_up_program = framework.default_startup_program()
param1_var = start_up_program.global_block().var("param1")
現在就可以開始訓練了,一共輸出的四個值:loss, conv1_out, param1, acc, weight,這些在圖像輸出上,我們都是用到的。
accuracy = fluid.average.WeightedAverage()
# 開始訓練,使用循環的方式來指定訓多少個Pass
for pass_id in range(num_passes):
# 從訓練數據中按照一個個batch來讀取數據
accuracy.reset()
for batch_id, data in enumerate(train_reader()):
loss, conv1_out, param1, acc, weight = exe.run(fluid.default_main_program(),
feed=feeder.feed(data),
fetch_list=[avg_cost, conv1, param1_var, batch_acc,
batch_size])
accuracy.add(value=acc, weight=weight)
pass_acc = accuracy.eval()
把數據都添加到VisualDL¶
加載卷積層和輸入圖像的數據加載到VisualDL中
# 重新啓動圖形化展示組件
if sample_num == 0:
input_image.start_sampling()
conv_image.start_sampling()
# 獲取taken
idx1 = input_image.is_sample_taken()
idx2 = conv_image.is_sample_taken()
# 保證它們的taken是一樣的
assert idx1 == idx2
idx = idx1
if idx != -1:
# 加載輸入圖像的數據數據
image_data = data[0][0]
input_image_data = np.transpose(
image_data.reshape(image_shape), axes=[1, 2, 0])
input_image.set_sample(idx, input_image_data.shape,
input_image_data.flatten())
# 加載卷積數據
conv_image_data = conv1_out[0][0]
conv_image.set_sample(idx, conv_image_data.shape,
conv_image_data.flatten())
# 完成輸出一次
sample_num += 1
if sample_num % num_samples == 0:
input_image.finish_sampling()
conv_image.finish_sampling()
sample_num = 0
加載趨勢圖的數據,這裏包括了loss和平均錯誤率。
# 加載趨勢圖的數據
loss_scalar.add_record(step, loss)
acc_scalar.add_record(step, acc)
加載參數變化的數據
# 添加模型結構數據
param1_histgram.add_record(step, param1.flatten())
然後是運行項目,在運行項目的時候,會輸出一下的日誌信息:
loss:[16.7996] acc:[0.0703125] pass_acc:[0.0703125]
loss:[15.192436] acc:[0.1171875] pass_acc:[0.09375]
loss:[14.519127] acc:[0.109375] pass_acc:[0.09895833]
loss:[15.262356] acc:[0.125] pass_acc:[0.10546875]
loss:[13.626783] acc:[0.078125] pass_acc:[0.1]
loss:[11.8960285] acc:[0.09375] pass_acc:[0.09895833]
同時運行我們的VisualDL,筆者把VisualDL的日誌都存放在data目錄下,所以我們要去到該目錄,然後輸入以下命令:
visualDL --logdir ./tmp --port 8080
然後在瀏覽器上輸入:
http://127.0.0.1:8080
即可看到我們項目的圖像了:
-
我們訓練的趨勢圖

-
卷積和輸入圖像的可視化頁面

-
訓練參數的變化情況

上一章:《我的PaddlePaddle學習之路》筆記十一——新版本Fluid的使用¶
下一章:《我的PaddlePaddle學習之路》筆記十三——把PaddlePaddle部署到網站服務器上¶
項目代碼¶
GitHub地址:https://github.com/yeyupiaoling/LearnPaddle
參考資料¶
- http://paddlepaddle.org/
- https://github.com/PaddlePaddle/VisualDL