1. 程式人生 > 其它 >防止在訓練模型時資訊丟失 用於TensorFlow、Keras和PyTorch的檢查點教程

防止在訓練模型時資訊丟失 用於TensorFlow、Keras和PyTorch的檢查點教程

如果你玩過電子遊戲,你就會明白為什麼檢查點(chekpoint)是有用的了。舉個例子,有時候你會在一個大Boss的城堡前把你的遊戲的當前進度儲存起來——以防進入城堡裡面就Game Over了。

機器學習和深度學習實驗中的檢查點本質上是一樣的,它們都是一種儲存你實驗狀態的方法,這樣你就可以從你離開的地方開始繼續學習。

如果你因為停電、作業系統故障、工作優先或其他型別的意外錯誤而丟失了一個或多個實驗,你一定會抓狂。其他時候,即使你沒有遇到不可預見的錯誤,你也可能只是想要恢復一種新實驗的訓練的特殊狀態,或者從一個給定的狀態中嘗試不同的事情。

這就是為什麼你需要檢查點!

但是,等等,還有一個很重要的原因。如果你在工作結束時不檢查你的訓練模式,你將會失去所有的結果!簡單來說,如果你想使用你訓練的模型,你就需要一些檢查點。

FloydHub是一個極其易用的深度學習雲端計算平臺。號稱“Zero Setup for Deep Learning”。它的服務主旨是: “您就專心研究您的深度學習,其它的環境配置、部署、版本控制等等都交給我們來做就可以了”。

  • FloydHub網址:https://www.floydhub.com

這篇文章將演示如何在FloydHub上對你的訓練模型進行檢查,以便你可以從這些儲存的狀態重新開始你的實驗。

什麼是檢查點?

Keras文件為檢查點提供了一個很好的解釋:

  • 模型的體系結構,允許你重新建立模型
  • 模型的權重
  • 訓練配置(損失、優化器、epochs和其他元資訊)
  • 優化器的狀態,允許在你離開的地方恢復訓練

同樣,一個檢查點包含了儲存當前實驗狀態所需的資訊,以便你可以從這一點恢復訓練。

  • Keras文件地址:https://keras.io/getting-started/faq/#how-can-i-save-a-keras-model

檢查點策略

你可以根據你正在執行的訓練型別,採用不同的檢查點策略。

  • 短期訓練制度(幾分鐘到幾小時)
  • 正常的訓練制度(數小時到一整天)
  • 長期訓練制度(數天至數週)

短期訓練制度 典型的做法是在訓練結束時,或者在每個epoch結束時,儲存一個檢查點。

正常的訓練制度 在這種情況下,在每個n_epochs中儲存多個檢查點,並跟蹤我們所關心的一些驗證度量,這是很常見的。通常,有一個固定的最大數量的檢查點,這樣就不會佔用太多的磁碟空間(例如,將你最大的檢查點數量限制在10個,新的位置將會取代最早的檢查點)。

長期訓練制度 在這種型別的訓練體系中,你可能希望採用與常規機制類似的策略:在每一個n_epochs中,你都可以節省多個檢查點,並在你所關心的驗證度量上保持最佳狀態。在這種情況下,由於訓練將花費很長的時間,所以減少檢查點的次數是很常見的,但是需要維護更多的檢查點。

哪種制度適合我?

這些不同策略之間的折衷是要保持頻率檢查點檔案的數量。讓我們來看看當我們對這兩個引數進行操作時發生了什麼:

在FloydHub中儲存和恢復

現在,讓我們研究FloydHub上的一些程式碼。我將向你展示如何在TensorFlow、Keras和PyTorch這三個流行的深度學習框架中儲存檢查點:

在開始之前,使用floyd login命令登入到FloydHub命令列工具,然後復刻(fork)並初始化(init)專案:

$ git clone https://github.com/floydhub/save-and-resume.git
$ cd save-and-resume
$ floyd init save-and-resume

對於我們的檢查點示例,我們將使用深度學習的Hello,World:使用卷積神經網路模型的MNIST分類任務。

因為預先清楚我們的檢查點策略是很重要的,我將說明我們將要採用的方法:

  • 只保留一個檢查點
  • 在每個epoch結束時採取策略
  • 儲存具有最佳(最大)驗證精確度的那個

如果是這樣的小例子,我們可以採用短期的訓練制度。

命令 在深入研究具體的工作示例之前,讓我們概述一下你需要的基本命令。當你開始新工作時,你的第一個命令看起來是這樣的:

floyd run 
 [--gpu] 
 --env <env> 
 --data <your_dataset>:<mounting_point_dataset> 
 "python <script_and_parameters>"

