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

Эта запись в блоге предназначена для того, чтобы дать вам обзор того, что такое трансферное обучение, как оно работает, почему вам следует его использовать и когда вы можете его использовать.

Темы:

- Передача обучения

- Предварительно обученная модель

- Типичный CNN

  1. Сверточная база
  2. Классификатор

- Перенос сценариев обучения:

  1. ConvNet как экстрактор фиксированных функций / поезд как классификатор
  2. Тонкая настройка ConvNet / точная настройка
  3. Предварительно обученные модели

- Передача обучения с использованием pytorch для классификации изображений

Программа / код / ​​приложение трансферного обучения ниже в этом блоге с точностью 98%

Думаю, Глубокое обучение сильно помогло Excel в классификации изображений: с 2014 года по настоящее время было введено несколько методов с широким использованием данных и вычислительных ресурсов . Несколько современных результатов в классификации изображений основаны на решениях для трансферного обучения.

Передача обучения:

Передача обучения в основном используется в Компьютерное зрение ( учебник) , Классификация изображений ( учебник) и Обработка естественного языка ( учебник ) Такие задачи, как анализ настроений, поскольку огромное количество вычислительной мощности, которая им необходима.

Передача обучения - это передача знаний.

Предварительно обученная модель:

Предварительно обученные модели (VGG, InceptionV3, Mobilenet) чрезвычайно полезны, когда они подходят для поставленной задачи, но они часто не оптимизированы для конкретного набора данных, с которым сталкиваются пользователи. . Например, InceptionV3 - это модель, оптимизированная для классификации изображений по широкому набору из 1000 категорий, но нашей областью может быть классификация пород собак. Часто используемый метод в глубоком обучении - это трансферное обучение, которое адаптирует модель, обученную для аналогичной задачи, к текущей задаче. По сравнению с обучением новой модели с нуля, трансферное обучение требует значительно меньше данных и ресурсов.

Пример: может быть смешно, но да! Если вы научитесь ездить на велосипеде, тогда будет легко ездить на велосипеде со знанием или изучением таких функций, как балансировка, управляемость, тормоза.

Несколько изображений, которые расскажут вам, что такое трансферное обучение

Несколько предварительно обученных моделей, используемых в трансферном обучении, основаны на больших сверточных нейронных сетях (CNN).

При трансферном обучении вы используете ранний и средний уровни и повторно тренируете только последние уровни.

Типичный CNN:

Типичный CNN состоит из двух важных частей (см. Рисунок выше):

  1. Сверточная база / изучение функций (Conv + Relu + Pooling)
  2. Классификатор / Классификация (полносвязный слой)
  3. Сверточная база, состоящая из набора сверточных и объединяющих слоев. Основная цель сверточной основы - создать на основе изображения элементы, такие как края / линии / кривые на более ранних слоях и формы на средних слоях.
  4. Классификатор, который обычно состоит из полностью связанных слоев. Классификатор классифицирует изображение на основе функций, связанных с конкретной задачей.

При трансферном обучении вы используете сверточную базу и только повторно обучаете классификатор для вашего набора данных.

Сценарии передачи обучения:

Трансферное обучение можно использовать тремя способами:

  1. ConvNet как экстрактор фиксированных функций / поезд как классификатор
  2. Тонкая настройка ConvNet / точная настройка
  3. Предварительно обученные модели
  4. ConvNet как средство извлечения фиксированных функций:

Возьмите ConvNet (VGG-16), предварительно обученную в ImageNet (1,2 млн входных изображений, оценка класса 1000 выходов), затем удалите последний полностью подключенный слой (выходы этого уровня представляют собой оценки класса 1000 для другой задачи, такой как ImageNet), затем обработайте остальная часть ConvNet в качестве экстрактора фиксированных функций для нового набора данных.

В VGG16, предварительно обученном в ImageNet (рисунок ниже), это будет вычислять вектор 4096-D для каждого изображения, которое содержит активации скрытого слоя непосредственно перед классификатором. После извлечения кодов 4096-D для всех изображений обучите линейный классификатор (например, линейный SVM или классификатор Softmax) для нового набора данных.

2. Тонкая настройка ConvNet:

Вторая стратегия состоит в том, чтобы не только заменить и переобучить классификатор поверх ConvNet в новом наборе данных, но также точно настроить веса предварительно обученной сети, продолжая обратное распространение.

а) Можно точно настроить все уровни ConvNet, или б) можно оставить некоторые из более ранних уровней фиксированными (из-за проблем с переобучением) и настроить только некоторую более высокоуровневую часть сети.

