Как использовать fastai для построения надежной базовой модели для классификации изображений?

TL; DR - фрагмент кода для использования

У вас есть базовая идея и фрагмент кода для построения вашей базовой модели? Использовать этот:

from fastai.vision import *
# Defining the data and the model
path = untar_data(URLs.CIFAR)
tfms = get_transforms(do_flip=False)
data = ImageDataBunch.from_folder(path, valid='test', ds_tfms=tfms, size=128)
learn = cnn_learner(data, models.resnet50, metrics=accuracy)
# Estimate learning rate
learn.lr_find()
learn.recorder.plot()
# Training
learn.fit_one_cycle(3, max_lr=1e-3)
# Finetuning
learn.unfreeze()
learn.fit_one_cycle(3, max_lr=slice(1e-6, 1e-4))
# Test Time Augmentation
preds,targs = learn.TTA()
accuracy(preds, targs).item()

Вступление

Компьютерное зрение существует с 1950-х годов, но только в последнее десятилетие эта область полностью изменилась (на самом деле особый момент случился в 2012 году, когда AlexNet выиграла конкурс ImageNet).

За последние несколько лет появилось много мощных фреймворков. Мы собираемся использовать fastai, поскольку на момент написания он предлагал самые простые API и самые надежные настройки по умолчанию. Это оболочка высокого уровня над PyTorch. Наша цель - создать базовый план классификации изображений общего назначения в соответствии со стандартами 2020 года.

Задача классификации изображений

Давайте воспользуемся популярным набором данных CIFAR-10, который содержит 60 000 цветных изображений 32x32 в 10 различных классах. Он разделен на 50 000 обучающих примеров и 10 000 тестовых примеров. Набор данных CIFAR уже предоставлен в качестве образца набора данных в библиотеке fastai.

from fastai.vision import *
path = untar_data(URLs.CIFAR)

Давайте начнем с минимального примера прямо из документации и будем изменять его по мере продвижения.

tfms = get_transforms(do_flip=False)
data = ImageDataBunch.from_folder(path, valid='test', ds_tfms=tfms)
learn = cnn_learner(data, models.resnet50, metrics=accuracy)
learn.fit(3)

Давайте разберем три наиболее важных вещи, которые здесь происходят:

  1. Увеличение данных. Такие методы, как обрезка, заполнение и горизонтальное отражение, обычно используются при обучении больших нейронных сетей классификации изображений. Это помогает избежать переобучения и лучше обобщать без фактического сбора каких-либо новых данных. Самый простой способ сделать это - использовать get_transforms в fastai, который позволяет вам выбирать из стандартного набора преобразований, где значения по умолчанию предназначены для фотографий.
  2. Разделение набора данных на наборы проверочных проверок: мы всегда должны разбивать набор данных на наборы проверочных проверок поездов. Если мы используем набор проверки для настройки любого гиперпараметра (например, архитектуры модели, скорости обучения и т. Д.), Также требуется набор тестов, если вы хотите сообщить окончательный показатель (например, точность). В этом примере мы не настраиваем какой-либо гиперпараметр с помощью набора проверки, поэтому мы не используем набор тестов. На практике вы можете использовать, скажем, 50000 примеров для обучения, 5000 для проверки и 5000 для набора тестов. ImageDatabunch API в fastai предоставляет простой способ загрузить ваши данные и разделить их, если они уже сохранены в некоторых стандартных форматах. Вы также можете использовать DataBlock API, если хотите больше настраиваемого контроля над тем, как выбирать данные, разделять и маркировать их.
  3. Трансферное обучение. Трансферное обучение предполагает взятие моделей, обученных одной задаче, а затем их использование для другой задачи. Здесь мы используем архитектуру ResNet50, обученную в ImageNet, которая содержит около 14 миллионов изображений. Вы также можете поэкспериментировать с другими архитектурами, включая более глубокие модели ResNet, когда у вас будет базовый уровень. Идея трансферного обучения заключается в том, что большинство более ранних уровней сети идентифицируют общие функции, такие как края, которые полезны для классификации любого изображения. Когда мы тренируемся для новой задачи, мы сохраним все сверточные слои (называемые телом или основой модели) с их весами, предварительно обученными в ImageNet, но определим новую голову, инициализированную случайным образом. Этот заголовок адаптирован к количеству классов, необходимых для новой задачи классификации. Вызывая fit на cnn_learner по умолчанию, мы оставляем тело замороженным и тренируем только голову.

На данный момент мы получаем около 70% точности после тренировки в течение 3 эпох.

Изменение размера входного изображения

Изначально ResNet был обучен на изображениях 224x224, а наш набор данных содержит изображения 32x32. Если вы используете входные изображения, размер которых слишком отличается от исходного, то это не оптимально для данной модели. Давайте посмотрим, как изменится размер этих изображений до 128x128, на точность. ImageDataBunch API позволяет передавать размер.