提示:在你的python指令碼中,你需要確保將檢查點儲存到/output資料夾中。FloydHub將自動儲存/outputdirectory的內容作為工作的輸出,這就是你將如何利用這些檢查點來恢復工作的方式。

一旦你的工作完成,你就可以將該工作的輸出作為下一項工作的輸入進行掛載(mount),從而允許你的指令碼利用你在該專案的下一個執行中建立的檢查點。

floyd run 
 [--gpu] 
 --env <env> 
 --data <your_dataset>:<mounting_point_dataset> 
 --data <output_of_previous_job>:<mounting_point_model> 
 "python <script_and_parameters>"

好了,讓我們看看如何使用這三個框架來實現這一點。

TensorFlow

  • 在FloydHub Jupyter Notebook檢視完整例子:https://www.floydhub.com/redeipirati/projects/save-and-resume/53/code/tf_mnist_cnn_jupyter.ipynb

TensorFlow提供了不同的儲存和恢復檢查點的方法。在我們的例子中,我們將使用tf.Estimator API,這種API背後採用了tf.train.Saver,tf.train.CheckpointSaverHook和tf.saved_model.builder.SavedModelBuilder三種函式。

更詳細地說,tf.EstimatorAPI使用第一個函式來儲存檢查點,第二個函式根據所採用的檢查點策略進行操作,最後一個以使用export_savedmodel()方法匯出模型。

儲存一個TensorFlow檢查點 在初始化一個評估器之前,我們必須定義檢查點策略。為此,我們必須使用tf.estimator.RunConfig API為預估程式建立一個配置。這裡有一個例子,我們可以這樣做:

# Save the checkpoint in the /output folder
filepath = "/output/mnist_convnet_model"

# Checkpoint Strategy configuration
run_config = tf.contrib.learn.RunConfig(
 model_dir=filepath,
 keep_checkpoint_max=1)

通過這種方式,我們告訴預估者應該從哪個目錄中儲存或恢復一個檢查點,以及要儲存多少個檢查點。

接下來,我們必須在評估器的初始化中提供這個配置:

# Create the Estimator
mnist_classifier = tf.estimator.Estimator(
 model_fn=cnn_model_fn, config=run_config)

現在我們已經設定好了在TensorFlow程式碼中儲存檢查點。

恢復一個TensorFlow檢查點 我們也已經準備好從下一個實驗執行的檢查點重新開始。如果評估器在給定的模型資料夾中找到一個檢查點,那麼它將從最後一個檢查點載入。

下面是執行TensorFlow檢查點示例的步驟。

通過FloydHub命令模式 第一次訓練命令:

floyd run 
 --gpu 
 --env tensorflow-1.3 
 --data redeipirati/datasets/mnist/1:input 
 'python tf_mnist_cnn.py'
  • –env標記指定該專案應該執行的環境(在Python3.0.6上的Tensorflow 1.3.0 + Keras 2.0.6)
  • --data標記指定pytorch-mnist資料集應該在/inputdirectory中可以使用
  • –gpu標記實際上是可選的,除非你想馬上開始執行GPU機器上的程式碼

從你的檢查點恢復:

floyd run 
 --gpu 
 --env tensorflow-1.3 
 --data redeipirati/datasets/mnist/1:input 
 --data <your-username>/projects/save-and-resume/<jobs>/output:/model 
 'python tf_mnist_cnn.py'
  • –env標記指定該專案應該執行的環境(在Python3.0.6上的Tensorflow 1.3.0 + Keras 2.0.6)
  • 第一個 --data標記指定pytorch-mnist資料集應該在/inputdirectory中可以使用
  • 第二個–data標記指定前一個工作的輸出應該在/modeldirectory中可以使用
  • –gpu標記實際上是可選的——除非你想馬上開始執行GPU機器上的程式碼

通過FloydHub的Jupyter Notebook模式

floyd run 
 --gpu 
 --env tensorflow-1.3 
 --data redeipirati/datasets/mnist/1:input 
 --mode jupyter
  • –env標記指定該專案應該執行的環境(在Python3.0.6上的Tensorflow 1.3.0 + Keras 2.0.6)
  • –data標記指定pytorch-mnist資料集應該在/inputdirectory中可以使用
  • –gpu標記實際上是可選的——除非你想馬上開始執行GPU機器上的程式碼
  • –mode標記指定該工作應該提供一個Jupyter notebook例項

從你的檢查點恢復: 如果你想從你的Jupyter notebook上的前一份工作中載入一個檢查點,那麼只需新增–data <your-username>/projects/save-and-resume/<jobs>/output:/model到之前的命令。

Keras

  • 在FloydHub Jupyter Notebook檢視完整例子:https://www.floydhub.com/redeipirati/projects/save-and-resume/53/code/keras_mnist_cnn_jupyter.ipynb

