機械学習 (14): 高度なハイパーパラメータ調整_RandomizedSearchCV と HalvingSearchCV

全文総文字数は19,000文字以上、読了時間の目安は約40~60分|乾物も充実、コレクションもオススメ!

ここに画像の説明を挿入
コードとデータセットのダウンロード

1. ハイパーパラメータの最適化と列挙グリッドの理論的制限

1.1 ハイパーパラメータの最適化 (HPO、HyperParameter Optimization)

ハイパーパラメーターの最適化 (HPO、HyperParameter Optimization) は機械学習の重要なタスクであり、その主な目標は、特定のタスクでモデルのパフォーマンスを最適化するための最適なモデルのハイパーパラメーター構成を見つけることです。

機械学習には、次の 2 種類のパラメータがあります。

  1. モデル パラメーター: これらは、トレーニング中にモデルが学習するパラメーターです。たとえば、線形回帰の傾きと切片。これらのパラメーターは、勾配降下法などの最適化アルゴリズムを通じて更新および学習されます。
  2. ハイパーパラメータ: これらのパラメータはトレーニング中に学習できませんが、事前に設定する必要があります。たとえば、学習率、トレーニング エポック数などです。ハイパーパラメーターの設定は、モデルのパフォーマンスに大きな影響を与えます。

ハイパーパラメーターの最適化は、検証セットでのモデルのパフォーマンスを最大化するために、これらのハイパーパラメーターの最適な設定を見つけることです。理論的には、コンピューティング能力とデータが十分であれば、HPO のパフォーマンスは人間のパフォーマンスを超えるはずですHPO は人間の作業負荷を軽減し、HPO によって得られた結果は検索よりも再現される可能性が高いため、科学研究の再現性と公平性を大幅に向上させることができます。現在、ハイパーパラメータ最適化アルゴリズムは主に次のように分類できます。

211

1.2 列挙グリッドの理論的限界

「ハイパーパラメータ調整の概要: 列挙型グリッド検索を理解するための記事」では、この記事では、ハイパーパラメータとは何か、およびグリッド検索を通じてハイパーパラメータを最適化する方法について説明します。

すべてのハイパーパラメータ最適化アルゴリズムの中で、列挙グリッド検索は最も基本的で古典的な方法です。検索を開始する前に、各ハイパーパラメータの代替値を 1 つずつ手動でリストし、複数の異なるハイパーパラメータの異なる値を配置して組み合わせてパラメータ空間 (パラメータ空間) を形成する必要があります。列挙グリッド検索アルゴリズムは、このパラメーター空間内のすべてのパラメーターの組み合わせをトレーニング用のモデルに取り込み、最終的に最も強い汎化能力を持つ組み合わせをモデルの最終ハイパーパラメーターとして選択します。

グリッド検索の場合、パラメーター空間内の特定の点が損失関数の実際の最小値を指している場合、グリッド検索を列挙するときに最小値と対応するパラメーターをキャプチャする必要があります (パラメーター空間がポイントを指さない場合、相対的に)損失関数の実際の最小値に一致する場合、グリッド検索では最小値に対応するパラメータの組み合わせを見つけることができません)。

パラメータ空間が大きく密度が高いほど、パラメータ空間内の組み合わせが損失関数の最小点をちょうどカバーする可能性が高くなります。つまり、極端な場合、パラメータ空間がすべての可能な値を使い果たす場合、グリッド検索は損失関数の最小値に対応する最適なパラメータの組み合わせを見つけることができなければならず、パラメータの組み合わせの一般化能力は、マニュアルチューニングに強い。

ただし、グリッド検索の欠点も非常に明白であり、特にパラメーター空間が大きい場合、グリッド検索には多くの時間と計算リソースが必要であり、パラメーターの次元が増加すると、グリッド検索に必要な計算量が指数関数的に増加します。ランダム フォレストを例に挙げます。

パラメーター n_estimators は 1 つだけあり、代替範囲は [50, 100, 150, 200, 250, 300] で、これを 6 回モデル化する必要があります
パラメータ max_ Depth を増やすと、代替範囲は [2,3,4,5,6] となり、30回モデル化する必要があります。
パラメーター min_sample_split を追加すると、代替範囲は [2,3,4,5] となり、120回モデル化する必要があります。

同時に、パラメーター最適化の目的は、モデルの汎化能力が最も強い組み合わせを見つけることであるため、モデルの汎化能力を反映するために相互検証が必要です。相互検証の数が 5 であると仮定します。 、3 つのパラメータを 600 回モデル化する必要があります。

人工ニューラル ネットワーク、融合モデル、および多くのハイパーパラメータと無限のハイパーパラメータ値を含む統合モデルに直面すると、データとモデルの複雑さが増すにつれてグリッド検索に必要な時間が急激に増加します。グリッド検索の実行には数日かかる場合があります。そして夜。

この問題を解決するために、研究者らはランダム検索とステップバイステップ検索という 2 つの戦略を提案しました。この記事では、前回の記事のテーマを継続し、これら 2 つの効率的な検索戦略を詳しく紹介し、そのパフォーマンスを比較します。

列挙型グリッド検索についてよくわからない場合は、この記事を読むことをお勧めします:
ハイパーパラメータ調整の概要: 列挙型グリッド検索を理解するための 1 つの記事

1.3 実践的な運用:<Kaggle競合事例:住宅価格予測>よりGridSearchCVを見てみる

競争の目的とデータの説明

このコンペティションの主な目的は、住宅の最終価格を予測することです。これは、連続的な生産量 (住宅価格) を予測する必要があるため、典型的な回帰問題です。

このデータセットには、品質、状態、平方フィート、ガレージの数、地下室の状態など、アイオワ州エイムズの住宅のほぼすべての側面を記述する 79 の説明変数が含まれています。これらの変数はすべて、住宅の最終販売価格を予測するために使用できます。

