web-dev-qa-db-ja.com

Kerasとsklearn GridSearchCVの相互検証による早期停止

KerasとskleanのGridSearchCVを使用して早期停止を実装したいと思います。

以下の作業用コードの例は、 ディープラーニングモデルのハイパーパラメーターをグリッド検索する方法Python With Keras から変更されています。データセットは ここからダウンロードできます。

この変更により、Keras EarlyStoppingコールバッククラスが追加され、過剰適合が防止されます。これを有効にするには、検証の精度を監視するためのmonitor='val_acc'引数が必要です。 val_accを使用するには、KerasClassifierが検証精度を生成するためにvalidation_split=0.1を必要とし、それ以外の場合はEarlyStoppingRuntimeWarning: Early stopping requires val_acc available!をレイズします。 FIXME:コードのコメントに注意してください!

val_accval_lossに置き換えることができます。

質問:の10%を無駄にする代わりに、GridSearchCV k-foldアルゴリズムによって生成された交差検証データセットを使用するにはどうすればよいですか?早期停止検証セットのトレーニングデータ?

# Use scikit-learn to grid search the learning rate and momentum
import numpy
from sklearn.model_selection 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

# Early stopping
from keras.callbacks import EarlyStopping
stopper = EarlyStopping(monitor='val_acc', patience=3, verbose=1)

# 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,
    epochs=100, batch_size=10,
    validation_split=0.1, # FIXME: Instead use GridSearchCV k-fold validation data.
    verbose=2)
# define the grid search parameters
learn_rate = [0.01, 0.1]
momentum = [0.2, 0.4]
param_grid = dict(learn_rate=learn_rate, momentum=momentum)
grid = GridSearchCV(estimator=model, param_grid=param_grid, verbose=2, n_jobs=1)

# Fitting parameters
fit_params = dict(callbacks=[stopper])
# Grid search.
grid_result = grid.fit(X, Y, **fit_params)

# summarize results
print("Best: %f using %s" % (grid_result.best_score_, grid_result.best_params_))
means = grid_result.cv_results_['mean_test_score']
stds = grid_result.cv_results_['std_test_score']
params = grid_result.cv_results_['params']
for mean, stdev, param in Zip(means, stds, params):
    print("%f (%f) with: %r" % (mean, stdev, param))
24
Justin Solms

[質問が編集および明確化された後の回答:]

実装の問題に突入する前に、方法論とタスク自体について考えるのに時間をかけることは常に良い習慣です。おそらく、早期停止を相互検証手順と混ぜることはnotが良い考えです。

議論を強調するための例を作ってみましょう。

実際に、100エポックの早期停止と、ハイパーパラメーター選択のための5分割交差検証(CV)を使用するとします。また、ハイパーパラメータセットXが最高のパフォーマンスを提供することになるとします。たとえば、89.3%のバイナリ分類精度です。

次に、2番目に優れたハイパーパラメーターセットYが89.2%の精度を与えると仮定します。個々のCVフォールドを詳しく調べると、ベストケースXでは、5つのCVフォールドのうち3つが最大100エポックを使い果たしましたが、他の2つの早期停止では、それぞれ89エポックと93エポックになりました。

次に、2番目に優れたセットYを調べると、5つのCVフォールドのうち4つが100エポックを使い果たし、5番目が約80エポックで早く停止したことがわかります。

そのような実験からあなたの結論は何でしょうか?

間違いなく、あなたは決定的でない状況にいることでしょう。さらに実験を行うと、実際に最も優れたハイパーパラメーターセットが明らかになる可能性があります。もちろん、最初にこれらの結果の詳細を調べようと考えた場合は、そして言うまでもなく、これらすべてがコールバックによって自動化された場合、実際に試してみたにもかかわらず、最良のモデルを見逃した可能性があります。


CVのアイデア全体は、「他のすべてが等しい」という議論に暗黙的に基づいています(もちろん、これは実際には決して当てはまりません。可能な限り最善の方法で概算されます)。エポックの数をハイパーパラメータにする必要があると思われる場合は、早期停止のバックドアから挿入するのではなく、それをCVに明示的に含めるだけで、プロセス全体を危険にさらす可能性があります(早期停止自体にハイパーパラメータpatience)があります。

これらの2つの手法を混在させないことは、もちろんそれらを使用できない順次に使用できないことを意味するわけではありません:CVを通じて最高のハイパーパラメータを取得したら、いつでも使用できますトレーニングセット全体にモデルを当てはめると、早期に停止します(もちろん、個別の検証セットがある場合)。


ディープニューラルネットの分野はまだ(非常に)若く、「ベストプラクティス」のガイドラインをまだ確立していないことは事実です。驚くべきコミュニティのおかげで、オープンソースの実装ではあらゆる種類のツールが利用可能であり、たまたま利用できるという理由だけで物事を混合する(確かに魅力的な)位置に容易に気付くことができるという事実を追加してください。これがあなたがここでしようとしていることであるとは必ずしも言っていません-一緒に機能するように設計されていない可能性のあるアイデアを組み合わせる場合は、さらに注意を促しています...

24
desertnaut

私は砂漠の飛行士に同意しません(しかし、コメントについての評判はありません)。早期停止では、エポックカウントのセットについて、どのハイパーパラメーターセットが検出されたのに貢献したのかが分からないのは事実です。しかし、これはそもそも問題ではありませんでした。メソッドが尋ねたのは、「与えられた最大で nエポックで、早期停止を使用して、最高のハイパーパラメータは何ですか?」でした。はい、早期に停止すると、グリッド検索で最適化する必要があるかどうかに関係なく、ハイパーパラメータがさらに導入されますが、これはモデル内のすべてのハイパーパラメータに当てはまります。実際、グリッド検索中の早期停止は、最初に停止するよりも、グリッド検索後に行う方が理にかなっていると思います。

2
user1721082

[質問が編集および明確化される前の古い回答-上記の更新され承認された回答を参照]

私はあなたの正確な問題を理解したかどうかわかりません(あなたの質問は非常に不明確であり、あなたはSO質問をするときに決して良くない多くの無関係な詳細を含んでいます-参照 ここ) )。

検証データに関する引数をmodel = KerasClassifier()関数呼び出しに含めないでください(実際には含めないでください)(それはここでもtrainingデータに対する同じ必要性を感じない理由は興味深いです。 grid.fit()は、トレーニングの検証フォールドの両方を処理します。例に含まれているとおりにハイパーパラメータ値を保持したい場合、この関数呼び出しは単純にする必要があります

model = KerasClassifier(build_fn=create_model, 
                        epochs=100, batch_size=32,
                        shuffle=True,
                        verbose=1)

Keras here でのGridSearchCVの使用に関する明確で十分に説明された例をいくつか見ることができます。

1
desertnaut

これは、1つの分割のみでそれを行う方法です。

fit_params['cl__validation_data'] = (X_val, y_val)
X_final = np.concatenate((X_train, X_val))
y_final = np.concatenate((y_train, y_val))
splits = [(range(len(X_train)), range(len(X_train), len(X_final)))]

GridSearchCV(estimator=model, param_grid=param_grid, cv=splits)I

さらに分割が必要な場合は、固定比率で 'cl__validation_split'を使用し、その基準を満たす分割を作成できます。

それは偏執的すぎるかもしれませんが、モデルを作成するために間接的に使用されたため、検証データセットとして早期停止データセットを使用しません。

また、最終モデルで早期停止を使用している場合は、ハイパーパラメーター検索を実行しているときにも停止する必要があると思います。

0
Bert Kellerman