Tensorflow-2-Tensorboard使用

1c8b: 概述

機器學習如此復雜筒捺,訓練模型的時候,摸不清背后到底是如何運行的纸厉。自己設置的參數(shù)和關鍵變量系吭,如果能看到在訓練時的變化情況,可以為后面的參數(shù)調(diào)優(yōu)階段提供很大的便利残腌。

Tensorboard就是這樣一個工具村斟。

它刻意將模型抽象成圖像,tensor每一步是如何流動的抛猫,一目了然蟆盹。

通過適當?shù)拇a設置,還能將指定的關鍵變量在訓練時的變化情況繪制成曲線圖闺金,以便訓練完成后觀察變量的變化情況逾滥,來更加準確定位問題。

這篇文章簡單介紹一下tensorboard的基本用法败匹。


1c8c: Tensorboard使用

?tensorboard(以下簡稱tb)的操作寨昙,從創(chuàng)建一個FileWriter開始。

在接下來的代碼中掀亩,我參照CS231N課程的數(shù)據(jù)集例子舔哪,用tensorflow(以下簡稱tf)寫了一個Logistic Regression,并以此來說明tb的基本用法槽棍。

用到的notebook我的github上可以找到捉蚤。使用之前,請確保執(zhí)行

conda env create -f environment_tf.yml

來創(chuàng)建和我一樣的運行環(huán)境炼七。如有問題缆巧,可以留言或者ISSUE。

創(chuàng)建好環(huán)境之后豌拙,運行

source activate tb-lab

激活conda環(huán)境陕悬,然后運行

jupyter notebook

來使用本例中的notebook

下面的示例程序用tf做了一個兩層的分類網(wǎng)絡按傅。將下圖中的數(shù)據(jù)集分類捉超。

待分類的數(shù)據(jù)集

最終分類效果是這樣的。

分類完成之后

tb的使用逞敷,大致歸納為三步:

  • 調(diào)用tf中的FileWriter將自己關注的數(shù)據(jù)寫到磁盤
  • 在命令行使用tensorboard --logdir /path/to/log啟動tbweb app
  • 然后在本地瀏覽器輸入localhost:6006來使用tb

下面具體看一下怎么使用狂秦。

1.生成模型圖

生成模型圖只需要一句話就行。比如說推捐,現(xiàn)在已經(jīng)初始化好了變量裂问,處理好了數(shù)據(jù),部分代碼如下:

# 數(shù)據(jù)初始化
N = 100 # number of points per class
D = 2 # dimensionality
K = 3 # number of classes
X = np.zeros((N * K, D)) # data matrix (each row = single example)
y = np.zeros(N * K, dtype='uint8') # class labels
for j in range(K):
    ix = range(N * j, N * (j + 1))
    r = np.linspace(0.0, 1, N) # radius
    t = np.linspace(j * 4, (j + 1) * 4, N) + np.random.randn(N) * 0.2 # theta
    X[ix] = np.c_[r * np.sin(t), r * np.cos(t)]
    y[ix] = j
# lets visualize the data:
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)
plt.show()

# 輸入數(shù)據(jù)
inputs = tf.placeholder(tf.float32, [N * K, D])

# 數(shù)據(jù)標簽
targets = tf.placeholder(tf.float32, [None, K])

softmax_w_1 = tf.Variable(tf.truncated_normal((D, h), stddev=0.1), dtype=tf.float32, name='weight_1')

softmax_b_1 = tf.Variable(tf.zeros((1, h)), dtype=tf.float32)

softmax_w_2 = tf.Variable(tf.truncated_normal((h, K), stddev=0.1), dtype=tf.float32, name='weight_2')

softmax_b_2 = tf.Variable(tf.zeros((1, K)), dtype=tf.float32)

省略部分代碼......

prediction = tf.nn.softmax(logits_2)

準備開始訓練的時候,加上一句

tf.summary.FileWriter('./logs/summary', session.graph)

例如堪簿,在session開始的時候添加就好痊乾。