データセットはトレーニング セットとテスト セットに分かれています。トレーニング セットはモデルの構築とトレーニングに使用され、テスト セットはモデルのパフォーマンスの評価に使用されます。トレーニング セットには住宅の特徴とそれに対応する販売価格が含まれていますが、テスト セットには住宅の特徴のみが含まれており、出場者はこれらの住宅の販売価格を予測する必要があります。

この競争の評価指標は、予測値の対数と観測された販売価格の対数の間の二乗平均平方根誤差 (RMSE) です。これは、予測価格と実際の価格の間の誤差が二乗され、平均され、最後に平方根として計算されることを意味します。生の価格の代わりに対数を使用すると、高すぎるまたは低すぎる価格を予測する際の大きな誤差が最小限に抑えられます。

ベンチマークの構築: ランダム フォレストを使用して列挙グリッド検索を実行する

ステップ 1: 基本ライブラリをインポートする

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_validate, KFold, GridSearchCV

import time

ステップ 2: データセットをインポートします (基本的な処理が完了したトレーニング セットをそのまま使用できます)

data = pd.read_csv("../datasets/House Price/train_encode.csv")

X = data.iloc[:,:-1]
y = data.iloc[:,-1]

data

画像-20230710101123554

ステップ 3: 基本的なデータ探索

# 显示数据集的基本信息(列名、数据类型、非空值数量等)
print(data.info())

# 数据的统计信息
print(data.describe())

# 检查缺失值
print(data.isnull().sum())

# 检查目标列(如果是监督学习的情况)
print(data['SalePrice'].describe())

# 数据分布情况,例如绘制柱状图、箱线图等(需要matplotlib或seaborn库)
plt.hist(data['SalePrice'])
plt.show()

ステップ 4: パラメータ空間を構築する

このパラメーター グリッドは、入力ランダム フォレスト パラメーターに対して総当たり検索を実行し、考えられるすべてのパラメーターの組み合わせに対してモデル トレーニングを実行し、事前に決定されたスコア基準に従って最適なパラメーターのセットを選択するために使用されます。

#参数空间
param_grid_simple = {
    
    "criterion": ["squared_error","poisson"]
                     , 'n_estimators': [*range(20,100,5)]
                     , 'max_depth': [*range(10,25,2)]
                     , "max_features": ["log2","sqrt",16,32,64,"auto"]
                     , "min_impurity_decrease": [*np.arange(0,5,10)]
                    }

ステップ5: グリッド検索をインスタンス化して構築する

グリッド検索のパラメーターとモデルを設定します。スコアリング方法は「neg_mean_squared_error」、つまり負の平均二乗誤差です。負の値は、sklearn がモデルを選択するときに最もスコアの高いモデルを選択するためです。二乗誤差は誤差を小さくするために使用され、スコアが高くなります。

model_rf = RandomForestRegressor(random_state=24, verbose=True,)
cv = KFold(n_splits=5, shuffle=True, random_state=24)
search = GridSearchCV(estimator=model_rf,
                     param_grid=param_grid_simple,
                     scoring = "neg_mean_squared_error",
                     verbose = True,
                     cv = cv,
                     n_jobs=-1)

ステップ 6: トレーニングと時間を計算する

モデルのトレーニングを実行し、消費された時間を「分 + 秒」の形式で出力します。divmod()この関数は 2 つの値を返します。最初の値は商 (分)、2 番目の値は余り (秒) であることに注意してください。

start = time.time()
search.fit(X, y)
end = time.time()

elapsed_time = end - start # 得到的时间是秒级别的
minutes, seconds = divmod(elapsed_time, 60) # 将秒转换为分钟和秒
print(f"Elapsed time: {
      
      int(minutes)} minutes {
      
      int(seconds)} seconds")

画像-20230710105010207

上記のプロセスでは、GridSearchCV と 5 分割交差検証法を使用して、1536 の異なるパラメーターの組み合わせの中から最適なパラメーターを見つけます。合計 7,680 のモデルがトレーニングされ、評価されました。このプロセスには合計 3 分 2 秒かかりました。最後に、見つかった最適なパラメーターを使用して、すべてのデータに対してモデルがトレーニングされました。これには 0.1 秒かかりました。

ステップ 7: 最適なパラメーターに従ってモデルを再構築し、パフォーマンスを評価する

次のコードは、GridSearchCV の最適モデルを取得し、最適モデルの RMSE を計算して出力し、次にこの最適モデルを相互検証に使用し、最後にトレーニング データとテスト データの RMSE を計算して出力するために使用されます。モデルのパフォーマンスを評価するため。

from sklearn.metrics import mean_squared_error
import warnings

# 获取最优模型
best_estimator = search.best_estimator_

# 打印最优模型
print("Best estimator:")
print(best_estimator)

# 获取GridSearchCV的最优分数(注意:这是负的MSE)
best_score = search.best_score_

# 将负的MSE转换为RMSE
rmse = np.sqrt(-best_score)

# 打印RMSE
print(f"RMSE of the best estimator found by GridSearchCV: {
      
      rmse:.4f}")

# 使用最优模型进行交叉验证,返回训练得分
from sklearn.model_selection import cross_validate
scores = cross_validate(best_estimator, X, y, cv=5, scoring='neg_mean_squared_error', return_train_score=True)

# 计算训练和测试的RMSE
train_rmse = np.sqrt(-scores['train_score'].mean())
test_rmse = np.sqrt(-scores['test_score'].mean())

# 打印训练和测试的RMSE
print(f"Train RMSE: {
      
      train_rmse:.4f}")
print(f"Test RMSE: {
      
      test_rmse:.4f}")

注意すべき点が 1 つあります。RMSE を計算する場合、np.sqrt(-scores). これは、GridSearchCV 関数とcross_validate 関数が「neg_mean_squared_error」スコアを計算するときに負の値を取るためです (これらの関数ではスコアが高いほどパフォーマンスが良いことを表しますが、MSE では値が低いほどパフォーマンスが良いことを表すためです)。したがって、RMSE を計算するときは、最初に負の値を取得し、次に平方根を取得する必要があります。

