當前位置:
首頁 > 知識 > keras參數調優

keras參數調優

本文主要想為大家介紹如何使用scikit-learn網格搜索功能,並給出一套代碼實例。你可以將代碼複製粘貼到自己的項目中,作為項目起始。

下文所涉及的議題列表:

通過用 KerasClassifier 或 KerasRegressor 類包裝Keras模型,可將其用於scikit-learn。

要使用這些包裝,必須定義一個函數,以便按順序模式創建並返回Keras,然後當構建 KerasClassifier 類時,把該函數傳遞給 build_fn 參數。

例如:

def create_model():

...

return model

model = KerasClassifier(build_fn=create_model)

KerasClassifier類 的構建器為可以採取默認參數,並將其被傳遞給 model.fit() 的調用函數,比如 epochs數目和批尺寸(batch size)。

例如:

def create_model():

...

return model

model = KerasClassifier(build_fn=create_model, nb_epoch=10)

KerasClassifier類的構造也可以使用新的參數,使之能夠傳遞給自定義的create_model()函數。這些新的參數,也必須由使用默認參數的 create_model() 函數的簽名定義。

例如:

def create_model(dropout_rate=0.0):

...

return model

model = KerasClassifier(build_fn=create_model, dropout_rate=0.2)

您可以在 Keras API文檔 中,了解到更多關於scikit-learn包裝器的知識。

網格搜索(grid search)是一項模型超參數優化技術。

在scikit-learn中,該技術由 GridSearchCV 類提供。

當構造該類時,你必須提供超參數字典,以便用來評價 param_grid 參數。這是模型參數名稱和大量列值的示意圖。

默認情況下,精確度是優化的核心,但其他核心可指定用於GridSearchCV構造函數的score參數。

默認情況下,網格搜索只使用一個線程。在GridSearchCV構造函數中,通過將 n_jobs參數設置為-1,則進程將使用計算機上的所有內核。這取決於你的Keras後端,並可能干擾主神經網路的訓練過程。

當構造並評估一個模型中各個參數的組合時,GridSearchCV會起作用。使用交叉驗證評估每個單個模型,且默認使用3層交叉驗證,儘管通過將cv參數指定給 GridSearchCV構造函數時,有可能將其覆蓋。

下面是定義一個簡單的網格搜索示例:

一旦完成,你可以訪問網格搜索的輸出,該輸出來自結果對象,由grid.fit()返回。best_score_成員提供優化過程期間觀察到的最好的評分, best_params_描述了已取得最佳結果的參數的組合。

您可以在 scikit-learn API文檔 中了解更多關於GridSearchCV類的知識。

現在我們知道了如何使用scikit-learn 的Keras模型,如何使用scikit-learn 的網格搜索。現在一起看看下面的例子。

所有的例子都將在一個小型的標準機器學習數據集上來演示,該數據集被稱為 Pima Indians onset of diabetes 分類數據集 。該小型數據集包括了所有容易工作的數值屬性。

下載數據集 ,並把它放置在你目前工作目錄下,命名為: pima-indians-diabetes.csv 。

當我們按照本文中的例子進行,能夠獲得最佳參數。因為參數可相互影響,所以這不是網格搜索的最佳方法,但出於演示目的,它是很好的方法。

所有示例的配置為了實現並行化(n_jobs=-1)。

如果顯示像下面這樣的錯誤:

INFO (theano.gof.compilelock): Waiting for existing lock by process "55614" (I am process "55613")

INFO (theano.gof.compilelock): To manually release the lock, delete ...

結束進程,並修改代碼,以便不並行地執行網格搜索,設置n_jobs=1。

在第一個簡單的例子中,當調整網路時,我們著眼於調整批尺寸和訓練epochs。

迭代梯度下降的批尺寸大小是權重更新之前顯示給網路的模式數量。它也是在網路訓練的優選法,定義一次讀取的模式數並保持在內存中。

訓練epochs是訓練期間整個訓練數據集顯示給網路的次數。有些網路對批尺寸大小敏感,如LSTM複發性神經網路和卷積神經網路。

在這裡,我們將以20的步長,從10到100逐步評估不同的微型批尺寸。

完整代碼如下:

# Use scikit-learn to grid search the batch size and epochs

import numpy

from sklearn.grid_search import GridSearchCV

from keras.models import Sequential

from keras.layers import Dense

from keras.wrappers.scikit_learn import KerasClassifier

# Function to create model, required for KerasClassifier

def create_model():

# create model

model = Sequential()

model.add(Dense(12, input_dim=8, activation="relu"))

