雖然tf官方希望用戶把 train , val 程序分開寫,但實際開發中,明顯寫在一起比較簡單舒服,但在保存數據到 summary 時, val 部分和 train 部分不太一樣,會有一些問題,下面討論如何在這種情況下記錄 train/val 的 summary 。
假設訓練時的主要代碼結構如下:
losssummary = ...
othersummary = ...
trainsummaries = tf.summary.merge([losssummary, othersummary])
for i in range(self.batchnum):
batching data...
... ... step ... trainsummaryresults = sess.run(... , trainsummaries)
trainfilewriter.addsummary(trainsummaryresults) if step % self.saveinter == 0:
... # save checkpoint if step % self.dispinter == 0:
... # display training process if step % self.testinter == 0:
... # run model on test data
保存 train 部分的 summary 很簡單,tf的示例代碼也給了很多,先利用 sess.run 計算出 trainsummaryresults ,即當前 batch 的統計數據,然后保存到文件
但在 val 部分時,一般都在所有驗證數據上獲取 loss , accuracy 等 summary 數據,再保存到文件。這樣只有兩種方法:
1. val 部分的 batchsize 改為驗證集大小
2. batchsize 不變,對所有 batch 上獲取的 loss , accuracy 計算平均
第一種方法存在的問題是,如果驗證集數據較大, batchsize 會設置的較大,可能會引起內存or顯存溢出,這個沒法解決。
第二種方法存在的問題是,沒法按照train部分的做法做,因為要的是整個驗證數據的平均值,而不是每個 batch 的值,這個有辦法解決。
在設計模型結構的時候,無論是 train 還是 val ,網絡結構都是一樣的,每次只能計算一個 batch 的 loss , accuracy ,沒法單獨為驗證集修改。於是我想到了如下投機取巧的方法:先利用循環計算驗證集每個 batch 的 loss , accuracy ,進行累加,記為 averageloss 和 averageaccuracy ,然后進行如下操作:
testsummaries = tf.Summary() lossval = testsummaries.value.add() lossval.tag = 'loss' lossval.simplevalue = averageloss / batchnum accval = testsummaries.value.add() accval.tag = 'accuracy' accval.simplevalue = averageaccuracy / batchnum testfilewriter.addsummary(testsummaries, step)
其實就是自己創建一個 test_summaries ,把需要的東西填進去,模仿利用 sess.run 生成的 train_summary_results ,再保存到文件。大家如果感興趣可以把 train_summary_results 打印出來,其實就是這么個結構。目前我只保存過 scalar ,但是其他值應該也可以這么保存。
