Перенос обучения с PyTorch

глубокое обучение

Обзор

  • Трансферное обучение может изменить способ построения моделей машинного обучения и глубокого обучения.
  • Узнайте, как использовать PyTorch для передачи обучения и как связать его с использованием предварительно обученных моделей.
  • Мы будем использовать наборы данных из реального мира и сравнивать производительность моделей, построенных с использованием сверточных нейронных сетей (CNN), и моделей, построенных с использованием трансферного обучения.

вводить

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

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

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

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

Эта статья является частью серии PyTorch для начинающих. Я твердо верю, что PyTorch — одна из лучших сред глубокого обучения, и в ближайшем будущем она будет становиться все более и более мощной. Это прекрасное время, чтобы узнать, как это работает, и принять участие.

содержание

  1. Введение в трансферное обучение
  2. Что такое предварительно обученная модель Как правильно выбрать предварительно обученную модель?
  3. Практический пример: классификация аварийных и неаварийных транспортных средств
  4. Использование сверточных нейронных сетей (CNN) для решения задач
  5. Решение проблем с использованием трансферного обучения PyTorch
  6. Сравнение производительности CNN и передача обучения

Введение в трансферное обучение

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

Какие разные подходы вы бы использовали для понимания предмета?

  • Поиск ресурсов в Интернете
  • Читайте статьи и блоги
  • Справочная литература
  • Найдите видеоуроки и т. д.

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

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

Вы можете проконсультироваться с экспертом в предметной области/предмете, компетентным в предмете, который вы хотите изучить. Этот человек поделится с вами своими знаниями. Тем самым ускоряя процесс обучения.

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

Да, идея трансферного обучения так проста!

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

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

Что такое предварительно обученная модель Как правильно выбрать предварительно обученную модель?

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

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

Имеется n предварительно обученных моделей. Нам нужно решить, какой режим лучше всего подходит для нашей задачи. Теперь предположим, что у нас есть три предварительно обученных сети — BERT, ULMFiT и VGG16.

Наша задача — классифицировать изображения (как мы это делали в предыдущих статьях этой серии). Итак, какие предварительно обученные модели вы бы выбрали?Позвольте мне сначала дать вам краткий обзор этих предварительно обученных сетей, который поможет нам выбрать правильную предварительно обученную модель.

Языковое моделирование использует BERT и ULMFiT, а задача классификации изображений использует VGG16. Если вы посмотрите на проблему под рукой, это проблема классификации изображений. Поэтому мы выбрали VGG16 как должное.

Теперь VGG16 может иметь разные веса, т. е. VGG16, обученный на ImageNet, или VGG16, обученный на MNIST:

ImageNet и МНИСТ

Теперь, чтобы определить правильную предварительно обученную модель для нашей проблемы, мы должны изучить эти наборы данных ImageNet и MNIST. Набор данных ImageNet состоит из 1000 классов и 1,2 миллиона изображений. Некоторыми из этих категорий данных являются животные, автомобили, магазины, собаки, продукты питания, инструменты и т. д.:

MNIST, с другой стороны, обучается на рукописных цифрах. Он включает в себя 10 категорий от 0 до 9:

Мы будем работать над проектом, в котором нам нужно разделить изображения на аварийные и неаварийные транспортные средства (о чем мы подробно поговорим в следующем разделе). Этот набор данных включает изображения транспортных средств, поэтому модель VGG16, обученная на наборе данных ImageNet, будет более полезной, поскольку в ней есть изображения транспортных средств.

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

Практический пример: классификация аварийных и неаварийных транспортных средств

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

Теперь давайте начнем разбираться в проблеме и визуализируем несколько примеров. Скачать изображение можно по этой ссылке: https://drive.google.com/file/d/1EbVifjP0FQkyB1axb7KQ26yPtWmneApJ/view

Сначала импортируйте необходимые библиотеки:

Далее мы прочитаем файл .csv, содержащий имена изображений и соответствующие метки:

CSV-файл состоит из двух столбцов:

  1. image_names: представляет имена всех изображений в наборе данных.
  2. emergencyorno: указывает, принадлежит ли конкретное изображение к срочному или несрочному классу. 0 означает, что изображение не является аварийным транспортным средством, 1 означает аварийный автомобиль

Далее мы загрузим все изображения и сохраним их в формате массива:

Загрузка этих изображений занимает около 12 секунд. В нашем наборе данных 1646 изображений, поскольку VGG16 нужны все изображения этой конкретной формы, мы сбрасываем их все на (224, 224, 3). Теперь давайте визуализируем некоторые изображения из набора данных:

