TensorfFlow2.0 (2) 超參數搜索代碼實戰

一、 概念

               在神經網絡中有許多參數,而超參數就是神經網絡訓練過程中不變的參數,也就是在訓練之前設置好的參數,

               而不是訓練

               得到的參數。比如說,神經網絡結構:層數,寬度,激活函數、訓練參數:batch_size,學習率,學習率衰減算法。

               而超參數搜索就是讓機器自己選擇合適的超參數的值,以省下我們大量的精力。

 

二、 搜索策略

               超參數的搜索策略一共有以下幾種

               2.1 網格搜索

               2.2 隨機搜索

               2.3 遺傳算法搜索

               2.4 啓發式搜索

          2.1 網格搜索

                         假設我們需要對兩個超參數進行搜索,那我們就設定一個二維矩陣,x 軸對應超參數 1 ,y 軸對應超參數 2,

                         機器就會將兩個超參數的值兩兩組合,找到最合適的值和最合適的搭配。

                         我們可以總結如下:

                          定義 n 維方格

                         每個方格對應一組超參數

                         一對一對嘗試

          2.2 隨機搜索

                         在選定的參數範圍內隨機生成超參數數組,並對超參數進行組合,以達到最優解。

                        總結如下:

                        生成方式隨機

                        可探索的空間更大

          2.3 遺傳算法搜索

                        初始化候選超參數集合

                        訓練篩選 -> 得到模型的生存概率

                        淘汰並選擇一部分

                        交叉 -> 變異

                        得到下一代

                        迭代

          2.4 啓發式搜索

                       啓發式搜索是以前研究熱點 —— AutoML 的一部分,在其的子領域神經網絡結構搜索

                       原理如下:(具體原理有空的話會再寫一篇博文)

                       使用循環神經網絡來生成參數,生成參數後根據參數生成新的網絡結構來進行訓練

                       訓練後,使用強化學習的思維,生成反饋機制,再來訓練我們的循環神經網絡

                       

三、 手工實現超參數搜索代碼實戰

              手工實現的話,缺點在於比較繁瑣,下面展示的只是一個參數的修改,而實際上我們需要修改的遠遠不止一個參數

          3.1 修改模型配置與訓練代碼

               代碼的基本框架與 wide and deep 模型代碼實戰 是一致的,這裏只編寫代碼的不同之處

               需要修改的地方爲,模型搭建以及模型訓練部分,並且因爲有多個模型訓練,需要建立 histories 數組,

               以便保存多個結果,從代碼上來說,就是模型層次搭建到 fit 部分

# 這裏用學習率 learning rate 來做演示,取值範圍爲 [1e-4,3e-4,1e-3,3e-3,1e-2,3e-2]
# 1e-4 = 1 * 10^(-4)
# W = W + grad * learning_rate

# 定義 learning_rate 集合,重複訓練模型 n 次
learning_rates = [1e-4,3e-4,1e-3,3e-3,1e-2,3e-2]
histories = []
for lr in learning_rates:
    # 實現多輸入 這裏使用函數式的方法
    # 我們假設我們將前 5 個 feature 輸入 wide 模型,後 6 個 feature 輸入 deep 模型,一共 8 個     feature ,也就是說, wide and deep 有交集部分
    input_wide = keras.layers.Input(shape=[5])
    input_deep = keras.layers.Input(shape=[6])
    # deep model 有兩個隱藏層
    hidden1 = keras.layers.Dense(30,activation='relu')(input_deep)
    hidden2 = keras.layers.Dense(30,activation='relu')(hidden1)
    # 合併兩個模型的輸出
    concat = keras.layers.concatenate([input_wide,hidden2])
    # 模型的輸入爲兩個模型的輸入,輸出只有一個
    model = keras.models.Model(inputs = [input_wide,input_deep],
                            outputs = [output])
    
# 因爲我們改變的是學習率,我們只需要將模型的 optimizer 修改即可
    optimizer = keras.optimizer.SGD(lr)
    
    model.compile(loss="mean_squared_error",optimizer=optimizer)

    callbacks = [keras.callbacks.EarlyStopping(
                patience= 5,min_delta=1e-2)]
 

    history = model.fit(x_train_scaled,y_train,
                    validation_data = (x_valid_scaled,y_valid),
                    epochs = 100,
                    callbacks = callbacks)
# 最後,因 histories 不只一個,需要進行保存
    histories.append(history)

          3.2 圖表展示代碼修改

                        因爲有多個模型需要展示,展示代碼也需要略微修改,多添加一個循環即可

                        最好把 learning_rate  和 history 組合顯示,方便對比

# 設定圖表展示函數,將模型訓練的接受對象 history 輸入到該函數中
def plot_learning_curves(history):
# 將 history 獲取到的訓練過程的參數變化的字典變爲矩陣形狀,並設定圖的尺寸大小爲 8 和 5
    pd.DataFrame(history.history).plot(figsize=(8,5))
# 顯示網格
    plt.grid(True)