with tf.Session() as session:
    session.run(init)
    
    merged = tf.summary.merge_all()
    writer = tf.summary.FileWriter('./logs/summary', session.graph)

我們要看整個模型的圖像,因此傳入session.graph對象椭更。

這時哪审,來到命令行,切換到notebook所在的目錄虑瀑,然后執(zhí)行

tensorboard --logdir logs/summary

logs/summary就是代碼中定義的目錄路徑湿滓。tb啟動后會提示到瀏覽器用localhost:6006去打開tb應用。

在瀏覽器打開后舌狗,切換到GRAPH標簽叽奥,看到的模型圖是這樣的。

這個時候其他標簽還沒有內(nèi)容痛侍,因為還沒有在代碼中進行添加朝氓。

上面的圖片,就是現(xiàn)在這個模型的原始圖像主届,沒有進行任何分組和加工赵哲。看起來很亂君丁,有一些標簽枫夺,例如slice什么的,都不知道是什么意思绘闷。

圖中筷屡,

  • 每條曲線代表tensor的流向
  • 每個橢圓代表一個操作,如add簸喂,matmul
  • 每個圓角矩形代表一組操作,可以雙擊放大燎潮,看到這個組里面的細節(jié)
  • 整張圖片可以放大縮小喻鳄,隨意拖動;點開每個節(jié)點确封,右上角都會有這個節(jié)點的詳細信息

下面來加工一下除呵,為模型圖分組,讓圖像更加清晰有條理爪喘。

2.使用name_scope分組

調(diào)用tf.name_scope()方法來為graph分組颜曾。

我想清楚看到

  • 輸入Inputs
  • 標簽Targets
  • 兩組Weightbias變量
  • 兩個隱藏層的輸出Logits_1Logits_2
  • 損失函數(shù)loss
  • 訓練準確率Accuracy以及
  • 整個訓練過程Train

示例代碼如下。

輸入Inputs

with tf.name_scope('Inputs') as scope:
    inputs = tf.placeholder(tf.float32, [N * K, D], name='inputs')

標簽Targets

with tf.name_scope('Targets') as scope:
    targets = tf.placeholder(tf.float32, [None, K], name='targets')

兩組Weight和bias變量

# 創(chuàng)建第一層的weights和bias
with tf.name_scope('Weight_Set_1') as scope:
    softmax_w_1 = tf.Variable(tf.truncated_normal((D, h), stddev=0.1), dtype=tf.float32, name='weight_1')
    softmax_b_1 = tf.Variable(tf.zeros((1, h)), dtype=tf.float32, name='bias_1')

# 創(chuàng)建第二層的weights和bias
with tf.name_scope('Weight_Set_2') as scope:
    softmax_w_2 = tf.Variable(tf.truncated_normal((h, K), stddev=0.1), dtype=tf.float32, name='weight_2')
    softmax_b_2 = tf.Variable(tf.zeros((1, K)), dtype=tf.float32, name='bias_2')

兩個隱藏曾的輸出Logits_1和Logits_2

with tf.name_scope('Logits_1') as scope:
    # 第一層的輸出logits_1,使用ReLU作為activation function
    logits_1 = tf.nn.relu(tf.add(tf.matmul(X, softmax_w_1), softmax_b_1), name='logits_1')

with tf.name_scope('Logits_2') as scope:
    logits_2 = tf.add(tf.matmul(logits_1, softmax_w_2), softmax_b_2, name='logits_2')

    # 計算最終的預測分數(shù),使用softmax計算最后的分數(shù)
    prediction = tf.nn.softmax(logits_2, name='prediction')

損失函數(shù)loss

with tf.name_scope('Loss') as scope:
    loss = tf.reduce_mean(
          tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=prediction, name='loss'))

訓練準確率Accuracy

with tf.name_scope('Accuracy') as scope:
    # Determine if the predictions are correct
    is_correct_prediction = tf.equal(tf.argmax(prediction, 1), tf.argmax(y_, 1))
    # Calculate the accuracy of the predictions
    accuracy = tf.reduce_mean(tf.cast(is_correct_prediction, tf.float32), name='accuracy')

訓練過程Train

