Обзор стратегий регуляризации в глубоком обучении (с кодом Python)

машинное обучение глубокое обучение Python

Автор: Е Ху

Монтажер: Хуан Цзюньцзя

Эта статья переведена из «Обзор методов регуляризации в глубоком обучении (с кодом Python)» (https://www.analyticsvidhya.com/blog/2018/04/fundamentals-deep-learning-regularization-techniques/), оригинальный автор сохраняет авторские права.

Предисловие

Одна из самых распространенных проблем, с которыми сталкиваются специалисты по науке о данных, — как избежатьпереоснащение. Вы когда-нибудь сталкивались с ситуацией, когда ваша модель исключительно хорошо работала на обучающих данных, но не могла предсказать тестовые данные? Или вы начали с вершины общедоступной таблицы лидеров, но в итоге отстали на сотни позиций? Что ж, вам нужно прочитать эту статью!

Производительность модели можно улучшить, просто избегая переобучения.

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

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

  • [Основы глубокого обучения — начиная с искусственной нейронной сети] (https://www.analyticsvidhya.com/blog/2016/03/introduction-deep-learning-fundamentals-neural-networks/)

  • [Tutorial: Optimizing Neural Networks using Keras (with Image recognition case study)](https://www.analyticsvidhya.com/blog/2016/10/tutorial-optimizing-neural-networks-using-keras-with-image-recognition-case-study/)

01

Что такое регуляризация?

Прежде чем мы объясним, давайте взглянем на эту картинку:

Вы видели эту картину раньше? Слева направо модель пытается хорошо изучить детали и шум в обучающих данных, что в конечном итоге приводит к плохой работе с неизвестными данными. Другими словами, при движении вправо сложность модели увеличивается и ошибка обучения уменьшается, а ошибка теста — нет, как показано на следующем рисунке:

Если вы разрабатывали модели нейронных сетей, вы знаете, что они сложны, что делает их склонными к переоснащению.

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

02

Почему регуляризация помогает уменьшить переоснащение?

Как показано на рисунке ниже, модель нейронной сети переоснащена на обучающих выборках.

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

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

03

Стратегии регуляризации в глубоком обучении

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

  • Регуляризация L2 и L1

L1 и L2 являются наиболее распространенными методами регуляризации. Они добавляют член регуляризации к функции стоимости:

Из-за добавления этого члена регуляризации значение матрицы весов уменьшается, поскольку предполагается, что нейронная сеть с меньшей матрицей весов приводит к более простой модели. Следовательно, это также в некоторой степени снижает переоснащение. Однако этот член регуляризации различен в L1 и L2.

  • Для уровня 2:

здесь,– параметр регуляризации. Это гиперпараметр, который необходимо оптимизировать. Регуляризация L2 также известна как уменьшение веса (с точки зрения градиентного спуска), потому что она заставляет веса стремиться к 0 (но не ко всем 0).

  • Для уровня 1:

Здесь мы штрафуем абсолютное значение весовой матрицы. В отличие от L2, значение веса может быть уменьшено до 0. Таким образом, L1 полезен для сжатия моделей. В других случаях общий выбор состоит в том, чтобы предпочесть регуляризацию L2.

существуетKeras, мы используем [модуль регуляризаторов](https://keras.io/regularizers/), чтобы применить регуляризацию L1 или L2 к определенному слою. Вот применение регуляризации L2 на плотном слое:

from keras import regularizersmodel.add(Dense(64, input_dim=64,kernel_regularizer=regularizers.l2(0.01)скопировать код

Примечание: 0,01 — это то, что я сказал ранее.значение, это гиперпараметр, который необходимо дополнительно оптимизировать, вы можете использовать[Метод поиска по сетке (поиск по сетке)](http://scikit-learn.org/stable/modules/grid_search.html) для оптимизации.

Точно так же мы также можем использовать регуляризацию L1, которая будет объяснена более подробно в следующем примере.

04

Dropout

Это один из самых интересных методов регуляризации. Он может дать очень хорошие результаты и поэтому является наиболее часто используемым методом регуляризации в области глубокого обучения. Чтобы понять отсев, предположим, что структура нашей нейронной сети аналогична показанной ниже:

Принцип Dropout прост: во время каждой итерации случайным образом выбираются некоторые узлы, а прямые и обратные соединения удаляются, как показано на следующем рисунке:

Следовательно, каждый итерационный процесс будет иметь разную комбинацию узлов, что приведет к разным результатам. Это можно рассматривать как метод ансамбля в машинном обучении. Ансамблевые модели, как правило, лучше, чем отдельные модели, потому что они охватывают больше случайностей. Точно так же отсев заставляет модели нейронных сетей превосходить обычные модели.

Значение вероятности выбора количества удаляемых узлов является гиперпараметром. Как показано на рисунке выше, выпадение можно применить не только к скрытому слою, но и к входному слою.

По этим причинам отсев часто предпочтительнее, чтобы ввести больше случайности, когда у нас есть более крупные нейронные сети.

В Керасе мы можем использовать[Выпадающий слой](https://keras.io/layers/core/#dropout) Для реализации отсева код выглядит следующим образом:

from keras.layers.core import Dropout        model = Sequential([     Dense(output_dim=hidden1_num_units, input_dim=input_num_units, activation='relu'),     Dropout(0.25),        Dense(output_dim=output_num_units, input_dim=hidden5_num_units, activation='softmax'),     ])скопировать код

Видно, что значение вероятности отсева, установленное отсевом, равно 0,25, что также может быть дополнительно оптимизировано методом поиска по сетке.

05

увеличение данных

Самый простой способ уменьшить переобучение — увеличить обучающую выборку. В машинном обучении, поскольку помеченные данные дороги, мы не можем увеличить количество обучающих выборок. Но для задач с изображениями существует несколько способов увеличения обучающих выборок — вращение, переворачивание, масштабирование, смещение и т. д. Вот некоторые преобразования изображений в наборе данных MNIST:

Этот метод называется агументацией данных, и он часто значительно повышает точность модели. Обычно считается, что это обязательный метод для улучшения прогнозов.

В Керасе вы можете использовать [ImageDataGenerator](https://keras.io/preprocessing/image/) для реализации вышеуказанного преобразования изображения, которое имеет множество параметров для управления предварительной обработкой обучающих данных. Вот пример кода:

from keras.preprocessing.image import ImageDataGenerator    datagen = ImageDataGenerator(horizontal_flip=True)    datagen.fit(train)скопировать код

06

ранняя остановка

Ранняя остановка — это стратегия перекрестной проверки, в которой мы используем часть обучающего набора в качестве набора проверки. Когда мы увидели, что производительность на проверочном наборе становится все хуже и хуже, мы сразу же прекратили обучение модели. Это называется ранней остановкой.

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

В Керасе мы можем использовать [callbacks](https://keras.io/callbacks/) для ранней остановки, ниже приведен пример кода:

from keras.callbacks import EarlyStopping        EarlyStopping(monitor='val_err', patience=5)скопировать код

выше,monitorПараметр указывает количество мониторинга, здесьval_errпредставляет ошибку набора проверки. иpatienceКоличество эпох параметра, когда в этом процессе не будет улучшения производительности, обучение будет остановлено. Для лучшего понимания давайте еще раз взглянем на изображение выше. После пунктирной линии каждая эпоха приводит к более высокой ошибке набора проверки. Следовательно, через 5 эпох после пунктира (patienceравно 5), модель прекратит обучение, потому что дальнейшее улучшение невозможно.

Уведомление: на 5 эпохах (обычно устанавливаетсяpatienceзначение), модель может снова начать улучшаться, и ошибка набора проверки начнет уменьшаться. Поэтому нам нужно быть осторожными при настройке этого гиперпараметра.

07

Пример MNIST на основе Keras

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

import numpy as np    import matplotlib.pyplot as plt    from keras import Sequential    from keras.layers import Dense, Dropout    from keras.datasets import mnist    from keras.utils import to_categorical    from keras.preprocessing.image import ImageDataGenerator    from keras import regularizers    from keras.callbacks import EarlyStopping        # 避免随机性,可以重复试验    seed = 128    rng = np.random.RandomState(seed)скопировать код

Затем загрузите набор данных:

# 加载数据集    (train_images, train_labels), (test_images, test_labels) = mnist.load_data()скопировать код

Визуализируйте несколько картинок:

img_idx = rng.randint(len(train_images))    img = train_images[img_idx]    plt.imshow(img, cmap='gray')    plt.axis('off')    plt.show()скопировать код

Создайте проверочный набор для оптимизации модели, здесь соотношение обучающего набора к проверочному набору составляет 7:3:

train_images, train_labels = train_images[:50000], train_labels[:50000] # 使用部分数据    train_images = train_images.reshape((-1, 28*28)).astype(np.float32) / 255.0    test_images = test_images.reshape((-1, 28*28)).astype(np.float32) / 255.0    train_labels = to_categorical(train_labels, 10)    test_labels = to_categorical(test_labels, 10)        split_size = int(len(train_images) * 0.7)    x_train, y_train = train_images[:split_size], train_labels[:split_size]    x_val, y_val = train_images[split_size:], train_labels[split_size:]скопировать код

Сначала мы создаем простую нейронную сеть с 5 скрытыми слоями, а количество нейронов скрытого слоя равно 500.

# 定义参数    input_num_units = 784    hidden1_num_units = 500    hidden2_num_units = 500    hidden3_num_units = 500    hidden4_num_units = 500    hidden5_num_units = 500    output_num_units = 10        epochs = 10    batch_size = 128        model = Sequential([     Dense(hidden1_num_units, input_shape=(input_num_units,), activation='relu'),     Dense(hidden2_num_units, activation='relu'),     Dense(hidden3_num_units, activation='relu'),     Dense(hidden4_num_units, activation='relu'),     Dense(hidden5_num_units, activation='relu'),     Dense(output_num_units, activation='softmax'),]      )скопировать код

Затем мы тренируемся в течение 10 эпох и видим производительность модели:

model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])        trained_model_5d = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=2, validation_data=(x_val, y_val))скопировать код

Затем мы добавляем регуляризацию L2, чтобы увидеть, улучшается ли модель по сравнению с оригиналом:

reg_w = 1e-4    model = Sequential([     Dense(hidden1_num_units, input_shape=(input_num_units,), activation='relu', kernel_regularizer=regularizers.l2(reg_w)),     Dense(hidden2_num_units, activation='relu', kernel_regularizer=regularizers.l2(reg_w)),     Dense(hidden3_num_units, activation='relu', kernel_regularizer=regularizers.l2(reg_w)),     Dense(hidden4_num_units, activation='relu', kernel_regularizer=regularizers.l2(reg_w)),     Dense(hidden5_num_units, activation='relu', kernel_regularizer=regularizers.l2(reg_w)),     Dense(output_num_units, activation='softmax'),]      )        model.compile(optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"])        trained_model_5d = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=2, validation_data=(x_val, y_val))скопировать код

выше мы использовалиПри значении 0,0001 обученная модель более точна, чем исходная модель.

Затем попробуйте регуляризацию L1:

## l1       reg_w = 1e-4    model = Sequential([     Dense(hidden1_num_units, input_shape=(input_num_units,), activation='relu', kernel_regularizer=regularizers.l1(reg_w)),     Dense(hidden2_num_units, activation='relu', kernel_regularizer=regularizers.l1(reg_w)),     Dense(hidden3_num_units, activation='relu', kernel_regularizer=regularizers.l1(reg_w)),     Dense(hidden4_num_units, activation='relu', kernel_regularizer=regularizers.l1(reg_w)),     Dense(hidden5_num_units, activation='relu', kernel_regularizer=regularizers.l1(reg_w)),     Dense(output_num_units, activation='softmax'),]      )        model.compile(optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"])        trained_model_5d = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=2, validation_data=(x_val, y_val))скопировать код

Видно, что нет улучшения производительности при использовании регуляризации L1. Затем попробуйте стратегию отсева:

## dropout    from keras.layers.core import Dropout    model = Sequential([     Dense(output_dim=hidden1_num_units, input_dim=input_num_units, activation='relu'),     Dropout(0.25),     Dense(output_dim=hidden2_num_units, input_dim=hidden1_num_units, activation='relu'),     Dropout(0.25),     Dense(output_dim=hidden3_num_units, input_dim=hidden2_num_units, activation='relu'),     Dropout(0.25),     Dense(output_dim=hidden4_num_units, input_dim=hidden3_num_units, activation='relu'),     Dropout(0.25),     Dense(output_dim=hidden5_num_units, input_dim=hidden4_num_units, activation='relu'),     Dropout(0.25),        Dense(output_dim=output_num_units, input_dim=hidden5_num_units, activation='softmax'),     ])    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])    trained_model_5d = model.fit(x_train, y_train, nb_epoch=epochs, batch_size=batch_size, validation_data=(x_test, y_test))скопировать код

Видно, что производительность модели немного улучшилась после использования отсева. Затем попробуйте методы увеличения данных:

train_images = np.reshape(train_images, (-1, 28, 28, 1))    datagen = ImageDataGenerator(rotation_range=20)    datagen.fit(train_images, augment=True)скопировать код

Здесь берется параметр rotate_range, который будет поворачивать изображение на определенный угол, а затем обучать модель:

model = Sequential([     Dense(hidden1_num_units, input_shape=(input_num_units,), activation='relu'),     Dense(hidden2_num_units, activation='relu'),     Dense(hidden3_num_units, activation='relu'),     Dense(hidden4_num_units, activation='relu'),     Dense(hidden5_num_units, activation='relu'),     Dense(output_num_units, activation='softmax'),]      )        model.compile(optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"])        for e in range(epochs):        print('Epoch', e)        batches = 0        for x_batch, y_batch in datagen.flow(x_train, y_train, batch_size=batch_size):            x_batch = np.reshape(x_batch, (-1, 784)) / 255.0            model.train_on_batch(x_batch, y_batch)            batches += 1            if batches >= len(x_train) // batch_size:             # we need to break the loop by hand because             # the generator loops indefinitely             break            results = model.evaluate(x_val.reshape(-1, 784), y_val, verbose=0, batch_size=batch_size)        print(results)скопировать код

После использования увеличения данных производительность повышается.Вы также можете попробовать другие методы увеличения данных.

Наконец, мы используемранняя остановкаСтратегия:

model = Sequential([     Dense(hidden1_num_units, input_shape=(input_num_units,), activation='relu'),     Dense(hidden2_num_units, activation='relu'),     Dense(hidden3_num_units, activation='relu'),     Dense(hidden4_num_units, activation='relu'),     Dense(hidden5_num_units, activation='relu'),     Dense(output_num_units, activation='softmax'),]      )        model.compile(optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"])        trained_model_5d = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=2,                                 validation_data=(x_val, y_val), callbacks=[EarlyStopping(monitor="val_acc", patience=2)])скопировать код

В этот момент видно, что обучение останавливается на 8-й эпохе, потому что точность проверочного набора не улучшалась в течение 2 последовательных эпох. Ранняя остановка более эффективна при обучении больших эпох, вы можете думать об этом как об оптимизации количества эпох для обучения.

 

заключительные замечания

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

Примечание. Часть примера MNIST была немного изменена по сравнению с исходным текстом.

Колонка Е Ху, автора прошлого обзора

【1】Пример введения во входной конвейер TensorFlow

【2】Pass Heavyweight | Обзор обнаружения целей на основе глубокого обучения (1)

【3】Обнаружение цели | Принцип и реализация YOLOv2 (с YOLOv3)

【4】Вы знаете, как рассчитать рецептивное поле CNN? Вот подробное руководство

【5】Приходите и управляйте своим графическим процессором | Минималистичный учебник для начала работы с программированием CUDA

Инженер по алгоритмам машинного обучения


Выделенный публичный аккаунт

Длительное нажатие, идентификация, добавление внимания

Присоединяйтесь к группе, учитесь, получайте помощь

Ваше внимание, наш энтузиазм,

Мы обязательно окажем вам наибольшую помощь в обучении