Вопрос или проблема
Я работаю над очень базовой задачей бинарной классификации. Для каждого набора из четырех чисел с плавающей точкой $(x,y,z,w)$ я хочу проверить, попадают ли они в одну из категорий или нет.
Я написал модель в Keras с 3 плотными слоями (функция активации ReLU) и выходным слоем (с функцией активации сигмоиды). Модель не переобучается, поэтому я пытался увеличить гиперпараметры, но она все равно не переобучается. Я думал, что добиться переобучения легко, если увеличить количество узлов. Разве это не так?
Сначала я думал, что проблема в данных, поэтому я решил сгенерировать искусственный набор данных, но модель все равно не переобучается. В приведенном ниже коде функция generate_pattern()
генерирует действительный шаблон, который я хочу пометить целым числом 1. Я заполняю датафрейм Pandas с помощью этой функции, и добавляю немного шума, вставляя случайно сгенерированные шаблоны.
Почему модель не переобучается? Какая лучшая архитектура модели для такого рода проблем?
import pandas as pd
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import train_test_split
def generate_pattern():
[x,y,z,w] = np.random.rand(4)/50
return [0.35+x,0.45+y,0.7+z,1.32+w]
mock_data = pd.DataFrame(columns=['x','y','z','w','target'])
i=0
while i < 10000:
if np.random.randint(2) == 0:
mock_data.loc[i] = generate_pattern() +[1]
i+=1
else:
if np.random.randint(2) == 0:
if np.random.randint(2) == 1:
mock_data.loc[i] = list(np.random.rand(4)) + [0]
i+=1
df_input = mock_data[['x','y','z','w']]
df_output = mock_data[['target']]
X = df_input.values
Y = df_output.astype(int).values
X_train, X_test, y_train, y_test = train_test_split(X, Y[:,0], test_size=0.33, random_state=52)
X_train, X_valid, y_train, y_valid = train_test_split(X_train, y_train, test_size=0.33, random_state=52)
# Создание модели нейронной сети
model = Sequential()
model.add(Dense(5, activation='relu', input_dim=4))
model.add(Dense(16, activation='relu'))
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# Компиляция модели
model.compile(loss=['binary_crossentropy'], optimizer="rmsprop", metrics=['accuracy','mean_squared_error','binary_crossentropy'])
# Обучение модели
history = model.fit(X_train, y_train, epochs=150, batch_size=64, validation_data=(X_valid,y_valid))
В шаблоне столбец w
равен 1.32 плюс немного шума. В шумных данных он находится в диапазоне от 0.0 до 1.0. Другими словами, между вашими двумя целями можно проехать автобусом, и это всего лишь при использовании одного из 4 входов.
Я думал, что добиться переобучения легко, если увеличить количество узлов.
Переобучение из-за увеличения мощностей модели — это когда у вас в данных есть случайный шум, из-за которого такое идеальное разделение нельзя выполнить, кроме как уделяя внимание шуму. Смотрите рисунок 1 на https://en.wikipedia.org/wiki/Overfitting, например. В вашем случае красные и синие точки достаточно удалены друг от друга, чтобы вы могли провести простую черную линию через них и не прибегать к переобученной зеленой линии.
Кстати, если я правильно понял ваш код, то 80% ваших данных имеют шаблон, и целевая переменная равна 1
, а 20% — это равномерно случайные значения с целевой переменной 0
? В этом случае модель также могла бы научиться просто угадывать мажоритарный класс.
(50% времени это 1
, затем в другие 50% она что-то делает только в одной четверти случаев, и три из четырех раз она не создает данные, так что данные имеют соотношение 4:1.)
Ответ или решение
Анализ проблематики переобучения модели бинарной классификации
Ваш вопрос связан с бинарной классификацией, где модель на основе 4-х входных числе (x, y, z, w) должна определять принадлежность к одной из двух категорий. Несмотря на увеличение гиперпараметров модели, вы не наблюдаете переобучения, и возникает вопрос, почему данная ситуация складывается.
Причины отсутствия переобучения
-
Структура данных и сложность задачи: Ваша задача может быть излишне простой по своей природе. Если классы, которые вы пытаетесь различить, находятся достаточно далеко друг от друга в пространстве признаков, модель может находить границу раздела, не прибегая к сложным, избыточным решениям. В этом случае, увеличение количества нейронов не приводит к улучшению подгонки к данным, поскольку модель просто принимает решение на основе простых правил.
-
Смешение данных: Как вы упомянули, у вас 80% данных относится к классу 1 и 20% к классу 0. Это несбалансированное распределение может приводить к тому, что ваша модель просто "учится" предсказывать наиболее распространённый класс (класс 1), что минимизирует ошибку без необходимости глубокого изучения структуры данных. Рекомендую использовать метрики, такие как F1-score, чтобы проверить производительность модели.
-
Шум в данных: В процессе генерации шумов вы добавляете случайные значения в набор данных, что также может помочь в отделении значимых данных от менее информативных. Однако, если среди этих шумов все же присутствуют данные, которые достаточно близки к истинным классам, это также может мешать модели учиться полностью.
Архитектура модели для бинарной классификации
Для достижения более надежных результатов и проверки возможности переобучения рекомендуется рассмотреть несколько аспектов архитектуры вашей модели:
-
Увеличение числа слоёв: Вы можете попробовать подойти к модели более комплексно, добавляя больше слоёв. Однако стоит помнить, что увеличение числа слоёв должно быть обоснованным. Убедитесь, что добавляете слои, на которых модель может действительно учиться.
-
Изменение количества нейронов в слоях: Экспериментируйте как с увеличением, так и с уменьшением количества нейронов. Иногда упрощённая модель может лучше обобщать данные.
-
Регуляризация: Включите методы регуляризации, такие как L1 или L2, а также дроп-аут (Dropout). Эти методы могут помочь модели избежать переобучения, снижая вероятность чрезмерного подстраивания под шумные данные.
-
Изменение функций активации: Попробуйте использовать разные функции активации для скрытых слоёв (например, Leaky ReLU или ELU). Иногда это может помочь модели глубже изучить зависимости в данных.
-
Более сложные алгоритмы: Если ваша модель по-прежнему не демонстрирует переобучение, возможно стоит рассмотреть использование более сложных архитектур, таких как свёрточные нейронные сети (CNN) или алгоритмы случайного леса и градиентного бустинга.
-
Увеличение данных: Попробуйте использовать augmentations для создания дополнительных примеров на основе имеющихся, чтобы расширить пространство данных, что может помочь в обучении.
Заключение
Вероятно, ваша модель не переобучается, потому что она не нуждается в этом для достижения высокой точности на ваших данных. Как упомянуто ранее, несбалансированные данные могут также затруднять обучение. Чтобы лучше оценить результаты, используйте более сложные метрики для анализа, и постарайтесь поэкспериментировать с архитектурой модели, чтобы найти сбалансированное решение.