Если вы видите это На левом изображении VGG-16 первые 4 блока Conv заморожены, здесь настраиваются последние Conv и FC, на правом изображении VGG16 первые 5 блоков Conv заморожены, здесь был точно настроен только последний блок FC . Это зависит от вас и вашего набора данных по вашему выбору.

3. Предварительно обученная модель: поскольку современные ConvNets занимают 2–3 недели для обучения с использованием нескольких графических процессоров в ImageNet, часто можно увидеть, как люди выпускают свои последние контрольные точки ConvNet в интересах других, которые могут использовать сети для точной настройки.

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

Перенос сценариев обучения:

  1. Новый набор данных невелик и похож на исходный набор данных. Поскольку данных мало, не рекомендуется выполнять тонкую настройку ConvNet из-за проблем с переобучением. Поскольку данные аналогичны исходным данным, мы ожидаем, что высокоуровневые функции в ConvNet также будут иметь отношение к этому набору данных. Следовательно, лучшей идеей может быть обучение линейного классификатора на кодах CNN.
  2. Новый набор данных большой и похож на исходный набор данных. Поскольку у нас больше данных, мы можем быть уверены в том, что не переобучаемся, если попытаемся выполнить точную настройку по всей сети.
  3. Новый набор данных невелик, но сильно отличается от исходного набора данных. Поскольку данных мало, лучше всего обучать только линейный классификатор. Поскольку набор данных сильно отличается, может быть не лучшим решением обучать классификатор на вершине сети, которая содержит больше функций, специфичных для набора данных. Вместо этого, возможно, будет лучше обучить классификатор SVM от активаций где-нибудь раньше в сети.
  4. Новый набор данных большой и сильно отличается от исходного набора данных. Поскольку набор данных очень велик, мы можем ожидать, что сможем позволить себе обучить ConvNet с нуля. Однако на практике очень часто бывает полезно инициализировать веса из предварительно обученной модели. В этом случае у нас будет достаточно данных и уверенности для точной настройки всей сети.

Перенос обучения с использованием pytorch для классификации изображений:

В этом руководстве вы узнаете, как обучить свою сеть с помощью трансферного обучения. Я рекомендую использовать google colab для быстрых вычислений и ускорения обработки.

вы можете посмотреть весь код google colab здесь, в моем github.

Эти два основных сценария трансферного обучения выглядят следующим образом:

  • Тонкая настройка свертки: вместо случайной инициализации мы инициализируем сеть с предварительно обученной сетью, например той, которая обучена на наборе данных imagenet 1000. Остальная часть тренировки выглядит как обычно.
  • ConvNet как средство извлечения фиксированных функций: здесь мы зафиксируем веса для всей сети, кроме последнего полностью подключенного уровня. Этот последний полностью связанный слой заменяется новым со случайными весами, и только этот слой обучается.

Пакеты:

from __future__ import print_function, division

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
import numpy as np
import torchvision
from torchvision import datasets, models, transforms
import matplotlib.pyplot as plt
import time
import os
import copy

plt.ion()   # interactive mode

Загрузка данных:

В тренировочном архиве 25000 изображений собак и кошек. вы можете скачать и узнать больше о данных здесь.

# Data augmentation and normalization for training
# Just normalization for validation
data_transforms = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
    'val': transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ]),
}
data_dir = '/content/Cat_Dog_data/'
image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x),
                                          data_transforms[x])
                  for x in ['train','val']}
dataloaders = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=4,
                                             shuffle=True, num_workers=4)
              for x in ['train','val']}
dataset_sizes = {x: len(image_datasets[x]) for x in ['train','val']}
class_names = image_datasets['train'].classes
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

Визуализируйте несколько изображений:

def imshow(inp, title=None):
    """Imshow for Tensor."""
    inp = inp.numpy().transpose((1, 2, 0))
    mean = np.array([0.485, 0.456, 0.406])
    std = np.array([0.229, 0.224, 0.225])
    inp = std * inp + mean
    inp = np.clip(inp, 0, 1)
    plt.imshow(inp)
    if title is not None:
        plt.title(title)
    plt.pause(0.001)  # pause a bit so that plots are updated
# Get a batch of training data
inputs, classes = next(iter(dataloaders['train']))
# Make a grid from batch
out = torchvision.utils.make_grid(inputs)
imshow(out, title=[class_names[x] for x in classes])

Обучение модели

Теперь давайте напишем общую функцию для обучения модели. Здесь мы проиллюстрируем:

  • Планирование скорости обучения
  • Сохранение лучшей модели

Далее параметр scheduler - это объект планировщика LR из torch.optim.lr_scheduler.