画像-20230710111849016

ステップ 8: 結論の出力

213

説明: GridSearchCV のプロセスは相互検証 (CV) に基づいており、パラメーターのセットごとに複数 (通常 5 または 10) の検証が実行されて平均値が計算され、このプロセスはある程度まで削減されます。 . 適合する可能性。したがって、得られた最適スコア (27984) は、すべての相互検証セットの平均として計算されます。

次に、この最適なパラメーターを使用してモデルを再トレーニングし、相互検証を実行すると、各データ分割 (つまり、トレーニング セットとテスト セットの分割) のデータが異なる可能性があるため、トレーニング セットとテスト セットで異なる結果が得られる可能性があります。 。したがって、このステップで得られる RMSE (29731) は異なる場合があります。

機械学習モデルのパフォーマンスは、データの分布、モデルの複雑さ、トレーニング データとテスト データの分割方法など、多くの要因によって影響を受けるため、この現象は実際には非常に一般的です。したがって、同じモデルであっても、異なるデータセットでは異なる結果が得られる可能性があります。

2. RandomizedSearchCVの概要

2.1 RandomizedSearchCVの基本概念

前の 2 つのセクションで説明したように、従来のグリッド検索方法 (GridSearchCV) は、事前に設定されたパラメーター空間を検索して最適なパラメーターを見つけます。ただし、特定の範囲内で最適な解を見つけることは保証できますが、パラメーター空間が増加すると、コンピューティングは必要な時間とリソースは飛躍的に増加します。たとえば、パラメータが 10 個あり、各パラメータに 5 つの可能な値がある場合、 5 10 = 9 , 765 , 625 5^{10} = 9,765,625となります。510=9 765 試行できるパラメータの組み合わせは625通りあり、非常に時間がかかります。

列挙型グリッド検索を使用する上記のプロセスを注意深く見ると、列挙型グリッド検索の動作速度を決定する 2 つの要素があることがわかります

1. パラメータ空間のサイズ: パラメータ空間が大きいほど、より多くのモデリング時間が必要になります。

2. データ ボリュームのサイズ: データ ボリュームが大きくなるほど、各モデリングに必要な計算能力と時間が増加します。

したがって、sklearn のグリッド検索最適化手法には主に 2 つのカテゴリが含まれます。1 つは検索空間を調整する方法、もう 1 つはトレーニングごとにデータを調整する方法です。このうち、パラメータ空間を調整する具体的な方法は、本来の検索で使用する必要があるグローバルハイパーパラメータ空間を放棄し、代わりにいくつかのパラメータの組み合わせを選択し、ハイパーパラメータ部分空間を構築し、その部分空間内でのみ検索を行うことです。

この問題を解決するために、RandomizedSearchCVが登場しました。GridSearchCV と比較すると、RandomizedSearchCV は考えられるすべてのパラメータの組み合わせを試行するのではなく、パラメータ空間内の組み合わせの一部をランダムにサンプリングして試行します。これにより、検索時間とコンピューティング リソースの消費量が大幅に削減されるだけでなく、多くの場合、RandomizedSearchCV のパフォーマンスは GridSearchCV に劣りません。

コードを見てください:

# 假设的参数组合
n_estimators = np.array([50,100,150,200,250,300])
max_depth = np.array([2,3,4,5,6])

# 创建参数组合的网格
param_grid = np.array(np.meshgrid(n_estimators, max_depth)).T.reshape(-1,2)

# 随机选择一部分参数组合来模拟随机搜索
np.random.seed(0)
param_grid_random = param_grid[np.random.choice(param_grid.shape[0], size=8, replace=False), :]

# 创建子图
fig, ax = plt.subplots(1, 2, figsize=(10, 5))

# 左图:网格搜索
ax[0].scatter(param_grid[:, 0], param_grid[:, 1], color='blue')
ax[0].set_title('Grid Search')
ax[0].set_xlabel('n_estimators')
ax[0].set_ylabel('max_depth')

# 右图:随机搜索
ax[1].scatter(param_grid[:, 0], param_grid[:, 1], color='blue', alpha=0.3)  # 画出所有的参数组合
ax[1].scatter(param_grid_random[:, 0], param_grid_random[:, 1], color='red')  # 画出被随机选择的参数组合
ax[1].set_title('Randomized Search')
ax[1].set_xlabel('n_estimators')
ax[1].set_ylabel('max_depth')

plt.tight_layout()
plt.show()

下図の2次元空間は一例であり、n_estimatorsとmax_ Depthで構成されるパラメータ空間において、n_estimatorsの値は[50,100,150,200,250,300]、max_ Depthの値は[2,3,4]と仮定します。 ,5,6]. 次に、列挙型グリッド検索では、30 個のパラメーターの組み合わせすべてを検索する必要があります。検索空間を調整する場合、実際には、オレンジ色のパラメータの組み合わせのみが「部分空間」としてサンプリングされ、オレンジ色のパラメータの組み合わせのみが検索されます。これにより、探索全体に必要な計算量が大幅に削減され、当初は 30 個のモデリングが必要でしたが、8 個のモデリングのみで済みます。

画像-20230711082717313

2.2 RandomizedSearchCVの動作原理

sklearnでは、パラメータの部分空間をランダムに抽出して部分空間内を検索する方法をRandomizedSearchCVと呼びます。検索空間が狭くなったことで、列挙して比較する必要があるパラメータ グループの数もそれに応じて減り、それに応じて全体の検索時間も短縮されます。

同じグローバル空間を設定する場合、ランダム検索は列挙型グリッド検索よりもはるかに高速です

同じトレーニング回数を設定する場合、ランダム検索は列挙型グリッド検索よりもはるかに広い領域をカバーできます。