Keras為儲存和載入檢查點提供了一個很棒的API。讓我們來看看:

儲存一個Keras檢查點 Keras提供了一組名為回撥(callbacks)的函式:你可以把回撥看作是在某些訓練狀態下觸發的事件。我們需要用於檢查點的回撥是ModelCheckpoint,它根據我們在示例中採用的檢查點策略提供所需的所有特性。

注意:這個函式只會儲存模型的權重——如果你想儲存整個模型或部分元件,你可以在儲存模型時檢視Keras文件。

  • Keras文件地址:https://keras.io/getting-started/faq/#how-can-i-save-a-keras-model

首先,我們必須匯入回撥函式:

from keras.callbacks import ModelCheckpoint

接下來,就在對model.fit(…)的呼叫之前,是時候準備檢查點策略了。

# Save the checkpoint in the /output folder
filepath = "/output/mnist-cnn-best.hdf5"

# Keep only a single checkpoint, the best over test accuracy.
checkpoint = ModelCheckpoint(filepath,
 monitor='val_acc',
 verbose=1,
 save_best_only=True,
 mode='max')
  • filepath=”/output/mnist-cnn-best.hdf5″:記住,FloydHub將儲存/output資料夾的內容!
  • monitor=’val_acc’:這是我們所關心的度量:驗證精確度
  • verbose=1:它將列印更多資訊
  • save_best_only=True:只保留最好的檢查點(在最大化驗證精確度的情況下)
  • mode=’max’:以最大化驗證精確度儲存檢查點

預設情況下,週期(或檢查點頻率)設定為1,這意味著在每個epoch結束。

最後,我們已經準備好看到在模型訓練期間應用的檢查點策略。為了做到這一點,我們需要將回調變數傳遞給model.fit(…)呼叫:

# Train
model.fit(x_train, y_train,
 batch_size=batch_size,
 epochs=epochs,
 verbose=1,
 validation_data=(x_test, y_test),
 callbacks=[checkpoint]) # <- Apply our checkpoint strategy

根據我們選擇的策略,你會看到:

# This line when the training reach a new max
Epoch < n_epoch >: val_acc improved from < previous val_acc > to < new max val_acc >, saving model to /output/mnist-cnn-best.hdf5

# Or this line
Epoch < n_epoch >: val_acc did not improve

就是這樣,你現在已經設定好儲存你的檢查點了。

恢復一個Keras檢查點 Keras模型提供了load_weights()方法,該方法從hdf5file檔案中載入權重。要載入模型的權重,你只需在模型定義之後新增這一命令列:

... # Model Definition

model.load_weights(resume_weights)

下面是如何在FloydHub執行這個Keras的示例:

通過FloydHub的命令模式 第一次訓練命令:

floyd run 
 --gpu 
 --env tensorflow-1.3 
 'python keras_mnist_cnn.py'
  • –env標記指定該專案應該執行的環境(在Python3.0.6上的Tensorflow 1.3.0 + Keras 2.0.6)
  • –gpu標記實際上是可選的——除非你想馬上開始執行GPU機器上的程式碼

Keras提供了一個用於處理MNIST資料的API,因此我們可以在本例中跳過資料集的安裝。

  • 地址:https://keras.io/datasets/#mnist-database-of-handwritten-digits

從你的檢查點恢復:

floyd run 
 --gpu 
 --env tensorflow-1.3 
 --data <your-username>/projects/save-and-resume/<jobs>/output:/model 
 'python keras_mnist_cnn.py'
  • –env標記指定該專案應該執行的環境(在Python3.0.6上的Tensorflow 1.3.0 + Keras 2.0.6)
  • --data標記指定之前工作的輸出應該在/modeldirectory中可以使用
  • –gpu標記實際上是可選的——除非你想馬上開始執行GPU機器上的程式碼

通過FloydHub的Jupyter Notebook模式

floyd run 
 --gpu 
 --env tensorflow-1.3 
 --mode jupyter
  • –env標記指定該專案應該執行的環境(在Python3.0.6上的Tensorflow 1.3.0 + Keras 2.0.6)
  • –gpu標記實際上是可選的——除非你想馬上開始執行GPU機器上的程式碼
  • –mode標記指定該工作應該提供一個Jupyter notebook例項

從你的檢查點恢復: 如果你想要從以前的工作中載入一個檢查點,那麼只需新增–data <your-username>/projects/save-and-resume/<jobs>/output:/model。

PyTorch

  • 在FloydHub Jupyter Notebook檢視完整例子:https://www.floydhub.com/redeipirati/projects/save-and-resume/53/code/pytorch_mnist_cnn_jupyter.ipynb