with tf.name_scope('Train') as scope:
    # 使用adam最為optimizer
    optimizer = tf.train.AdamOptimizer(learning_rate).minimize(loss)

設置好這些代碼之后秉剑,就可以跟第一步中一樣泛豪,使用

with tf.Session() as session:
    session.run(init)

    writer = tf.summary.FileWriter('./logs/summary', session.graph)
    
......

來生成模型圖。

訓練完成后,再次執(zhí)行tensorboard --logdir logs/summary诡曙,在瀏覽器中看到的模型圖就是這樣的了臀叙。

跟剛才相比,是不是清晰了很多价卤,我所需的所有關注點劝萤,這個圖上都有了。

這時如何為圖中的節(jié)點分組慎璧。

3.添加變量詳情

添加變量詳情床嫌,刻意在訓練結(jié)束后,直接看到變量的變化情況胸私。上面兩步中厌处,只有GRAPH標簽下面有內(nèi)容,其他標簽下面都沒有盖文。這一步就是往其他標簽下面添加內(nèi)容嘱蛋。

添加變量詳情,使用

tf.summary.histogram()
tf.summary.scalar()

這兩個方法五续。

比如洒敏,我想關注:

  • 兩組Weight和bias的變化情況
  • 每一次的預測結(jié)果的變化情況
  • 訓練過程中l(wèi)oss的變化情況
  • 訓練過程中準確率的變化情況

我可以通過上述兩個方法來添加代碼。

注意在使用這兩個方法之前疙驾,要為變量都加上name關鍵字參數(shù)凶伙。

看上面的代碼中,有

softmax_w_1 = tf.Variable(tf.truncated_normal((D, h), stddev=0.1), dtype=tf.float32, name='weight_1')

最后這個name='weight_1'就是用來標識softmax_w_1的名稱它碎。

為了使結(jié)果更加準確函荣,務必為分組中的變量都添加相應的名稱標識。

名稱都添加了之后扳肛,就可以使用下面的代碼來添加我們想要的結(jié)果了傻挂。

# 兩組Weight和bias的直方圖,用histogram
w_1_hist = tf.summary.histogram('weight_1', softmax_w_1)
b_1_hist = tf.summary.histogram('bias_1', softmax_b_1)
w_2_hist = tf.summary.histogram('weight_2', softmax_w_2)
b_2_hist = tf.summary.histogram('bias_2', softmax_b_2)

# 每次預測值的直方圖
logits = tf.summary.histogram('prediction', prediction)

# 損失loss和準確率accuracy的變化挖息,這里用scalar就好金拒,具體原因還沒有深究
# 用histogram應該也沒有問題的,用了scalar之后套腹,scalar標簽下面就有內(nèi)容了
loss_hist = tf.summary.scalar('loss', loss)
acc_hist = tf.summary.scalar('accuracy', accuracy)

然后绪抛,在訓練的時候,要調(diào)用merge_all()电禀,并用session去執(zhí)行merge幢码,最后將merge_all()返回的對象(本例中叫summary)添加到FileWriter中才行〖夥桑看著復雜症副,一步步看代碼還是很清晰的店雅。

# 初始化Variable
init = tf.global_variables_initializer()

# 打開session
with tf.Session() as session:
    # 運行初始化
    session.run(init)
    
    # 調(diào)用merge_all(),將前面添加的所有histogram和scalar合并到一起瓦糕,方便觀察
    merged = tf.summary.merge_all()
    # 同樣寫入到logs中
    writer = tf.summary.FileWriter('./logs/summary', session.graph)
    
    training_feed_dict = {inputs: X, targets: y_.eval()}
    
    for i in range(epochs):
        # 訓練的時候底洗,第一個傳入merged對象,返回summary
        summary, _, l = session.run(
                [merged, optimizer, loss],
                feed_dict=training_feed_dict)

        if not i % 50:
            print('Epoch {}/{} '.format(i + 1, epochs), 
                  'Training loss: {:.4f}'.format(l))
            # 每50步咕娄,將summary對象添加到writer寫入磁盤亥揖,最后來觀察變化
            writer.add_summary(summary, i)