また、良いことに、ランダム グリッド検索からの最小損失は、列挙グリッド検索からの最小損失に非常に近いです

検索の精度をあまり損なうことなく計算速度が向上していると言えます。

RandomizedSearchCV の動作原理は非常にシンプルです。**事前に設定されたパラメータ空間と事前に設定された試行回数が与えられると、トレーニングと検証のためにパラメータ空間内のパラメータの組み合わせの一部がランダムに選択され、最終的に試行されたパラメータの組み合わせパラメータの中で最も優れたパフォーマンスを発揮するグループが返されます。**ただし、ランダム グリッド検索が実際に実行されるときは、最初に部分空間をサンプリングしてから部分空間を検索するのではなく、あたかも「ループ反復」であるかのように、この反復 A セットでランダムに 1 を選択することに注意してくださいのパラメータがモデリングに使用され、次の反復でのモデリング用にパラメータのセットがランダムに選択されます。このランダム サンプリングは置き換えられないため、同じパラメータのセットを 2 回描画しても問題はありません。ランダム グリッド サーチの反復回数を制御することで、全体として抽出されるパラメータ部分空間のサイズを制御できます。このアプローチは、よく「ランダム グリッド サーチに一定の計算量を与える」と呼ばれます。計算量がすべて消費されると、ランダム グリッド検索が停止します。」

このようなアプローチに基づく仮定は、すべてのパラメーターがモデルのパフォーマンスに同等に重要な影響を与えるわけではなく、一部の重要なパラメーターの変更は他のパラメーターよりもモデルのパフォーマンスに大きな影響を与えるということです。ランダム サンプリングを通じて、これらの重要なパラメーターの最適値が見つかる可能性が高く、その結果、優れたパフォーマンスのモデルが得られます。

2.3 Sklearn における RandomizedSearchCV パラメータの解釈

まず、Sklearn の RandomizedSearchCV のパラメータを見てみましょう。

画像-20230711083421536

それを読んで:

135

ランダム グリッド検索が効果的である基本的な理由は次のとおりです。

サンプリングされた部分空間は、大域空間の分布をある程度フィードバックすることができ、部分空間が大きくなるほど (含まれるパラメーターの組み合わせが多くなるほど)、部分空間の分布は大域空間の分布に近づきます。

大域空間自体が十分に密度が高い場合、小さな部分空間も大域空間と同様の分布を得ることができます。

大域空間に損失関数の理論上の最小値が含まれる場合、大域空間分布に非常に類似した部分空間には、損失関数の最小値も含まれるか、または次に小さい一連の値が含まれる可能性があります。最小値に非常に近い

したがって、部分空間が十分に大きい限り、ランダム グリッド検索の効果は列挙グリッド検索と非常に類似している必要があります。グローバル パラメーター空間が固定されている場合、ランダム グリッド検索は効率と精度の間でトレードオフを行う可能性があります部分空間が大きいほど精度が高くなり、部分空間が小さいほど効率が高くなります。

2.4 実務運用:<Kaggle競合事例:住宅価格予測>よりRandomizedSearchCVを見てみる

RandomizedSearchCV と GridSearchCV の違いを直感的に理解するために、Kaggle の住宅価格予測を例として、ランダム フォレスト モデルを使用してみましょう。n_estimatorsランダム フォレストには、 (ツリーの数)、max_features(ツリーあたりの最大フィーチャ数)、max_depth(ツリーの最大深さ) など、調整できるパラメーターが多数あります。各パラメーターに 5 つの可能な値が設定されている場合、GridSearchCV の使用にはトレーニングと検証の5^3 = 125時間が必要です。ただし、RandomizedSearchCV を使用し、試行回数を 30 に設定すると、トレーニングと検証を 30 回行うだけで済み、計算の複雑さが大幅に軽減され、GridSearchCV と同様の結果を取得することも可能です。

セクション 1.3 の同じデータを引き続き使用します

ステップ 1: 基本ライブラリをインポートする

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import cross_validate, KFold, GridSearchCV

import time

ステップ 2: データセットをインポートします (基本的な処理が完了したトレーニング セットをそのまま使用できます)

data = pd.read_csv("../datasets/House Price/train_encode.csv")

X = data.iloc[:,:-1]
y = data.iloc[:,-1]

data

画像-20230710101123554

ステップ 3: 同じグローバル パラメータ空間を構築する

#创造参数空间 - 使用与网格搜索时完全一致的空间,以便于对比
param_grid_simple = {"criterion": ["squared_error","poisson"]
                     , 'n_estimators': [*range(20,100,5)]
                     , 'max_depth': [*range(10,25,2)]
                     , "max_features": ["log2","sqrt",16,32,64,"auto"]
                     , "min_impurity_decrease": [*np.arange(0,5,10)]
                    }

ステップ 4: ランダム グリッド検索をインスタンス化して構築します。部分空間サイズは 800 にのみ設定されます (グリッド検索の検索パラメーターは 1536)。

model_rf1 = RandomForestRegressor(random_state=24, verbose=True,)
cv = KFold(n_splits=5, shuffle=True, random_state=24)

#定义随机搜索
search1 = RandomizedSearchCV(estimator=model_rf1
                            ,param_distributions=param_grid_simple
                            ,n_iter = 800 #子空间的大小是全域空间的一半左右
                            ,scoring = "neg_mean_squared_error"
                            ,verbose = True
                            ,cv = cv
                            ,random_state=24
                            ,n_jobs=-1
                           )

ステップ 5: トレーニングと時間を計算する

モデルのトレーニングを実行し、消費された時間を「分 + 秒」の形式で出力します。divmod()この関数は 2 つの値を返します。最初の値は商 (分)、2 番目の値は余り (秒) であることに注意してください。

start = time.time()
search1.fit(X, y)
end = time.time()

