keras自定義回調(diào)函數(shù)查看訓(xùn)練的loss和accuracy方式
前言:
keras是一個(gè)十分便捷的開發(fā)框架,為了更好的追蹤網(wǎng)絡(luò)訓(xùn)練過程中的損失函數(shù)loss和準(zhǔn)確率accuracy,我們有幾種處理方式,第一種是直接通過 history=model.fit(),來返回一個(gè)history對(duì)象,通過這個(gè)對(duì)象可以訪問到訓(xùn)練過程訓(xùn)練集的loss和accuracy以及驗(yàn)證集的loss和accuracy。
第二種方式就是通過自定義一個(gè)回調(diào)函數(shù)Call backs,來實(shí)現(xiàn)這一功能,本文主要講解第二種方式。
一、如何構(gòu)建回調(diào)函數(shù)Callbacks
本文所針對(duì)的例子是卷積神經(jīng)網(wǎng)絡(luò)Lenet-5,數(shù)據(jù)集是mnist數(shù)據(jù)集。
1.1 什么是回調(diào)函數(shù)
回調(diào)函數(shù)是一個(gè)函數(shù)的合集,會(huì)在訓(xùn)練的階段中所使用。你可以使用回調(diào)函數(shù)來查看訓(xùn)練模型的內(nèi)在狀態(tài)和統(tǒng)計(jì)。你可以傳遞一個(gè)列表的回調(diào)函數(shù)(作為 callbacks 關(guān)鍵字參數(shù))到 Sequential 或 Model 類型的 .fit() 方法。在訓(xùn)練時(shí),相應(yīng)的回調(diào)函數(shù)的方法就會(huì)被在各自的階段被調(diào)用。
這里有兩個(gè)關(guān)鍵的點(diǎn):
(1)狀態(tài)和統(tǒng)計(jì):其實(shí)就是我們希望模型在訓(xùn)練過程中需要從過程中獲取什么信息,比如我的損失loss,準(zhǔn)確率accuracy等信息就是訓(xùn)練過程中的狀態(tài)與統(tǒng)計(jì)信息;再比如我希望每一個(gè)epoch結(jié)束之后打印一些相應(yīng)的自定義提示信息,這也是狀態(tài)信息。
(2)各自的階段:模型的訓(xùn)練一般是分為多少個(gè)epoch,然后每一個(gè)epoch又分為多少個(gè)batch,所以這個(gè)階段可以是在每一個(gè)epoch之后執(zhí)行回調(diào)函數(shù),也可以是在每一個(gè)batch之后執(zhí)行回調(diào)函數(shù)。
1.2 回調(diào)函數(shù)的本質(zhì)
其實(shí)回調(diào)函數(shù)只是一個(gè)很形象的說法,它的本質(zhì)是一個(gè)類,我們直接通過 history=model.fit()返回的history對(duì)象就是一個(gè)回調(diào)函數(shù)History類的對(duì)象,而History類又繼承自Callback類。
回調(diào)函數(shù)的基類——Call back,他的定義如下:
class Callback(object): # 用來組建新的回調(diào)函數(shù)的抽象基類 def __init__(self): self.validation_data = None self.model = None def set_params(self, params): self.params = params def set_model(self, model): self.model = model def on_epoch_begin(self, epoch, logs=None): pass def on_epoch_end(self, epoch, logs=None): pass def on_batch_begin(self, batch, logs=None): pass def on_batch_end(self, batch, logs=None): pass def on_train_begin(self, logs=None): pass def on_train_end(self, logs=None): pass
屬性
params: 它是一個(gè)字典類型。訓(xùn)練參數(shù), (例如,verbosity, batch size, number of epochs...)。
model: keras.models.Model 的實(shí)例。 指代被訓(xùn)練模型。
被回調(diào)函數(shù)作為參數(shù)的 logs 字典,它會(huì)含有于當(dāng)前批量或訓(xùn)練輪相關(guān)數(shù)據(jù)的鍵。
特別需要注意的是,上面的每一個(gè)函數(shù)里面均有一個(gè)logs參數(shù),這個(gè)參數(shù)也是記錄訓(xùn)練信息的關(guān)鍵,需要注意以下幾個(gè)點(diǎn):
(1)logs是一個(gè)字典對(duì)象directory;
(2)在不同的方法中這個(gè)logs有不同的鍵值;分別如下:
on_epoch_end: 包括 acc 和 loss 的日志, 也可以選擇性的包括 val_loss(如果在 fit 中啟用驗(yàn)證),和 val_acc(如果啟用驗(yàn)證和監(jiān)測精確值)。這個(gè)用的是最多的。
on_batch_begin: 包括 size 的日志,在當(dāng)前批量內(nèi)的樣本數(shù)量。
on_batch_end: 包括 loss 的日志,也可以選擇性的包括 acc
1.3 系統(tǒng)預(yù)定義的回調(diào)函數(shù)
BaseLogger TerminateOnNaN ProgbarLogger History ModelCheckpoint EarlyStopping RemoteMonitor LearningRateScheduler TensorBoard ReduceLROnPlateau CSVLogger LambdaCallback
二、keras實(shí)現(xiàn)自定義History回調(diào)函數(shù)記錄loss和accuracy
2.1 回調(diào)函數(shù)的定義
# 寫一個(gè)LossHistory類,保存訓(xùn)練集的loss和acc # 當(dāng)然我也可以完全不這么做,可以直接使用model.fit()方法返回的 history對(duì)象去做 '''Callback有6個(gè)常用的方法,這里實(shí)現(xiàn)其中的四個(gè) def on_epoch_begin(self, epoch, logs=None): def on_epoch_end(self, epoch, logs=None): def on_batch_begin(self, batch, logs=None): def on_batch_end(self, batch, logs=None): def on_train_begin(self, logs=None): def on_train_end(self, logs=None): ''' class LossHistory(Callback): # 繼承自Callback類 ''' 在模型開始的時(shí)候定義四個(gè)屬性,每一個(gè)屬性都是字典類型,存儲(chǔ)相對(duì)應(yīng)的值和epoch ''' def on_train_begin(self, logs={}): self.losses = {'batch':[], 'epoch':[]} self.accuracy = {'batch':[], 'epoch':[]} self.val_loss = {'batch':[], 'epoch':[]} self.val_acc = {'batch':[], 'epoch':[]} # 在每一個(gè)batch結(jié)束后記錄相應(yīng)的值 def on_batch_end(self, batch, logs={}): self.losses['batch'].append(logs.get('loss')) self.accuracy['batch'].append(logs.get('acc')) self.val_loss['batch'].append(logs.get('val_loss')) self.val_acc['batch'].append(logs.get('val_acc')) # 在每一個(gè)epoch之后記錄相應(yīng)的值 def on_epoch_end(self, batch, logs={}): self.losses['epoch'].append(logs.get('loss')) self.accuracy['epoch'].append(logs.get('acc')) self.val_loss['epoch'].append(logs.get('val_loss')) self.val_acc['epoch'].append(logs.get('val_acc')) def loss_plot(self, loss_type): ''' loss_type:指的是 'epoch'或者是'batch',分別表示是一個(gè)batch之后記錄還是一個(gè)epoch之后記錄 ''' iters = range(len(self.losses[loss_type])) plt.figure() # acc plt.plot(iters, self.accuracy[loss_type], 'r', label='train acc') # loss plt.plot(iters, self.losses[loss_type], 'g', label='train loss') if loss_type == 'epoch': # val_acc plt.plot(iters, self.val_acc[loss_type], 'b', label='val acc') # val_loss plt.plot(iters, self.val_loss[loss_type], 'k', label='val loss') plt.grid(True) plt.xlabel(loss_type) plt.ylabel('acc-loss') plt.legend(loc="upper right") plt.savefig("mnist_keras.png") plt.show()
2.2 模型的搭建以及訓(xùn)練
mnist數(shù)據(jù)準(zhǔn)備
# 訓(xùn)練參數(shù) learning_rate = 0.001 epochs = 10 batch_size = 128 n_classes = 10 # 定義圖像維度reshape img_rows, img_cols = 28, 28 # 加載keras中的mnist數(shù)據(jù)集 分為60,000個(gè)訓(xùn)練集,10,000個(gè)測試集 (x_train, y_train), (x_test, y_test) = mnist.load_data() # 將圖片轉(zhuǎn)化為(samples,width,height,channels)的格式 x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1) x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1) # 將X_train, X_test的數(shù)據(jù)格式轉(zhuǎn)為float32 x_train = x_train.astype('float32') x_test = x_test.astype('float32') # 將X_train, X_test歸一化0-1 x_train /= 255 x_test /= 255 # 輸出0-9轉(zhuǎn)換為ont-hot形式 y_train = np_utils.to_categorical(y_train, n_classes) y_test = np_utils.to_categorical(y_test, n_classes)
模型的搭建以及訓(xùn)練
# 建立模型 model = Sequential() # lenet-5 model.add(Convolution2D(filters=6, kernel_size=(5, 5), padding='valid', input_shape=(img_rows, img_cols, 1), activation='tanh')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Convolution2D(filters=16, kernel_size=(5, 5), padding='valid', activation='tanh')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dense(120, activation='tanh')) model.add(Dense(84, activation='tanh')) model.add(Dense(n_classes, activation='softmax')) #打印模型# verbose=1顯示進(jìn)度條 model.summary() # 編譯模型 model.compile(optimizer=Adam(lr=learning_rate), loss='categorical_crossentropy',metrics=['accuracy']) history = LossHistory() # 這里是使用自定義的Callback回調(diào)函數(shù),當(dāng)然本身fit函數(shù)也會(huì)返回一個(gè)history可供使用 model.fit(x_train, y_train,batch_size=batch_size,epochs=epochs, verbose=1,validation_data=(x_test, y_test),callbacks=[history]) model.save('./models/lenet5_weight.h5')
繪制訓(xùn)練過程loss和acc曲線
#繪制訓(xùn)練的acc-loss曲線
history.loss_plot('epoch') # 每一個(gè)epoch展示一次
最終的運(yùn)行結(jié)果如下:
Epoch 1/10 2019-06-23 08:44:32.930737: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1432] Found device 0 with properties: name: GeForce GTX 950 major: 5 minor: 2 memoryClockRate(GHz): 1.2155 pciBusID: 0000:01:00.0 totalMemory: 2.00GiB freeMemory: 1.64GiB 2019-06-23 08:44:32.937390: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1511] Adding visible gpu devices: 0 2019-06-23 08:44:37.003650: I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] Device interconnect StreamExecutor with strength 1 edge matrix: 2019-06-23 08:44:37.006358: I tensorflow/core/common_runtime/gpu/gpu_device.cc:988] 0 2019-06-23 08:44:37.008076: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 0: N 2019-06-23 08:44:37.012620: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 1388 MB memory) -> physical GPU (device: 0, name: GeForce GTX 950, pci bus id: 0000:01:00.0, compute capability: 5.2) 60000/60000 [==============================] - 18s 302us/step - loss: 0.2979 - acc: 0.9151 - val_loss: 0.0863 - val_acc: 0.9730 Epoch 2/10 60000/60000 [==============================] - 4s 61us/step - loss: 0.0810 - acc: 0.9753 - val_loss: 0.0611 - val_acc: 0.9808 Epoch 3/10 60000/60000 [==============================] - 4s 59us/step - loss: 0.0575 - acc: 0.9826 - val_loss: 0.0518 - val_acc: 0.9849 Epoch 4/10 60000/60000 [==============================] - 4s 59us/step - loss: 0.0451 - acc: 0.9857 - val_loss: 0.0480 - val_acc: 0.9848 Epoch 5/10 60000/60000 [==============================] - 4s 59us/step - loss: 0.0375 - acc: 0.9886 - val_loss: 0.0449 - val_acc: 0.9860 Epoch 6/10 60000/60000 [==============================] - 3s 57us/step - loss: 0.0307 - acc: 0.9907 - val_loss: 0.0392 - val_acc: 0.9863 Epoch 7/10 60000/60000 [==============================] - 4s 68us/step - loss: 0.0242 - acc: 0.9923 - val_loss: 0.0389 - val_acc: 0.9882 Epoch 8/10 60000/60000 [==============================] - 4s 75us/step - loss: 0.0192 - acc: 0.9944 - val_loss: 0.0354 - val_acc: 0.9891 Epoch 9/10 60000/60000 [==============================] - 4s 66us/step - loss: 0.0180 - acc: 0.9942 - val_loss: 0.0385 - val_acc: 0.9885 Epoch 10/10 60000/60000 [==============================] - 4s 67us/step - loss: 0.0143 - acc: 0.9956 - val_loss: 0.0516 - val_acc: 0.9860
得到的訓(xùn)練曲線如下:
三、模型的結(jié)果測試
這里需要使用到sklearn庫,代碼如下:
from keras.models import load_model from sklearn.metrics import confusion_matrix, f1_score, precision_score, recall_score,accuracy_score # 測試 model=load_model('./models/lenet5_weight.h5') y_predict = model.predict(x_test, batch_size=512, verbose=1) # y_predict = (y_predict > 0.007).astype(int) y_predict = (y_predict > 0.01).astype(int) y_true = np.reshape(y_test, [-1]) y_pred = np.reshape(y_predict, [-1]) # 評(píng)價(jià)指標(biāo) accuracy = accuracy_score(y_true, y_pred) precision = precision_score(y_true, y_pred) recall = recall_score(y_true, y_pred, average='binary') f1score = f1_score(y_true, y_pred, average='binary') # Micro F1: 將n分類的評(píng)價(jià)拆成n個(gè)二分類的評(píng)價(jià),將n個(gè)二分類評(píng)價(jià)的TP、FP、RN對(duì)應(yīng)相加,計(jì)算評(píng)價(jià)準(zhǔn)確率和召回率,由這2個(gè)準(zhǔn)確率和召回率計(jì)算的F1 score即為Micro F1。 # Macro F1: 將n分類的評(píng)價(jià)拆成n個(gè)二分類的評(píng)價(jià),計(jì)算每個(gè)二分類的F1 score,n個(gè)F1 score的平均值即為Macro F1。 # 一般來講,Macro F1、Micro F1高的分類效果好。Macro F1受樣本數(shù)量少的類別影響大。 micro_f1 = f1_score(y_true, y_pred,average='micro') macro_f1 = f1_score(y_true, y_pred,average='macro') print('accuracy:',accuracy) print('precision:',precision) print('recall:',recall) print('f1score:',f1score) print('Macro-F1: {}'.format(macro_f1)) print('Micro-F1: {}'.format(micro_f1))
運(yùn)行結(jié)果是:
10000/10000 [==============================] - 2s 151us/step accuracy: 0.98813 precision: 0.8956631049654306 recall: 0.9975 f1score: 0.9438425509769599 Macro-F1: 0.9686030934161676 Micro-F1: 0.98813
以上這篇keras自定義回調(diào)函數(shù)查看訓(xùn)練的loss和accuracy方式就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
python的tkinter布局之簡單的聊天窗口實(shí)現(xiàn)方法
這篇文章主要介紹了python的tkinter布局之簡單的聊天窗口實(shí)現(xiàn)方法,對(duì)于tkinter用法做了初步的介紹與應(yīng)用展示,需要的朋友可以參考下2014-09-09昨晚我用python幫隔壁小姐姐P證件照然后發(fā)現(xiàn)
大家好,我是Lex 喜歡欺負(fù)超人那個(gè)Lex 建議大家收藏哦,以后幫小姐姐P自拍,證件照,調(diào)尺寸,背景,摳圖,直接10行代碼搞定,瞬間高大上2021-08-08一行代碼python實(shí)現(xiàn)文件共享服務(wù)器
這篇文章主要介紹了一行代碼python實(shí)現(xiàn)文件共享服務(wù)器,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04python實(shí)現(xiàn)xlwt xlrd 指定條件給excel行添加顏色
這篇文章主要介紹了python實(shí)現(xiàn)xlwt xlrd 指定條件給excel行添加顏色,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07Python 文件數(shù)據(jù)讀寫的具體實(shí)現(xiàn)
這篇文章主要介紹了Python 文件數(shù)據(jù)讀寫的具體實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01python3 http.client/server post傳輸json問題
這篇文章主要介紹了python3 http.client/server post傳輸json問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09Python多線程編程threading模塊使用最佳實(shí)踐及常見問題解析
這篇文章主要為大家介紹了Python多線程編程threading模塊使用最佳實(shí)踐及常見問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01python實(shí)現(xiàn)在IDLE中輸入多行的方法
下面小編就為大家分享一篇python實(shí)現(xiàn)在IDLE中輸入多行的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-04-04Python+OpenCV圖片局部區(qū)域像素值處理詳解
這篇文章主要為大家詳細(xì)介紹了Python+OpenCV圖片局部區(qū)域像素值處理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Python3實(shí)現(xiàn)并發(fā)檢驗(yàn)代理池地址的方法
這篇文章主要介紹了Python3實(shí)現(xiàn)并發(fā)檢驗(yàn)代理池地址的方法,實(shí)例分析了Python3基于線程的代理檢驗(yàn)操作相關(guān)技巧,需要的朋友可以參考下2016-09-09