tfms = get_transforms(do_flip=False)
data = ImageDataBunch.from_folder(path, valid='test', ds_tfms=tfms, size=128)
learn = cnn_learner(data, models.resnet50, metrics=accuracy)
learn.fit(3)

Кучность стрельбы до 94%. Мы уже достигли уровня выполнения этой задачи на уровне человека. Мы также могли бы изменить размер до 224x224, но это увеличит время обучения, а также, поскольку это изображения с довольно низким разрешением, при большом увеличении могут остаться артефакты. При необходимости вы можете поэкспериментировать с этим позже, когда у вас будет базовый уровень.

Изменение скорости обучения

Скорость обучения часто является наиболее важным гиперпараметром, который нужно настраивать при обучении нейронных сетей. Это влияет на скорость, с которой веса сети изменяются с каждым пакетом обучения. Очень низкая скорость обучения может привести к медленному обучению. С другой стороны, очень большая скорость обучения может привести к колебаниям функции потерь около минимума или даже к расхождению. Традиционно это гиперпараметр, настраиваемый и устанавливаемый с помощью поиска по сетке с дополнительными формулами, которые снижают скорость обучения с использованием определенной стратегии (например, Time-Based Decay, Step Decay и т. Д.).

Лесли Смит в 2015 году разработал новый метод установки скорости обучения, названный Cyclical Learning Rate (CLR). Вместо монотонного уменьшения скорости обучения этот метод позволяет скорости обучения циклически варьироваться между разумными граничными значениями. Это избавляет от необходимости подбирать наилучшее значение для скорости обучения. Fastai реализует политику CLR с одним циклом, в которой скорость обучения начинается с низкого значения, увеличивается до очень большого значения, а затем уменьшается до значения, намного меньшего, чем его начальное.

Fastai также предлагает удобный метод для оценки максимальной скорости обучения, которая будет использоваться в политике одного цикла. Для этого он начинает обучать модель, увеличивая скорость обучения с очень низкого значения до очень большого. Первоначально потери снижаются, но по мере того, как скорость обучения продолжает расти, потери начинают увеличиваться. Когда потери примерно минимальны, скорость обучения уже слишком высока. Практическое правило - установить максимальную скорость обучения на порядок меньше минимальной.

learn = cnn_learner(data, models.resnet50, metrics=accuracy)
learn.lr_find()
learn.recorder.plot()

Здесь вы можете попробовать установить скорость обучения между 1e-03 и 1-e02. Пока мы будем использовать 1e-03.

learn = cnn_learner(data, models.resnet50, metrics=accuracy)
learn.fit_one_cycle(3, max_lr=1e-3)

Мы достигаем точности около 95% на проверке, установленной сейчас за 3 эпохи.

Тонкая настройка

Ранее мы обучили только новую случайно инициализированную голову нашей модели, сохраняя веса тела замороженными. Теперь мы можем разморозить тело и обучить всю сеть. Давайте используем lr_find и оценим новую скорость обучения, которую нужно использовать, прежде чем мы это сделаем.

learn.lr_find()
learn.recorder.plot()

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

learn.unfreeze()
learn.fit_one_cycle(3, max_lr=slice(1e-6, 1e-4))

Мы видим, что точность все еще улучшается.

Увеличение времени тестирования

И последнее, что вы можете сделать для своего универсального теста, - это увеличение времени тестирования (TTA). TTA выполняется на наборе для тестирования / проверки для улучшения качества прогнозирования - он включает в себя сначала создание нескольких версий каждого изображения с использованием увеличения данных, а затем мы пропускаем их через нашу обученную модель, чтобы получить несколько прогнозов, и, наконец, мы берем среднее значение этих прогнозов. чтобы получить окончательный прогноз. TTA часто дает нам лучшую производительность без необходимости какого-либо дополнительного обучения, но требует времени на окончательное прогнозирование.

preds,targs = learn.TTA()
accuracy(preds, targs).item()

Мы достигли точности более 96%. Замечательно. Еще одна простая вещь, которая может улучшить нашу точность, - это просто обучение и точная настройка на большее количество эпох. Но давайте на этом остановимся.

Где мы находимся?

Ознакомьтесь с современными контрольными показателями, достигнутыми на CIFAR-10. Выше 96% - это результат, достигнутый только за последние пару лет. Большинство моделей обучаются в течение значительно более длительного времени, используют больше ресурсов, чем блокнот для совместной работы, и имеют больше параметров - следовательно, мы можем быть уверены, что наши 96% для этой классификации изображений общего назначения действительно хороши.

Заключение

Одна из самых полезных вещей, которые вы можете сделать в начале нового проекта машинного обучения, - это установить базовый уровень. Для классификации изображений fastai помогает быстро создать надежную базовую линию практически без настройки гиперпараметров.

Вы можете найти полный код, использованный для этого поста, в этой колаб-записной книжке. Не стесняйтесь экспериментировать с ним и использовать в своих проектах. Я хотел бы обсудить, если у вас есть какие-либо мысли или вопросы.