elapsed_time = end - start # 得到的时间是秒级别的
minutes, seconds = divmod(elapsed_time, 60) # 将秒转换为分钟和秒
print(f"Elapsed time: {
      
      int(minutes)} minutes {
      
      int(seconds)} seconds")

画像-20230711091512571

上記のプロセスでは、RandomizedSearchCV と 5 分割交差検証法を使用して、800 の異なるパラメーターの組み合わせの中から最適なパラメーターを見つけます。合計 4000 のモデルがトレーニングされ、評価されます。このプロセスには合計 1 分 33 秒かかりました。最後に、見つかった最適なパラメーターを使用して、すべてのデータに対してモデルがトレーニングされました。これには 0.1 秒かかりました。

ステップ 6: 最適なパラメーターに従ってモデルを再構築し、パフォーマンスを評価する

次のコードは、RandomizedSearchCV の最適モデルを取得し、最適モデルの RMSE を計算して出力し、次にこの最適モデルを相互検証に使用して、最後にトレーニング データとテスト データの RMSE を計算して出力するために使用されます。モデルのパフォーマンスを評価するため。

from sklearn.metrics import mean_squared_error
import warnings

# 获取最优模型
best_estimator = search1.best_estimator_

# 打印最优模型
print("Best estimator:")
print(best_estimator)

# 获取GridSearchCV的最优分数(注意:这是负的MSE)
best_score = search1.best_score_

# 将负的MSE转换为RMSE
rmse = np.sqrt(-best_score)

# 打印RMSE
print(f"RMSE of the best estimator found by GridSearchCV: {
      
      rmse:.4f}")

# 使用最优模型进行交叉验证,返回训练得分
scores = cross_validate(best_estimator, X, y, cv=5, scoring='neg_mean_squared_error', return_train_score=True)

# 计算训练和测试的RMSE
train_rmse = np.sqrt(-scores['train_score'].mean())
test_rmse = np.sqrt(-scores['test_score'].mean())

# 打印训练和测试的RMSE
print(f"Train RMSE: {
      
      train_rmse:.4f}")
print(f"Test RMSE: {
      
      test_rmse:.4f}")

画像-20230711091956533

ステップ 7: 結論の出力

136

全体として、ランダム グリッド検索は比較的短い時間で列挙型グリッド検索と同じくらい優れたモデルを見つけます。これは、大規模なパラメーター空間を検索する場合のランダム グリッド検索の利点を示しています。ただし、小規模なパラメーター空間の場合は、列挙グリッド検索の方が正確な場合があります。さらに、現在の最適なモデルには過学習がある可能性があり、モデルのパラメーターをさらに調整するか、モデルの正則化の強度を高める、より複雑なモデル構造を使用するなど、過学習を防ぐための戦略を採用する必要がある場合があります。 。

3. RandomizedSearchCVの優れた機能

3.1 部分空間が大きいほど精度が高く、部分空間が小さいほど効率が高い

セクション 2.3 では、次のような結論があります。部分空間が十分に大きい限り、ランダム グリッド検索の効果は列挙グリッド検索と非常に似ているはずです。グローバル パラメーター空間が固定されている場合、ランダム グリッド検索は効率と精度の間でトレードオフを行う可能性があります

検証するには、より大きな検索スペースを設定し、ランダム グリッド検索を実行します。他のコードを変更する必要はありません。ステップ 3: 同じグローバル パラメーター スペースの構築のプロセスを変更するだけで済みます。

#创造参数空间 - 让整体参数空间变得更密
param_grid_simple = {'n_estimators': [*range(80,100,1)]
                     , 'max_depth': [*range(10,25,1)]
                     , "max_features": [*range(10,20,1)]
                     , "min_impurity_decrease": [*np.arange(0,5,10)]
                    }

model_rf1 = RandomForestRegressor(random_state=24, verbose=True,)
cv = KFold(n_splits=5, shuffle=True, random_state=24)

#定义随机搜索
search1 = RandomizedSearchCV(estimator=model_rf1
                            ,param_distributions=param_grid_simple
                            ,n_iter = 1536 #使用与枚举网格搜索类似的拟合次数
                            ,scoring = "neg_mean_squared_error"
                            ,verbose = True
                            ,cv = cv
                            ,random_state=24
                            ,n_jobs=-1
                           )

start = time.time()
search1.fit(X, y)
end = time.time()

elapsed_time = end - start # 得到的时间是秒级别的
minutes, seconds = divmod(elapsed_time, 60) # 将秒转换为分钟和秒
print(f"Elapsed time: {int(minutes)} minutes {int(seconds)} seconds")

実行結果を見てください。

画像-20230711104610725

画像-20230711104633582

もう一度比較してください:

137

グローバル パラメーター空間が拡大されると、ランダム グリッド サーチは、小さな空間でのグリッド サーチと同等かそれより短い時間を使用して、より高密度/より大きな空間を探索し、より良い結果を得ることができます。

3.2 連続パラメータスペースを受け入れる

グリッド検索の場合、パラメータ空間内の点は均等に分布し、均一な間隔で配置されます。これは、グリッド検索では特定の「分布」からデータを抽出できず、結合パラメータを使用して点を結合することしかできないためです。一方、ランダム検索は「分布」を入力として受け入れることができます。 。

損失関数の最低点が 2 つのパラメーター セットの間にある場合、この場合、列挙グリッド検索で最小値を見つけることは 100% 不可能です。しかし、ランダム グリッド検索の場合、パラメータ ポイントは同じパラメータ空間内の分布上でランダムに選択されるため、より良い値が得られる可能性が高くなります。

コードを見てください:

import scipy #使用scipy建立分布

param_grid_simple = {
    
    'n_estimators': [*range(80,100,1)]
                     , 'max_depth': [*range(10,25,1)]
                     , "max_features": [*range(10,20,1)]
                     , "min_impurity_decrease": scipy.stats.uniform(0,50)
                    }

