Skip to main content

SSL - Pretext - Report

SSL Course
Created on February 1|Last edited on February 1


Введение

DISCLAIMER: К сожалению, я поздно подключился к курсу -- на 60% (по времени) из-за сложностей с учебкой (согласовать курс как маголего); на 40%, т.к. не ожидал ДЗ в самом начале курса и искал нормальную GPU. В результате на это ДЗ у меня было 2 дня. Поэтому мне пришлось отойти от своих привычек оформлять репозиторий и логировать все и вся, да и на эксперименты осталось мало времени. Впредь буду внимательнее.
В этом задании требовалось обучить ResNet-18 на задачу классификации (10 классов), дополнительно используя неразмеченные данные, которых было гораздо больше обучающих. Использовать можно было только классические Pretext задачи: Rotations, Jigsaw, Relative Context Prediction и другие.
В результате мне довольно просто удалось обучить модель на 0.75121 accuracy (на тесте), используя всего одну Pretext задачу (Rotations) и немного плясок на Supervised задаче.

Обучение

1. No Pretraining

Чтобы оценить сколько вообще Pretraining может дать в качестве, я решил сначала оценить качество без предобучения, то есть сразу начал учить на supervised задаче. Начинаю я всегда с переобучения на одном батче, тут с этим было все ок. Я специально не использовал какие-либо трюки для поднятия качества (я бы назвал это Zero-Tuning policy), чтобы оценить дальнейший прогресс. К тому же размеченная часть довольно маленькая, поэтому модель быстро сошлась (даже в колабе).
Однако результат оказался совсем не приемлемым: модель достигла ~0.5 accuracy на валидации (20% размеченных данных).
К сожалению, на тот момент я не прикрутил WandB логгирование, рисовал все matplotlib'ом, а затем и вообще потерял все логи; так что придется поверить мне на слово. В любом случае, там не было ничего интересного, а мне нужен был лишь ориентир.

2. Rotations

Можно было бы стараться выбить все качество только на supervised задаче, но по заветам Karpathy, стоит начать с добавления новых данных, коих у нас полно неразмеченных. Так что я сразу принялся имплементить один из способов pretraining'а. Выбор пал на Rotations, т.к. 1. их просто и быстро реализовать, 2. в чате вскользь упомянули об их крутости на этих данных.
После их реализации, я протестил на одном батче, добавил логирование и запустил обучение в той же конфигурации, что и раньше (Zero-Tuning). Метрики здесь не очень осмысленны, но я ориентировался на accuracy на валидации, то есть на способность модели правильно классифицировать поворот.
"Качество" на валидации росло монотонно, поэтому я воспользовался одним из самых эффективных методов -- долгое обучение -- оно меня пока не подводило:)

Run set
1

Обучение заняло у меня 3 часа на слабой colab GPU, после чего у меня кончилась квота (какая-то она маленькая стала, а вот раньше...). После чего я принялся обучать на supervised задаче.

  1. 01.finetune: Я снова воспользовался Zero-Tuning Policy , чтобы сравниться с чистым supervised подходом. Обученная таким образом модель дает ~0.63 accuracy на валидации, что уже значительно лучше, но все равно не хватает для посылки в kaggle (по опыту на тесте обычно чуть меньше, хотя я мб просто переобучался под валидацию).
  2. 02.finetune-augs: Немного начал приседать в supervised задаче. Первое, что сделал -- это добавил аугментации, чтобы немного затрейдить качество на обучении и качество на тесте. С картинками я работал нечасто, поэтому подбирать аугментации пока не очень умею, выбрал из пресетов (AutoAugment и другие); насколько я помню именно AutoAugment слишком агрессивный, поэтому выбор пал в пользу TrivialAugmentWide, к тому же он самый новый (2018) из представленных. Смущало только наличие поворотов и флипов в нем, но на это забил. Такой сетап добился ~0.73 accuracy на валидации и 0.75121 на тесте, чему я был рад, так как боялся не успеть. Также я еще раз запускал обучаться, чтобы собрать ансамбль и залутать проценты, но потом решил, что это лишнее.

Run set
2


Детали и наблюдения

  • Наверное у всех, кто обучает модели, есть свой стандартный сетап оптимизатора/шедулера по умолчанию. В моем случае это Adam(lr=3e-4, weight_decay=1e-4) и OneCycleLR(max_lr=4e-3, pct_start=0.3). Он используется во всех запусках. Тюнил бы я его в самом конце.
  • Я использовал все доступные картинки (в т.ч. тестовые) в качестве unlabeled данных.
  • Я старался везде фиксировать seed, но в одном месте, кажется, забыл -- при разделении данных на train/val.
  • Вполне вероятно, что аугментации стоило заводить еще на этапе претрейна. Там бы точно стоило отказаться от флипов и поворотов.
  • На этапе дообучения можно наблюдать феномен Deep Double Descent. Особенно видно, если сгладить графики. Вообще с 10 по 50 эпоху модель сильно флуктирует.
  • Если бы я продолжал эксперименты, я бы попробовал реализовать Context Prediction и DeepCluster, так как они довольно просты идейно, а также несколько задач одновременно (это еще интересно с точки зрения реализации, чтобы не было страшно смотреть). Inpainting я бы не трогал, в нем был бы слишком большой (относительно) upscale декодер.
  • Весь код в ноутбуке:( но я постарался причесать его и сделать читаемым. Все логи можно смотреть в WandB.

Итог

Мне удалось обучить модель на хорошее качество, используя неразмеченные данные и всего один Pretext подход. В целом ожидаемо увидел улучшение качества за счет использования новых данных, но не ожидаемо, что на это способно простое обучение поворотам.
Сводная таблица:
Методval_acctest_acc
Supervised0.5---
+ Rotations0.63---
+ Augmentations0.730.75121