Это полицейская машина, поэтому на ней наклейка с изображением машины скорой помощи. Теперь мы сохраняем цель в отдельной переменной:

Давайте создадим проверочный набор для оценки нашей модели:

У нас есть 1481 изображение в обучающем наборе и 165 изображений в проверочном наборе. Теперь нам нужно преобразовать набор данных в формат факела:

Точно так же мы преобразуем набор проверки:

Наши данные готовы!В следующем разделе мы построим свёрточную нейронную сеть (CNN), а затем воспользуемся предварительно обученной моделью для решения этой задачи.

Использование сверточных нейронных сетей (CNN) для решения задач

Наконец-то мы добрались до части создания модели! Прежде чем использовать трансферное обучение для решения этой проблемы, давайте установим для себя эталон с моделью CNN.

Мы построим очень простую архитектуру CNN с двумя сверточными слоями для извлечения функций из изображений и, наконец, полностью связанным слоем для классификации этих функций:

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

Вот так выглядит архитектура модели. Наконец, мы будем обучать модель на 15 эпох. Я установил для модели batch_size значение 128 (вы можете попробовать):

Это также распечатает сводку обучения. Потери при обучении уменьшаются после каждой эпохи, что является хорошим признаком. Проверим точность обучения и валидации:

Наша точность обучения составляет около 82%, что является достойным показателем. Проверьте точность проверки ниже:

# 验证集预测
prediction_val = []
target_val = []
permutation = torch.randperm(val_x.size()[0])
for i in tqdm(range(0,val_x.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = val_x[indices], val_y[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction_val.append(predictions)
    target_val.append(batch_y)
    
# 验证集精确度
accuracy_val = []
for i in range(len(prediction_val)):
    accuracy_val.append(accuracy_score(target_val[i],prediction_val[i]))
    
print('validation accuracy: \t', np.average(accuracy_val))

Точность проверки составляет 76%. Теперь, когда у нас есть эталон, пришло время использовать трансферное обучение для классификации аварийных и неаварийных транспортных средств!

Решение проблем с использованием трансферного обучения PyTorch

Я упоминал об этом выше и повторю здесь — мы будем использовать предварительно обученную модель VGG16, обученную на наборе данных ImageNet. Давайте посмотрим, какие шаги мы будем выполнять, чтобы обучить модель с помощью трансферного обучения:

  1. Во-первых, мы загрузим веса предварительно обученной модели — в нашем случае VGG16.
  2. Затем мы настроим модель в зависимости от имеющейся проблемы.
  3. Далее мы будем использовать эти предварительно обученные веса и извлекать особенности изображения.
  4. Наконец, мы будем использовать извлеченные функции для обучения точно настроенной модели.

Итак, начнем с загрузки весов модели:

# 加载预训练模型
model = models.vgg16_bn(pretrained=True)

Теперь займемся тонкой настройкой модели. Мы не обучаем слои модели VGG16, поэтому зафиксируем веса этих слоев:

# 固定模型权重
for param in model.parameters():
    param.requires_grad = False

Поскольку нам нужно предсказать только 2 класса, а VGG16 обучается на ImageNet, в котором 1000 классов, нам нужно обновить последний слой в соответствии с нашей задачей:

# 最后加一个分类器
model.classifier[6] = Sequential(
                      Linear(4096, 2))
for param in model.classifier[6].parameters():
    param.requires_grad = True

Поскольку мы тренируем только последний слой, я установил для параметра require_grad последнего слоя значение True. Ставим обучение на GPU:

# 检查GPU是否可用
if torch.cuda.is_available():
    model = model.cuda()

Теперь мы будем использовать модель и извлекать функции для обучения и проверки изображений. я сделаю партиюразмер установлен на 128 (опять же, вы можете увеличить или уменьшить размер пакета по мере необходимостиsize):

# batch大小
batch_size = 128

# 从训练集提取特征
data_x = []
label_x = []

inputs,labels = train_x, train_y

for i in tqdm(range(int(train_x.shape[0]/batch_size)+1)):
    input_data = inputs[i*batch_size:(i+1)*batch_size]
    label_data = labels[i*batch_size:(i+1)*batch_size]
    input_data , label_data = Variable(input_data.cuda()),Variable(label_data.cuda())
    x = model.features(input_data)
    data_x.extend(x.data.cpu().numpy())
    label_x.extend(label_data.data.cpu().numpy())

Точно так же давайте извлечем функции проверочного изображения:

# 从验证集提取特征
data_y = []
label_y = []

inputs,labels = val_x, val_y

for i in tqdm(range(int(val_x.shape[0]/batch_size)+1)):
    input_data = inputs[i*batch_size:(i+1)*batch_size]
    label_data = labels[i*batch_size:(i+1)*batch_size]
    input_data , label_data = Variable(input_data.cuda()),Variable(label_data.cuda())
    x = model.features(input_data)
    data_y.extend(x.data.cpu().numpy())
    label_y.extend(label_data.data.cpu().numpy())

Далее мы конвертируем эти данные в формат факела:

# 转换这些数据到torch格式
x_train  = torch.from_numpy(np.array(data_x))
x_train = x_train.view(x_train.size(0), -1)
y_train  = torch.from_numpy(np.array(label_x))
x_val  = torch.from_numpy(np.array(data_y))
x_val = x_val.view(x_val.size(0), -1)
y_val  = torch.from_numpy(np.array(label_y))

Мы также должны определить оптимизатор и функцию потерь для нашей модели:

# batch大小
batch_size = 128

# 30个epochs
n_epochs = 30

for epoch in tqdm(range(1, n_epochs+1)):

    # 跟踪训练与验证集损失
    train_loss = 0.0
        
    permutation = torch.randperm(x_train.size()[0])

    training_loss = []
    for i in range(0,x_train.size()[0], batch_size):

        indices = permutation[i:i+batch_size]
        batch_x, batch_y = x_train[indices], y_train[indices]
        
        if torch.cuda.is_available():
            batch_x, batch_y = batch_x.cuda(), batch_y.cuda()
        
        optimizer.zero_grad()
        outputs = model.classifier(batch_x)
        loss = criterion(outputs,batch_y)

        training_loss.append(loss.item())
        loss.backward()
        optimizer.step()
        
    training_loss = np.average(training_loss)
    print('epoch: \t', epoch, '\t training loss: \t', training_loss)

Ниже приводится краткое описание модели. Вы видите, что потери уменьшились, поэтому можно сказать, что модель улучшается. Давайте проверим это, посмотрев на точность обучения и проверки:

# 预测训练集
prediction = []
target = []
permutation = torch.randperm(x_train.size()[0])
for i in tqdm(range(0,x_train.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = x_train[indices], y_train[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model.classifier(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction.append(predictions)
    target.append(batch_y)
    
# 训练精度
accuracy = []
for i in range(len(prediction)):
    accuracy.append(accuracy_score(target[i],prediction[i]))
    
print('training accuracy: \t', np.average(accuracy))

На тренировочном наборе мы получаем точность около 84%. Теперь давайте проверим точность проверки:

# 预测验证集
prediction = []
target = []
permutation = torch.randperm(x_train.size()[0])
for i in tqdm(range(0,x_train.size()[0], batch_size)):
    indices = permutation[i:i+batch_size]
    batch_x, batch_y = x_train[indices], y_train[indices]

    if torch.cuda.is_available():
        batch_x, batch_y = batch_x.cuda(), batch_y.cuda()

    with torch.no_grad():
        output = model.classifier(batch_x.cuda())

    softmax = torch.exp(output).cpu()
    prob = list(softmax.numpy())
    predictions = np.argmax(prob, axis=1)
    prediction.append(predictions)
    target.append(batch_y)
    
# 验证精度
accuracy = []
for i in range(len(prediction)):
    accuracy.append(accuracy_score(target[i],prediction[i]))
    
print('training accuracy: \t', np.average(accuracy))

Точность проверки модели также аналогична, 83%. Точности обучения и проверки почти синхронизированы, поэтому можно сказать, что модель является обобщенной. Ниже приводится краткое изложение наших выводов:

Model Training Accuracy Validation Accuracy
CNN 81.57% 76.26%
VGG16
83.70% 83.47%

Мы можем сделать вывод, что предварительно обученная модель VGG16 имеет улучшенную точность по сравнению с моделью CNN!

конец

В этом посте мы узнали, как использовать предварительно обученную модель и передавать обучение для решения задачи классификации изображений. Начнем с понимания того, что такое предварительно обученная модель и как выбрать правильную модель для решения поставленной задачи. Затем мы проводим классификационное исследование экстренных и неаварийных изображений на примере изображений автомобилей. Сначала мы решили этот пример, используя модель CNN, а затем ту же проблему, используя предварительно обученную модель VGG16.

Мы обнаружили, что использование предварительно обученной модели VGG16 значительно улучшило производительность модели, и мы получили лучшие результаты по сравнению с моделью CNN. Надеюсь, теперь у вас есть четкое представление о том, как использовать трансферное обучение и правильную предварительно обученную модель для решения задач в PyTorch.

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