Вы написали скрипт Python, который обучает и оценивает вашу модель машинного обучения. Теперь вы хотите автоматически настраивать гиперпараметры для повышения производительности?

Понял тебя!

В этой статье я покажу вам, как преобразовать ваш скрипт в целевую функцию, которую можно оптимизировать с помощью любой библиотеки оптимизации гиперпараметров.

Это займет всего 3 шага, и вы будете настраивать параметры модели, как будто завтра не наступит.

Готовый?

Пойдем!

Я предполагаю, что ваш сценарий main.py выглядит примерно так:

import pandas as pd
import lightgbm as lgb
from sklearn.model_selection import train_test_split
data = pd.read_csv('data/train.csv', nrows=10000)
X = data.drop(['ID_code', 'target'], axis=1)
y = data['target']
(X_train, X_valid, 
y_train, y_valid )= train_test_split(X, y, test_size=0.2, random_state=1234)
train_data = lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)
params = {'objective': 'binary',
          'metric': 'auc',
          'learning_rate': 0.4,
          'max_depth': 15,
          'num_leaves': 20,
          'feature_fraction': 0.8,
          'subsample': 0.2}
model = lgb.train(params, train_data,
                  num_boost_round=300,
                  early_stopping_rounds=30,
                  valid_sets=[valid_data],
                  valid_names=['valid'])
score = model.best_score['valid']['auc']
print('validation AUC:', score)

Шаг 1. Отделите параметры поиска от кода

Возьмите параметры, которые вы хотите настроить, и поместите их в словарь в верхней части скрипта. Тем самым вы эффективно отделяете параметры поиска от остального кода.

import pandas as pd
import lightgbm as lgb
from sklearn.model_selection import train_test_split
SEARCH_PARAMS = {'learning_rate': 0.4,
                 'max_depth': 15,
                 'num_leaves': 20,
                 'feature_fraction': 0.8,
                 'subsample': 0.2}
data = pd.read_csv('../data/train.csv', nrows=10000)
X = data.drop(['ID_code', 'target'], axis=1)
y = data['target']
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=1234)
train_data = lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)
params = {'objective': 'binary',
          'metric': 'auc',
          **SEARCH_PARAMS}
model = lgb.train(params, train_data,
                  num_boost_round=300,
                  early_stopping_rounds=30,
                  valid_sets=[valid_data],
                  valid_names=['valid'])
score = model.best_score['valid']['auc']
print('validation AUC:', score)

Шаг 2. Превратите обучение и оценку в функцию

Теперь вы можете поместить всю логику обучения и оценки в функцию train_evaluate. Эта функция принимает параметры в качестве входных данных и выводит оценку валидации.

import pandas as pd
import lightgbm as lgb
from sklearn.model_selection import train_test_split
SEARCH_PARAMS = {'learning_rate': 0.4,
                 'max_depth': 15,
                 'num_leaves': 20,
                 'feature_fraction': 0.8,
                 'subsample': 0.2}

def train_evaluate(search_params):
    data = pd.read_csv('../data/train.csv', nrows=10000)
    X = data.drop(['ID_code', 'target'], axis=1)
    y = data['target']
    X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=1234)
    train_data = lgb.Dataset(X_train, label=y_train)
    valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)
    params = {'objective': 'binary',
              'metric': 'auc',
              **search_params}
    model = lgb.train(params, train_data,
                      num_boost_round=300,
                      early_stopping_rounds=30,
                      valid_sets=[valid_data],
                      valid_names=['valid'])
    score = model.best_score['valid']['auc']
    return score

if __name__ == '__main__':
    score = train_evaluate(SEARCH_PARAMS)
    print('validation AUC:', score)

Шаг 3. Запустите скрипт настройки гиперпараметров

Мы почти на месте.

Все, что вам нужно сделать сейчас, это использовать эту функцию train_evaluate в качестве цели для выбранной вами библиотеки оптимизации черного ящика.

Я буду использовать Scikit Optimize, который я подробно описал в другой статье, но вы можете использовать любую библиотеку оптимизации гиперпараметров.

Вкратце я:

  • определите поиск ПРОБЕЛ,
  • создайте функцию target, которая будет минимизирована,
  • запустите оптимизацию с помощью функции skopt.forest_minimize.

В этом примере я попробую 100 различных конфигураций, начиная с 10 случайно выбранных наборов параметров.

import skopt
from script_step2 import train_evaluate
SPACE = [
    skopt.space.Real(0.01, 0.5, name='learning_rate', prior='log-uniform'),
    skopt.space.Integer(1, 30, name='max_depth'),
    skopt.space.Integer(2, 100, name='num_leaves'),
    skopt.space.Real(0.1, 1.0, name='feature_fraction', prior='uniform'),
    skopt.space.Real(0.1, 1.0, name='subsample', prior='uniform')]

@skopt.utils.use_named_args(SPACE)
def objective(**params):
    return -1.0 * train_evaluate(params)

results = skopt.forest_minimize(objective, SPACE, n_calls=30, n_random_starts=10)
best_auc = -1.0 * results.fun
best_params = results.x
print('best result: ', best_auc)
print('best parameters: ', best_params)

Это оно.

Объект results содержит информацию о лучшем результате и параметрах, по которым оно было получено.

Примечание.

Если вы хотите визуализировать свое обучение и сохранить диагностические диаграммы после его завершения, вы можете добавить один обратный вызов и один вызов функции для регистрации каждого поиска гиперпараметров в Нептун.

Просто воспользуйтесь этой вспомогательной функцией мониторинга optuna.

import neptune
import neptunecontrib.monitoring.skopt as sk_utils
import skopt
from script_step2 import train_evaluate
neptune.init('jakub-czakon/blog-hpo')
neptune.create_experiment('hpo-on-any-script', upload_source_files=['*.py'])
SPACE = [
    skopt.space.Real(0.01, 0.5, name='learning_rate', prior='log-uniform'),
    skopt.space.Integer(1, 30, name='max_depth'),
    skopt.space.Integer(2, 100, name='num_leaves'),
    skopt.space.Real(0.1, 1.0, name='feature_fraction', prior='uniform'),
    skopt.space.Real(0.1, 1.0, name='subsample', prior='uniform')]

@skopt.utils.use_named_args(SPACE)
def objective(**params):
    return -1.0 * train_evaluate(params)

monitor = sk_utils.NeptuneMonitor()
results = skopt.forest_minimize(objective, SPACE, n_calls=100, n_random_starts=10, callback=[monitor])
sk_utils.log_results(results)
neptune.stop()

Теперь, когда вы запустите поиск параметров, вы увидите следующее:

Оцените эксперимент с разверткой гиперпараметров skopt со всем кодом, диаграммами и результатами.

Последние мысли

Из этой статьи вы узнали, как оптимизировать гиперпараметры практически любого скрипта Python всего за 3 шага.

Надеюсь, что с этими знаниями вы сможете строить более совершенные модели машинного обучения с меньшими усилиями.

Удачной тренировки!

Эта статья изначально была размещена в блоге Neptune. Если понравилось, может и там понравится :)

Вы также можете найти, что я пишу в Твиттере @Neptune_a i » или «публикую в LinkedIn о машинном обучении и науке о данных.