def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
    since = time.time()

    best_model_wts = copy.deepcopy(model.state_dict())
    best_acc = 0.0

    for epoch in range(num_epochs):
        print('Epoch {}/{}'.format(epoch, num_epochs - 1))
        print('-' * 10)

        # Each epoch has a training and validation phase
        for phase in ['train', 'val']:
            if phase == 'train':
                scheduler.step()
                model.train()  # Set model to training mode
            else:
                model.eval()   # Set model to evaluate mode

            running_loss = 0.0
            running_corrects = 0

            # Iterate over data.
            for inputs, labels in dataloaders[phase]:
                inputs = inputs.to(device)
                labels = labels.to(device)

                # zero the parameter gradients
                optimizer.zero_grad()

                # forward
                # track history if only in train
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)

                    # backward + optimize only if in training phase
                    if phase == 'train':
                        loss.backward()
                        optimizer.step()

                # statistics
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)

            epoch_loss = running_loss / dataset_sizes[phase]
            epoch_acc = running_corrects.double() / dataset_sizes[phase]

            print('{} Loss: {:.4f} Acc: {:.4f}'.format(
                phase, epoch_loss, epoch_acc))

            # deep copy the model
            if phase == 'val' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy(model.state_dict())

        print()

    time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(
        time_elapsed // 60, time_elapsed % 60))
    print('Best val Acc: {:4f}'.format(best_acc))

    # load best model weights
    model.load_state_dict(best_model_wts)
    return model

Визуализация прогнозов модели:

Общая функция для отображения прогнозов для нескольких изображений

def visualize_model(model, num_images=6):
    was_training = model.training
    model.eval()
    images_so_far = 0
    fig = plt.figure()

    with torch.no_grad():
        for i, (inputs, labels) in enumerate(dataloaders['val']):
            inputs = inputs.to(device)
            labels = labels.to(device)

            outputs = model(inputs)
            _, preds = torch.max(outputs, 1)

            for j in range(inputs.size()[0]):
                images_so_far += 1
                ax = plt.subplot(num_images//2, 2, images_so_far)
                ax.axis('off')
                ax.set_title('predicted: {}'.format(class_names[preds[j]]))
                imshow(inputs.cpu().data[j])

                if images_so_far == num_images:
                    model.train(mode=was_training)
                    return
        model.train(mode=was_training)

Тонкая настройка свёрточной сети:

Загрузите предварительно обученную модель и сбросьте окончательный полностью связанный слой.

model_ft = models.resnet18(pretrained=True)
num_ftrs = model_ft.fc.in_features
model_ft.fc = nn.Linear(num_ftrs, 2)

model_ft = model_ft.to(device)

criterion = nn.CrossEntropyLoss()

# Observe that all parameters are being optimized
optimizer_ft = optim.SGD(model_ft.parameters(), lr=0.001, momentum=0.9)

# Decay LR by a factor of 0.1 every 7 epochs
exp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)

Тренируйте и оценивайте

Это займет около 45–60 минут на ЦП. Однако на графическом процессоре это занимает меньше часа, так как мы работаем с огромным набором данных из 25000 изображений.

model_ft = train_model(model_ft, criterion, optimizer_ft, exp_lr_scheduler,num_epochs=25)

наконец эпоха:

Epoch 24/24
----------
train Loss: 0.0822 Acc: 0.9650
val Loss: 0.0315 Acc: 0.9876

Training complete in 133m 50s
Best val Acc: 0.988400

Мы получили Точность на проверочном наборе 98,84%.

Визуализируйте результат

visualize_model(model_ft)

Подобный учебник

Вы можете найти аналогичный учебник по Муравьям и Пчелам здесь, на официальном сайте pytorch здесь.

Отличные умы в области трансферного обучения:

Резюме:

- Передача обучения

- Предварительно обученная модель

- Типичный CNN

  1. Сверточная база
  2. Классификатор

- Перенос сценариев обучения:

  1. ConvNet как экстрактор фиксированных функций / поезд как классификатор
  2. Тонкая настройка ConvNet / точная настройка
  3. Предварительно обученные модели

- Передача обучения с использованием pytorch для классификации изображений

Программа / код / ​​приложение трансферного обучения выше в этом блоге с точностью 98%.

Спасибо

Вы можете комментировать свои взгляды. будет обновлено, если будут обнаружены какие-либо ошибки. пожалуйста, не стесняйтесь комментировать и, как обычно, вы можете связаться со мной по linkedin ниже.



Спасибо.

Ссылки / другие полезные руководства:

Себастьян Рудер блог.

Андрей карпатый блог.

Хакерская земля блог.

Pytorch Transfer Learning блог.