Ранняя остановка стохастического градиентного спуска

Machine LearningMachine LearningBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

Стохастический градиентный спуск - это популярный метод оптимизации, используемый для минимизации функции потерь. Метод выполняет градиентный спуск шаг за шагом по-стахстически, то есть при каждой итерации случайным образом выбирает выборки. Метод эффективен, особенно при подгонке линейных моделей. Однако гарантии сходимости на каждой итерации нет, и функция потерь не обязательно уменьшается на каждой итерации. В этом случае отслеживание сходимости по функции потерь может быть сложным. В этом лабе мы исследуем стратегию ранней остановки, которая представляет собой подход для отслеживания сходимости по валидационному показателю. Мы будем использовать модель SGDClassifier из библиотеки scikit-learn и датасет MNIST, чтобы показать, как ранняя остановка может быть использована для достижения практически той же точности, что и у модели, построенной без ранней остановки, и значительного сокращения времени обучения.

Советы по работе с ВМ

После запуска ВМ кликните в верхнем левом углу, чтобы переключиться на вкладку Notebook и получить доступ к Jupyter Notebook для практики.

Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook загрузится. Валидация операций не может быть автоматизирована из-за ограничений Jupyter Notebook.

Если вы сталкиваетесь с проблемами во время обучения, не стесняйтесь обращаться к Labby. Оставьте отзыв после занятия, и мы оперативно решим проблему для вас.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL ml(("Machine Learning")) -.-> ml/FrameworkandSoftwareGroup(["Framework and Software"]) sklearn(("Sklearn")) -.-> sklearn/ModelSelectionandEvaluationGroup(["Model Selection and Evaluation"]) sklearn(("Sklearn")) -.-> sklearn/UtilitiesandDatasetsGroup(["Utilities and Datasets"]) sklearn/ModelSelectionandEvaluationGroup -.-> sklearn/model_selection("Model Selection") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/utils("Utilities") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/datasets("Datasets") sklearn/UtilitiesandDatasetsGroup -.-> sklearn/exceptions("Exceptions and Warnings") ml/FrameworkandSoftwareGroup -.-> ml/sklearn("scikit-learn") subgraph Lab Skills sklearn/model_selection -.-> lab-49287{{"Ранняя остановка стохастического градиентного спуска"}} sklearn/utils -.-> lab-49287{{"Ранняя остановка стохастического градиентного спуска"}} sklearn/datasets -.-> lab-49287{{"Ранняя остановка стохастического градиентного спуска"}} sklearn/exceptions -.-> lab-49287{{"Ранняя остановка стохастического градиентного спуска"}} ml/sklearn -.-> lab-49287{{"Ранняя остановка стохастического градиентного спуска"}} end

Загрузка необходимых библиотек и датасета MNIST

Первым шагом является загрузка необходимых библиотек и датасета. Мы будем использовать библиотеки pandas, numpy, matplotlib и scikit-learn. Также мы будем использовать функцию fetch_openml из scikit-learn для загрузки датасета MNIST.

import time
import sys
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn import linear_model
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.utils._testing import ignore_warnings
from sklearn.exceptions import ConvergenceWarning
from sklearn.utils import shuffle

## Загрузка датасета MNIST
def load_mnist(n_samples=None, class_0="0", class_1="8"):
    """Загрузка MNIST, выбор двух классов, перемешивание и возврат только n_samples."""
    ## Загрузка данных из http://openml.org/d/554
    mnist = fetch_openml("mnist_784", version=1, as_frame=False, parser="pandas")

    ## выбираем только два класса для бинарной классификации
    mask = np.logical_or(mnist.target == class_0, mnist.target == class_1)

    X, y = shuffle(mnist.data[mask], mnist.target[mask], random_state=42)
    if n_samples is not None:
        X, y = X[:n_samples], y[:n_samples]
    return X, y

X, y = load_mnist(n_samples=10000)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)

Определение оценщика и стратегии ранней остановки

Следующим шагом является определение оценщика и стратегии ранней остановки. Мы будем использовать модель SGDClassifier из scikit-learn. Мы определим три различных критерия остановки: отсутствие критерия остановки, потеря на обучении и валидационный показатель. Мы будем использовать функцию fit_and_score, чтобы подогнать оценщик на обучающем наборе и оценить его на обоих наборах.

