машинное обучение
June 9, 2022

Ранняя остановка обучения нейросети с H2O

Рассмотрим, как использовать опцию раннего останова в H2O на примере работы H2ODeepLearningEstimator. Большая часть из регулирующих данный процесс параметров задается в конструкторе класса:

stopping_metric - метрика останова;

stopping_rounds - количество итераций в течение которых отслеживается изменение метрики для проверки критерия останова (по умолчанию 5, с каждой итерацией берется скользящее среднее метрик по предыдущим раундам). Минимальное количество итераций, после которых обучение может остановиться равно 2*stopping_rounds (сравниваются скользящие средние с окном stopping_rounds);

stopping_tolerance - минимальная доля улучшения метрики для проверки критерия останова (по умолчанию 0);

есть параметры останова, не зависящие от stopping_metric:

classification_stop - для продолжения обучения доля улучшения классификации (1-accuracy) должна быть выше этой границы (по умолчанию 0). Для отключения следует задать -1;

regression_stop - для продолжения обучения доля улучшения регрессии (MSE) должна быть выше этой границы (по умолчанию 1e-06). Для отключения следует задать -1;

train_samples_per_iteration - количество обучающих примеров в одной итерации (это промежуток от обучения до обмена информацией между узлами кластера). Есть служебные значения:
0 - итерацией считается одна эпоха (один проход по тренировочным данным, не обязательно на одном узле, так как на кластере данные распределяются между узлами);
-1 - все тренировочные данные реплицируются и используются на всех узлах кластера (то есть не дробятся, как в случае 0);
Если в кластере только один узел, то значения 0 и 1 подразумевают одно и то же;
-2 - размер определяется автоматически. При этом значении решение принимается на основе target_ratio_comm_to_comp. Также на размер итерации могут повлиять score_duty_cycle, score_interval.
target_ratio_comm_to_comp - соотношение времени на обмен данными между узлами (в том числе оценку) и вычислениями (по умолчанию 0.05). Применимо при train_samples_per_iteration = -2;
score_duty_cycle - соотношение затрат на оценку и обучение (по умолчанию 0.1)
score_interval - минимальное время между проверками в сек. (по умолчанию 5 сек и чаще происходить не будет).
max_runtime_secs - максимальное время обучения в сек (по умолчанию = 0, не используется);

score_each_iteration - считать ли метрики на каждой итерации.

Для раннего останова по валидационной выборке ее следует передать в метод train:

validation_frame - валидационный h2o фрейм;

training_frame - h2o фрейм для обучения;

y - название колонки с целью;

x - список имен признаков;

Аналогично ранее рассмотренному примеру использования H2O создадим демонстрационный датасет:

import pandas as pd
from sklearn.datasets import make_classification
import numpy as np
np.random.seed(0)

ar, y = make_classification(n_samples=1000, n_features=3, n_informative=2, 
                           n_redundant=0, class_sep = 0.5, shuffle=False, 
                           flip_y=0, n_clusters_per_class=2)

df = pd.DataFrame(ar, columns = ['feat1', 'feat2', 'feat3'])
df['feat4'] = pd.cut(df['feat2'], 5, labels=False)
df['y'] = y
df

Зададим индексы выборок и H2O фрейм:

# мешаем
df = df.sample(frac=1).reset_index(drop=True)
tr_idx, val_idx = np.split(np.arange(df.shape[0]), [round(0.8*df.shape[0])])
import h2o
from h2o import H2OFrame
h2o.init()

h2o_df = H2OFrame(df)
h2o_df['y'] = h2o_df['y'].asfactor()
h2o_df['feat4'] = h2o_df['feat4'].asfactor()

x_cols = df.drop(columns='y').columns.to_list()
y_col = 'y'

Рассмотрим параметры, регулирующие размеры выборок и частоту скоринга.

В частности, установим train_samples_per_iteration =-1 или 0 (так как работаем на локальном кластере) итерация равна одной эпохе и скорится каждая эпоха, так как score_each_iteration установлен в True:

from h2o.estimators.deeplearning import H2ODeepLearningEstimator

clf = H2ODeepLearningEstimator(distribution='bernoulli', activation = 'Rectifier with dropout',
                               epochs=50, hidden_dropout_ratios=[0.4,0.4], l1=0.003, hidden=[10,10], 
                               stopping_rounds=10, stopping_tolerance=0.01, stopping_metric='auc', 
                               score_each_iteration=True, train_samples_per_iteration=-1)


clf.train(x=x_cols, y=y_col, training_frame=h2o_df[list(tr_idx),:], validation_frame=h2o_df[list(val_idx),:])
clf.scoring_history()

Здесь так же оценка происходит на каждой итерации, но ее размер определяется автоматически (train_samples_per_iteration=-2). В результате скоринг на каждой 5-ой эпохе:

clf = H2ODeepLearningEstimator(distribution='bernoulli', activation = 'Rectifier with dropout', 
                               epochs=50, hidden_dropout_ratios=[0.4,0.4], l1=0.003, hidden=[10,10],
                               stopping_rounds=10, stopping_tolerance=0.01, stopping_metric='auc', 
                               score_each_iteration=True, train_samples_per_iteration=-2)


clf.train(x=x_cols, y=y_col, training_frame=h2o_df[list(tr_idx),:], 
                              validation_frame=h2o_df[list(val_idx),:])
clf.scoring_history()

А в данном примере размер итерации определяется автоматически плюс и оценка происходит не на каждой итерации (примерно каждая 7000-ая эпоха скорится, всего установил 50000, иначе наши 10 stopping_rounds ни разу не наступят)

clf = H2ODeepLearningEstimator(distribution='bernoulli', activation = 'Rectifier with dropout',
                               epochs=50000, hidden_dropout_ratios=[0.4,0.4], l1=0.003, hidden=[10,10], 
                               stopping_rounds=10, stopping_tolerance=0.01, stopping_metric='auc', 
                               train_samples_per_iteration=-2)

clf.train(x=x_cols, y=y_col, training_frame=h2o_df[list(tr_idx),:], 
                              validation_frame=h2o_df[list(val_idx),:])
clf.scoring_history()

Полезные ссылки:

Быстрый запуск нейросети с библиотекой H2O

Не пропустите ничего интересного и подписывайтесь на страницы канала в других социальных сетях:

Яндекс Дзен

Telegram