model_rf1 = RandomForestRegressor(random_state=24, verbose=True,)
cv = KFold(n_splits=5, shuffle=True, random_state=24)

#定义随机搜索
search1 = RandomizedSearchCV(estimator=model_rf1
                            ,param_distributions=param_grid_simple
                            ,n_iter = 1536 #使用与枚举网格搜索类似的拟合次数
                            ,scoring = "neg_mean_squared_error"
                            ,verbose = True
                            ,cv = cv
                            ,random_state=24
                            ,n_jobs=-1
                           )

start = time.time()
search1.fit(X, y)
end = time.time()

elapsed_time = end - start # 得到的时间是秒级别的
minutes, seconds = divmod(elapsed_time, 60) # 将秒转换为分钟和秒
print(f"Elapsed time: {
      
      int(minutes)} minutes {
      
      int(seconds)} seconds")

結果を見てください:

画像-20230711105821576

画像-20230711105841472

もう一度比較してください:

138

理論的には、列挙型グリッド検索で使用されるグローバル パラメーター空間が十分に大きい/十分な密度がある場合、列挙型グリッド検索の最適解はランダム グリッド検索の上限となるため、理論上、ランダム グリッド検索は列挙型グリッド検索よりも良い結果は得られません

しかし実際の問題は、列挙型グリッド検索の速度が遅すぎるため、多くの場合、列挙型グリッド検索のグローバル パラメータ空間をあまり大きく設定できなかったり、非常に高密度に設定できなかったりするため、グリッド検索の結果が難しくなるということです。理論上の最適値に達します。ランダムグリッド探索では、空間をより大きく、より密に設定すると、より広い空間の分布を捉えることができ、当然理論上の最適値を捉えることが可能となります。

4. HalvingSearchCVの概要

6.1 HalvingSearchCVの基本概念

グリッド検索が遅いという問題を列挙すると、sklearn には 2 つの最適化方法があります。1 つは検索空間を調整する方法、もう 1 つはトレーニングごとにデータを調整する方法です。探索空間の調整方法はランダムグリッドサーチ、各学習データの調整方法はハーフグリッドサーチです。

HalvingSearchCV では、データのごく一部を使用してすべてのパラメーターの組み合わせを迅速に評価し、その後、より多くのデータを使用してさらに評価するために最もパフォーマンスの高いパラメーターの組み合わせのみを予約します。このようにして、パフォーマンスの悪いパラメータの組み合わせをすぐに除外できるため、より多くのリソースを有望なパラメータの組み合わせに集中させることができます。

例えば:

データセットDDがあるとします。D、データセットDDDからサブセットdd をd . データセットDD全体にパラメータのセットがある場合、Dのパフォーマンスが低い場合、このパラメータのセットがデータ セットのサブセットdddでのパフォーマンスはあまり良くありません。逆に、パラメータのセットがサブセットdddのパフォーマンスは良くないため、このパラメータのセットは完全なデータ セットDDDでのパフォーマンス。

サブセット内のパラメーターと完全なデータ セットのパフォーマンスは一貫しています。この仮定が正しい場合、グリッド検索では、毎回パラメーター セットを検証するためにすべてのデータを使用する代わりに、トレーニング データ。サブセットはハイパーパラメータのフィルタリングに使用され、これにより操作が大幅に高速化されます。

しかし、実際のデータでは、この仮定は条件付きです。つまり、サブセットの分布は完全なデータセット D の分布に似ています。サブセットの分布が完全なデータ セットの分布に近い場合、サブセットと完全なデータ セットに対する同じパラメーター セットのパフォーマンスが一貫している可能性が高くなります。ランダム グリッド検索における以前の結論によると、サブセットが大きいほど、その分布は完全なデータ セットの分布に近づきますが、サブセットが大きいとトレーニング時間が長くなるため、全体的なトレーニング効率を考えると、サブセットを無限に増やすことは不可能です。これにより矛盾が生じます。大規模なサブセットの結果の信頼性は高くなりますが、大規模なサブセットの計算は遅くなります。

6.2 HalvingSearchCVの動作原理

セミグリッド探索アルゴリズムには、サブセットのサイズと計算効率のバランスをうまくとることができる絶妙なプロセスが設計されています。具体的なプロセスを見てみましょう。

  1. 最初の段階では、HalvingSearchCV はトレーニング データのごく一部を使用してすべてのパラメーターの組み合わせを評価します。このフェーズは迅速に実行できますが、データのごく一部しか使用されないため、評価結果の精度が低くなる可能性があります。
  2. 第 2 段階では、HalvingSearchCV は第 1 段階の評価結果に基づいて、最もパフォーマンスの高いパラメーターの組み合わせの一部のみを保持します。このフェーズでは、より多くのデータを使用してこれらのパラメーターの組み合わせを評価し、より正確な結果をもたらします。
  3. HalvingSearchCV は上記のプロセスを繰り返し、パラメータの組み合わせが 1 つだけ残るまで、各ステージでパラメータの組み合わせの半分が削除されます。このパラメータの組み合わせは、HalvingSearchCV によって選択された最適なパラメータの組み合わせです。

例えば:

データセットDDがあるとします。D、データセットDDDからサブセットdd をd

  1. まず、小さなサブセットd 0 d_0が、置換なしで完全なデータセットからランダムにサンプリングされます。d0、そしてd 0 d_0でd0すべてのパラメータの組み合わせのパフォーマンスを確認します。d 0 d_0によるとd0上記の検証結果より、スコアが下位 1/2 にランクされるパラメータの組み合わせの半数が除外されます。
  2. 次に、完全なデータセットから置換せずに比率d 0 d_0をサンプリングします。d02 倍の大きさのサブセットd 1 d_1d1、そしてd 1 d_1でd1残り半分のパラメーターの組み合わせのパフォーマンスを確認します。d1 d_1によるとd1上記の検証結果より、スコアの下位 1/2 のパラメータの組み合わせは除外されます。
  3. 次に、完全なデータセットから、置換せずに比率d 1 d_1をサンプリングします。d12 倍の大きさのサブセットd 2 d_2d2、そしてd 2 d_2でd2残りの 1/4 パラメータの組み合わせのパフォーマンスを確認します。d 2 d_2によるとd2上記の検証結果によると、最後の1/2のスコアを持つパラメータの組み合わせは除外されます...

