Что будет, если не вызвать model.eval() на этапе валидации?
Что проверяют
Понимаете ли вы, что model.eval() это переключатель режима слоёв, а не заморозка весов и не отключение градиентов. Вопрос отсеивает тех, кто копировал цикл обучения, не разбираясь, зачем в нём каждая строка.
Как отвечать
model.eval() выставляет всем подмодулям флаг режима. На поведение влияет он только у тех слоёв, которые ведут себя в обучении и в предсказании по-разному:
- слой прореживания перестаёт занулять активации, и выход становится детерминированным;
- нормализация по батчу переключается с текущей батчевой статистики на накопленные
running_meanиrunning_var.
Если вызов забыт, валидация считается с включённым прореживанием и по статистике конкретного батча: метрика шумит, меняется от прогона к прогону и зависит от размера и состава батча. Хуже другое: в режиме обучения нормализация ещё и обновляет накопленную статистику, то есть валидационные данные протекают в параметры модели, и честность оценки теряется совсем.
Отдельно скажите, что режим не отключает построение графа вычислений. Память и время экономит torch.no_grad(), это независимый механизм:
model.eval()
with torch.no_grad():
for x, y in val_loader:
loss = criterion(model(x), y)
model.train()Где спотыкаются
Считают, что режим предсказания замораживает веса. Веса меняет только шаг оптимизатора, и вызов внутри валидационного цикла испортит модель независимо от режима, ровно как и забытое обнуление градиентов.
Второе: переключают в режим предсказания и не возвращают обратно. Дальнейшее обучение идёт без прореживания и с замороженной статистикой нормализации, качество тихо просаживается, а причину ищут в данных.
Третье: валидируют по одному объекту, оставшись в режиме обучения. Одномерная нормализация по батчу не может посчитать дисперсию по единственному элементу и падает с ошибкой, которую списывают на битый батч.