摘要: 在本文中,咱們將討論爲深度學習模型搜索最佳超參數集合的動機和策略,並演示如何在FloydHub上來完成任務。學習本文以後,這將會在深度學習工做中爲你自動化尋找最佳配置的過程。
與機器學習模型不一樣,深度學習模型裏面充滿了各類超參數。並且,並不是全部參數都能對模型的學習過程產生一樣的貢獻。考慮到這種額外的複雜性,在一個多維空間中找到合適的參數變量成爲了挑戰。幸運的是,咱們有不一樣的策略和工具能夠解決搜索問題。python
每一位研究人員都但願在現有的資源條件下,找到最佳的模型。一般狀況下,他們會在開發的最後階段嘗試一種搜索策略,這可能會有助於改進他們辛辛苦訓練出來的模型。算法
此外,在半自動/全自動深度學習過程當中,超參數搜索也是的一個很是重要的階段。網絡
超參數究竟是什麼?框架
讓咱們從最簡單的定義開始,超參數是在構建機器/深度學習模型時能夠轉動的旋鈕。或者這樣解釋,超參數是開始訓練以前,用預先肯定的值來手動設置的全部訓練變量。dom
咱們應該都會承認Learning Rate和Dropout Rate是超參數。可是模型設計的變量呢?這些變量包括嵌入值、網絡層數、激活函數等等,咱們應該把這些變量視爲超參數嗎?curl
模型設計變量+超參數→模型參數機器學習
那麼,從訓練過程當中得到的參數,以及從數據中得到的變量應該如何考慮呢?這被稱爲模型參數,咱們將把它們排除在超參數集以外。函數
請看下圖,舉例說明在深度學習模型中變量的分類。工具
變量分類實例佈局
下一個問題: 搜索代價巨大
尋找超參數的最佳配置,面臨的挑戰是尋找超參數是一個消耗巨大的工做。
超參數搜索週期
咱們從配置的猜想開始,須要等到一個完整的訓練結束,來得到對相關指標的實際評估,以後是跟蹤搜索過程的進度,最後根據搜索策略,選擇新的猜想。
策略討論
咱們有四種主要的策略用於尋找最佳配置。
Babysitting
在研究領域,Babysitting也被稱爲「試錯法」。100%手工操做,被你們普遍採用。
流程很是簡單:好比學生設計了一個實驗後,遵循學習過程的全部步驟(從數據收集到特徵圖映射的可視化),而後在超參數上依次迭代直到時間終止。
若是你學習過deeplearning.ai的課程,那麼你確定對吳恩達教授的熊貓工做流程很熟悉。
這種方法很是有教育意義。可是,在一個團隊或者一個公司裏,這種方法並不適用,由於數據科學家的時間是很是寶貴的。
這就給咱們提出了一個問題:「有沒有更好的方法來利用咱們的時間?」
固然有,咱們能夠經過定義超參數搜索的自動策略來優化時間!
網格搜索
網格搜索,是一種簡單嘗試全部可能配置的方法。
它的工做流程是這樣的:
下圖說明了一個簡單的二維網格搜索的Dropout Rate和Learning Rate。
並行執行兩個變量的網格搜索
這種策略沒有考慮到計算背景,但這意味着可用的計算資源越多,那麼同時能夠嘗試的猜想就會越多。它的痛點被稱爲維度災難,意思是咱們增長的維度越多,搜索就會變得越困難,最終致使策略失敗。
當維度小於或等於4時,經常使用這種方法。可是在實踐中,即便保證最後找到最佳配置,它仍然不可取,而是應該使用隨機搜索。
你可使用FloydHub的Workspace在配置完整的雲主機上運行下面的代碼(使用Scikit-learn和Keras進行網格搜索):
# Load the dataset x, y = load_dataset() # Create model for KerasClassifier defcreate_model(hparams1=dvalue, hparams2=dvalue, ... hparamsn=dvalue): # Model definition ... model = KerasClassifier(build_fn=create_model) # Define the range hparams1 = [2, 4, ...] hparams2 = ['elu', 'relu', ...] ... hparamsn = [1, 2, 3, 4, ...] # Prepare the Grid param_grid = dict(hparams1=hparams1, hparams2=hparams2, ... hparamsn=hparamsn) # GridSearch in action grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=, cv=, verbose=) grid_result = grid.fit(x, y) # Show the results print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_)) means = grid_result.cv_results_['mean_test_score'] stds = grid_result.cv_results_['std_test_score'] params = grid_result.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
隨機搜索
幾年前,Bergstra和Bengio發表了一篇論文,論證了網格搜索的效率低下。
網格搜索和隨機搜索之間惟一的區別在於策略週期的第一步:隨機搜索在配置空間上隨機選擇點。
請看下圖:
網格搜索vs隨機搜索
經過在兩個超參數空間上搜索最佳配置來對比這兩種方法,並假定一個參數比另外一個參數更重要。深度學習模型,如前面所說,實際上包含許多超參數,一般研究者知道哪些對訓練影響最大。
在網格搜索中,即便咱們已經訓練了9個模型,但給每一個變量只使用了3個值,然而,在隨機搜索中,屢次選擇相同變量的可能性微乎其微。若是用第二種方法,那麼就會給每一個變量使用9個不一樣的值來訓練9個模型。
上圖中,從每一個佈局頂部的空間搜索能夠看出,使用隨機搜索更普遍地研究了超參數空間,這將幫助咱們在較少的迭代中找到最佳配置。
總之,若是搜索空間包含3到4個維度,則不要使用網格搜索。相反,使用隨機搜索,則會爲每一個搜索任務提供了一個很是好的基線。
網格搜索與隨機搜索的利弊
你可使FloydHub的Workspace在配置完整的雲主機上運行下面的代碼:
# Load the dataset X, Y = load_dataset() # Create model for KerasClassifier defcreate_model(hparams1=dvalue, hparams2=dvalue, ... hparamsn=dvalue): # Model definition ... model = KerasClassifier(build_fn=create_model) # Specify parameters and distributions to sample from hparams1 = randint(1, 100) hparams2 = ['elu', 'relu', ...] ... hparamsn = uniform(0, 1) # Prepare the Dict for the Search param_dist = dict(hparams1=hparams1, hparams2=hparams2, ... hparamsn=hparamsn) # Search in action! n_iter_search = 16 # Number of parameter settings that are sampled. random_search = RandomizedSearchCV(estimator=model, param_distributions=param_dist, n_iter=n_iter_search, n_jobs=, cv=, verbose=) random_search.fit(X, Y) # Show the results print("Best: %f using %s" % (random_search.best_score_, random_search.best_params_)) means = random_search.cv_results_['mean_test_score'] stds = random_search.cv_results_['std_test_score'] params = random_search.cv_results_['params'] for mean, stdev, param in zip(means, stds, params): print("%f (%f) with: %r" % (mean, stdev, param))
另外,當你爲每一個維度設置空間時,爲每一個變量設定正確的尺度是很是重要的。
批量大小和Learning Rate的通用比例空間
例如,使用批量大小的值做爲2的冪指數,而且在日誌中對Learning Rate進行抽樣是很常見的。
放大
另外一個很常見的作法是,在必定次數的迭代中,從上面的一個佈局開始,而後經過在每一個變量範圍內進行更密集的採樣,甚至使用相同或不一樣的搜索策略開始新的搜索,從而放大到一個子空間。
還有一個問題:獨立猜想。
不幸的是,網格搜索和隨機搜索有一個共同的缺點:「每一個新的猜想都獨立於以前的運行!」
相比之下,Babysitting的優點就顯現出來了。Babysitting之因此有效,是由於研究者有能力利用過去的猜想,將其做爲改進下一步工做的資源,來有效地推進搜索和實驗。
貝葉斯優化
貝葉斯策略創建了一個代理模型,試圖從超參數配置中預測咱們所關注的度量指標。在每一次的迭代中,咱們對代理會變得愈來愈有信心,新的猜想會帶來新的改進,就像其它搜索策略同樣,它也會等到耗盡資源的時候終止。
貝葉斯優化工做流程
高斯過程
咱們能夠將高斯過程定義爲學習從超參數配置到度量映射的替代過程。它不只產生一個預測值,並且還會給咱們一個不肯定性的範圍。
2個點的高斯過程
在上圖中,咱們在單個變量上(在橫軸上)遵循高斯過程優化的第一步,在這個例子中,能夠表明Learning Rate或Dropout Rate。在縱軸上,咱們將某個度量指標繪製成單個超參數的函數。因爲咱們正在尋找儘量低的值,因此能夠把它看做是損失函數。
圖中黑線表明了訓練出來的模型,紅線是真實值,也就是咱們正在試圖學習的函數。黑線表明咱們對真實值函數假設的平均值,而灰色區域代表空間中相關的不肯定性或方差。正如咱們看到的,點周圍的不肯定性減小了,由於咱們對這些點周圍的結果很是有信心,由於咱們已經在這裏訓練了模型。而在信息較少的區域,不肯定性會增長。
如今已經定義了起點,咱們準備好選擇下一個變量來訓練模型。爲此,須要定義一個採集函數,它會告訴咱們在哪裏採樣下一個配置。
在這個例子中,若是咱們使用不肯定性區域中的配置,則函數將尋找儘量低的值。上圖中的藍點顯示了下一次訓練所選擇的點。
3個點的高斯過程
咱們訓練的模型越多,代理對下一個採樣的點就越有信心。下圖是8次訓練後的模型:
8個點的高斯過程
高斯過程屬於一類稱爲基於序列模型的優化(SMBO)的算法。正如剛剛看到的,這些算法爲搜索最佳超參數配置提供了很是好的基準。可是,就像每種工具同樣,它們都有缺點:
你可使用FloydHub的Workspace在配置完整的雲主機上運行下面的代碼:
def data(): """ Data providing function: This function is separated from model() so that hyperopt won't reload data for each evaluation run. """ # Load / Cleaning / Preprocessing ... returnx_train, y_train, x_test, y_test def model(x_train, y_train, x_test, y_test): """ Model providing function: Create Keras model with double curly brackets dropped-in as needed. Return value has to be a valid python dictionary with two customary keys: - loss: Specify a numeric evaluation metric to be minimized - status: Just use STATUS_OK and see hyperopt documentation if not feasible The last one is optional, though recommended, namely: - model: specify the model just created so that we can later use it again. "" # Model definition / hyperparameters space definition / fit / eval return {'loss': <metrics_to_minimize>, 'status': STATUS_OK, 'model': model} # SMBO - TPE in action best_run, best_model = optim.minimize(model=model, data=data, algo=tpe.suggest, max_evals=, trials=Trials()) # Show the results x_train, y_train, x_test, y_test = data() print("Evalutation of best performing model:") print(best_model.evaluate(x_test, y_test)) print("Best performing model chosen hyper-parameters:") print(best_run)
下圖總結了咱們所涉及的內容,瞭解每一個策略的優缺點:
總結
只要資源沒有限制,貝葉斯SMBO多是最好的選擇,但還應該考慮創建一個隨機搜索的基準。
若是你還處於學習或者初級階段,那麼選擇Babysitting。即便從空間搜索的角度來看不切實際,也是一種可行的方法。
若是訓練表現不佳,這些策略都不會提供節省資源的機制,只能等到計算結束。
早停的力量
「早停」不只是一種規則化技術,並且在訓練方向不正確時,它會提供防止資源浪費的機制。
下圖是最經常使用的中止標準:
中止標準
前三個標準不用多說,因此你們集中看最後一個標準。
一般狀況下,根據實驗類別來限定訓練時長,這能夠對團隊內部的資源進行優化。經過這種方式,咱們可以分配更多的資源給最有但願的實驗。
這些標準能夠在Babysitting過程當中手動應用,或者經過在最多見框架中提供的鉤子/回調組件將這些規則集成到實驗中:
在FloydHub上管理實驗
FloydHub的最大特性之一是,當使用不一樣的超參數集時可以比較正在訓練的模型。
下圖顯示了FloydHub項目中的任務列表。能夠看到,該用戶正在使用任務消息,突出顯示在這些任務中使用的超參數。
另外,還能夠看到每一個任務的訓練度量指標,並提供了一個快速瀏覽,以幫助你瞭解哪些任務表現的最好,以及使用的機器類型和總的訓練時間。
FloydHub的dashboard爲你提供了一種簡便的方式來比較在超參數搜索中的訓練任務,並且是實時更新的。咱們的建議是爲每個任務建立一個不一樣的FloydHub項目,這樣,你就能夠更容易地組織工做和團隊合做。
訓練度量指標
如上所述,你能夠輕鬆地在FloydHub上發佈與工做相關的訓練度量指標。當你在FloydHub的dashboard上查看任務時,能夠很容易地爲每一個指標找到相應的實時圖表。這個特性並非要取代Tensorboard,而是由所選擇的超參數配置來突出訓練的狀態。
例如,若是你正在Babysitting訓練的過程當中,那麼訓練度量指標確定會幫你肯定和應用中止標準。
訓練度量指標
本文做者:【方向】
本文爲雲棲社區原創內容,未經容許不得轉載。