# 設置座標範圍 ,設定 y 爲 0~1 之間
    plt.gca().set_ylim(0,1)
# 顯示這張圖
    plt.show()

#多添加一個循環即可
for lr, history in zip(learning_rates, histories):
    print("Learning rate: ", lr)
    plot_learning_curves(history)

          3.3 刪除模型評測部分

                     因爲模型評測是針對最後一個模型,對我們幫助不大,直接刪除

                     將以下代碼刪除

# 輸入測試集的特徵與標籤
model.evaluate(x_test_scaled,y_test)

四、 keras 庫實現超參數搜索-隨機搜索

          4.1 資源庫導入

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy
import sklearn
import pandas as pd
import os
import sys
import time
import tensorflow as tf

from tensorflow import keras 

print(tf.__version__)
print(sys.version_info)
for module in mpl,np,pd,sklearn,tf,keras:
    print(module.__name__,module.__version__)

           

           4.2 導入數據

from sklearn.datasets import fetch_california_housing

housing = fetch_california_housing()
print(housing.DESCR)
print(housing.data.shape)
print(housing.target.shape)

 

            4.3 數據劃分

from skleran.model_selection import train_test_split

x_train_all,x_test,y_train_all,y_test = train_test_split(
        housing.data,housing.target,random_state = 7)
x_train,x_valid,y_train,y_valid=train_test_split(
        x_train_all,y_train_all,random_state = 11)
print(x_train.shape,y_train.shape)
print(x_valid.shape,y_valid.shape)
print(x_test.shape,y_test.shape)

 

             4.4 數據標準化

from skleran.preprocessing import StandarScaler

scaler = StandarScaler()
x_train_scaled = scaler.fit_transform(x_train)
x_valid_scaled = scaler.transform(x_valid)
x_test_scaled = scaler.transform(x_test)

            

              4.5 將模型設定爲函數 API

# 設定模型的默認值
# hodden_layer: 模型隱藏層默認爲 1 
# layer_size: 神經元的數量默認爲 30
# learning_rate:3e-3 
def build_model(hodden_layer = 1,
                layer_size = 30,
                learning_rate  = 3e-3):
# 使用 Sequential 的方式在函數內構件模型
    model = keras.models.Sequential()
# 設定輸入層,輸入的矩陣形狀爲 x_train.shape
    model.add(keras.layers.Dense(layer_size,activation = 'relu',
                                input_shape=x_train.shape[1:]))
# 設定隱藏層生成循環
    for _ in range(hidden_layers -1):
        model.add(keras.layers.Dense(layer_size,
                                    activation = 'relu'))
# 添加輸出層
    model.add(keras.layers.Dense(1))
# 使用 keras.optimizers.SGD  API 來修改模型中的學習率
    optimizer = keras.optimizer.SGD(learning_rate)
# 編譯模型
    model.compile(loss='mse'.optimizer = optimizer)
    return model

 

              4.6 進行試訓練

# 引用函數,建立函數
sklearn_model = keras.wrappers.scikit_learn.KerasRegressor(
    build_fn = build_model)
# 設定早停函數
callbacks = [keras.callbacks.EarlyStopping(patience=5,min_delta=1e-2)]
# 試訓練
history = sklern_model.fit(x_train_scaled,y_train,
                            epochs = 10,
                            validation_data = (x_valid_scaled,y_valid),

                            callbacks = callbacks)

 

              4.7 可視化

def plot_learning_curves(history):
    pd.DataFrame(history.history).plot(figsize = (8,5))
    plt.grid(True)
    plt.gca().set_ylim(0,1)
    plt.show()

plot_learning_curves(history)

              

              4.8 設定超參數字典

# 加入分佈庫 reciprocal
# f(x) = 1/(x*log(b/a)) a<= x <= b
from scipy.stats import reciprocal

param_distribution = [
    "hidden_layers":[1,2,3,4],
    "layer_size":np.arange(1,100),
    "learning_rate":reciprocal(1e-4,1e-2),
]

 

               4.9 搜索參數

from sklearn.model_selection import RandomizedSearchCV
# RandomizedSearchCV 參數說明
# sklearn model: 訓練模型
# param_distribution: 字典參數
# n_iter: 訓練次數
# cv: 交叉驗證的折數,默認爲 5 
# n_jobs: 運行的 CPU 數量,-1 默認爲 1 
random_search_cv = RandomizedSearchCV(sklearn_model,
                                      param_distribution,
                                      n_iter = 10,
                                        cv = 3,
                                        n_jobs =1)
random_search_cv.fit(x_train_scaled,y_train,epochs = 100,
                    validation_data = (x_valid_scaled,y_valid),
                    callbacks = callbacks )
# cross_validation: 訓練集分成 n 份,n-1 訓練,最後一份驗證

print(random_search_cv.best_params_)
print(random_search_cv.best_score_)
print(random_search_cv.best_estimator_)

 

                4.10 顯示最佳的模型以及最佳的精確

model = random_search_cv.best_estimator_.model
model.evalute(x_test_scaled,y_test)

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章