継続的なサイクル。S が最初の反復でのサブセットのサンプル サイズを表すために使用され、C がすべてのパラメーターの組み合わせの数を表す場合、反復プロセスでは、パラメーターの検証に使用されるデータ サブセットはますます大きくなり、その数は検証する必要があるパラメータの組み合わせはますます少なくなります。

反復 サブセットのサンプルサイズ パラメータの組み合わせ数
1 S C
2 2S 1 2 \frac{1}{2}21C
3 4S 1 4 \frac{1}{4}41C
4 8S 1 8 \frac{1}{8}81C
……
(Cが割り切れない場合は切り上げ)

候補パラメータの組み合わせが 1 セットしか残っていない場合、または利用可能なデータが不十分な場合、ループは停止します。

具体的には、1 n \frac{1}{n}の場合n1C <= 1 または nS > 母集団サンプルサイズの場合、検索は停止します

このモードでは、異なるサブセットで継続的に優れた結果が得られるパラメータの組み合わせのみを反復の後段まで保持することができ、最終的に選択されるパラメータの組み合わせは、すべてのサブセットで良好なパフォーマンスを発揮するパラメータの組み合わせである必要があります。このようなパラメーターの組み合わせが完全なデータに対して適切に機能する可能性は非常に高く、グリッド/ランダム検索から得られるものよりも優れた一般化機能を示す可能性もあります。

このアプローチの利点は、パフォーマンスの悪いパラメータの組み合わせを、完全にトレーニングして評価する必要がなく、すぐに除外できることです。したがって、HalvingSearchCV は通常、特にパラメーター空間が大きい場合やトレーニング データ セットが大きい場合、従来のグリッド検索やランダム検索よりも高速です。

6.3 Sklearn の HalvingSearchCV パラメータの解釈

まず、Sklearn の HalvingSearchCV のパラメータを見てみましょう。

画像-20230711125108735

それを読んで:

139

理解する必要があるパラメータは次のとおりです。

要因

各反復で追加されるサンプル サイズの比率は、各反復後に残されるパラメーターの組み合わせの比率でもあります。たとえば、factor=2 の場合、次の反復のサンプル サイズは前の反復の 2 倍になり、パラメーターの組み合わせの 1/2 が各反復後に残ります。Factor=3 の場合、次の反復のサンプル サイズは前の反復の 3 倍になり、パラメーターの組み合わせの 1/3 が各反復後に残ります。通常、このパラメータは 3 に設定するとより適切に機能します。

リソース

各反復で追加される検証リソースのタイプを文字列として入力して設定します。デフォルトはサンプル サイズで、入力は「n_samples」です。また、「n_estimators」や「n_iteration」など、アンサンブル アルゴリズムで正の整数を入力する弱分類器にすることもできます。

min_resource

最初の反復でパラメーターの組み合わせを検証するために使用されるサンプル サイズ r0。正の整数、または「最小」、「排気」という 2 つの文字列を入力できます。
正の整数 n を入力します。これは、最初の反復で n 個のサンプルが使用されることを示します。
「最小」と入力し、ルールに従って r0 を計算します。

リソース タイプがサンプル サイズの場合、回帰アルゴリズムの場合、r0 = 交差検証倍数 n_splits * 2

リソース タイプがサンプル サイズの場合、分類アルゴリズムの場合、r0 = カテゴリ数 n_classes_ * 交差検証倍数 n_splits * 2

リソースタイプがサンプルサイズではない場合は 1 に等しい

「exhaust」と入力し、最後の反復ラウンドで利用可能な最大リソースに従って r0 を反転します。たとえば、factor=2、サンプル サイズが 1000、合計 3 回の反復がある場合、反復の最後のラウンドで利用可能な最大リソースは 1000、最後から 2 番目のラウンドは 500、最後から 3 番目のラウンド (最初のラウンド) は 500 です。ラウンド)は250です。この時点では r0 = 250 です。「排出」モードでは良好な結果が得られる可能性が最も高くなりますが、計算コストがわずかに高くなり、計算時間もわずかに長くなります。

6.4 HalvingSearchCV の制限

HalvingSearchCV プロセスには問題が発生します。サブセットが大きいほど、サブセットの分布と完全なデータセット D はより類似しますが、半探索アルゴリズム全体では、最も小さいサブセットを使用して、ほとんどのパラメーターの組み合わせを選別します。初めに。初期サブセットの分布が完全なデータ セットと大きく異なる場合、完全なデータ セット D に有効な多くのパラメーターが、半グリッド検索の最初の数回の反復で除外される可能性があるため、最初の半グリッド検索はサブセットが小さすぎてはなりません。

6.5 実践的な操作: <Kaggle 競合事例: 住宅価格予測> の HalvingSearchCV を見てみる

前述の制限に従って、初期サブセットが小さすぎてはならず、半探索サンプリングが非置換サンプリングであるという前提の下では、データ全体のサンプル サイズが大きくなければなりません

実際のモデリング経験では、小さなデータセットに対するハーフグリッド検索のパフォーマンスは、ランダムグリッド検索や通常のグリッド検索ほど良くないことがよくあります。たとえば、上記で使用した Kaggle 住宅価格予測データセットは、ハーフグリッド検索を使用すると、検索結果は列挙グリッド検索ほど良くなく、検索時間が長いことがわかりました。ただし、大規模なデータ セット (サンプル サイズが w より大きいデータ セットなど) では、ハーフグリッド検索は計算速度と精度において大きな利点を示します。

