超強!機器學習超參數調優指南
超參數調優是機器學習和深度學習中重要的步驟,旨在選擇最佳的超參數組合,以提高模型的性能。
超參數是那些在訓練模型之前需要設置的參數,而不是在訓練過程中自動學習的參數。
常見的超參數包括學習率、批大小、正則化參數、神經網絡的層數和每層的神經元數等。
常見的超參數調優技術
1.網格搜索
網格搜索是一種窮舉搜索技術,用于系統地遍歷多種參數組合,以找到最佳的模型參數。
這種方法簡單直接,但計算成本可能較高,尤其是當參數空間較大時。
優點:
- 簡單易懂:網格搜索直觀易理解,適用于參數數量較少時。
- 徹底性:可以保證在給定的參數網格內找到最優的組合。
缺點:
- 計算成本高:當參數空間大或者模型復雜時,計算成本非常高,因為它需要評估所有可能的參數組合。
代碼示例
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
import numpy as np
# 定義模型
model = RandomForestClassifier()
# 定義參數網格
param_grid = {
'n_estimators': [50, 100, 200],
'max_features': ['auto', 'sqrt', 'log2'],
'max_depth': [None, 10, 20, 30]
}
# 創建網格搜索對象
grid_search = GridSearchCV(estimator=model, param_grid=param_grid, cv=3, scoring='accuracy')
# 擬合網格搜索
grid_search.fit(X_train, y_train)
# 最優參數和最優得分
print("最優參數:", grid_search.best_params_)
print("最高得分:", grid_search.best_score_)
2.隨機搜索
隨機搜索不像網格搜索那樣嘗試所有可能的組合,而是在參數空間中隨機選取參數組合。
這種方法可以在更大的參數空間內更快地找到不錯的解。
優點:
- 高效:在大參數空間中比網格搜索更加高效,不需要測試所有可能的參數組合。
缺點:
- 無保證:由于其隨機性,不能保證找到全局最優解,特別是在迭代次數有限的情況下。
- 結果的隨機性: 同樣的參數和設置可能導致不同的搜索結果。
代碼示例
from sklearn.model_selection import RandomizedSearchCV
from sklearn.ensemble import RandomForestClassifier
# 定義模型
model = RandomForestClassifier()
# 定義參數分布
param_dist = {
'n_estimators': [50, 100, 200, 300],
'max_features': ['auto', 'sqrt', 'log2'],
'max_depth': [None, 10, 20, 30, 40]
}
# 創建隨機搜索對象
random_search = RandomizedSearchCV(estimator=model, param_distributinotallow=param_dist, n_iter=100, cv=3, scoring='accuracy')
# 擬合隨機搜索
random_search.fit(X_train, y_train)
# 最優參數和最優得分
print("最優參數:", random_search.best_params_)
print("最高得分:", random_search.best_score_)
3.貝葉斯優化
貝葉斯優化是一種高效的全局優化技術,廣泛用于機器學習領域中模型超參數的調優。
這種方法利用貝葉斯統計理論,通過構建一個代理模型(通常是高斯過程)來預測目標函數的表現,并基于這個模型進行決策,以選擇新的參數值來測試。
優點:
- 高效且有效:在較少的函數評估次數內找到最優解,適用于評估代價高的情況。
- 適用于復雜空間:可以很好地處理非凸的優化問題。
缺點:
- 實現復雜:相對于網格搜索和隨機搜索,貝葉斯優化算法的實現和調試更為復雜。
- 計算密集型:在每一步都需要更新代理模型,可能需要高昂的計算成本,尤其是在參數維度非常高的情況下。
代碼示例
from bayes_opt import BayesianOptimization
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
# 定義目標函數
def rf_cv(n_estimators, max_features, max_depth):
estimator = RandomForestClassifier(
n_estimators=int(n_estimators),
max_features=min(max_features, 0.999), # 浮點類型
max_depth=int(max_depth),
random_state=2
)
cval = cross_val_score(estimator, X_train, y_train, scoring='accuracy', cv=5)
return cval.mean()
# 定義參數范圍
pbounds = {
'n_estimators': (50, 300),
'max_features': (0.1, 0.999),
'max_depth': (5, 50)
}
# 初始化貝葉斯優化
optimizer = BayesianOptimization(f=rf_cv, pbounds=pbounds, random_state=1)
# 執行優化
optimizer.maximize(init_points=2, n_iter=10)
# 輸出最優參數
print("最優參數:", optimizer.max['params'])
4.Hyperband
Hyperband 是一種基于多武裝賭博機的優化技術,利用資源分配和早期停止策略來快速找到最優參數。
這種方法主要適用于需要大量計算資源的情況,如大規模深度學習模型訓練。
優點:
- 快速且高效: 通過早期停止低效的模型來節省時間和資源,使得它在處理需要大量資源的訓練任務時特別有效。
- 動態資源分配:可以更智能地分配計算資源,優先給予表現良好的配置更多的資源。
缺點:
- 依賴于早期表現:基于早期停止策略,可能會錯過最初表現不佳但最終可能優化良好的配置。
- 實現復雜性:相較于其他方法,Hyperband 的實現更為復雜,需要對資源管理和調度有較好的控制。
代碼示例
在這個例子中,我們定義了一個簡單的神經網絡,并用 Hyperband 算法來調整網絡中的隱藏層單元數和學習率。
此外,我們使用了 Fashion MNIST 數據集來訓練和驗證模型。
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from kerastuner.tuners import Hyperband
def build_model(hp):
model = keras.Sequential()
model.add(layers.Flatten(input_shape=(28, 28)))
# 使用hp.Int()來定義學習的參數
model.add(layers.Dense(units=hp.Int('units', min_value=32, max_value=512, step=32), activatinotallow='relu'))
model.add(layers.Dense(10, activatinotallow='softmax'))
model.compile(
optimizer=keras.optimizers.Adam(
hp.Choice('learning_rate', [1e-2, 1e-3, 1e-4])),
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
return model
# 加載數據
(x_train, y_train), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()
x_train = x_train.astype('float32') / 255
x_test = x_test.astype('float32') / 255
# 初始化Hyperband調優器
tuner = Hyperband(
build_model,
objective='val_accuracy',
max_epochs=40,
directory='my_dir',
project_name='hyperband_tuning'
)
# 執行超參數搜索
tuner.search(x_train, y_train, epochs=10, validation_split=0.2)
# 獲取最優模型
best_model = tuner.get_best_models(num_models=1)[0]
best_model.evaluate(x_test, y_test)