@ignore_warnings(category=ConvergenceWarning)
def fit_and_score(estimator, max_iter, X_train, X_test, y_train, y_test):
    """Подгоняет оценщик на обучающем наборе и оценивает его на обоих наборах"""
    estimator.set_params(max_iter=max_iter)
    estimator.set_params(random_state=0)

    start = time.time()
    estimator.fit(X_train, y_train)

    fit_time = time.time() - start
    n_iter = estimator.n_iter_
    train_score = estimator.score(X_train, y_train)
    test_score = estimator.score(X_test, y_test)

    return fit_time, n_iter, train_score, test_score

## Определение оценщика для сравнения
estimator_dict = {
    "Без критерия остановки": linear_model.SGDClassifier(n_iter_no_change=3),
    "Потеря на обучении": linear_model.SGDClassifier(
        early_stopping=False, n_iter_no_change=3, tol=0.1
    ),
    "Валидационный показатель": linear_model.SGDClassifier(
        early_stopping=True, n_iter_no_change=3, tol=0.0001, validation_fraction=0.2
    ),
}

Обучение и оценка оценщика

Следующим шагом является обучение и оценка оценщика с использованием каждого критерия остановки. Мы будем использовать цикл для перебора каждого оценщика и критерия остановки, а также другой цикл для перебора различных максимальных итераций. Затем мы сохраним результаты в pandas dataframe для удобной визуализации.

results = []
for estimator_name, estimator in estimator_dict.items():
    print(estimator_name + ": ", end="")
    for max_iter in range(1, 50):
        print(".", end="")
        sys.stdout.flush()

        fit_time, n_iter, train_score, test_score = fit_and_score(
            estimator, max_iter, X_train, X_test, y_train, y_test
        )

        results.append(
            (estimator_name, max_iter, fit_time, n_iter, train_score, test_score)
        )
    print("")

## Преобразование результатов в pandas dataframe для удобной визуализации
columns = [
    "Критерий остановки",
    "max_iter",
    "Время обучения (сек)",
    "n_iter_",
    "Оценка на обучающем наборе",
    "Оценка на тестовом наборе",
]
results_df = pd.DataFrame(results, columns=columns)

Построение графиков результатов

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

## Определяем, что будем отображать
lines = "Критерий остановки"
x_axis = "max_iter"
styles = ["-.", "--", "-"]

## Первый график: оценки на обучающем и тестовом наборах
fig, axes = plt.subplots(nrows=1, ncols=2, sharey=True, figsize=(12, 4))
for ax, y_axis in zip(axes, ["Оценка на обучающем наборе", "Оценка на тестовом наборе"]):
    for style, (criterion, group_df) in zip(styles, results_df.groupby(lines)):
        group_df.plot(x=x_axis, y=y_axis, label=criterion, ax=ax, style=style)
    ax.set_title(y_axis)
    ax.legend(title=lines)
fig.tight_layout()

## Второй график: n_iter и время обучения
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 4))
for ax, y_axis in zip(axes, ["n_iter_", "Время обучения (сек)"]):
    for style, (criterion, group_df) in zip(styles, results_df.groupby(lines)):
        group_df.plot(x=x_axis, y=y_axis, label=criterion, ax=ax, style=style)
    ax.set_title(y_axis)
    ax.legend(title=lines)
fig.tight_layout()

plt.show()

Резюме

В этом практическом занятии мы изучили стратегию ранней остановки для мониторинга сходимости по валидационному показателю при использовании стохастического градиентного спуска для минимизации функции потерь. Мы использовали модель SGDClassifier из scikit-learn и датасет MNIST, чтобы показать, как ранняя остановка может быть использована для достижения практически той же точности, по сравнению с моделью, построенной без ранней остановки, и значительного сокращения времени обучения. Мы определили три различных критерия остановки: отсутствие критерия остановки, потеря на обучении и валидационный показатель, и использовали цикл для обучения и оценки оценщика с использованием каждого критерия остановки. Затем мы построили графики результатов, используя разные стили линий для каждого оценщика и критерия остановки.