使用Keras訓練神經網絡備忘錄


文章太長,放個目錄:

1.優化函數的選擇

先寫結論,后面再補上每個優化函數的詳細解釋:

  1. 如果你的數據很稀疏,那應該選擇有自適應性的優化函數。並且你還可以減少調參的時間,用默認參數取得好的結果。 
  2. RMSprop是adagrad的一個拓展,旨在解決它提前結束的問題。 
  3. 而RMSprop和Adadelta類似,只是adadelta采用了RMS的方法更新參數。 
  4. 在RMSprop基礎上增加了偏差校正和momentum,形成了Adam。 
  5. 綜上,RMSprop、Adadelta、Adam都是類似的。 
  6. Kingma【Kingma, D. P., & Ba, J. L. (2015). Adam: a Method for Stochastic Optimization. International Conference on Learning Representations, 1–13.】的實驗表示,偏差校正使得Adam在優化到后面梯度變的稀疏的時候使得其優化性能最好。 
  7. 所以,可能Adam是最好的優化函數。 
  8. 所以,如果你希望你的訓練能變的更快,或者你要訓練的是一個復雜的深度的網絡,盡量選擇自適應的優化函數。 

摘自:深度學習各種優化函數詳解

2.損失函數的選擇

編譯模型必須的兩個參數之一:

model.compile(loss='mean_squared_error', optimizer='sgd')

  1. from keras import losses 
  2. model.compile(loss=losses.mean_squared_error, optimizer='sgd') 

2.2常用的損失函數

mean_squared_error或mse
mean_absolute_error或mae
mean_absolute_percentage_error或mape
mean_squared_logarithmic_error或msle
squared_hinge
hinge
categorical_hinge
logcosh
categorical_crossentropy:亦稱作多類的對數損失,注意使用該目標函數時,需要將標簽轉化為形如(nb_samples, nb_classes)的二值序列
sparse_categorical_crossentropy:如上,但接受稀疏標簽。注意,使用該函數時仍然需要你的標簽與輸出值的維度相同,你可能需要在標簽數據上增加一個維度:np.expand_dims(y,-1)
binary_crossentropy:(亦稱作對數損失,logloss)
kullback_leibler_divergence:從預測值概率分布Q到真值概率分布P的信息增益,用以度量兩個分布的差異
poisson:即(predictions - targets * log(predictions))的均值
cosine_proximity:即預測值與真實標簽的余弦距離平均值的相反數

注:當使用”categorical_crossentropy”作為目標函數時,標簽應該為多類模式,即one-hot編碼的向量,而不是單個數值. 可以使用工具中的to_categorical函數完成該轉換.示例如下:

  1. from keras.utils.np_utils import to_categorical 
  2. categorical_labels = to_categorical(int_labels, num_classes=None) 

摘自:目標函數objectives

2.2自定義函數

keras的Losses部分的源碼是這樣的:

部分losses
部分losses

可以看出,每次計算loss時,會傳給損失函數兩個值,一個是正確的標簽(y_true),一是模型預測的標簽(y_pred),這兩個值是shape相同的Theano/TensorFlow張量,根據這一規則,可以設計自己的損失函數.

2.1實踐

(1)基本用法
自定義一個,對真實和預測的差距求4次方的損失函數:

  1. #自定義損失函數 
  2. def myloss(pred,true): 
  3. result = np.power(pred-true,4) 
  4. return result.mean() 
  5. #編譯模型 
  6. model.compile(optimizer='adam',loss=myloss) 

(2)實際例子
使用one hot分類時,擬合one hot分布的同時,還你擬合均勻分布
自定義的函數是:

實際用keras是這樣的:

  1. #自定義損失函數 
  2. def mycrossentropy(y_true, y_pred, e=0.1): 
  3. return (1-e)*K.categorical_crossentropy(y_pred,y_true) + e*K.categorical_crossentropy(y_pred, K.ones_like(y_pred)/nb_classes) 
  4. #編譯模型  
  5. model.compile(optimizer='adam', loss=mycrossentropy) 

例子來源Keras中自定義復雜的loss函數

2.2將損失函數自定義為網絡層

使用均方差和KL散度定義損失函數

  1. class CustomVariationalLayer(Layer): 
  2. def __init__(self, **kwargs): 
  3. self.is_placeholder = True 
  4. super(CustomVariationalLayer, self).__init__(**kwargs) 
  5.  
  6. def vae_loss(self, x, x_decoded_mean): 
  7. xent_loss = original_dim * metrics.binary_crossentropy(x, x_decoded_mean)#Square Loss 
  8. kl_loss = - 0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)# KL-Divergence Loss 
  9. return K.mean(xent_loss + kl_loss) 
  10.  
  11. def call(self, inputs): 
  12. x = inputs[0] 
  13. x_decoded_mean = inputs[1] 
  14. loss = self.vae_loss(x, x_decoded_mean) 
  15. self.add_loss(loss, inputs=inputs) 
  16. # We won't actually use the output. 
  17. return x 
  18.  
  19. y = CustomVariationalLayer()([x, x_decoded_mean]) 
  20. vae = Model(x, y) 
  21. vae.compile(optimizer='rmsprop', loss=None) 

例子來源Keras自定義Loss函數

3.模型的保存

