Вопрос или проблема
Каковы подводные камни такого подхода и почему это плохая практика? Может ли так случиться, что модель начинает запоминать изображения “наизусть” вместо того, чтобы понимать лежащую в основе логику?
Да, вы совершенно правы.
Как учитель, вы не дадите своим ученикам экзамен с точно такими же заданиями, которые вы задали на дом: вы хотите выяснить, действительно ли они (а) поняли интуицию методов, которые вы им преподавали, и (б) чтобы убедиться, что они не просто заучили домашние задания.
Это неправильно, потому что:
- это фундаментально некорректно (теоретическая проблема)
- это приводит к плохим результатам (практическая проблема)
Это фундаментально некорректно, потому что обычно цель тестирования модели заключается в оценке того, насколько хорошо она будет предсказывать данные, которые модель не видела.
Довольно трудно получить хорошие оценки реальной производительности, даже когда вы делаете все правильно. Если вы используете тренировочные данные для оценки производительности, результат хуже, чем бесполезен, он активно вводит в заблуждение.
Существует несколько способов, которыми это может привести к плохим результатам.
Переобучение
Если вы обучаете сложную модель на небольшом количестве данных, ваша модель с высокой вероятностью переобучится. Упрощенно говоря, можно сказать, что если у модели много “памяти” (параметров), она запоминает тренировочные данные и не понимает их основную структуру.
Представьте, что вы строите модель, которая предсказывает цену дома на основе его площади. Ваш тренировочный набор выглядит следующим образом:
площадь цена
30 100001
50 150002
80 200003
Вы обучаете свою модель, затем просите её предсказать цену для дома с площадью=50, и она говорит вам, что цена должна быть 150002. Это впечатляюще точно? Не совсем. Она просто запоминает тренировочные данные.
Переобучение обычно определяется через большую разницу в производительности между тренировочным и тестовым наборами. Если вы тестируете на тренировочном наборе, вы не сможете зафиксировать переобучение.
Сдвиг концепции
Если вы убедитесь, что обучаете очень простую модель на большом количестве данных, даже если не происходит переобучения, для моделей обычно характерен сдвиг концепции.
Это означает, что основная структура данных может изменяться с течением времени. Например, попытка предсказать, сколько продаж сделает магазин в выходные, после обучения на данных с понедельника по пятницу.
Если ваши тестовые данные недостаточно разнообразны по временной шкале по сравнению с тренировочным набором, вы не заметите этой проблемы.
Случается, что модель, которую вы обучаете, “узнает слишком много” или запоминает тренировочные данные, а затем плохо работает на невидимых данных. Это называется “переобучение”.
Проблема в том, что тренируя и тестируя на одном и том же наборе данных, вы не осознаете, что ваша модель переобучается, потому что производительность вашей модели на тестовом наборе хороша. Цель тестирования на данных, которые не были видены во время обучения, заключается в том, чтобы вы могли правильно оценить, происходит ли переобучение.
Простой ответ: круговая логика. То, что ваша модель “знает” ответ на что-то, о чем вы уже ей сказали, действительно ничего не доказывает.
Другими словами: вся суть тестирования заключается в том, чтобы получить представление о том, насколько хорошо ваша модель сработает с данными, которые она еще не видела, и тестирование с данными, которые она уже видела, этого не делает.
Может ли так случиться, что модель начинает запоминать изображения наизусть вместо того, чтобы понимать лежащую в основе логику?
Если модель запоминает тренировочные данные, когда эти же данные используются для тестового набора, она будет продолжать запоминать тренировочные данные, когда для тестового набора будут использованы другие данные. Использование отдельного тестового набора не может предотвратить это запоминание. Более того, тестовый набор не оказывает прямого влияния на обучение модели.
Тем не менее, отдельный тестовый набор позволяет исследователям выявить то, что модель действительно запоминает отдельные образцы данных и цели, вместо того, чтобы учиться распознавать основные паттерны. Когда исследователи видят, что потери уменьшаются на тренировочном наборе, но увеличиваются на тестовом наборе, они понимают, что происходит переобучение. В этом случае они могут настроить гиперпараметры модели, пытаясь уменьшить её мощность (т.е. количество узлов и/или слоев), а затем повторно обучить модель, чтобы проверить, решена ли проблема.
Поскольку исследователи используют тестовый набор для настройки гиперпараметров модели, тестовые данные могут косвенно влиять на производительность окончательной модели. Может случиться так, что исследователи выберут гиперпараметры, которые хорошо работают для тестового набора, но не для данных в целом. По этой причине иногда рекомендуется использовать три различных набора данных: тренировочный набор, используемый для обучения модели, первоначальный тестовый набор, используемый для решения проблем переобучения и других проблем путем настройки гиперпараметров (это более обычно известно как валидационный набор), и окончательный тестовый набор, который используется только для оценки финализированной модели (и не оказывает никакого влияния, ни прямого, ни косвенного, на обучение модели).
Чтобы выразить это по-другому, что может быть более полезно при объяснении нетерпеливым заинтересованным сторонам:
Представьте, что вы пришли на ярмарку, и дама с множеством шарфов и хрустальным шаром говорит вам: “Я могу посмотреть на человека и сказать, женат ли он”. Вы не уверены, правда ли это.
Если она начинает показывать на своих коллег с ярмарки и говорит: “он женат, она не жената, та женщина тоже не жената” – что это вам говорит? Ничего. Она уже знает этих людей, она знает, кто женат! Чтобы начать доверять её способности, вы хотите, чтобы она сделала свои предположения о людях, которых она никогда не видела.
В науке о данных у вас всегда есть проблема, должны ли люди (включая вас!) доверять модели или нет. Она может доказать свою состоятельность, показывая, что может находить информацию, которой не знала заранее. По определению, она должна знать свои тренировочные данные, поэтому ваш единственный вариант – оставить некоторые данные “скрытыми” от неё (тестовый набор).
На самом деле, идеально, если вы подозреваете, что ваши данные слишком однородны, провести вторичное тестирование с другим набором данных, созданным другим способом, чтобы подтвердить, что она работает в общем. Это делается в основном в науке, если данные доступны, например, если вы обучали и тестировали данные по пациентам из одной больницы, вы в идеале пробуете их на пациентах из другой больницы, на случай, если данные были закодированы иначе, или у вас имелись проблемы с отбором и так далее.
Чтобы дать простую иллюстрацию того, насколько плохим может быть переобучение, рассмотрим пример подбора (обучения) полинома порядка, равного количеству точек данных, которые у вас есть. В этом случае я сгенерировал данные с наклоном и добавил некоторый нормально распределенный случайный шум. Если вы протестируете его с точно такими же значениями x и y, которые вы использовали для генерации полиномиальной подгонки, посмотрев на остатки, вы увидите только числовую ошибку, и вы можете наивно сказать, что это хорошая подгонка, или, по крайней мере, лучше, чем линейная подгонка (изображённая в зелёном), которая имеет гораздо большие остатки. Если вы построите график фактического полинома, который вы получили (в красном), вы, вероятно, увидите, что он на самом деле ужасно интерполирует между этими тестовыми данными (поскольку мы знаем, что основной процесс – это просто прямая линия), как на этом графике:
Если вы сгенерируете новый набор данных с теми же значениями x, вы увидите, что, помимо того, что он плохо интерполирует, он показывает примерно такие же результаты, как линейная подгонка по остаткам:
И, возможно, что хуже всего, он полностью проваливается при попытке экстраполяции, поскольку полином предсказуемо взрывается в обе стороны:
Таким образом, если “предсказание” для вашей модели заключается в интерполяции, то переобучение делает её плохой в этом, и это не будет заметно, если вы не протестируете её на данных, не входивших в обучающий набор. Если предсказание – это экстраполяция, то, вероятно, она даже хуже в этом, чем в интерполяции, и снова вы не сможете это установить, если не протестируете её на нужных данных.
Используемый для генерации этих графиков код на Python:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(0)
nSamples = 15
slope = 10
xvals = np.arange(nSamples)
yvals = slope*xvals + np.random.normal(scale=slope/10.0, size=nSamples)
plt.figure(1)
plt.clf()
plt.subplot(211)
plt.title('"Идеальная" полиномиальная подгонка')
plt.plot(xvals, yvals, '.', markersize=10)
polyCoeffs = np.polyfit(xvals, yvals, nSamples-1)
poly_model = np.poly1d(polyCoeffs)
linearCoeffs = np.polyfit(xvals, yvals, 1)
linear_model = np.poly1d(linearCoeffs)
xfit = np.linspace(0, nSamples-1, num=nSamples*50)
#yfit_dense = poly_model(xfit)
plt.plot(xfit, poly_model(xfit), 'r')
plt.plot(xfit, linear_model(xfit), 'g')
plt.subplot(212)
plt.plot(xvals, poly_model(xvals) - yvals, 'r.')
plt.plot(xvals, linear_model(xvals) - yvals, 'g.')
plt.title('Остатки подгонки для тренировочных данных (не нулевые только из-за числовой ошибки)')
#%% Тестирование интерполяции
plt.figure(2)
plt.clf()
test_yvals = slope*xvals + np.random.normal(scale=slope, size=nSamples)
plt.subplot(211)
plt.title('Тестирование "идеальной" полиномиальной подгонки с новыми образцами')
plt.plot(xvals, test_yvals, '.', markersize=10)
plt.plot(xfit, poly_model(xfit), 'r')
plt.plot(xfit, linear_model(xfit), 'g')
plt.subplot(212)
plt.title('Остатки подгонки для тестовых данных')
plt.plot(xvals, poly_model(xvals) - test_yvals, 'r.')
plt.plot(xvals, linear_model(xvals) - test_yvals, 'g.')
#%% Тестирование экстраполяции
extrap_xmin = -5
extrap_xmax = nSamples + 5
xvals_extrap = np.arange(extrap_xmin, extrap_xmax)
yvals_extrap = slope*xvals_extrap + np.random.normal(scale=slope, size=len(xvals_extrap))
plt.figure(3)
plt.clf()
plt.subplot(211)
plt.title('Тестирование экстраполяции "идеальной" полиномиальной подгонки')
plt.plot(xvals_extrap, yvals_extrap, '.', markersize=10)
plt.plot(xvals_extrap, poly_model(xvals_extrap), 'r')
plt.plot(xvals_extrap, linear_model(xvals_extrap), 'g')
plt.subplot(212)
plt.title('Остатки подгонки для экстраполяции')
plt.plot(xvals_extrap, poly_model(xvals_extrap) - yvals_extrap, 'r.')
plt.plot(xvals_extrap, linear_model(xvals_extrap) - yvals_extrap, 'g.')
В дополнение ко всем хорошим объяснениям о переобучении я также хотел бы процитировать закон Гудхарта. Поскольку вы обучались, оптимизируя потери на обучающем наборе (некую метрику), она таким образом стала плохой метрикой для измерения качества вашей модели.
Проблема состоит в том, что базовый набор данных используется для обучения нейронной сети. Тестовые данные используются для проверки. Теперь, если у вас есть единственный и единственный соответствующий набор данных, по которому вы хотите сделать прогноз в будущем, у вас возникает проблема, как это сделать. Вы можете разделить этот исходный набор данных, как только определите гиперпараметры, на любую пропорцию 50/50%, 70/20%, 80/20% или “оставив один” с использованием K-Folds, фиксированной пропорции столбцов, бутстрепа, случайной выборки, стратифицированной … до сих пор все понятно. Для обучения нейронной сети необходимо указать целевой столбец. Если ваш целевой столбец, скажем, c1000, и вы хотите предсказать c1001, вы не можете сделать это на одном и том же наборе данных напрямую. Теперь вам нужно создать второй набор данных из базового набора данных. Вы можете “перемешать” в небольшом проценте весь базовый набор данных или только пропорцию, чтобы нейронная сеть не видела “одни и те же данные” и предсказала будущее c1000 на этом наборе данных, если это вам подходит. Допустимая ошибка будет достаточно малой, чтобы не потерять достигнутую точность. Это одно решение. Другое — вы сдвигаете весь или только “пропорцию тестового набора данных” влево в новом наборе данных, чтобы у вас была целевая переменная на тестовом файле c1001, смещенная на c1000 (это теперь становится правильной целью) в базовом наборе данных и в тестовом или предсказательном наборе данных. У вас теперь c1000, сдвинутое влево, становится c999, и “c1000” теперь становится столбцом предсказания, который фактически является c1001 в базовом наборе данных, который вы хотите предсказать. Посмотрите на x = kx, который мы сдвигаем на y = kx-1, то же самое касается полиномиальных функций. Вот что я использую с методом бутстрепа без перемешивания. Но это приходит с некоторыми оговорками. Весь процесс определения гиперпараметров, который был действителен для базового набора данных, катится коту под хвост (это -1 на тестовом файле не включается в обученную модель). Теперь вам нужно обучить вашу нейронную сеть на этой базе данных, сдвинутой влево, и определить гиперпараметры для этого подхода. Теперь мы решили проблему предсказания c1000 и c1001, но точность пострадает, и вам придется проделать много работы, чтобы найти “правильные” гиперпараметры и предварительно настроить их, более глубоко исследуя скрытые слои. Это то, о чем вам никто не скажет, но это имеет решающее значение для выполнения прогноза таким образом (я не нашел этой информации нигде, ни в учебниках, охватывающих этот подход, вам придется много пробовать, это утомительно и времязатратно). Другое решение – если вы можете, преобразовать ваш набор данных в “временной ряд” и использовать нейронные сети временных рядов (это совершенно другой подход), но не требует целевого столбца (нелинейная регрессия, которая просто продолжается за пределы этого столбца c1000), только для бинарных, числовых значений данных. Возможно, это также работает для многоклассовых наборов данных, не знаю, не пробовал и не использовал. В конце концов, вы можете попробовать использовать оба подхода: нейронные сети временных рядов для прогнозирования c1001 (вы не получите высокой точности на временном ряду, но все же лучше, чем угадать или плохо предсказать c1001), а затем передать эти результаты в базовый набор данных, сделав его целевым, и попробовать прогнозировать на тестовом наборе данных c1001 нормально (небольшой процент перемешивания при обучении, как на тестовом файл и без перемешивания на файловом предсказании, так сказать, сохраняя оригинал, но только сдвинутым на -1 столбец влево). Чтобы подтвердить этот подход, вы можете начать предсказывать от c900 и выше, а для известных значений проверить прогнозы и настроить свои гиперпараметры для лучшей точности. Надеюсь, это прояснит эту тему и поможет многим пользователям, которые не могут этого сделать. Это одно, другое дело – используемое программное обеспечение, которое может сильно отличаться в использовании по тем же/аналогичным принципам.
Нет ничего плохого в тестировании модели на данных, на которых вы её обучали, но есть что-то неправильное в том, чтобы не тестировать свою модель на данных, которые она раньше не видела.
Как объяснили другие ответы, тесты на данных, на которых модель была обучена, отнюдь не могут заменить тесты на новых данных, и в случае переобучения результаты могут сильно отличаться. Тем не менее, тестирование модели на данных, на которых она была обучена, по-прежнему имеет ценность. Например, если ваша модель плохо подстраивается к данным, на которых она была обучена, вы знаете, что у вас проблема недообучения, и ваша модель слишком проста.
Другими словами, если ваша точность по тестовым данным составляет 0.6, вы будете действовать по-разному в зависимости от того, какая ваша точность по обучающим данным: если 0.999, значит, вы переобучаетесь, если 0.62, значит, вы недообучаетесь.
Обычно вы смотрите на оба анализа, так как это помогает вам в направлении улучшения модели.
Ответ или решение
Почему неверно обучать и тестировать модель на одном и том же наборе данных
Обучение и тестирование модели на одном и том же наборе данных представляет собой серьезную ошибку в области анализа данных и машинного обучения. Эта практика не только теоретически неправомерна, но и приводит к практически пагубным последствиям. Рассмотрим более подробно все аспекты этой проблемы.
Теоретические основания
Основная цель тестирования модели заключается в оценке того, как хорошо она будет предсказывать на данных, которые не были использованы в процессе обучения. Если модель тестируется на тех же данных, на которых она обучалась, она не может показать реальную способность обобщения. Это создает риск, что мы получим чрезмерно оптимистичные результаты — модель может показывать высокую точность, но это не является индикатором ее эффективности в реальных условиях.
Практические проблемы
1. Переподгонка (overfitting)
Один из наиболее значимых недостатков использования одного и того же набора данных для обучения и тестирования — это возможность переподгонки модели. В случае, если модель обладает высокой сложностью (например, слишком большим количеством параметров), она может «запомнить» Training Data, вместо того чтобы понять скрытые закономерности. При этом вы не сможете обнаружить, что модель реально не способна к обобщению — на тестовых данных она покажет отличные результаты, так как эти данные фактически являются частью обучающего набора.
Пример: Если вы обучаете модель для прогнозирования цен на жилье, и ваша модель с точностью предсказывает цену на основе доступных данных, это не обязательно говорит о том, что она действительно уловила структуру данных. Например, если ваша модель всегда отвечает, что дом с площадью 50 квадратных метров стоит ровно 150,002, это не говорит о ее эффективности, так как она просто запомнила значения из обучающего набора.
2. Концептуальные изменения (concept drift)
В реальных приложениях данные могут меняться со временем. Если вы обучаете модель на одном наборе данных и одновременно тестируете ее, то ваша модель может не заметить изменений в структуре данных и, соответственно, не будет готова справляться с новыми условиями. Например, модель, обученная на данных продаж за один период, может не сработать должным образом в будущем, если поведение покупателей изменится.
Круговая логика и самопроверка
Использование одного и того же набора данных для тестирования порождает круговую логику: когда ваша модель «знает» ответ, который вы ей уже предоставили, это никак не доказывает ее способность к предсказанию. По сути, это как если бы учитель сдавал тесты своим ученикам на основе домашних заданий — это не позволяет выяснить, усвоили ли они материал, так как студенты могут просто запомнить ответы.
Подходы к тестированию моделей
Для адекватной оценки эффективности модели рекомендуется использовать разбиение данных на три основных набора:
- Обучающий набор: Используется непосредственно для обучения модели.
- Валидационный набор: Применяется для настройки гиперпараметров и оценки возможной переподгонки. Данный набор позволяет выявить, как сильно модель «помнит» обучающие данные.
- Тестовый набор: Используется строго для проверки итоговой модели и не должен воздействовать на обучение или настройку параметров.
Такой подход дает возможность более точно оценить возможности модели и минимизировать вероятность перетренированности.
Заключение
Таким образом, использование одного и того же набора данных для обучения и тестирования модели влечет за собой множество проблем, начиная от переобучения и заканчивая неправильной оценкой ее эффективности. Это не только теоретически неверно, но также может привести к серьезным ошибкам при принятии решений на основе прогнозов модели. Правильная практика включает разбитие данных на независимые наборы, позволяя более точно оценивать и обобщать результаты.