Узнайте, как использовать поиск по сетке для оптимизации гиперпараметров
Поздравляем! Ваша статья в прямом эфире в нашем издании. Подумайте о том, чтобы представить больше статей. Не забудьте подписаться на нас в https://blog.devops.dev/ и в Twitter (https://twitter.com/devops_blog). Гиперпараметры в моделях машинного обучения — это параметры, которые не извлекаются из обучения. данные, но устанавливаются перед тренировкой. Эти параметры влияют на поведение модели во время обучения и могут оказать существенное влияние на производительность модели и ее способность обобщать новые данные.
Примеры гиперпараметров включают скорость обучения, которая контролирует размер шага, предпринимаемого во время оптимизации, силу регуляризации, которая контролирует степень штрафа, применяемого к параметрам модели для предотвращения переобучения, количество скрытых слоев в нейронной сети, количество деревьев в случайном лесу и функция ядра, используемая в машине опорных векторов.
Поиск по сетке — это метод настройки гиперпараметров, используемый в машинном обучении для поиска оптимальных значений гиперпараметров модели. Он включает в себя определение сетки значений гиперпараметров для поиска, а затем исчерпывающую оценку каждой комбинации значений в сетке.
Я буду использовать набор данных о ценах на ноутбуки от Kaggle, чтобы продемонстрировать, как использовать поиск по сетке в Python. Получить данные можно здесь.
Для начала нам нужно предварительно обработать набор данных и подготовить его к разработке модели. Поскольку это не является основной темой статьи, мы кратко рассмотрели ее.
import pandas as pd import xgboost as xgb import numpy as np from sklearn.metrics import mean_squared_error from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.preprocessing import OneHotEncoder, StandardScaler from sklearn.compose import ColumnTransformer df = pd.read_csv("laptopPrice.csv") # there are some duplicates in the dataset df = df.drop_duplicates() df.reset_index(drop=True,inplace=True) # some replacements df['ram_gb'] = df['ram_gb'].str.replace(' GB', '').astype(int) df['ssd'] = df['ssd'].str.replace(' GB', '').astype(int) df['hdd'] = df['hdd'].str.replace(' GB', '').astype(int) df['graphic_card_gb'] = df['graphic_card_gb'].str.replace(' GB', '').astype(int) df['os_bit'] = df['os_bit'].str.replace('-bit', '').astype(int) df["rating"] = df["rating"].replace({"1 star": "1 stars"}) df['rating'] = df['rating'].str.replace(' stars', '').astype(int) mapping = {'ThinNlight': 1, 'Casual': 2, 'Gaming': 3} df["weight"] = df["weight"].replace(mapping) mapping = {'No warranty': 0, '1 year':1, '2 years':2, '3 years':3} df["warranty"] = df["warranty"].replace(mapping) mapping = {'No': 0, 'Yes': 1} df["Touchscreen"] = df["Touchscreen"].replace(mapping) mapping = {'No': 0, 'Yes': 1} df["msoffice"] = df["msoffice"].replace(mapping) df.head(10)
num_features = [feature for feature in df.columns if df[feature].dtype != 'object' and feature != "Price"] cat_features = [feature for feature in df.columns if df[feature].dtype == 'object'] print("Numerical features: ", num_features) print("Categorical featues:", cat_features) """ Numerical features: ['ram_gb', 'ssd', 'hdd', 'os_bit', 'graphic_card_gb', 'weight', 'warranty', 'Touchscreen', 'msoffice', 'rating', 'Number of Ratings', 'Number of Reviews'] Categorical featues: ['brand', 'processor_brand', 'processor_name', 'processor_gnrtn', 'ram_type', 'os'] """ # feature transformation cat_transformer = OneHotEncoder(handle_unknown='ignore') num_transformer = StandardScaler() preprocessor = ColumnTransformer( transformers=[ ('cat', cat_transformer, cat_features), ('num', num_transformer, num_features) ]) X = preprocessor.fit_transform(df) y = df["Price"].values.reshape(-1,1) print(f"X: {X.shape}, y: {y.shape}") # X: (802, 51), y: (802, 1) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, shuffle=True)
Хорошо, теперь мы предварительно обработали как входные, так и целевые данные, и они готовы к использованию в модели.
Давайте обучим нашу базовую модель. Я буду использовать XGBoost с его гиперпараметрами по умолчанию.
model = xgb.XGBRegressor() model.fit(X_train, y_train) y_pred = model.predict(X_test) rmse_train = np.sqrt(mean_squared_error(y_train, model.predict(X_train))) rmse_test = np.sqrt(mean_squared_error(y_test, y_pred)) print(f"Train RMSE: {rmse_train}, Test RMSE: {rmse_test}") # Train RMSE: 2079.484814769608, Test RMSE: 19711.16864024852
Наша модель выглядит сильно переобученной. Поэтому теперь мы включим Grid Search для решения этой проблемы.
from sklearn.model_selection import GridSearchCV
Теперь давайте подробнее рассмотрим класс GridSearchCV
. Параметры, которые он принимает, следующие:
estimator
— это модель, которая будет использоваться для обучения.param_grid
указывает пространство гиперпараметров для поиска. Это должен быть словарь или список словарей, где каждый словарь содержит набор гиперпараметров, которые нужно попробовать.scoring
— это показатель, используемый для оценки производительности модели. Он может принимать множество различных форм, включая строки, вызываемые функции и словари с несколькими метриками. Показатели классификации: точность, прецизионность, полнота, f1. Показатели регрессии: neg_mean_squared_error, r2. Показатели кластеризации: Adjust_rand_score, silhoutte_score. Это были самые популярные, заходите сюда, чтобы посмотреть весь список.n_jobs
указывает количество ядер ЦП, используемых для распараллеливания вычислений. Значение-1
указывает, что должны использоваться все доступные ядра.refit
указывает, следует ли переоборудовать наилучшую оценку для всего набора данных, используя лучшие гиперпараметры, найденные во время поиска. По умолчанию дляrefit
установлено значениеTrue
, что означает, что после завершения поиска в сетке объектGridSearchCV
автоматически подгонит лучшую оценку для всего набора данных, используя лучшие найденные гиперпараметры.cv
указывает стратегию разделения перекрестной проверки. Это может быть целочисленное значение, указывающее количество сгибов, или генератор перекрестной проверки, который можно использовать для определения более продвинутых стратегий перекрестной проверки.verbose
управляет подробностью вывода во время поиска.pre_dispatch
используется для управления количеством заданий, которые запускаются параллельно во время поиска по сетке. Он принимает целочисленное значение, указывающее максимальное количество заданий, которые могут быть запущены в любой момент времени. Например, еслиpre_dispatch=2
, то одновременно будет запущено не более 2-х заданий.error_score
используется для указания того, какую оценку следует присвоить комбинации гиперпараметров, если она не может завершить процесс подбора. В процессе поиска по сетке алгоритмGridSearchCV
обучает и оценивает модель для каждой комбинации гиперпараметров. Однако иногда модель может не соответствовать или не набирать баллы из-за таких причин, как нехватка памяти или численная нестабильность. В таких случаях алгоритмуGridSearchCV
необходимо присвоить оценку неудачной комбинации гиперпараметров, чтобы продолжить поиск.return_train_score
указывает, следует ли включать результаты обучения в выходные данные.
param_grid = { 'learning_rate': [0.01, 0.1], 'n_estimators': [100, 500], 'max_depth': [3, 5], 'colsample_bytree': [0.5, 0.9], 'gamma': [0, 0.1, 0.5], 'reg_alpha': [0, 1, 10], 'reg_lambda': [0, 1, 10], } xgb = xgb.XGBRegressor(random_state=1) grid_search = GridSearchCV(xgb, param_grid=param_grid, cv=5, n_jobs=-1, verbose=1, scoring="neg_root_mean_squared_error", ) grid_search.fit(X_train, y_train) #Fitting 5 folds for each of 432 candidates, totaling 2160 fits
GridSearchCV
выполняет 5-кратную перекрестную проверку (т. е. разбивает данные на 5 частей и обучает модель 5 раз, каждый раз используя другую часть в качестве набора проверки) для каждой из 432 различных комбинаций гиперпараметров в пространстве поиска. В результате получается 2160 подгонок (т. е. обучение модели и оценка ее производительности 2160 раз).
Теперь мы создали наш объект поиска по сетке. Далее давайте рассмотрим доступные атрибуты, которые мы можем использовать.
best_estimator_
возвращает оценщик, который был выбран как лучший среди всех кандидатов на основе указанной метрики оценки.best_score_
возвращает средний балл перекрестной проверки, полученный лучшим оценщиком тестовых данных.best_params_
возвращает словарь гиперпараметров, которые дали наилучший результат.cv_results_
возвращает словарь, содержащий подробную информацию о производительности каждой комбинации гиперпараметров, включая среднее значение и стандартное отклонение показателей перекрестной проверки, время, необходимое для подгонки и оценки каждой модели, а также значения гиперпараметров для каждой модели.best_index_
возвращает индекс лучшей комбинации гиперпараметров в словареcv_results_
.scorer_
представляет функцию оценки, используемую для оценки производительности моделей во время поиска по сетке.n_splits_
представляет количество кратностей, использованных в процедуре перекрестной проверки во время поиска по сетке.refit_time_
представляет время, которое потребовалось для переоснащения наилучшей оценки для всего набора данных.multimetric_
указывает, использовались ли во время поиска по сетке несколько показателей оценки.classes_
возвращает уникальные метки класса в целевой переменной.n_features_in_
возвращает количество объектов во входных данных.feature_names_in_
— это имена функций, видимых во время подгонки.
print("Best estimator: ", grid_search.best_estimator_) """ Best estimator: XGBRegressor(base_score=0.5, booster='gbtree', callbacks=None, colsample_bylevel=1, colsample_bynode=1, colsample_bytree=0.5, early_stopping_rounds=None, enable_categorical=False, eval_metric=None, gamma=0, gpu_id=-1, grow_policy='depthwise', importance_type=None, interaction_constraints='', learning_rate=0.1, max_bin=256, max_cat_to_onehot=4, max_delta_step=0, max_depth=5, max_leaves=0, min_child_weight=1, missing=nan, monotone_constraints='()', n_estimators=100, n_jobs=0, num_parallel_tree=1, predictor='auto', random_state=1, reg_alpha=0, reg_lambda=0, ...) """ print("Best score: ", grid_search.best_score_) print("Best hyperparameters: ", grid_search.best_params_) """ Best score: -23298.387344638286 Best hyperparameters: {'colsample_bytree': 0.5, 'gamma': 0, 'learning_rate': 0.1, 'max_depth': 5, 'n_estimators': 100, 'reg_alpha': 0, 'reg_lambda': 0} """ results_df = pd.DataFrame(grid_search.cv_results_) results_df.head()
print("Best index: ", grid_search.best_index_) print("Best scorer: ", grid_search.scorer_) print("Best n splits: ", grid_search.n_splits_) print("Best refit time: ", grid_search.refit_time_) print("Best multi metric: ", grid_search.multimetric_) print("Best n features: ", grid_search.n_features_in_) """ Best index: 54 Best scorer: make_scorer(mean_squared_error, greater_is_better=False, squared=False) Best n splits: 5 Best refit time: 0.055130958557128906 Best multi metric: False Best n features: 51 """
Теперь мы можем использовать лучшую модель. Мы добились небольшого улучшения.
best_model = grid_search.best_estimator_ best_model.fit(X_train, y_train) y_pred = best_model.predict(X_test) rmse_train = np.sqrt(mean_squared_error(y_train, best_model.predict(X_train))) rmse_test = np.sqrt(mean_squared_error(y_test, y_pred)) print(f"Train RMSE: {rmse_train}, Test RMSE: {rmse_test}") """ Train RMSE: 6502.070891973686, Test RMSE: 17419.48195947506 """
GridSearchCV оценивает все возможные комбинации указанных гиперпараметров, что может помочь определить лучший набор гиперпараметров для данной модели. Кроме того, это гарантирует, что одни и те же гиперпараметры используются в разных прогонах модели, что способствует воспроизводимости.
Оценка всех возможных комбинаций гиперпараметров может быть затратной в вычислительном отношении, особенно для больших наборов данных и более сложных моделей. Он также может быть склонен к переоснащению, если пространство поиска слишком велико, что может привести к плохой производительности обобщения невидимых данных.
Читать далее
Источники
https://www.kaggle.com/datasets/anubhavgoyal10/laptop-prices-dataset/code
https://community.alteryx.com/t5/Data-Science/Hyperparameter-Tuning-Black-Magic/ba-p/449289
https://scikit-learn.org/stable/modules/model_evaluation.html#скоринг-параметр