不幸的是,目前,檢查點對於PyTorch的API來說並不像Keras那樣容易。我們需要根據所選的檢查點策略編寫自己的解決方案。

儲存一個PyTorch檢查點 PyTorch沒有提供一個一體化(all-in-one)的API來定義一個檢查點策略,但是它提供了一個簡單的方法來儲存和恢復一個檢查點。根據語義序列化(semantic serialization)的官方文件,最好的做法是隻儲存權重,這是由於程式碼重構問題造成的。

  • 語義序列化文件:http://pytorch.org/docs/master/notes/serialization.html

因此,讓我們來看看如何在PyTorch中儲存模型的權重。

首先,讓我們定義一個save_checkpoint函式,該函式負責處理要保留的檢查點數量和檔案序列化的所有指令。

def save_checkpoint(state, is_best, filename='/output/checkpoint.pth.tar'):
 """Save checkpoint if a new best is achieved"""
 if is_best:
 print ("=> Saving a new best")
 torch.save(state, filename) # save checkpoint
 else:
 print ("=> Validation Accuracy did not improve")

然後,在訓練中(通常是一個迴圈的次數),我們定義了檢查點的頻率(在我們的例子中,指的是在每個epoch結束時)和我們想要儲存的資訊(epoch,模型的權重,以及達到的最佳精確度):

...

# Training the Model
for epoch in range(num_epochs):
 train(...) # Train
 acc = eval(...) # Evaluate after every epoch

# Some stuff with acc(accuracy)
 ...

# Get bool not ByteTensor
 is_best = bool(acc.numpy() > best_accuracy.numpy())
 # Get greater Tensor to keep track best acc
 best_accuracy = torch.FloatTensor(max(acc.numpy(), best_accuracy.numpy()))
 # Save checkpoint if is a new best
 save_checkpoint({
 'epoch': start_epoch + epoch + 1,
 'state_dict': model.state_dict(),
 'best_accuracy': best_accuracy
 }, is_best)

你現在可以在你的PyTorch實驗中儲存檢查點。

恢復一個PyTorch檢查點 為了恢復一個PyTorch檢查點,我們必須在訓練前載入我們需要的權重和元資訊。

# cuda = torch.cuda.is_available()
if cuda:
 checkpoint = torch.load(resume_weights)
else:
 # Load GPU model on CPU
 checkpoint = torch.load(resume_weights,
 map_location=lambda storage,
 loc: storage)
start_epoch = checkpoint['epoch']
best_accuracy = checkpoint['best_accuracy']
model.load_state_dict(checkpoint['state_dict'])
print("=> loaded checkpoint '{}' (trained for {} epochs)".format(resume_weights, checkpoint['epoch']))

下面是如何在FloydHub執行這個PyTorch的示例:

通過FloydHub的命令模式 第一次訓練命令:

floyd run 
 --gpu 
 --env pytorch-0.2 
 --data redeipirati/datasets/pytorch-mnist/1:input 
 'python pytorch_mnist_cnn.py'
  • –env標記指定該專案應該執行的環境(在Python 3上的PyTorch 0.2.0)
  • –data標記指定pytorch-mnist資料集應該在/inputdirectory中可用
  • –gpu標記實際上是可選的——除非你想馬上開始執行GPU機器上的程式碼

從你的檢查點恢復:

floyd run 
 --gpu 
 --env pytorch-0.2 
 --data redeipirati/datasets/pytorch-mnist/1:input 
 --data <your-username>/projects/save-and-resume/<jobs>/output:/model 
 'python pytorch_mnist_cnn.py'
  • –env標記指定該專案應該執行的環境(在Python 3上的PyTorch 0.2.0)
  • 第一個–data標記指定pytorch-mnist資料集應該在/inputdirectory中可以使用
  • 第二個–data標記指定前一個工作的輸出應該在/modeldirectory中可以使用
  • –gpu標記實際上是可選的——除非你想馬上開始執行GPU機器上的程式碼

通過FloydHub的Jupyter Notebook模式

floyd run 
 --gpu 
 --env pytorch-0.2 
 --data redeipirati/datasets/pytorch-mnist/1:input 
 --mode jupyter
  • –env標記指定該專案應該執行的環境(在Python 3上的PyTorch 0.2.0)
  • –data標記指定pytorch-mnist資料集應該在/inputdirectory中可以使用
  • –gpu標記實際上是可選的——除非你想馬上開始執行GPU機器上的程式碼
  • –mode標記指定該工作應該為我們提供一個Jupyter notebook

從你的檢查點恢復: 如果你想要從以前的工作中載入一個檢查點,那麼只需新增–data <your-username>/projects/save-and-resume/<jobs>/output:/model。