在這里,就可以通過觀察這些變量的行為來找問題所在了圣勒。

訓練完成后费变,同理打開tb

可以看到SCALAR標簽下,就有剛才添加的lossaccuracy了。

看這兩個變量的行為不錯视事,loss一直降低瓶殃,accuracy最后達到了%99左右泡嘴。

這個圖片時可以通過選定指定一個區(qū)域來放大的,放大之后如下圖。

這是accuracy放大之后的效果圖,可以更加清晰矮慕。

接下來到DISTRIBUTIONHISTOGRAM里看看。

上圖是兩組Weights在訓練過程中的行為啄骇,這里分布均勻痴鳄,挺正常。如果有問題的話缸夹,會保持不變痪寻,也就是說模型沒有進行學習。

這里是兩組bias的行為虽惭。這里可以看出點問題了橡类,這個實例模型在訓練的時候,雖然準確率能到%99芽唇,但是loss降到0.5左右就下不去了猫态。

如果在notebook中多次嘗試運行整個模型,會發(fā)現(xiàn)最后分類完成的那張圖片披摄,無法很精準的分類。

看上圖勇凭,bias_2的分布有點可疑疚膊,我還不確定,但是這樣異常的不均勻的情況可以給予一定的方向虾标。我現(xiàn)在要做的就是就去看看什么影響了bias_2的正常更新寓盗,并且這個影響是不是引起了最終的loss瓶頸。

上圖是HISTOGRAMWeights的分布,看起來還是比較正常的傀蚌,分布很均勻基显。

再來看看bias的。

這是兩個bias的分部情況善炫,第一個看起來還不錯撩幽。但是第二個就異常了÷嵋眨刻意點一下圖像左下角那個按鈕窜醉,就可以將圖像放大。我放大了第二個bias的圖像艺谆,如下榨惰。

簡直是找不到規(guī)律,雖然不是很明白為什么會這樣静汤,但是感覺問題就出在這里了琅催。

這里看到的是2D圖像,點左邊欄中的OFFSET虫给,就能看到和Weights那一樣的3D圖像了藤抡。


1c8d: 總結(jié)

就像上面的例子,如果沒有tb狰右,我并不能準確知道到底是哪一個變量有異常杰捂。tb的可視化功能大大提高了訓練網(wǎng)絡的效率。

這里是tb的基本使用方式棋蚌,還有很多有待研究嫁佳。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市谷暮,隨后出現(xiàn)的幾起案子蒿往,更是在濱河造成了極大的恐慌,老刑警劉巖湿弦,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓤漏,死亡現(xiàn)場離奇詭異,居然都是意外死亡颊埃,警方通過查閱死者的電腦和手機蔬充,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來班利,“玉大人饥漫,你說我怎么就攤上這事÷薇辏” “怎么了庸队?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵积蜻,是天一觀的道長。 經(jīng)常有香客問我彻消,道長竿拆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任宾尚,我火速辦了婚禮丙笋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘央勒。我一直安慰自己不见,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布崔步。 她就那樣靜靜地躺著稳吮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪井濒。 梳的紋絲不亂的頭發(fā)上灶似,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音瑞你,去河邊找鬼酪惭。 笑死,一個胖子當著我的面吹牛者甲,可吹牛的內(nèi)容都是我干的春感。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼虏缸,長吁一口氣:“原來是場噩夢啊……” “哼鲫懒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刽辙,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤窥岩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后宰缤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颂翼,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年慨灭,在試婚紗的時候發(fā)現(xiàn)自己被綠了朦乏。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡氧骤,死狀恐怖呻疹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情语淘,我是刑警寧澤诲宇,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站惶翻,受9級特大地震影響姑蓝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吕粗,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一纺荧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧颅筋,春花似錦宙暇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至先口,卻和暖如春型奥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碉京。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工厢汹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谐宙。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓烫葬,卻偏偏與公主長得像,于是被迫代替她去往敵國和親凡蜻。 傳聞我的和親對象是個殘疾皇子搭综,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容