したがって、セミグリッド検索を実装するときは、2w9 サンプルを含む一連の拡張住宅価格データ セットが使用されます。

ステップ 1: 基本ライブラリをインポートする

import numpy as np
import pandas as pd
import matplotlib as mlp
import matplotlib.pyplot as plt
import time
from sklearn.ensemble import RandomForestRegressor
from sklearn.experimental import enable_halving_search_cv
from sklearn.model_selection import KFold, HalvingGridSearchCV, cross_validate, RandomizedSearchCV

import re
import sklearn

ステップ 2: データセットをインポートします (基本的な処理が完了したトレーニング セットをそのまま使用できます)

data1 = pd.read_csv("./datasets/House Price/big_train.csv",index_col=0)

data1 

X = data1.iloc[:,:-1]
y = data1.iloc[:,-1]

画像-20230711124804444

ステップ 3: 同じグローバル パラメータ空間を構築する

#创造参数空间 - 使用与网格搜索时完全一致的空间,以便于对比
param_grid_simple = {"criterion": ["squared_error","poisson"]
                     , 'n_estimators': [*range(20,100,5)]
                     , 'max_depth': [*range(10,25,2)]
                     , "max_features": ["log2","sqrt",16,32,64,"auto"]
                     , "min_impurity_decrease": [*np.arange(0,5,10)]
                    }

ステップ 4: 因子とパラメーターの組み合わせを決定する

セミグリッド検索アプリケーションの場合、最も難しい部分は、検索自体のパラメータの複雑な組み合わせを決定することです。

パラメーターを調整するときに、パラメーター空間内のすべての代替の組み合わせを完全に検証したい場合は、反復回数が小さすぎてはならず (たとえば、反復が 3 回だけ)、係数が大きすぎてはなりません。ただし、係数が小さすぎると反復回数が増加し、検索全体の実行時間が長くなります。同時に、反復回数は、最終的に使用できるデータの量と、反復の完了後にさらに検証する必要があるパラメーターの組み合わせの数にも影響しますが、どちらも小さすぎてはなりません。したがって、一般にハーフグリッド検索を使用する場合は、次の 3 つの点を考慮する必要があります。

1. min_resources の値は小さすぎてはならず、すべての反復が終了する前にできるだけ多くのデータを使用することが望まれます 2. 反復が完了した後、残りの検証パラメータの組み合わせが多すぎてはいけません

。 10 未満であることが最善で、それが不可能な場合は 30 未満でも許容されます

。 3. 反復回数は多すぎてはなりません。そうしないと、時間が長すぎる可能性があります。

factor = 1.5
n_samples = X.shape[0]
min_resources = 500
space = 1536

for i in range(100):
    if (min_resources*factor**i > n_samples) or (space/factor**i < 1):
        break
    print(i+1,"本轮迭代样本:{}".format(min_resources*factor**i)
          ,"本轮验证参数组合:{}".format(space//factor**i + 1))

画像-20230711130110342

ステップ 5: ハーフグリッド検索をインスタンス化して構築する

model_rf2 = RandomForestRegressor(random_state=24, verbose=True,)
cv = KFold(n_splits=5, shuffle=True, random_state=24)

#定义对半搜索
search2 = HalvingGridSearchCV(estimator=model_rf2
                            ,param_grid=param_grid_simple
                            ,factor=1.5
                            ,min_resources=500
                            ,scoring = "neg_mean_squared_error"
                            ,verbose = True
                            ,random_state=1412
                            ,cv = cv
                            ,n_jobs=-1)

ステップ 6: トレーニングと時間を計算する

モデルのトレーニングを実行し、消費された時間を「分 + 秒」の形式で出力します。divmod()この関数は 2 つの値を返します。最初の値は商 (分)、2 番目の値は余り (秒) であることに注意してください。

start = time.time()
search2.fit(X, y)
end = time.time()

elapsed_time = end - start # 得到的时间是秒级别的
minutes, seconds = divmod(elapsed_time, 60) # 将秒转换为分钟和秒
print(f"Elapsed time: {
      
      int(minutes)} minutes {
      
      int(seconds)} seconds")

画像-20230711132344156

異なるデータセットが使用されているため、GridSearchCV や RandomizedSearchCV とは比較できなくなりました。

V. 結論

このペーパーでは、理論的な観点から従来の列挙グリッド検索の限界を分析し、より効率的な 2 つのハイパーパラメータ検索方法、RandomizedSearchCV と HalvingSearchCV を紹介します。動作原理、パラメーター設定、使用シナリオを詳細に説明し、特定の Kaggle コンペティションの事例を通じて、読者がこれら 2 つの方法の利点と制限をより直観的に理解できるように支援します。

この記事を読むと、RandomizedSearchCV と HalvingSearchCV の基本概念と動作原理を理解でき、独自のニーズとコンピューティング リソース手法の制限に応じて、特定の機械学習問題で適切なハイパーパラメーター検索を選択して使用できるようになります。さらに、さまざまなパラメーター空間を選択することで、検索の精度と効率のバランスを取る方法を学びます。

次の記事では、より高度でインテリジェントなハイパーパラメータ最適化手法であるベイジアン最適化を紹介します。この方法では、事前知識とベイズ推論を使用して、より小さい検索空間でより適切なパラメーターの組み合わせを見つけます。

最後に、この記事を読んでいただきありがとうございます! 何か得をしたと感じたら、ぜひ「いいね!」「ブックマーク」「フォロー」をしてください。これが私が創作を続けるモチベーションです。ご質問やご提案がございましたら、コメント欄にメッセージを残してください。できる限りお答えし、フィードバックを受け付けます。知りたい特定のトピックがございましたら、お知らせください。喜んでそれに関する記事を書きます。

ご支援に感謝し、あなたと一緒に成長することを楽しみにしています!

おすすめ

転載: blog.csdn.net/Lvbaby_/article/details/131666028