model.add(Dense(1, activation="sigmoid"))

# Compile model

model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

return model

# fix random seed for reproducibility

seed = 7

numpy.random.seed(seed)

# load dataset

dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")

# split into input (X) and output (Y) variables

X = dataset[:,0:8]

Y = dataset[:,8]

# create model

model = KerasClassifier(build_fn=create_model, verbose=0)

# define the grid search parameters

batch_size = [10, 20, 40, 60, 80, 100]

epochs = [10, 50, 100]

param_grid = dict(batch_size=batch_size, nb_epoch=epochs)

grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)

grid_result = grid.fit(X, Y)

# summarize results

print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))

for params, mean_score, scores in grid_result.grid_scores_:

print("%f (%f) with: %r" % (scores.mean(), scores.std(), params))

運行之後輸出如下:

我們可以看到,批尺寸為20、100 epochs能夠獲得最好的結果,精確度約68%。

Keras提供了一套最先進的不同的優化演算法。

在這個例子中,我們調整用來訓練網路的優化演算法,每個都用默認參數。

這個例子有點奇怪,因為往往你會先選擇一種方法,而不是將重點放在調整問題參數上(參見下一個示例)。

在這裡,我們將評估 Keras API支持的整套優化演算法 。

完整代碼如下:

# Use scikit-learn to grid search the batch size and epochs

import numpy

from sklearn.grid_search import GridSearchCV

from keras.models import Sequential

from keras.layers import Dense

from keras.wrappers.scikit_learn import KerasClassifier

# Function to create model, required for KerasClassifier

def create_model(optimizer="adam"):

# create model

model = Sequential()

model.add(Dense(12, input_dim=8, activation="relu"))

model.add(Dense(1, activation="sigmoid"))

# Compile model

model.compile(loss="binary_crossentropy", optimizer=optimizer, metrics=["accuracy"])

return model

# fix random seed for reproducibility

seed = 7

numpy.random.seed(seed)

# load dataset

dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")

# split into input (X) and output (Y) variables

X = dataset[:,0:8]

Y = dataset[:,8]

# create model

model = KerasClassifier(build_fn=create_model, nb_epoch=100, batch_size=10, verbose=0)

# define the grid search parameters

optimizer = ["SGD", "RMSprop", "Adagrad", "Adadelta", "Adam", "Adamax", "Nadam"]

param_grid = dict(optimizer=optimizer)

grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)

grid_result = grid.fit(X, Y)

# summarize results

print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))

for params, mean_score, scores in grid_result.grid_scores_:

print("%f (%f) with: %r" % (scores.mean(), scores.std(), params))

運行之後輸出如下:

結果表明,ATOM優化演算法結果最好,精確度約為70%。

預先選擇一個優化演算法來訓練你的網路和參數調整是十分常見的。目前,最常用的優化演算法是普通的隨機梯度下降法(Stochastic Gradient Descent,SGD),因為它十分易於理解。在本例中,我們將著眼於優化SGD的學習速率和動量因子(momentum)。

學習速率控制每批(batch)結束時更新的權重,動量因子控制上次權重的更新對本次權重更新的影響程度。

我們選取了一組較小的學習速率和動量因子的取值範圍:從0.2到0.8,步長為0.2,以及0.9(實際中常用參數值)。

一般來說,在優化演算法中包含epoch的數目是一個好主意,因為每批(batch)學習量(學習速率)、每個 epoch更新的數目(批尺寸)和 epoch的數量之間都具有相關性。

完整代碼如下:

# Use scikit-learn to grid search the learning rate and momentum

import numpy

from sklearn.grid_search import GridSearchCV

from keras.models import Sequential

from keras.layers import Dense

from keras.wrappers.scikit_learn import KerasClassifier

from keras.optimizers import SGD

# Function to create model, required for KerasClassifier

def create_model(learn_rate=0.01, momentum=0):

# create model

model = Sequential()

model.add(Dense(12, input_dim=8, activation="relu"))

model.add(Dense(1, activation="sigmoid"))

# Compile model

optimizer = SGD(lr=learn_rate, momentum=momentum)

model.compile(loss="binary_crossentropy", optimizer=optimizer, metrics=["accuracy"])

return model

# fix random seed for reproducibility

seed = 7

numpy.random.seed(seed)

# load dataset

dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")

# split into input (X) and output (Y) variables

X = dataset[:,0:8]

Y = dataset[:,8]

# create model

model = KerasClassifier(build_fn=create_model, nb_epoch=100, batch_size=10, verbose=0)

# define the grid search parameters

learn_rate = [0.001, 0.01, 0.1, 0.2, 0.3]

