K重交叉驗證和網格搜尋驗證

SpikeKing發表於2018-05-03

本文介紹Keras一些常見的驗證和調參技巧,快速地驗證模型和調節超參(Super Parameters)。

小技巧:

  • CSV資料檔案載入
  • Dense初始化警告

驗證與調參:

  • 模型驗證(Validation)
  • K重交叉驗證(K-fold Cross-Validation)
  • 網格搜尋驗證(Grid Search Cross-Validation)

CSV資料檔案載入

使用NumPy的 loadtxt() 方法載入CSV資料檔案

  • delimiter:資料單元的分割符;
  • skiprows:略過首行標題;
dataset = np.loadtxt(raw_path, delimiter=',', skiprows=1)
複製程式碼

Dense初始化警告

Dense初始化引數的警告:

UserWarning: Update your `Dense` call to the Keras 2 API
`Dense(units=12, activation="relu", kernel_initializer="uniform")`
output = Dense(units=12, init='uniform', activation='relu')(main_input)
複製程式碼

將init引數替換為kernel_initializer引數即可。


模型驗證

fit()自動劃分驗證集:

通過設定引數validation_split的值(0~1)確定驗證集的比例。

實現:

history = self.model.fit(
    self.data[0], self.data[1],
    epochs=self.config.num_epochs,
    verbose=1,
    batch_size=self.config.batch_size,
    validation_split=0.33,
)
複製程式碼

fit()手動劃分驗證集:

train_test_split來源sklearn.model_selection:

  • test_size:驗證集的比例;
  • random_state:隨機數的種子;

通過引數validation_data新增驗證資料,格式是 資料+標籤 的元組。

實現:

X_train, X_test, y_train, y_test = \
    train_test_split(self.data[0], self.data[1], test_size=0.33, random_state=47)

history = self.model.fit(
    X_train, y_train,
    validation_data=(X_test, y_test),
    epochs=self.config.num_epochs,
    batch_size=self.config.batch_size,
    verbose=1,
)
複製程式碼

交叉驗證

K重交叉驗證(K-fold Cross-Validation)是常見的模型評估統計。

人工模式

交叉驗證函式 StratifiedKFold() 來源於sklearn.model_selection:

  • n_splits:交叉的重數,即N重交叉驗證;
  • shuffle:資料和標籤是否隨機洗牌;
  • random_state:隨機數種子;
  • skf.split(X, y):劃分資料和標籤的索引。

cvscores用於統計K重交叉驗證的結果,計算均值和方差。

實現:

X = self.data[0]  # 資料
y = self.data[1]  # 標籤
skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=47)
cvscores = []  # 交叉驗證結果
for train_index, test_index in skf.split(X, y):  # 索引值
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]

    history = self.model.fit(
        X_train, y_train,
        epochs=self.config.num_epochs,
        batch_size=self.config.batch_size,
        verbose=0,
    )
    self.loss.extend(history.history['loss'])
    self.acc.extend(history.history['acc'])

    # scores的第一維是loss,第二維是acc
    scores = self.model.evaluate(X_test, y_test)
    print('[INFO] %s: %.2f%%' % (self.model.metrics_names[1], scores[1] * 100))
    cvscores.append(scores[1] * 100)
cvscores = np.asarray(cvscores)
print('[INFO] %.2f%% (+/- %.2f%%)' % (np.mean(cvscores), np.std(cvscores)))
複製程式碼

輸出:

[INFO] acc: 79.22%
[INFO] acc: 70.13%
[INFO] acc: 75.32%
[INFO] acc: 75.32%
[INFO] acc: 80.52%
[INFO] acc: 81.82%
[INFO] acc: 75.32%
[INFO] acc: 85.71%
[INFO] acc: 75.00%
[INFO] acc: 76.32%
[INFO] 77.47% (+/- 4.18%)
複製程式碼

Wrapper模式

通過 cross_val_score() 函式整合模型和交叉驗證邏輯。

  • 將模型封裝成wrapper,注意使用內建函式,而呼叫,沒有括號()
  • epochs即輪次,batch_size即批次數;
  • StratifiedKFold是K重交叉驗證的邏輯;

cross_val_score的輸入是模型wrapper、資料X、標籤Y、交叉驗證cv;輸出是每次驗證的結果,再計算均值和方差。

實現:

X = self.data[0]  # 資料
Y = self.data[1]  # 標籤

model_wrapper = KerasClassifier(
    build_fn=create_model,
    epochs=self.config.num_epochs,
    batch_size=self.config.batch_size,
    verbose=0
)  # keras wrapper

kfold = StratifiedKFold(n_splits=10, shuffle=True, random_state=47)
results = cross_val_score(model_wrapper, X, Y, cv=kfold)
print('[INFO] %.2f%% (+/- %.2f%%)' % (np.mean(results) * 100.0, np.std(results) * 100.0))
複製程式碼

輸出:

[INFO] 74.74% (+/- 4.37%)
複製程式碼

網格搜尋驗證

網格搜尋驗證(Grid Search Cross-Validation)用於選擇模型的最優超參值。

交叉驗證函式 GridSearchCV() 來源於sklearn.model_selection:

  • 設定超參列表,如optimizers、init_modes、epochs、batches;
  • 建立引數字典,key值是模型的引數,或者wrapper的引數;
  • estimator是模型,param_grid是網格引數字典,n_jobs是程式數;
  • 輸出最優結果和其他排列組合結果。

實現:

X = self.data[0]  # 資料
Y = self.data[1]  # 標籤

model_wrapper = KerasClassifier(
    build_fn=create_model,
    verbose=0
)  # 模型

optimizers = ['rmsprop', 'adam']  # 優化器
init_modes = ['glorot_uniform', 'normal', 'uniform']  # 初始化模式
epochs = np.array([50, 100, 150])  # Epoch數
batches = np.array([5, 10, 20])  # 批次數

# 網格字典optimizer和init_mode是模型的引數,epochs和batch_size是wrapper的引數
param_grid = dict(optimizer=optimizers, epochs=epochs, batch_size=batches, init_mode=init_modes)
grid = GridSearchCV(estimator=model_wrapper, param_grid=param_grid, n_jobs=4)
grid_result = grid.fit(X, Y)

print('[INFO] Best: %f using %s' % (grid_result.best_score_, grid_result.best_params_))

for params, mean_score, scores in grid_result.grid_scores_:
    print('[INFO] %f (%f) with %r' % (scores.mean(), scores.std(), params))
複製程式碼

輸出:

[INFO] Best: 0.721354 using {'epochs': 100, 'init_mode': 'uniform', 'optimizer': 'adam', 'batch_size': 20}
[INFO] 0.697917 (0.025976) with {'epochs': 50, 'init_mode': 'normal', 'optimizer': 'rmsprop', 'batch_size': 10}
[INFO] 0.700521 (0.006639) with {'epochs': 50, 'init_mode': 'normal', 'optimizer': 'adam', 'batch_size': 10}
[INFO] 0.697917 (0.018414) with {'epochs': 50, 'init_mode': 'uniform', 'optimizer': 'rmsprop', 'batch_size': 10}
[INFO] 0.701823 (0.030314) with {'epochs': 50, 'init_mode': 'uniform', 'optimizer': 'adam', 'batch_size': 10}
[INFO] 0.632813 (0.059069) with {'epochs': 100, 'init_mode': 'normal', 'optimizer': 'rmsprop', 'batch_size': 10}
...
複製程式碼

歡迎Follow我的GitHub:https://github.com/SpikeKing

By C. L. Wang

OK, that's all! Enjoy it!

相關文章