1 神器級的TensorBoard¶
TensorBoard是TensorFlow中的又一神器級工具,想用戶提供了模型可視化的功能。我們都知道,在構建神經網絡模型時,只要模型開始訓練,很多細節對外界來說都是不可見的,參數如何變化,准確率怎么樣了,loss還在減小嗎,這些問題都很難弄明白。但是,TensorBoard通過結合web應用為我們提供了這一功能,它將模型訓練過程的細節以圖表的形式通過瀏覽器可視化得展現在我們眼前,通過這種方式我們可以清晰感知weight、bias、accuracy的變化,把握訓練的趨勢。
本文介紹兩種使用TensorBoard的方式。不過,無論使用那種方式,請先啟動TensorBoard的web應用,這個web應用讀取模型訓練時的日志數據,每隔30秒更新到網頁端。在TensorFlow2.0中,TensorBoard是默認安裝好的,所以,可以直接根據以下命令啟動:
tensorboard --logdir "/home/chb/jupyter/logs"
logdir指的是日志目錄,每次訓練模型時,TensorBoard會在日志目錄中創建一個子目錄,在其中寫入日志,TensorBoard的web應用正是通過日志來感知模型的訓練狀態,然后更新到網頁端。
如果命令成功運行,可以通過本地的6006端口打開網頁,但是,此時打開的頁面時下面這個樣子,因為還沒有開始訓練模型,更沒有將日志寫入到指定的目錄。
要將訓練數據寫入指定目錄就必須將TensorBoard嵌入模型的訓練過程,TensorFlow介紹了兩種方式。下面,我們通過mnist數據集訓練過程來介紹着兩種方式。
2 在Model.fit()中使用TensorBoard¶
import tensorflow as tf
import tensorboard
import datetime
mnist = tf.keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
def create_model():
return tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
model = create_model()
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# 定義日志目錄,必須是啟動web應用時指定目錄的子目錄,建議使用日期時間作為子目錄名
log_dir="/home/chb/jupyter/logs/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1) # 定義TensorBoard對象
model.fit(x=x_train,
y=y_train,
epochs=5,
validation_data=(x_test, y_test),
callbacks=[tensorboard_callback]) # 將定義好的TensorBoard對象作為回調傳給fit方法,這樣就將TensorBoard嵌入了模型訓練過程
Train on 60000 samples, validate on 10000 samples Epoch 1/5 60000/60000 [==============================] - 4s 71us/sample - loss: 0.2186 - accuracy: 0.9349 - val_loss: 0.1180 - val_accuracy: 0.9640 Epoch 2/5 60000/60000 [==============================] - 4s 66us/sample - loss: 0.0972 - accuracy: 0.9706 - val_loss: 0.0754 - val_accuracy: 0.9764 Epoch 3/5 60000/60000 [==============================] - 4s 66us/sample - loss: 0.0685 - accuracy: 0.9781 - val_loss: 0.0696 - val_accuracy: 0.9781 Epoch 4/5 60000/60000 [==============================] - 4s 66us/sample - loss: 0.0527 - accuracy: 0.9831 - val_loss: 0.0608 - val_accuracy: 0.9808 Epoch 5/5 60000/60000 [==============================] - 4s 66us/sample - loss: 0.0444 - accuracy: 0.9859 - val_loss: 0.0637 - val_accuracy: 0.9803
<tensorflow.python.keras.callbacks.History at 0x7f9b690893d0>
通過TensorBoard提供的圖標,我們可以清楚的知道訓練模型時loss和accuracy在每一個epoch中是怎么變化的,甚至,在網頁菜單欄我們可以看到,TensorBoard提供了查看其他內容的功能:
-
在 scalars 下可以看到 accuracy,cross entropy,dropout,bias,weights 等的趨勢。
-
在 images 和 audio 下可以看到輸入的數據。
-
在 graphs 中可以看到模型的結構。
-
在 histogram 可以看到 activations,gradients 或者 weights 等變量的每一步的分布,越靠前面就是越新的步數的結果。
-
distribution 和 histogram 是兩種不同的形式,可以看到整體的狀況。
-
在 embedding 中可以看到用 PCA 主成分分析方法將高維數據投影到 3D 空間后的數據的關系。
這就是TensorBoard提供的功能,不可為不強大。這里,我們在介紹一下TensorBoard構造方法中的參數: 工具在Tensorflow中是非常常用的其參數解釋如下:
- log_dir:保存TensorBoard要解析的日志文件的目錄的路徑。
- histogram_freq:頻率(在epoch中),計算模型層的激活和權重直方圖。如果設置為0,則不會計算直方圖。必須為直方圖可視化指定驗證數據(或拆分)。
- write_graph:是否在TensorBoard中可視化圖像。當write_graph設置為True時,日志文件可能會變得非常大。
- write_grads:是否在TensorBoard中可視化漸變直方圖。 histogram_freq必須大於0。
- batch_size:用以直方圖計算的傳入神經元網絡輸入批的大小。
- write_images:是否在TensorBoard中編寫模型權重以顯示為圖像。
- embeddings_freq:將保存所選嵌入層的頻率(在epoch中)。如果設置為0,則不會計算嵌入。要在TensorBoard的嵌入選項卡中顯示的數據必須作為embeddings_data傳遞。
- embeddings_layer_names:要關注的層名稱列表。如果為None或空列表,則將監測所有嵌入層。
- embeddings_metadata:將層名稱映射到文件名的字典,其中保存了此嵌入層的元數據。如果相同的元數據文件用於所有嵌入層,則可以傳遞字符串。
- embeddings_data:要嵌入在embeddings_layer_names指定的層的數據。Numpy數組(如果模型有單個輸入)或Numpy數組列表(如果模型有多個輸入)。
- update_freq:‘batch’或’epoch’或整數。使用’batch’時,在每個batch后將損失和指標寫入TensorBoard。這同樣適用’epoch’。如果使用整數,比方說1000,回調將會在每1000個樣本后將指標和損失寫入TensorBoard。請注意,過於頻繁地寫入TensorBoard會降低您的訓練速度。 還有可能引發的異常:
- ValueError:如果設置了histogram_freq且未提供驗證數據。
3 在其他功能函數中嵌入TensorBoard¶
在訓練模型時,我們可以在 tf.GradientTape()等等功能函數中個性化得通過tf.summary()方法指定需要TensorBoard展示的參數。
同樣適用fashion_mnist數據集建立一個模型:
import datetime
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, optimizers, Sequential ,metrics
def preprocess(x, y):
x = tf.cast(x, dtype=tf.float32) / 255.
y = tf.cast(y, dtype=tf.int32)
return x, y
(x, y), (x_test, y_test) = datasets.fashion_mnist.load_data()
db = tf.data.Dataset.from_tensor_slices((x, y))
db = db.map(preprocess).shuffle(10000).batch(128)
db_test = tf.data.Dataset.from_tensor_slices((x_test, y_test))
db_test = db_test.map(preprocess).batch(128)
model = Sequential([
layers.Dense(256, activation=tf.nn.relu), # [b, 784] --> [b, 256]
layers.Dense(128, activation=tf.nn.relu), # [b, 256] --> [b, 128]
layers.Dense(64, activation=tf.nn.relu), # [b, 128] --> [b, 64]
layers.Dense(32, activation=tf.nn.relu), # [b, 64] --> [b, 32]
layers.Dense(10) # [b, 32] --> [b, 10]
]
)
model.build(input_shape=[None,28*28])
model.summary()
optimizer = optimizers.Adam(lr=1e-3)#1e-3
# 指定日志目錄
log_dir="/home/chb/jupyter/logs/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
summary_writer = tf.summary.create_file_writer(log_dir) # 創建日志文件句柄
Model: "sequential_3" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_15 (Dense) multiple 200960 _________________________________________________________________ dense_16 (Dense) multiple 32896 _________________________________________________________________ dense_17 (Dense) multiple 8256 _________________________________________________________________ dense_18 (Dense) multiple 2080 _________________________________________________________________ dense_19 (Dense) multiple 330 ================================================================= Total params: 244,522 Trainable params: 244,522 Non-trainable params: 0 _________________________________________________________________
db_iter = iter(db)
images = next(db_iter)
# 必須進行reshape,第一個緯度是圖片數量或者說簇大小,28*28是圖片大小,1是chanel,因為只灰度圖片所以是1
images = tf.reshape(x, (-1, 28, 28, 1))
with summary_writer.as_default(): # 將第一個簇的圖片寫入TensorBoard
tf.summary.image('Training data', images, max_outputs=5, step=0) # max_outputs設置最大顯示圖片數量
tf.summary.trace_on(graph=True, profiler=True)
for epoch in range(30):
train_loss = 0
train_num = 0
for step, (x, y) in enumerate(db):
x = tf.reshape(x, [-1, 28*28])
with tf.GradientTape() as tape:
logits = model(x)
y_onehot = tf.one_hot(y,depth=10)
loss_mse = tf.reduce_mean(tf.losses.MSE(y_onehot, logits))
loss_ce = tf.losses.categorical_crossentropy(y_onehot, logits, from_logits=True)
loss_ce = tf.reduce_mean(loss_ce) # 計算整個簇的平均loss
grads = tape.gradient(loss_ce, model.trainable_variables) # 計算梯度
optimizer.apply_gradients(zip(grads, model.trainable_variables)) # 更新梯度
train_loss += float(loss_ce)
train_num += x.shape[0]
loss = train_loss / train_num # 計算每一次迭代的平均loss
with summary_writer.as_default(): # 將loss寫入TensorBoard
tf.summary.scalar('train_loss', train_loss, step=epoch)
total_correct = 0
total_num = 0
for x,y in db_test: # 用測試集驗證每一次迭代后的准確率
x = tf.reshape(x, [-1, 28*28])
logits = model(x)
prob = tf.nn.softmax(logits, axis=1)
pred = tf.argmax(prob, axis=1)
pred = tf.cast(pred, dtype=tf.int32)
correct = tf.equal(pred, y)
correct = tf.reduce_sum(tf.cast(correct, dtype=tf.int32))
total_correct += int(correct)
total_num += x.shape[0]
acc = total_correct / total_num # 平均准確率
with summary_writer.as_default(): # 將acc寫入TensorBoard
tf.summary.scalar('test_acc', acc, step=epoch)
print(epoch, 'train_loss:',loss,'test_acc:', acc)
0 train_loss: 0.004282377735277017 test_acc: 0.8435 1 train_loss: 0.0029437638364732265 test_acc: 0.8635 2 train_loss: 0.0025979293311635654 test_acc: 0.858 3 train_loss: 0.0024499946276346843 test_acc: 0.8698 4 train_loss: 0.0022926158788303536 test_acc: 0.8777 5 train_loss: 0.002190616005907456 test_acc: 0.8703 6 train_loss: 0.0020421392366290095 test_acc: 0.8672 7 train_loss: 0.001972314653545618 test_acc: 0.8815 8 train_loss: 0.0018821696805457274 test_acc: 0.882 9 train_loss: 0.0018143038821717104 test_acc: 0.8874 10 train_loss: 0.0017742110469688972 test_acc: 0.8776 11 train_loss: 0.0017088291154553493 test_acc: 0.8867 12 train_loss: 0.0016564140267670154 test_acc: 0.8883 13 train_loss: 0.001609446036318938 test_acc: 0.8853 14 train_loss: 0.0015313156222303709 test_acc: 0.8939 15 train_loss: 0.0014887714397162199 test_acc: 0.8793 16 train_loss: 0.001450310030952096 test_acc: 0.8853 17 train_loss: 0.001389076333368818 test_acc: 0.892 18 train_loss: 0.0013547154798482855 test_acc: 0.892 19 train_loss: 0.0013331565233568351 test_acc: 0.8879 20 train_loss: 0.001276270254018406 test_acc: 0.8919 21 train_loss: 0.001228199392867585 test_acc: 0.8911 22 train_loss: 0.0012089030482495824 test_acc: 0.8848 23 train_loss: 0.0011713500657429298 test_acc: 0.8822 24 train_loss: 0.0011197352315609655 test_acc: 0.8898 25 train_loss: 0.0011078068762707214 test_acc: 0.8925 26 train_loss: 0.0010750674727062384 test_acc: 0.8874 27 train_loss: 0.0010422117731223503 test_acc: 0.8917 28 train_loss: 0.0010244071063275138 test_acc: 0.8851 29 train_loss: 0.0009715937084207933 test_acc: 0.8929
TensorBoard中web界面如下:
除了上述示例中使用過的scalar、image之外,summary模塊還提供了替他數據嵌入TensorBoard方法:
參考