momentum = [0.0, 0.2, 0.4, 0.6, 0.8, 0.9]

param_grid = dict(learn_rate=learn_rate, momentum=momentum)

grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)

grid_result = grid.fit(X, Y)

# summarize results

print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))

for params, mean_score, scores in grid_result.grid_scores_:

print("%f (%f) with: %r" % (scores.mean(), scores.std(), params))

運行之後輸出如下:

可以看到,SGD在該問題上相對表現不是很好,但當學習速率為0.01、動量因子為0.0時可取得最好的結果,正確率約為68%。

神經網路權值初始化一度十分簡單:採用小的隨機數即可。

現在,有許多不同的技術可供選擇。 點擊此處查看Keras 提供的清單 。

在本例中,我們將著眼於通過評估所有可用的技術,來調優網路權值初始化的選擇。

我們將在每一層採用相同的權值初始化方法。理想情況下,根據每層使用的激活函數選用不同的權值初始化方法效果可能更好。在下面的例子中,我們在隱藏層使用了整流器(rectifier)。因為預測是二進位,因此在輸出層使用了sigmoid函數。

完整代碼如下:

# Use scikit-learn to grid search the weight initialization

import numpy

from sklearn.grid_search import GridSearchCV

from keras.models import Sequential

from keras.layers import Dense

from keras.wrappers.scikit_learn import KerasClassifier

# Function to create model, required for KerasClassifier

def create_model(init_mode="uniform"):

# create model

model = Sequential()

model.add(Dense(12, input_dim=8, init=init_mode, activation="relu"))

model.add(Dense(1, init=init_mode, activation="sigmoid"))

# Compile model

model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

return model

# fix random seed for reproducibility

seed = 7

numpy.random.seed(seed)

# load dataset

dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")

# split into input (X) and output (Y) variables

X = dataset[:,0:8]

Y = dataset[:,8]

# create model

model = KerasClassifier(build_fn=create_model, nb_epoch=100, batch_size=10, verbose=0)

# define the grid search parameters

init_mode = ["uniform", "lecun_uniform", "normal", "zero", "glorot_normal", "glorot_uniform", "he_normal", "he_uniform"]

param_grid = dict(init_mode=init_mode)

grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)

grid_result = grid.fit(X, Y)

# summarize results

print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))

for params, mean_score, scores in grid_result.grid_scores_:

print("%f (%f) with: %r" % (scores.mean(), scores.std(), params))

運行之後輸出如下:

我們可以看到,當採用均勻權值初始化方案(uniform weight initialization )時取得最好的結果,可以實現約72%的性能。

激活函數控制著單個神經元的非線性以及何時激活。

通常來說,整流器(rectifier)的激活功能是最受歡迎的,但應對不同的問題, sigmoid函數和tanh 函數可能是更好的選擇。

在本例中,我們將探討、評估、比較 Keras提供的不同類型的激活函數 。我們僅在隱層中使用這些函數。考慮到二元分類問題,需要在輸出層使用sigmoid激活函數。

通常而言,為不同範圍的傳遞函數準備數據是一個好主意,但在本例中我們不會這麼做。

完整代碼如下:

# Use scikit-learn to grid search the activation function

import numpy

from sklearn.grid_search import GridSearchCV

from keras.models import Sequential

from keras.layers import Dense

from keras.wrappers.scikit_learn import KerasClassifier

# Function to create model, required for KerasClassifier

def create_model(activation="relu"):

# create model

model = Sequential()

model.add(Dense(12, input_dim=8, init="uniform", activation=activation))

model.add(Dense(1, init="uniform", activation="sigmoid"))

# Compile model

model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

return model

# fix random seed for reproducibility

seed = 7

numpy.random.seed(seed)

# load dataset

dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")

# split into input (X) and output (Y) variables

X = dataset[:,0:8]

Y = dataset[:,8]

# create model

model = KerasClassifier(build_fn=create_model, nb_epoch=100, batch_size=10, verbose=0)

# define the grid search parameters

activation = ["softmax", "softplus", "softsign", "relu", "tanh", "sigmoid", "hard_sigmoid", "linear"]

param_grid = dict(activation=activation)

grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)

grid_result = grid.fit(X, Y)

# summarize results

print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))

for params, mean_score, scores in grid_result.grid_scores_:

print("%f (%f) with: %r" % (scores.mean(), scores.std(), params))

運行之後輸出如下:

令人驚訝的是(至少對我來說是),「線性(linear)」激活函數取得了最好的效果,準確率約為72%。

在本例中,我們將著眼於調整正則化中的dropout速率,以期限制過擬合(overfitting)和提高模型的泛化能力。為了得到較好的結果,dropout最好結合一個如最大範數約束之類的權值約束。

了解更多dropout在深度學習框架Keras的使用請查看下面這篇文章:

它涉及到擬合dropout率和權值約束。我們選定dropout percentages取值範圍是:0.0-0.9(1.0無意義);最大範數權值約束( maxnorm weight constraint)的取值範圍是0-5。

完整代碼如下:

# Use scikit-learn to grid search the dropout rate

import numpy

from sklearn.grid_search import GridSearchCV

from keras.models import Sequential

from keras.layers import Dense

from keras.layers import Dropout

from keras.wrappers.scikit_learn import KerasClassifier

from keras.constraints import maxnorm

# Function to create model, required for KerasClassifier

def create_model(dropout_rate=0.0, weight_constraint=0):

# create model

model = Sequential()

model.add(Dense(12, input_dim=8, init="uniform", activation="linear", W_constraint=maxnorm(weight_constraint)))

model.add(Dropout(dropout_rate))

model.add(Dense(1, init="uniform", activation="sigmoid"))

# Compile model

model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

return model

# fix random seed for reproducibility

seed = 7

numpy.random.seed(seed)

# load dataset

dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")

# split into input (X) and output (Y) variables

X = dataset[:,0:8]

Y = dataset[:,8]

# create model

model = KerasClassifier(build_fn=create_model, nb_epoch=100, batch_size=10, verbose=0)

# define the grid search parameters

weight_constraint = [1, 2, 3, 4, 5]

dropout_rate = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

param_grid = dict(dropout_rate=dropout_rate, weight_constraint=weight_constraint)

grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)

grid_result = grid.fit(X, Y)

# summarize results

print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))

for params, mean_score, scores in grid_result.grid_scores_:

print("%f (%f) with: %r" % (scores.mean(), scores.std(), params))

運行之後輸出如下:

我們可以看到,當 dropout率為0.2%、最大範數權值約束( maxnorm weight constraint)取值為4時,可以取得準確率約為72%的最好結果。

每一層中的神經元數目是一個非常重要的參數。通常情況下,一層之中的神經元數目控制著網路的代表性容量,至少是拓撲結構某一節點的容量。

此外,一般來說,一個足夠大的單層網路是接近於任何神經網路的,至少在理論上成立。

在本例中,我們將著眼於調整單個隱藏層神經元的數量。取值範圍是:1—30,步長為5。

一個大型網路要求更多的訓練,此外,至少批尺寸(batch size)和 epoch的數量應該與神經元的數量優化。

完整代碼如下:

# Use scikit-learn to grid search the number of neurons

import numpy

from sklearn.grid_search import GridSearchCV

from keras.models import Sequential

from keras.layers import Dense

from keras.layers import Dropout

from keras.wrappers.scikit_learn import KerasClassifier

from keras.constraints import maxnorm

# Function to create model, required for KerasClassifier

def create_model(neurons=1):

# create model

model = Sequential()

model.add(Dense(neurons, input_dim=8, init="uniform", activation="linear", W_constraint=maxnorm(4)))

model.add(Dropout(0.2))

model.add(Dense(1, init="uniform", activation="sigmoid"))

# Compile model

model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])

return model

# fix random seed for reproducibility

seed = 7

numpy.random.seed(seed)

# load dataset

dataset = numpy.loadtxt("pima-indians-diabetes.csv", delimiter=",")

# split into input (X) and output (Y) variables

X = dataset[:,0:8]

Y = dataset[:,8]

# create model

model = KerasClassifier(build_fn=create_model, nb_epoch=100, batch_size=10, verbose=0)

# define the grid search parameters

neurons = [1, 5, 10, 15, 20, 25, 30]

param_grid = dict(neurons=neurons)

grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1)

grid_result = grid.fit(X, Y)

# summarize results

print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))

for params, mean_score, scores in grid_result.grid_scores_:

print("%f (%f) with: %r" % (scores.mean(), scores.std(), params))

運行之後輸出如下:

我們可以看到,當網路中隱藏層內神經元的個數為5時,可以達到最佳結果,準確性約為71%。

本節羅列了一些神經網路超參數調整時常用的小技巧。

在這篇文章中,你可以了解到如何使用Keras和scikit-learn/Python調優神經網路中的超參數。

keras參數調優

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

帶你全方位學習Picasso(二)
退到後台,線程被掛起,系統回收所有的socket資源問題及解決方案

TAG:程序員小新人學習 |