Deep learning with Python 学习笔记(9)
神經(jīng)網(wǎng)絡模型的優(yōu)化
使用 Keras 回調(diào)函數(shù)
使用 model.fit()或 model.fit_generator() 在一個大型數(shù)據(jù)集上啟動數(shù)十輪的訓練,有點類似于扔一架紙飛機,一開始給它一點推力,之后你便再也無法控制其飛行軌跡或著陸點。如果想要避免不好的結(jié)果(并避免浪費紙飛機),更聰明的做法是不用紙飛機,而是用一架無人機,它可以感知其環(huán)境,將數(shù)據(jù)發(fā)回給操縱者,并且能夠基于當前狀態(tài)自主航行。下面要介紹的技術(shù),可以讓model.fit() 的調(diào)用從紙飛機變?yōu)橹悄艿淖灾鳠o人機,可以自我反省并動態(tài)地采取行動
訓練過程中將回調(diào)函數(shù)作用于模型
訓練模型時,很多事情一開始都無法預測。尤其是你不知道需要多少輪才能得到最佳驗證損失。前面所有例子都采用這樣一種策略:訓練足夠多的輪次,這時模型已經(jīng)開始過擬合,根據(jù)這第一次運行來確定訓練所需要的正確輪數(shù),然后使用這個最佳輪數(shù)從頭開始再啟動一次新的訓練。當然,這種方法很浪費
處理這個問題的更好方法是,當觀測到驗證損失不再改善時就停止訓練。這可以使用 Keras 回調(diào)函數(shù)來實現(xiàn)。回調(diào)函數(shù)(callback)是在調(diào)用 fit 時傳入模型的一個對象(即實現(xiàn)特定方法的類實例),它在訓練過程中的不同時間點都會被模型調(diào)用。它可以訪問關于模型狀態(tài)與性能的所有可用數(shù)據(jù),還可以采取行動:中斷訓練、保存模型、加載一組不同的權(quán)重或改變模型的狀態(tài)
回調(diào)函數(shù)的一些用法示例如下所示
keras.callbacks 模塊包含許多內(nèi)置的回調(diào)函數(shù),如
keras.callbacks.ModelCheckpoint
keras.callbacks.EarlyStopping
keras.callbacks.LearningRateScheduler
keras.callbacks.ReduceLROnPlateau
keras.callbacks.CSVLogger
等
ModelCheckpoint 與 EarlyStopping 回調(diào)函數(shù)
如果監(jiān)控的目標指標在設定的輪數(shù)內(nèi)不再改善,可以用 EarlyStopping 回調(diào)函數(shù)來中斷訓練。比如,這個回調(diào)函數(shù)可以在剛開始過擬合的時候就中斷訓練,從而避免用更少的輪次重新訓練模型。這個回調(diào)函數(shù)通常與ModelCheckpoint 結(jié)合使用,后者可以在訓練過程中持續(xù)不斷地保存模型(你也可以選擇只保存目前的最佳模型,即一輪結(jié)束后具有最佳性能的模型)
import keras# 通過 fit 的 callbacks 參數(shù)將回調(diào)函數(shù)傳入模型中,這個參數(shù)接收一個回調(diào)函數(shù)的列表。你可以傳入任意個數(shù)的回調(diào)函數(shù) # EarlyStopping: 1. 如果不再改善,就中斷訓練 2. 監(jiān)控模型的驗證精度 3. 如果精度在多于一輪的時間(即兩輪)內(nèi)不再改善,中斷訓練 # ModelCheckpoint: 1. 在每輪過后保存當前權(quán)重 2. 如果 val_loss 沒有改善,那么不需要覆蓋模型文件 callbacks_list = [ keras.callbacks.EarlyStopping(monitor='acc', patience=1, ),keras.callbacks.ModelCheckpoint( filepath='model.h5', monitor='val_loss', save_best_only=True,) ]# 監(jiān)控精度,所以" metrics=['acc'] "應該是模型指標的一部分 model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc']) # 由于回調(diào)函數(shù)要監(jiān)控驗證損失和驗證精度,所以在調(diào)用 fit 時需要傳入 validation_data(驗證數(shù)據(jù)) model.fit(x, y, epochs=10, batch_size=32, validation_data=(x_val, y_val), callbacks=callbacks_list)ReduceLROnPlateau 回調(diào)函數(shù)
如果驗證損失不再改善,你可以使用這個回調(diào)函數(shù)來降低學習率。在訓練過程中如果出現(xiàn)了損失平臺(loss plateau),那么增大或減小學習率都是跳出局部最小值的有效策略
自定義回調(diào)函數(shù)
回調(diào)函數(shù)的實現(xiàn)方式是創(chuàng)建 keras.callbacks.Callback 類的子類。然后你可以實現(xiàn)下面這些方法(從名稱中即可看出這些方法的作用),它們分別在訓練過程中的不同時間點被調(diào)用
這些方法被調(diào)用時都有一個 logs 參數(shù),這個參數(shù)是一個字典,里面包含前一個批量、前一個輪次或前一次訓練的信息,即訓練指標和驗證指標等。此外,回調(diào)函數(shù)還可以訪問下列屬性
自定義回調(diào)函數(shù)的簡單示例,它可以在每輪結(jié)束后將模型每層的激活保存到硬盤(格式為 Numpy 數(shù)組),這個激活是對驗證集的第一個樣本計算得到的
import keras import numpy as npclass ActivationLogger(keras.callbacks.Callback):def set_model(self, model):self.model = model layer_outputs = [layer.output for layer in model.layers]self.activations_model = keras.models.Model(model.input, layer_outputs) def on_epoch_end(self, epoch, logs=None):if self.validation_data is None:raise RuntimeError('Requires validation_data.')validation_sample = self.validation_data[0][0:1] activations = self.activations_model.predict(validation_sample)f = open('activations_at_epoch_' + str(epoch) + '.npz', 'w') np.savez(f, activations)f.close()TensorBoard 簡介:TensorFlow 的可視化框架
TensorBoard,一個內(nèi)置于 TensorFlow 中的基于瀏覽器的可視化工具。只有當 Keras 使用 TensorFlow 后端時,這一方法才能用于 Keras 模型
-- 等待嘗試
讓模型性能發(fā)揮到極致
高級架構(gòu)模式
除殘差連接外,標準化和深度可分離卷積在構(gòu)建高性能深度卷積神經(jīng)網(wǎng)絡時也特別重要
批標準化
標準化(normalization)是一大類方法,用于讓機器學習模型看到的不同樣本彼此之間更加相似,這有助于模型的學習與對新數(shù)據(jù)的泛化。最常見的數(shù)據(jù)標準化形式就是:將數(shù)據(jù)減去其平均值使其中心為 0,然后將數(shù)據(jù)除以其標準差使其標準差為 1。實際上,這種做法假設數(shù)據(jù)服從正態(tài)分布(也叫高斯分布),并確保讓該分布的中心為 0,同時縮放到方差為 1
normalized_data = (data - np.mean(data, axis=...)) / np.std(data, axis=...)前面的示例都是在將數(shù)據(jù)輸入模型之前對數(shù)據(jù)做標準化。但在網(wǎng)絡的每一次變換之后都應該考慮數(shù)據(jù)標準化。即使輸入 Dense 或 Conv2D 網(wǎng)絡的數(shù)據(jù)均值為 0、方差為 1,也沒有理由 假定網(wǎng)絡輸出的數(shù)據(jù)也是這樣
批標準化(batch normalization)是在 2015 年提出的一種層的類型(在Keras 中是 BatchNormalization),即使在訓練過程中均值和方差隨時間發(fā)生變化,它也可以適應性地將數(shù)據(jù)標準化。批標準化的工作原理是,訓練過程中在內(nèi)部保存已讀取每批數(shù)據(jù)均值和方差的指數(shù)移動平均值。批標準化的主要效果是,它有助于梯度傳播(這一點和殘差連接很像),因此允許更深的網(wǎng)絡。對于有些特別深的網(wǎng)絡,只有包含多個 BatchNormalization 層時才能進行訓練
BatchNormalization 層通常在卷積層或密集連接層之后使用
conv_model.add(layers.Conv2D(32, 3, activation='relu')) conv_model.add(layers.BatchNormalization())dense_model.add(layers.Dense(32, activation='relu')) dense_model.add(layers.BatchNormalization())BatchNormalization 層接收一個 axis 參數(shù),它指定應該對哪個特征軸做標準化。這個參數(shù)的默認值是 -1,即輸入張量的最后一個軸。對于 Dense 層、Conv1D 層、RNN 層和將data_format 設為 "channels_last"(通道在后)的 Conv2D 層,這個默認值都是正確的。但有少數(shù)人使用將 data_format 設為 "channels_first"(通道在前)的 Conv2D 層,這時特征軸是編號為 1 的軸,因此 BatchNormalization 的 axis 參數(shù)應該相應地設為 1
深度可分離卷積
深度可分離卷積(depthwise separable convolution)層(SeparableConv2D)可以替代 Conv2D,并可以讓模型更加輕量(即更少的可訓練權(quán)重參數(shù))、速度更快(即更少的浮點數(shù)運算),還可以讓任務性能提高幾個百分點。這個層對輸入的每個通道分別執(zhí)行空間卷積,然后通過逐點卷積(1×1 卷積)將輸出通道混合
如圖示
這相當于將空間特征學習和通道特征學習分開,如果你假設輸入中的空間位置高度相關,但不同的通道之間相對獨立,那么這么做是很有意義的。它需要的參數(shù)要少很多,計算量也更小,因此可以得到更小、更快的模型。因為它是一種執(zhí)行卷積更高效的方法,所以往往能夠使用更少的數(shù)據(jù)學到更好的表示,從而得到性能更好的模型
demo
from keras.models import Sequential, Model from keras import layersheight = 64 width = 64 channels = 3 num_classes = 10 model = Sequential() model.add(layers.SeparableConv2D(32, 3, activation='relu', input_shape=(height, width, channels,))) model.add(layers.SeparableConv2D(64, 3, activation='relu')) model.add(layers.MaxPooling2D(2)) model.add(layers.SeparableConv2D(64, 3, activation='relu')) model.add(layers.SeparableConv2D(128, 3, activation='relu')) model.add(layers.MaxPooling2D(2)) model.add(layers.SeparableConv2D(64, 3, activation='relu')) model.add(layers.SeparableConv2D(128, 3, activation='relu')) model.add(layers.GlobalAveragePooling2D()) model.add(layers.Dense(32, activation='relu')) model.add(layers.Dense(num_classes, activation='softmax')) model.compile(optimizer='rmsprop', loss='categorical_crossentropy')超參數(shù)優(yōu)化
構(gòu)建深度學習模型時,你必須做出許多看似隨意的決定:應該堆疊多少層?每層應該包含多少個單元或過濾器?激活應該使用 relu 還是其他函數(shù)?在某一層之后是否應該使用BatchNormalization ?應該使用多大的 dropout 比率?還有很多。這些在架構(gòu)層面的參數(shù)叫作超參數(shù)(hyperparameter),以便將其與模型參數(shù)區(qū)分開來,后者通過反向傳播進行訓練
超參數(shù)優(yōu)化的過程通常如下所示:
這個過程的關鍵在于,給定許多組超參數(shù),使用驗證性能的歷史來選擇下一組需要評估的超參數(shù)的算法。有多種不同的技術(shù)可供選擇:貝葉斯優(yōu)化、遺傳算法、簡單隨機搜索等
更新超參數(shù)非常具有挑戰(zhàn)性,如
通常情況下,隨機搜索(隨機選擇需要評估的超參數(shù),并重復這一過程)就是最好的解決方案,雖然這也是最簡單的解決方案。也存在一些工具比隨機搜索要好很多,如:Hyperopt。它是一個用于超參數(shù)優(yōu)化的 Python 庫,其內(nèi)部使用 Parzen 估計器的樹來預測哪組超參數(shù)可能會得到好的結(jié)果。另一個叫作 Hyperas 的庫將 Hyperopt 與 Keras 模型集成在一起
模型集成
集成是指將一系列不同模型的預測結(jié)果匯集到一起,從而得到更好的預測結(jié)果。集成依賴于這樣的假設,即對于獨立訓練的不同良好模型,它們表現(xiàn)良好可能是因為不同的原因:每個模型都從略有不同的角度觀察數(shù)據(jù)來做出預測,得到了“真相”的一部分,但不是全部真相。每個模型都得到了數(shù)據(jù)真相的一部分,但不是全部真相。將他們的觀點匯集在一起,你可以得到對數(shù)據(jù)更加準確的描述
集成最簡單的方法就是就不同模型的結(jié)果進行平均,以平均值作為預測的結(jié)果。但是這種方法假設了所使用的分類器的性能都差不多好。如果其中一個模型性能比其他的差很多,那么最終預測結(jié)果可能不如這一組中的最佳模型好
而更加適用的方法是對各個模型的結(jié)果進行加權(quán)平均,其權(quán)重從驗證數(shù)據(jù)上學習得到。通常來說,更好的模型被賦予更大的權(quán)重,而較差的模型則被賦予較小的權(quán)重。為了找到一組好的集成權(quán)重,你可以使用隨機搜索或簡單的優(yōu)化算法(比如 Nelder-Mead 方法)
還有許多其他變體,比如你可以對預測結(jié)果先取指數(shù)再做平均。一般來說,簡單的加權(quán)平均,其權(quán)重在驗證數(shù)據(jù)上進行最優(yōu)化,這是一個很強大的基準方法。想要保證集成方法有效,關鍵在于這組分類器的多樣性(diversity)。多樣性能夠讓集成方法取得良好效果。用機器學習的術(shù)語來說,如果所有模型的偏差都在同一個方向上,那么集成也會保留同樣的偏差。如果各個模型的偏差在不同方向上,那么這些偏差會彼此抵消,集成結(jié)果會更加穩(wěn)定、更加準確
因此,集成的模型應該盡可能好,同時盡可能不同。這通常意味著使用非常不同的架構(gòu),甚至使用不同類型的機器學習方法。有一件事情基本上是不值得做的,就是對相同的網(wǎng)絡,使用不同的隨機初始化多次獨立訓練,然后集成。如果模型之間的唯一區(qū)別是隨機初始化和訓練數(shù)據(jù)的讀取順序,那么集成的多樣性很小,與單一模型相比只會有微小的改進。集成不在于你的最佳模型有多好,而在于候選模型集合的多樣性
注
在進行大規(guī)模超參數(shù)自動優(yōu)化時,有一個重要的問題需要牢記,那就是驗證集過擬合。因為你是使用驗證數(shù)據(jù)計算出一個信號,然后根據(jù)這個信號更新超參數(shù),所以你實際上是在驗證數(shù)據(jù)上訓練超參數(shù),很快會對驗證數(shù)據(jù)過擬合Deep learning with Python 學習筆記(10)
Deep learning with Python 學習筆記(8)
轉(zhuǎn)載于:https://www.cnblogs.com/zhhfan/p/10304763.html
總結(jié)
以上是生活随笔為你收集整理的Deep learning with Python 学习笔记(9)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 消防工程师 10.2 火灾自动报警系统-
- 下一篇: 灰度图的width和widthstep的