3.1同時保存結構和權重

官方保持模型的API是這樣的:

def save_model(model, filepath, overwrite=True, include_optimizer=True)

調用這個函數保持的內容包括:

  • 模型的結構
  • 模型的權重
  • 優化器的狀態(即保存時優化器的狀態,一遍后面從該狀態出發繼續訓練)
  1. from keras.models import load_model 
  2.  
  3. #保持模型 
  4. model.save('my_model.h5')  
  5.  
  6. #載入模型 
  7. model = load_model('my_model.h5') 

3.2模型結構的保存

如果只希望保持模型結構,可以使用以下方法保存和重建.

  1. # save as JSON 
  2. json_string = model.to_json() 
  3.  
  4. # save as YAML 
  5. yaml_string = model.to_yaml() 
  6.  
  7. # model reconstruction from JSON: 
  8. from keras.models import model_from_json 
  9. model = model_from_json(json_string) 
  10.  
  11. # model reconstruction from YAML 
  12. model = model_from_yaml(yaml_string) 

3.3模型權重的保存

如果只希望保持權重,可以使用以下方法保持和載入.

  1. model.save_weights('my_model_weights.h5') 
  2. model.load_weights('my_model_weights.h5') 

3.5選擇網絡層載入

  1. """ 
  2. 假如原模型為: 
  3. model = Sequential() 
  4. model.add(Dense(2, input_dim=3, name="dense_1")) 
  5. model.add(Dense(3, name="dense_2")) 
  6. ... 
  7. model.save_weights(fname) 
  8. """ 
  9. # new model 
  10. model = Sequential() 
  11. model.add(Dense(2, input_dim=3, name="dense_1")) # will be loaded 
  12. model.add(Dense(10, name="new_dense")) # will not be loaded 
  13.  
  14. # load weights from first model; will only affect the first layer, dense_1. 
  15. model.load_weights(fname, by_name=True) 

摘自:如何保存Keras模型

4.訓練歷史的保存

4.1檢測運行過程的參數

深度學習像煉丹一樣,有時候看見出現了仙丹(非常好的訓練結果),但是忘記保持了,之后再怎么訓練也找不回曾經的那個 .有沒有有一種機制,檢測訓練過程中的參數,如果結果比前一次好,我就保存模型權重下來呢?
有的,官方提供回調函數檢測訓練參數.
定義好檢測的參數和保存的格式,就可以將回調函數寫到訓練函數的callbacks即可:

  1. Checkpoint = keras.callbacks.ModelCheckpoint( 
  2. 'Train_record/{epoch:02d}.{val_acc:.2f}.V0.hdf5', 
  3. monitor='val_loss', 
  4. verbose=1, 
  5. save_best_only=True, 
  6. save_weights_only=False, 
  7. mode='auto', 
  8. period=1) 
  9.  
  10. history = model.fit([train_X_lstm,train_X_resnet],train_y,verbose=1,epochs=150,batch_size=256,validation_data=([vali_X_lstm,vali_X_resnet],vali_y),shuffle=True,callbacks=[Checkpoint])  

回調函數Checkpoint設置:

filepath:保存模型的路徑,你可以按照上面的方式自定義你的文件名,很直觀
monitor: 被監測的數據,訓練歷史必須包含改值,比如:如果你的訓練過程沒有設置驗證集,就無法檢測val_acc
save_best_only:每次是否保存當前的最佳模型
mode:auto, min, max} 的其中之一。 如果 save_best_only=True,那么是否覆蓋保存文件的決定就取決於被監測數據的最大或者最小值。 對於 val_acc,模式就會是 max,而對於 val_loss,模式就需要是 min.
save_weights_only: 如果 True,那么只有模型的權重會被保存 (model.save_weights(filepath)), 否則的話,整個模型會被保存 (model.save(filepath))。
period: 每個檢查點之間的間隔(訓練輪數

4.2保持訓練過程得到的所有數據

這里的所有數據是指model.fit()返回的所有數據,包括acc(訓練准確度),loss(訓練損失),如果指定了驗證集,還會有val_acc(驗證集准確度),val_loss(訓練集損失).保持方法是在訓練完成后寫入到文件中:

  1. history=model.fit(train_set_x,train_set_y,batch_size=256,shuffle=True,nb_epoch=nb_epoch,validation_split=0.1) 
  2. with open('train_history.txt','w') as f: 
  3. f.write(str(history.history)) 

5.陷阱:validation_split與shuffle

模型訓練時,有一個參數可以從訓練集抽取一定比例的數據做驗證,這個參數是validation_split.

訓練過程抽取訓練數據的10%作驗證

history = model.fit([train_X_lstm,train_X_resnet],train_y,verbose=1,epochs=150,batch_size=256,validation_split=0.1,shuffle=True,callbacks=[Checkpoint])

但是使用這個參數時,必須注意先對數據Shuffle,據說是因為validation_split只抽取訓練集的后面10%數據作驗證,如果你前面的數據沒有打亂,這樣抽取是可能只抽取到一個類別的樣本,這樣的驗證集將沒有意義.

所以,使用這個參數前,先將訓練數據(標簽同步)打亂.

例外需要關注的是:validation_split划分出來的驗證集是固定的,不隨每次epoch變化

官方文檔-Losses


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM