Логотип Зефирнет

Понимание переоснащения в ConvNets

Дата:

Введение

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

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

Цели обучения

  • Понять причины, последствия и сценарии переобучения в Конвсети.
  • Интерпретируйте кривые обучения, чтобы обнаружить переобучение и недостаточное оснащение в моделях нейронных сетей.
  • Изучите различные методы уменьшения переобучения, такие как ранняя остановка, отсев, пакетная нормализация, регуляризация и увеличение данных.
  • Реализуйте эти методы, используя TensorFlow и Keras для обучения ConvNets на наборе данных CIFAR-10.
  • Анализируйте влияние различных методов на производительность модели и обобщение.

Содержание

Распространенные сценарии переобучения в ConvNet

Давайте рассмотрим некоторые распространенные сценарии переобучения в ConvNet:

Сценарий 1: Очень сложная модель с недостаточным количеством данных

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

Следствие

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

Как решить эту проблему?

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

Сценарий 2: Чрезмерное обучение

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

Следствие

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

Как решить эту проблему?

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

Сценарий 3: Игнорирование регуляризации

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

Следствие

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

Как решить эту проблему?

Внедрить регуляризацию, перекрестную проверку, настройку гиперпараметров. 

Какова мощность модели?

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

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

Интерпретация кривых обучения

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

Объект истории возвращается в результате вызовов функции fit(), используемой для обучения модели. Метрики хранятся в словаре в элементе истории возвращаемого объекта.

Например, вы можете перечислить метрики, собранные в объекте истории, используя следующий фрагмент кода после обучения модели:

# list all data in history
print(history.history.keys())

Вывод:

['точность', 'потеря', 'значение_точность', 'значение_потеря']

Тип информации

Вы можете подумать, что информация в обучающих данных бывает двух видов:

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

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

Кривые обучения

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

Методы предотвращения переобучения

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

Способ 1: использовать больше данных

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

Метод 2: ранняя остановка

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

Недооснащение и переоснащение

Метод 3: Отсев

Мы знаем, что переобучение вызвано ложными закономерностями (шумом) обучения сети в обучающих данных. Чтобы распознать эти ложные закономерности, сеть часто полагается на очень специфические комбинации весов, своего рода «заговор» весов. Будучи настолько конкретными, они, как правило, хрупкие: уберите хотя бы одну, и заговор развалится.

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

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

Переобучение в ConvNets

Метод 4: пакетная нормализация

Следующий специальный метод, который мы рассмотрим, выполняет «пакетную нормализацию» (или «batchnorm»), которая может помочь скорректировать медленное или нестабильное обучение.

В случае с нейронными сетями обычно рекомендуется поместить все ваши данные в общий масштаб, например, с помощью чего-то вроде StandardScaler или MinMaxScaler от scikit-learn. Причина в том, что SGD сместит веса сети пропорционально тому, насколько большую активацию производят данные. Функции, которые имеют тенденцию вызывать активации самого разного размера, могут привести к нестабильному поведению при обучении.

Теперь, если нормализовать данные перед их отправкой в ​​сеть — это хорошо, возможно, лучше будет также нормализовать внутри сети! На самом деле у нас есть особый вид слоя, который может это сделать, — слой пакетной нормализации. Уровень нормализации партии просматривает каждую партию по мере ее поступления, сначала нормализуя партию по ее собственному среднему значению и стандартному отклонению, а затем помещая данные в новую шкалу с двумя обучаемыми параметрами масштабирования. По сути, Batchnorm выполняет своего рода скоординированное изменение масштаба входных данных.

Чаще всего пакетная норма добавляется в качестве вспомогательного средства в процессе оптимизации (хотя иногда она также может помочь в прогнозировании производительности). Модели с пакетной нормой, как правило, требуют меньше эпох для завершения обучения. Более того, пакетная норма также может исправить различные проблемы, которые могут привести к «застреванию» обучения. Рассмотрите возможность добавления пакетной нормализации в ваши модели, особенно если у вас возникли проблемы во время обучения.

Метод 5: регуляризация L1 и L2

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

Выбор между регуляризацией L1 и L2 часто зависит от конкретной задачи и желаемых свойств модели.

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

Метод 6: увеличение данных

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

Один из простых способов получить больше данных — использовать уже имеющиеся у вас данные. Если мы сможем преобразовать изображения в нашем наборе данных способами, сохраняющими класс (пример: Классификация цифр MNIST, если мы попытаемся увеличить 6, будет трудно отличить 6 от 9), мы можем научить наш классификатор игнорировать такие виды преобразований. Например, то, смотрит ли автомобиль на фотографии влево или вправо, не меняет того факта, что это автомобиль, а не грузовик. Итак, если мы дополним наши обучающие данные перевернутыми изображениями, наш классификатор узнает, что «лево или право» — это разница, которую он должен игнорировать.

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

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

Реализация вышеуказанных методов с данными

Давайте рассмотрим этапы реализации вышеуказанных методов:

Шаг 1. Загрузка необходимых библиотек

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import ModelCheckpoint
import keras
from keras.preprocessing import image
from keras import models, layers, regularizers
from tqdm import tqdm
import warnings
warnings.filterwarnings(action='ignore')

Шаг 2. Загрузка набора данных и предварительная обработка

#Here all the images are in the form of a numpy array
cifar10 = tf.keras.datasets.cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
x_train = x_train / 255.0
x_test = x_test / 255.0

Шаг 3: Набор обучающих данных

x_train.shape, y_train.shape, x_test.shape, y_test.shape 

Вывод:

Результат
np.unique(y_train)

Вывод:

Результат
#These labels are in the order and taken from the documentaion
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck']

Шаг 4. Визуализация изображения из набора данных

def show_image(IMG_INDEX):
    plt.imshow(x_train[20] ,cmap=plt.cm.binary)
    plt.xlabel(class_names[y_train[IMG_INDEX][0]])
    plt.show()
show_image(20)
Переобучение в ConvNets
model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.AveragePooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.AveragePooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))
model.summary()

Давайте теперь инициализируем гиперпараметры и скомпилируем модель с оптимизатором, функцией потерь и метрикой оценки.


train_hyperparameters_config={'optim':keras.optimizers.Adam(learning_rate=0.001),
                             'epochs':20,
                              'batch_size':16
                             }
model.compile(optimizer=train_hyperparameters_config['optim'],
                  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                  metrics=['accuracy'])

Шаг 6: Модель обучения

history = model.fit(x_train, y_train, 
                        epochs=train_hyperparameters_config['epochs'], 
                        batch_size=train_hyperparameters_config['batch_size'], 
                        verbose=1,
                        validation_data=(x_test, y_test))

Шаг 7: Оцените модель

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

print(history.history.keys()) 
def learning_curves(history):
# Plotting Accuracy
    plt.figure(figsize=(14, 5))  # Adjust the figure size as needed
    plt.subplot(1, 2, 1)  # Subplot with 1 row, 2 columns, and index 1
    plt.plot(history.history['accuracy'], label='train_accuracy', marker='s', markersize=4)
    plt.plot(history.history['val_accuracy'], label='val_accuracy', marker='*', markersize=4)
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend(loc='lower right')

    # Plotting Loss
    plt.subplot(1, 2, 2)  # Subplot with 1 row, 2 columns, and index 2
    plt.plot(history.history['loss'], label='train_loss', marker='s', markersize=4)
    plt.plot(history.history['val_loss'], label='val_loss', marker='*', markersize=4)
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend(loc='lower right')

    plt.show()
learning_curves(history)
Переобучение в ConvNets

Из кривых мы видим, что точность проверки достигает плато после 4-й эпохи, и модель начинает улавливать шум. Следовательно, мы реализуем раннюю остановку, чтобы избежать переобучения модели и восстановить лучшие веса на основе val_loss. Мы будем использовать val_loss для мониторинга ранней остановки, поскольку наша нейронная сеть пытается уменьшить потери с помощью оптимизаторов. Точность и точность проверки зависят от порога (вероятность разделения классов - обычно 0.5 для двоичной классификации), поэтому, если наш набор данных несбалансирован, в большинстве случаев нам следует беспокоиться о потере. 

Шаг 8: Реализация ранней остановки

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

model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.AveragePooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.AveragePooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))
model.summary()

# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 5,
    'epochs': 50,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)

def model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config):
    model.compile(optimizer=train_hyperparameters_config['optim'],
                      loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
                      metrics=['accuracy'])
    ht = model.fit(x_train, y_train, 
                            epochs=train_hyperparameters_config['epochs'], 
                            batch_size=train_hyperparameters_config['batch_size'],
                            callbacks=[callback],
                            verbose=1,
                            validation_data=(x_test, y_test))
    return ht

ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)
learning_curves(ht)
Переобучение в ConvNets

Чтобы узнать наши лучшие веса, которые взяла модель. 

print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

Шаг 9: Увеличение сложности модели

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

model = models.Sequential()

model.add(layers.Conv2D(128, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(128, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()
Результат

Мы видим, что наблюдается увеличение общих параметров. Это поможет найти более сложные связи в нашей модели. Примечание. Наш набор данных состоит из изображений размером 32X32; это относительно небольшие изображения. Следовательно, использование более сложных моделей в начале наверняка приведет к переобучению модели, поэтому мы склонны постепенно увеличивать сложность нашей модели.

# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 5,
    'epochs': 50,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)
ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)

learning_curves(ht)
Переобучение в ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

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

Шаг 10. Использование слоев исключения и слоев пакетной нормализации

model = models.Sequential()

model.add(layers.Conv2D(128, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(256, (3, 3), activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Conv2D(512, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D((2, 2)))

model.add(layers.Flatten())
model.add(layers.Dense(256, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.3))

model.add(layers.Dense(128, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.3))

model.add(layers.Dense(10, activation='softmax'))
model.summary()
Результат
# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 5,
    'epochs': 50,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)
ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)
learning_curves(ht)
Переобучение в ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

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

Шаг 11: Увеличение слоев свертки

Уменьшите обучаемый параметр, но увеличьте количество слоев свертки, чтобы извлечь больше функций.

model = models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.2))

model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.3))

model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.4))

model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.5))

model.add(layers.Dense(10, activation='softmax'))

model.summary()
# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 5,
    'epochs': 50,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)
ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)
выходной
learning_curves(ht)
Переобучение в ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

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

Шаг 12: Использование регуляризации L1/L2

from tensorflow.keras import regularizers

model = models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l1(0.0005)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.2))

model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(0.0005)))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.3))

model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.4))

model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu', kernel_regularizer=regularizers.l1_l2(0.0005, 0.0005)))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.5))
model.add(layers.Dense(10, activation='softmax'))

model.summary()
# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 7,
    'epochs': 70,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)
ht=model_train(model, x_train, y_train, x_test, y_test, train_hyperparameters_config)
learning_curves(ht)
Переобучение в ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

Теперь мы видим, что регуляризация L1/L2 даже после использования низкого штрафного балла 0.0001 привела к тому, что наша модель оказалась неподходящей на 4%. Поэтому рекомендуется осторожно использовать все методы вместе. Поскольку пакетная нормализация и регуляризация влияют на модель одинаковым образом, нам не понадобится регуляризация L1/L2. 

Шаг 13: Увеличение данных

Мы будем использовать ImageDataGenerator из tensorflow keras.

# creates a data generator object that transforms images
datagen = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')

# pick an image to transform
test_img = x_train[20]
img = image.img_to_array(test_img)  # convert image to numpy arry
img = img.reshape((1,) + img.shape)  # reshape image

i = 0

for batch in datagen.flow(img, save_prefix='test', save_format='jpeg'):  # this loops runs forever until we break, saving images to current directory with specified prefix
    plt.figure(i)
    plot = plt.imshow(image.img_to_array(batch[0]))
    i += 1
    if i > 4:  # show 4 images
        break

plt.show()
Переобучение в ConvNets

Это четыре дополненных изображения и одно оригинальное изображение.

# Create an instance of the ImageDataGenerator
datagen = ImageDataGenerator(
    rotation_range=40,
    width_shift_range=0.2,
    height_shift_range=0.2,
    shear_range=0.2,
    zoom_range=0.2,
    horizontal_flip=True,
    fill_mode='nearest'
)

# Create an iterator for the data generator
data_generator = datagen.flow(x_train, y_train, batch_size=32)

# Create empty lists to store the augmented images and labels
augmented_images = []
augmented_labels = []

# Loop over the data generator and append the augmented data to the lists
num_batches = len(x_train) // 32
progress_bar = tqdm(total=num_batches, desc="Augmenting data", unit="batch")

for i in range(num_batches):
    batch_images, batch_labels = next(data_generator)
    augmented_images.append(batch_images)
    augmented_labels.append(batch_labels)
    progress_bar.update(1)

progress_bar.close()

# Convert the lists to NumPy arrays
augmented_images = np.concatenate(augmented_images, axis=0)
augmented_labels = np.concatenate(augmented_labels, axis=0)

# Combine the original and augmented data
x_train_augmented = np.concatenate((x_train, augmented_images), axis=0)
y_train_augmented = np.concatenate((y_train, augmented_labels), axis=0)
выходной

Мы использовали библиотеку tqdm, чтобы знать, как продвигается наше расширение.

x_train_augmented.shape, y_train_augmented.shape
Результат

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

model = models.Sequential()

model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(32, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.2))

model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.3))

model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.Conv2D(128, (3, 3), activation='relu', padding='same'))
model.add(layers.BatchNormalization())
model.add(layers.MaxPool2D((2, 2)))
model.add(layers.Dropout(0.4))

model.add(layers.Flatten())
model.add(layers.Dense(128, activation='relu'))
model.add(layers.BatchNormalization())
model.add(layers.Dropout(0.5))

model.add(layers.Dense(10, activation='softmax'))

model.summary()

# Here we have used more epochs than needed since we use patience parameter which we stop the model from overfitting
train_hyperparameters_config = {
    'optim': keras.optimizers.Adam(learning_rate=0.001),
    'patience': 10,
    'epochs': 70,
    'batch_size': 32, 
}
print('Setting the callback and early stopping configurations...')
callback = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', 
    min_delta=0.001, # minimium amount of change to count as an improvement
    patience=train_hyperparameters_config['patience'], 
    restore_best_weights=True)

ht=model_train(model, x_train_augmented, y_train_augmented, x_test, y_test, train_hyperparameters_config)


learning_curves(ht)
Переобучение в ConvNets
print('Testing ..................')
test_loss, test_acc = model.evaluate(x_test,  y_test, verbose=2)
print('test_loss : ', test_loss, 'test_accuracy : ', test_acc)

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

Заключение

Переобучение — распространенная проблема в глубоком обучении, особенно в случае сложных архитектур нейронных сетей, таких как ConvNets. Практики могут предотвратить переобучение в ConvNets, понимая его основные причины и распознавая сценарии, в которых оно происходит. Такие методы, как ранняя остановка, исключение, пакетная нормализация, регуляризация и увеличение данных, могут помочь смягчить эту проблему. Реализация этих методов в наборе данных CIFAR-10 показала значительные улучшения в обобщении и производительности модели. Овладение этими методами и понимание их принципов может привести к созданию надежных и надежных моделей нейронных сетей.

Часто задаваемые вопросы

Вопрос 1. Что такое переобучение и почему оно является проблемой глубокого обучения? 

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

В2. Как я могу обнаружить переобучение в моей модели нейронной сети?

О. Вы можете обнаружить переобучение в ConvNets, интерпретируя кривые обучения, которые отображают показатели обучения и проверки (например, потери, точность) по эпохам. Если показатели проверки перестают улучшаться или начинают ухудшаться, в то время как показатели обучения продолжают улучшаться, это признак переобучения.

Вопрос 3. Что такое ранняя остановка и как она помогает предотвратить переобучение?

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

Вопрос 4. Как увеличение данных помогает уменьшить переобучение? 

А. Увеличение данных — это процесс создания новых синтетических обучающих данных путем применения преобразований (например, переворота, вращения, масштабирования) к существующим данным. Это помогает модели лучше обобщать, предоставляя ей более разнообразные примеры, снижая риск переобучения в ConvNets ограниченным обучающим данным.

Spot_img

Последняя разведка

Spot_img