Модуль: PyTorch. Теория: как обучается нейросеть


Batch, DataLoader и проверка


Войдите на сайт, чтобы ответы сохранялись и баллы за тетрадь засчитывались.

Как модель учится на наборе примеров

Одного примера недостаточно, чтобы понять, какое правило стоит за данными. Покажем модели несколько входов и правильных ответов: числам 0, 1, 2, 3 поставим в соответствие 1, 3, 5, 7. Человек быстро замечает зависимость y = 2x + 1. Модели мы эту формулу не сообщим. Ей будет доступен линейный слой с изменяемыми весом и смещением, а обучение должно подобрать значения, при которых предсказания согласуются с примерами.

Каждый объект здесь имеет только один признак, поэтому входная таблица содержит четыре строки и один столбец. Правильные ответы тоже запишем столбцом формы (4, 1), чтобы сравнение происходило попарно. Когда мы передаём всю таблицу в nn.Linear(1, 1), один и тот же вес и одно и то же смещение применяются ко всем четырём строкам. Сеть не создаёт отдельное правило для каждого объекта: она ищет общие параметры.



Вход и выход имеют одинаковую форму (4, 1). Это позволяет вычислить среднюю квадратичную ошибку сразу по всем объектам. Каждый вносит свой вклад, а усреднение превращает четыре отклонения в одно число для обратного прохода. Производная этой средней ошибки учитывает весь набор, поэтому обновление параметров становится компромиссом между примерами. В нашей искусственной задаче точное общее правило существует, и линейного слоя достаточно, чтобы к нему приблизиться.

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



Вес приближается к 2, а смещение — к 1. Мы заранее знаем правильную зависимость, поэтому можем сопоставить найденные параметры с формулой. При работе с рукописными цифрами такой простой проверки не будет: правильные веса заранее неизвестны, и результат придётся оценивать по ответам модели на данных. Но принцип обучения останется тем же — одни параметры подбираются с учётом многих примеров.

Зачем делить данные на небольшие порции

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

В PyTorch объект TensorDataset связывает входы и ответы в пары с одинаковыми индексами. Затем DataLoader выдаёт эти пары порциями указанного размера. В примере выберем batch_size=2: четыре объекта дадут две порции. Отключим перемешивание с помощью shuffle=False, чтобы порядок было легко проследить. При обучении часто используют shuffle=True, чтобы порядок объектов при новых проходах менялся.



Цикл дважды печатает формы (2, 1) для входов и ответов. Это две порции, а не два разных набора данных. Если бы объектов было пять, при обычном сохранении последней неполной порции размеры составили бы 2, 2 и 1. Число обновлений за эпоху определяется количеством порций. Например, 103 объекта при размере порции 20 и drop_last=False дадут шесть обновлений: пять полных порций и одну из трёх объектов.

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



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

Можно также считать среднюю ошибку, наблюдавшуюся в течение эпохи. Если порции неодинаковы, нужно учитывать их размеры. Например, средние ошибки 1 и 5 на порциях из четырёх и одного объекта дают общую среднюю (4 · 1 + 1 · 5) / 5 = 1.8, а не 3. В коде для этого суммируют loss.item() * len(xb) и делят на общее число объектов, если ошибка внутри порции усреднена по объектам. Но даже правильно взвешенная средняя собрана при меняющихся весах; она может отличаться от ошибки, заново измеренной после эпохи.

Что означает честная проверка

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

При оценке вызывают model.eval() и отключают отслеживание производных с помощью torch.no_grad(). Первое переключает режим работы тех слоёв, у которых обучение и применение различаются; второе убирает ненужное построение графа. Следующий самостоятельный блок показывает только устройство такого вычисления. В нём создаётся новая, ещё не обученная модель и используются те же четыре точки, поэтому это не итоговая проверка качества.



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

Проверим понимание

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


103 объекта, batch_size=20, drop_last=False. Сколько обновлений за эпоху?


У двух batch размеры 4 и 1; средние ошибки 1 и 5. Какова средняя по всем 5 объектам?