# 六、超參數優化
使用深度神經網絡的最大缺點之一是它們具有許多應優化的超參數,以使網絡發揮最佳表現。 在前面的每個章節中,我們都遇到但沒有涵蓋超參數估計的挑戰。 超參數優化是一個非常重要的話題。 在大多數情況下,這是一個未解決的問題,盡管我們不能涵蓋本書的全部主題,但我認為它仍然值得一章。
在本章中,我將為您提供一些我認為是選擇超參數的實用建議。 可以肯定的是,由于本章是基于我自己的經驗,因此本章可能會有些偏頗和偏頗。 我希望經驗會有所幫助,同時也帶您進一步對該主題進行調查。
我們將在本章介紹以下主題:
* 是否應該將網絡架構視為超參數?
* 我們應該優化哪些超參數?
* 超參數優化策略
# 是否應該將網絡架構視為超參數?
在構建最簡單的網絡時,我們必須對網絡架構做出各種選擇。 我們應該使用 1 個隱藏層還是 1,000 個? 每層應包含多少個神經元? 他們都應該使用`relu`激活函數還是`tanh`? 我們應該在每個隱藏層上還是僅在第一層上使用丟棄? 在設計網絡架構時,我們必須做出許多選擇。
在最典型的情況下,我們窮舉搜索每個超參數的最佳值。 但是,要窮舉搜索網絡架構并不容易。 實際上,我們可能沒有時間或計算能力。 我們很少看到研究人員通過窮舉搜索來尋找最佳架構,因為選擇的數量非常多,而且存在不只一個正確的答案。 取而代之的是,我們看到該領域的研究人員通過實驗嘗試建立已知的架構,以嘗試創建新的新穎架構并改善現有架構。
因此,在介紹詳盡搜索超參數的策略之前,讓我們看一下兩種推論出合理的,甚至不是最佳的網絡架構的策略。
# 找到一個巨人然后站在他的肩膀上
沙特爾的伯納德(Bernard of Chartres)被賦予了通過借鑒他人的發現來學習的概念。 但是,正是艾薩克·牛頓(Isaac Newton)說:“如果我進一步觀察,那就是站在巨人的肩膀上。” 要明確的是,這正是我在這里建議的。
如果我要設計一個用于新的深度學習問題的網絡架構,我要做的第一件事就是嘗試找到一個令人滿意的方式,以前已經解決了類似的問題。 盡管可能沒有人能夠解決您面臨的任務,但可能存在類似的情況。
很可能存在幾種可能的解決方案。 如果是這樣,并且在時間允許的情況下,每次運行幾次的平均結果可能會告訴您哪個運行效果最好。 當然,在這里我們發現自己很快進入了研究領域。
# 添加,直到過擬合,然后進行正則化
希望通過尋找類似問題的架構,您至少接近適合您的架構。 您如何做才能進一步優化網絡架構?
* 在多個實驗運行中,添加層和/或神經元,直到您的網絡開始針對問題過擬合。 在深度學習中,添加單元,直到您不再具有高偏差模型為止。
* 一旦開始過擬合,您就會發現一些網絡架構能夠很好地擬合訓練數據,甚至可能擬合得很好。 在這一點上,您應該集中精力通過使用丟棄,正則化,提早停止等方法來減少方差。
這種方法通常歸因于著名的神經網絡研究員 Geoffrey Hinton。 這是一個有趣的想法,因為它使過擬合不是要避免的事情,而是構建網絡架構的良好第一步。
盡管沒有規則可供我們選擇最佳網絡架構,并且可能存在許多最佳架構,但我發現這種策略在實踐中對我來說非常有效。
# 實用建議
如果您對上述內容不太了解,我同意。 這對我也不是,我也不希望那樣。 您當然可以在一組預定義的配置之間搜索最佳的網絡架構,這也是正確的方法。 實際上,它可以說是更正確,更嚴格。 此過程旨在為您提供實用的建議,以幫助您在盡可能短的時間內達到最佳狀態。
# 我們應該優化哪些超參數?
即使您遵循我的建議并選擇了一個足夠好的架構,您也可以并且仍然應該嘗試在該架構中搜索理想的超參數。 我們可能要搜索的一些超參數包括:
* 我們選擇的優化器。 到目前為止,我一直在使用 Adam,但是 rmsprop 優化器或調整良好的 SGD 可能會更好。
* 每個優化器都有一組我們可能需要調整的超參數,例如學習率,動量和衰減。
* 網絡權重初始化。
* 神經元激活。
* 正則化參數(例如丟棄概率)或 12 正則化中使用的正則化參數。
* 批次大小。
如上所述,這不是詳盡的清單。 當然,您可以嘗試更多的選擇,包括在每個隱藏層中引入可變數量的神經元,每層中丟棄概率的變化等等。 就像我們一直暗示的那樣,超參數的可能組合是無限的。 這些選擇也很可能并非獨立于網絡架構,添加和刪除層可能會為這些超參數中的任何一個帶來新的最佳選擇。
# 超參數優化策略
在本章的這一點上,我們建議,在大多數情況下,嘗試我們可能想嘗試的每個超參數組合在計算上都是不可能的,或者至少是不切實際的。 深度神經網絡肯定會花費很長時間進行訓練。 盡管您可以并行處理問題并投入計算資源,但搜索超參數的最大限制可能仍然是時間。
如果時間是我們最大的限制,并且我們無法合理地探索擁有的所有可能性,那么我們將必須制定一種策略,使我們在擁有的時間內獲得最大的效用。
在本節的其余部分,我將介紹一些用于超參數優化的常用策略,然后向您展示如何使用我最喜歡的兩種方法在 Keras 中優化超參數。
# 通用策略
在所有機器學習模型中都有一套通用的超參數優化策略。 從總體上講,這些策略包括:
* 網格搜索
* 隨機搜索
* 貝葉斯優化
* 遺傳算法
* 機器學習的超參數
**網格搜索**只是嘗試嘗試所有事物,或者至少嘗試離散事物,然后報告我們用蠻力找到的最佳超參數的最佳組合。 可以保證在我們確定的參數空間中找到最佳解決方案,以及其他較差的解決方案。
網格搜索對于深度學習并不是很實用。 除了最基本的深度神經網絡,我們無法現實地探索所有可能參數的每個可能值。 使用**隨機搜索**,我們從每個參數分布中隨機抽樣,并嘗試其中的`n`,其中(`n x`每個示例訓練時間)是我們愿意分配給這個問題的時間預算。
**貝葉斯優化**方法使用以前的觀察結果來預測接下來要采樣的超參數集。 盡管貝葉斯優化方法通常勝過蠻力技術,但目前的研究表明,與窮舉方法相比,表現提升較小。 此外,由于貝葉斯方法取決于先前的經驗,因此無論如何都不會令人尷尬地并行進行。
**遺傳算法**是機器學習中非常有趣且活躍的研究領域。 但是,我目前的觀點是,它們也不是深度神經網絡參數優化的理想選擇,因為它們再次依賴于先前的經驗。
該領域中的一些最新研究著眼于訓練神經網絡,該神經網絡可以預測給定網絡架構的最佳參數。 可以參數化模型的模型的想法當然非常有趣,這是一個值得密切關注的地方。 這也可能是我們獲得天網的方式。 只有時間證明一切。
# 在 scikit-learn 中使用隨機搜索
使用 scikit-learn 可以輕松實現網格搜索和隨機搜索。 在此示例中,我們將使用 Keras 的`KerasClassifier`類包裝模型并使其與 scikit-learn API 兼容。 然后,我們將使用 scikit-learn 的`RandomSearchCV`類進行超參數搜索。
為此,我們將從稍微更改現在熟悉的模型構建函數開始。 我們將使用我們要搜索的超參數對其進行參數化,如以下代碼所示:
```py
def build_network(keep_prob=0.5, optimizer='adam'):
inputs = Input(shape=(784,), name="input")
x = Dense(512, activation='relu', name="hidden1")(inputs)
x = Dropout(keep_prob)(x)
x = Dense(256, activation='relu', name="hidden2")(x)
x = Dropout(keep_prob)(x)
x = Dense(128, activation='relu', name="hidden3")(x)
x = Dropout(keep_prob)(x)
prediction = Dense(10, activation='softmax', name="output")(x)
model = Model(inputs=inputs, outputs=prediction)
model.compile(optimizer=optimizer, loss='categorical_crossentropy',
metrics=["accuracy"])
return model
```
在此示例中,我想搜索一個理想的丟棄值,并且我想嘗試幾個不同的優化器。 為了實現這一點,我需要將它們作為參數包含在函數中,以便可以通過我們的隨機搜索方法對其進行更改。 當然,我們可以使用相同的方法來參數化和測試許多其他網絡架構選擇,但是我們在這里保持簡單。
接下來,我們將創建一個函數,該函數返回一個字典,其中包含我們想搜索的所有可能的超參數及其值空間,如以下代碼所示:
```py
def create_hyperparameters():
batches = [10, 20, 30, 40, 50]
optimizers = ['rmsprop', 'adam', 'adadelta']
dropout = np.linspace(0.1, 0.5, 5)
return {"batch_size": batches, "optimizer": optimizers,
"keep_prob": dropout}
```
剩下的就是使用`RandomSearchCV`將這兩部分連接在一起。 首先,我們將模型包裝到`keras.wrappers.scikit_learn.KerasClassifier`中,以便與 scikit-learn 兼容,如以下代碼所示:
```py
model = KerasClassifier(build_fn=build_network, verbose=0)
```
接下來,我們將使用以下代碼獲得超參數字典:
```py
hyperparameters = create_hyperparameters()
```
然后,最后,我們將創建一個`RandomSearchCV`對象,該對象將用于搜索模型的參數空間,如以下代碼所示:
```py
search = RandomizedSearchCV(estimator=model, param_distributions=hyperparameters, n_iter=10, n_jobs=1, cv=3, verbose=1)
```
擬合此`RandomizedSearchCV`對象后,它將從參數分布中隨機選擇值并將其應用于模型。 它將執行 10 次(`n_iter=10`),并且將嘗試每種組合 3 次,因為我們使用了 3 倍交叉驗證。 這意味著我們將總共擬合模型 30 次。 使用每次運行的平均準確率,它將返回最佳模型作為類屬性`.best_estimator`,并且將返回最佳參數作為`.best_params_`。
為了適合它,我們只需調用它的`fit`方法,就好像它是一個模型一樣,如以下代碼所示:
```py
search.fit(data["train_X"], data["train_y"])
print(search.best_params_)
```
在 Tesla K80 GPU 實例上,在上述網格上擬合第 5 章,“使用 Keras 進行多分類”所使用的 MNIST 模型。 在完成本節之前,讓我們看一下搜索的一些輸出,如以下代碼所示:
```py
Using TensorFlow backend.
Fitting 3 folds for each of 10 candidates, totalling 30 fits
tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties:
name: Tesla K80 major: 3 minor: 7 memoryClockRate(GHz): 0.8235
pciBusID: 0000:00:1e.0
totalMemory: 11.17GiB freeMemory: 11.10GiB
tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0, compute capability: 3.7)
[Parallel(n_jobs=1)]: Done 30 out of 30 | elapsed: 8.8min finished
{'keep_prob': 0.20000000000000001, 'batch_size': 40, 'optimizer': 'adam'}
```
如您在此輸出中看到的,在 10 次運行中,加粗的超參數似乎是表現最好的集合。 當然,我們當然可以運行更多的迭代,并且我們可能會找到一個更好的選擇。 我們的預算僅由時間,耐心以及云帳戶附帶的信用卡決定。
# Hyperband
Hyperband 是一項超參數優化技術,由 Lisha Li,Kevin Jamieson,Guilia DeSalvo,Afshin Rostamizadeh 和 Ameet Talwalker 于 2016 年在伯克利開發。 您可以在[這里](https://arxiv.org/pdf/1603.06560.pdf)閱讀他們的原始論文。
想象一下,就像我們在`RandomSearchCV`中所做的那樣,隨機采樣許多潛在的超參數集。 完成`RandomSearchCV`后,它將選擇一個單一的超參數配置作為其采樣的*最優值*。 Hyperband 利用這樣的思想,即即使經過少量迭代,最佳的超參數配置也可能會勝過其他配置。 Hyperband 中的樂隊來自土匪,指的是基于多臂土匪技術(用于優化競爭選擇之間的資源分配以優化表現為目標的技術)的勘探與開發。
使用 Hyperband,我們可以嘗試一些可能的配置集(`n`),僅訓練一次迭代。 作者將迭代一詞留作多種可能的用途。 但是,我將周期作為迭代。 一旦完成第一個訓練循環,就將根據表現對結果進行配置。 然后,對該列表的上半部分進行大量迭代的訓練。 然后重復進行減半和剔除的過程,我們得到了一些非常小的配置集,我們將針對在搜索中定義的完整迭代次數進行訓練。 與在每種可能的配置中搜索最大周期相比,此過程使我們在更短的時間內獲得了*最佳*超參數集。
在本章的 GitHub 存儲庫中,我在`hyperband.py`中包括了`hyperband`算法的實現。 此實現主要源自 FastML 的實現,您可以在[這個頁面](http://fastml.com/tuning-hyperparams-fast-with-hyperband/)中找到。 要使用它,您需要首先實例化一個`hyperband`對象,如以下代碼所示:
```py
from hyperband import Hyperband
hb = Hyperband(data, get_params, try_params)
```
Hyperband 構造器需要三個參數:
* `data`:到目前為止,我在示例中一直在使用的數據字典
* `get_params`:用于從我們正在搜索的超參數空間中采樣的函數的名稱
* `try_param`:可用于評估`n_iter`迭代的超參數配置并返回損失的函數的名稱
在下面的示例中,我實現了`get_params`以在參數空間中以統一的方式進行采樣:
```py
def get_params():
batches = np.random.choice([5, 10, 100])
optimizers = np.random.choice(['rmsprop', 'adam', 'adadelta'])
dropout = np.random.choice(np.linspace(0.1, 0.5, 10))
return {"batch_size": batches, "optimizer": optimizers,
"keep_prob": dropout}
```
如您所見,所選的超參數配置將作為字典返回。
接下來,可以實現`try_params`以在超參數配置上針對指定的迭代次數擬合模型,如下所示:
```py
def try_params(data, num_iters, hyperparameters):
model = build_network(keep_prob=hyperparameters["keep_prob"],
optimizer=hyperparameters["optimizer"])
model.fit(x=data["train_X"], y=data["train_y"],
batch_size=hyperparameters["batch_size"],
epochs=int(num_iters))
loss = model.evaluate(x=data["val_X"], y=data["val_y"], verbose=0)
return {"loss": loss}
```
`try_params`函數返回一個字典,可用于跟蹤任何數量的度量; 但是,由于它用于比較運行,因此需要損失。
通過在對象上調用`.run()`方法,`hyperband`對象將通過我們上面描述的算法運行。
```py
results = hb.run()
```
在這種情況下,`results`將是每次運行,其運行時間和測試的超參數的字典。 因為即使這種高度優化的搜索都需要花費大量時間,并且 GPU 時間也很昂貴,所以我將 MNIST 搜索的結果包括在本章的 GitHub 存儲庫的`hyperband-output-mnist.txt`中,[可以在以下位置找到](https://github.com/mbernico/deep_learning_quick_reference/tree/master/chapter_6)。
# 總結
超參數優化是從我們的深度神經網絡獲得最佳效果的重要一步。 尋找搜索超參數的最佳方法是機器學習研究的一個開放而活躍的領域。 盡管您當然可以將最新技術應用于自己的深度學習問題,但您需要在決策中權衡實現的復雜性和搜索運行時間。
有一些與網絡架構有關的決策可以肯定地進行詳盡地搜索,但是,如我上面提供的那樣,一組啟發式方法和最佳實踐可能使您足夠接近甚至減少搜索參數的數量。
最終,超參數搜索是一個經濟問題,任何超參數搜索的第一部分都應考慮您的計算時間和個人時間預算,以試圖找出最佳的超參數配置。
本章總結了深度學習的基礎。 在下一章中,我們將從計算機視覺入手,介紹神經網絡的一些更有趣和更高級的應用。
- TensorFlow 1.x 深度學習秘籍
- 零、前言
- 一、TensorFlow 簡介
- 二、回歸
- 三、神經網絡:感知器
- 四、卷積神經網絡
- 五、高級卷積神經網絡
- 六、循環神經網絡
- 七、無監督學習
- 八、自編碼器
- 九、強化學習
- 十、移動計算
- 十一、生成模型和 CapsNet
- 十二、分布式 TensorFlow 和云深度學習
- 十三、AutoML 和學習如何學習(元學習)
- 十四、TensorFlow 處理單元
- 使用 TensorFlow 構建機器學習項目中文版
- 一、探索和轉換數據
- 二、聚類
- 三、線性回歸
- 四、邏輯回歸
- 五、簡單的前饋神經網絡
- 六、卷積神經網絡
- 七、循環神經網絡和 LSTM
- 八、深度神經網絡
- 九、大規模運行模型 -- GPU 和服務
- 十、庫安裝和其他提示
- TensorFlow 深度學習中文第二版
- 一、人工神經網絡
- 二、TensorFlow v1.6 的新功能是什么?
- 三、實現前饋神經網絡
- 四、CNN 實戰
- 五、使用 TensorFlow 實現自編碼器
- 六、RNN 和梯度消失或爆炸問題
- 七、TensorFlow GPU 配置
- 八、TFLearn
- 九、使用協同過濾的電影推薦
- 十、OpenAI Gym
- TensorFlow 深度學習實戰指南中文版
- 一、入門
- 二、深度神經網絡
- 三、卷積神經網絡
- 四、循環神經網絡介紹
- 五、總結
- 精通 TensorFlow 1.x
- 一、TensorFlow 101
- 二、TensorFlow 的高級庫
- 三、Keras 101
- 四、TensorFlow 中的經典機器學習
- 五、TensorFlow 和 Keras 中的神經網絡和 MLP
- 六、TensorFlow 和 Keras 中的 RNN
- 七、TensorFlow 和 Keras 中的用于時間序列數據的 RNN
- 八、TensorFlow 和 Keras 中的用于文本數據的 RNN
- 九、TensorFlow 和 Keras 中的 CNN
- 十、TensorFlow 和 Keras 中的自編碼器
- 十一、TF 服務:生產中的 TensorFlow 模型
- 十二、遷移學習和預訓練模型
- 十三、深度強化學習
- 十四、生成對抗網絡
- 十五、TensorFlow 集群的分布式模型
- 十六、移動和嵌入式平臺上的 TensorFlow 模型
- 十七、R 中的 TensorFlow 和 Keras
- 十八、調試 TensorFlow 模型
- 十九、張量處理單元
- TensorFlow 機器學習秘籍中文第二版
- 一、TensorFlow 入門
- 二、TensorFlow 的方式
- 三、線性回歸
- 四、支持向量機
- 五、最近鄰方法
- 六、神經網絡
- 七、自然語言處理
- 八、卷積神經網絡
- 九、循環神經網絡
- 十、將 TensorFlow 投入生產
- 十一、更多 TensorFlow
- 與 TensorFlow 的初次接觸
- 前言
- 1.?TensorFlow 基礎知識
- 2. TensorFlow 中的線性回歸
- 3. TensorFlow 中的聚類
- 4. TensorFlow 中的單層神經網絡
- 5. TensorFlow 中的多層神經網絡
- 6. 并行
- 后記
- TensorFlow 學習指南
- 一、基礎
- 二、線性模型
- 三、學習
- 四、分布式
- TensorFlow Rager 教程
- 一、如何使用 TensorFlow Eager 構建簡單的神經網絡
- 二、在 Eager 模式中使用指標
- 三、如何保存和恢復訓練模型
- 四、文本序列到 TFRecords
- 五、如何將原始圖片數據轉換為 TFRecords
- 六、如何使用 TensorFlow Eager 從 TFRecords 批量讀取數據
- 七、使用 TensorFlow Eager 構建用于情感識別的卷積神經網絡(CNN)
- 八、用于 TensorFlow Eager 序列分類的動態循壞神經網絡
- 九、用于 TensorFlow Eager 時間序列回歸的遞歸神經網絡
- TensorFlow 高效編程
- 圖嵌入綜述:問題,技術與應用
- 一、引言
- 三、圖嵌入的問題設定
- 四、圖嵌入技術
- 基于邊重構的優化問題
- 應用
- 基于深度學習的推薦系統:綜述和新視角
- 引言
- 基于深度學習的推薦:最先進的技術
- 基于卷積神經網絡的推薦
- 關于卷積神經網絡我們理解了什么
- 第1章概論
- 第2章多層網絡
- 2.1.4生成對抗網絡
- 2.2.1最近ConvNets演變中的關鍵架構
- 2.2.2走向ConvNet不變性
- 2.3時空卷積網絡
- 第3章了解ConvNets構建塊
- 3.2整改
- 3.3規范化
- 3.4匯集
- 第四章現狀
- 4.2打開問題
- 參考
- 機器學習超級復習筆記
- Python 遷移學習實用指南
- 零、前言
- 一、機器學習基礎
- 二、深度學習基礎
- 三、了解深度學習架構
- 四、遷移學習基礎
- 五、釋放遷移學習的力量
- 六、圖像識別與分類
- 七、文本文件分類
- 八、音頻事件識別與分類
- 九、DeepDream
- 十、自動圖像字幕生成器
- 十一、圖像著色
- 面向計算機視覺的深度學習
- 零、前言
- 一、入門
- 二、圖像分類
- 三、圖像檢索
- 四、對象檢測
- 五、語義分割
- 六、相似性學習
- 七、圖像字幕
- 八、生成模型
- 九、視頻分類
- 十、部署
- 深度學習快速參考
- 零、前言
- 一、深度學習的基礎
- 二、使用深度學習解決回歸問題
- 三、使用 TensorBoard 監控網絡訓練
- 四、使用深度學習解決二分類問題
- 五、使用 Keras 解決多分類問題
- 六、超參數優化
- 七、從頭開始訓練 CNN
- 八、將預訓練的 CNN 用于遷移學習
- 九、從頭開始訓練 RNN
- 十、使用詞嵌入從頭開始訓練 LSTM
- 十一、訓練 Seq2Seq 模型
- 十二、深度強化學習
- 十三、生成對抗網絡
- TensorFlow 2.0 快速入門指南
- 零、前言
- 第 1 部分:TensorFlow 2.00 Alpha 簡介
- 一、TensorFlow 2 簡介
- 二、Keras:TensorFlow 2 的高級 API
- 三、TensorFlow 2 和 ANN 技術
- 第 2 部分:TensorFlow 2.00 Alpha 中的監督和無監督學習
- 四、TensorFlow 2 和監督機器學習
- 五、TensorFlow 2 和無監督學習
- 第 3 部分:TensorFlow 2.00 Alpha 的神經網絡應用
- 六、使用 TensorFlow 2 識別圖像
- 七、TensorFlow 2 和神經風格遷移
- 八、TensorFlow 2 和循環神經網絡
- 九、TensorFlow 估計器和 TensorFlow HUB
- 十、從 tf1.12 轉換為 tf2
- TensorFlow 入門
- 零、前言
- 一、TensorFlow 基本概念
- 二、TensorFlow 數學運算
- 三、機器學習入門
- 四、神經網絡簡介
- 五、深度學習
- 六、TensorFlow GPU 編程和服務
- TensorFlow 卷積神經網絡實用指南
- 零、前言
- 一、TensorFlow 的設置和介紹
- 二、深度學習和卷積神經網絡
- 三、TensorFlow 中的圖像分類
- 四、目標檢測與分割
- 五、VGG,Inception,ResNet 和 MobileNets
- 六、自編碼器,變分自編碼器和生成對抗網絡
- 七、遷移學習
- 八、機器學習最佳實踐和故障排除
- 九、大規模訓練
- 十、參考文獻