CIFAR10 - это подмножество помеченного набора данных, собранного из набора данных из 80 миллионов крошечных изображений. этот набор данных собран Алексом Крижевски, Винодом Наиром и Джеффри Хинтоном.

  1. CIFAR10 в упаковке torch содержит 60 000 изображений 10 этикеток размером 32x32 пикселя. По умолчанию torchvision.datasets.CIFAR10 разделяет набор данных на 50 000 изображений для обучения и 10 000 изображений для тестирования.
  2. VGG16 - это очень глубокая сверточная нейронная сеть, разработанная и построенная Кареном Симоняном и Эндрю Зиссерманом. Если вам интересна их работа, я настоятельно рекомендую нажать эту ссылку, чтобы прочитать об их исследовании.
  3. Трансферное обучение - это метод повторного использования предварительно обученной модели для соответствия требованиям разработчиков / специалистов по данным. В этом случае я повторно использовал модель VGG16 для решения набора данных CIFAR10.

Я использовал Google Collab в качестве основной рабочей среды в этом проекте. Первый шаг - указать машину, используемую для обучения модели, cuda или cpu. затем я выбираю количество эпох, размер пакета и скорость обучения для этого обучения. Как упоминалось во введении, CIFAR10 имеет 10 меток, эти 10 меток хранятся в classes переменных.

import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms
from torchvision import models
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
num_epochs = 5
batch_size = 40
learning_rate = 0.001
classes = ('plane', 'car' , 'bird',
    'cat', 'deer', 'dog',
    'frog', 'horse', 'ship', 'truck')

Затем я подготовил набор данных CIFAR10 для использования в этом проекте с функцией transforms.Compose, эта функция получит список шагов, которые преобразуют входные данные. Вы можете видеть это как конвейер данных, этот конвейер сначала изменит размер всех изображений из CIFAR10 до размера 224x224, который является входным слоем модели VGG16, а затем он преобразует изображение в тензорный тип данных для последующих шагов. наконец, он нормализует масштаб значения пикселя до среднего значения ~ 0,47 и стандартного отклонения ~ 0,2, и поскольку изображения имеют 3-канальный цвет (красный - зеленый - синий), входные данные tranforms.Normailize были 2 кортежами из 3 чисел с плавающей запятой, представляющих для пары средних и стандартных значений из 3 цветовых каналов соответственно.

После указания конвейера преобразования данных я загрузил набор данных CIFAR10 из пакета torchvision (код ниже). Я получил набор обучающих данных, назначив гиперпараметр train True, тестовый набор данных установив для него значение False, и оба были применены thetransform к вышеуказанному конвейеру данных.

transform = transforms.Compose([
    transforms.Resize(size=(224, 224)),
    transforms.ToTensor(),
    transforms.Normalize( 
       (0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010) 
    )
])
train_dataset = torchvision.datasets.CIFAR10(
    root= './data', train = True,
    download =True, transform = transform)
test_dataset = torchvision.datasets.CIFAR10(
    root= './data', train = False,
    download =True, transform = transform)

Следующим шагом в подготовке набора данных является его загрузка в параметр Python. Я назначаю batch_size функции torch.untils.data.DataLoader размеру пакета, который я выбираю на первом шаге. Я также выбираю метод Shuffle, он особенно полезен для набора обучающих данных. n_total_step в моем случае составляет 1250 шагов, он рассчитывается по ‹общему количеству записей› / ‹размер пакета›, поэтому в моем случае 50 000/40 = 1250. это означает, что на этапе обучения мой код будет выполнять цикл из 1250 шагов каждую эпоху.

train_loader = torch.utils.data.DataLoader(train_dataset
    , batch_size = batch_size
    , shuffle = True)
test_loader = torch.utils.data.DataLoader(test_dataset
    , batch_size = batch_size
    , shuffle = True)
n_total_step = len(train_loader)
print(n_total_step)

Вот важная часть этого проекта: я импортирую модель vgg16 из torchvision.models и выбираю предварительно обученную версию. Эта модель имеет по умолчанию 1000 функций вывода, но в моем случае мне нужно только 10 функций вывода. Эти 10 выходных характеристик рассчитываются функцией nn.Linear, вы можете посмотреть более детально, отобразив переменную model ниже. Я также рекомендую вам попробовать другие предварительно обученные модели и испытать себя в настройке той модели, которая соответствует вашим личным проблемам. Вы можете увидеть больше предварительно обученных моделей в Pytorch по этой ссылке.

Я использовал функцию CrossEntropyLoss в torch, чтобы вычислить значение потерь. Эта функция получила прогнозируемое значение y для n-функций и меток и выполняет расчет softmax. В моем случае у меня есть прогнозируемые выходные данные по 10 функциям для каждого изображения. Вы можете увидеть математическую формулу softmax на рисунках ниже.

Наконец, я выбираю метод SGD Стохастический градиентный спуск в качестве своего оптимизатора, передавая параметр, который я хочу оптимизировать, а именно model.parameters(), применяю гиперпараметры скорости обучения, импульса и веса_распада как 0,001, 0,5 и 5e-4. соответственно. Не стесняйтесь настраивать эти параметры самостоятельно.

Примечание. VGG16 имеет 10 функций линейного вывода, и нам не нужно применять функцию активации softmax в качестве последнего уровня модели, поскольку softmax интегрирован с функцией потерь nn.CrossEntropyLoss.

model = models.vgg16(pretrained = True)
input_lastLayer = model.classifier[6].in_features
model.classifier[6] = nn.Linear(input_lastLayer,10)
model = model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr = learning_rate, momentum=0.9,weight_decay=5e-4)

Обучение модели, передача пакета изображений в model, результат имеет размер (40,10), где 40 - размер пакета, 10 - количество функций. Затем получите метку вывода на .argmax(axis=1), вывод будет (40,), что означает, что каждое изображение имеет вывод с 10 объектами и получит индекс объекта с наибольшим значением. Затем получите значение потерь с помощью функции nn.CrossEntropyLoss(), затем примените метод .backward() к значению потерь, чтобы получить градиентный спуск после каждого цикла и обновить model.parameters(), запустив метод .step() оптимизатора, наконец, не забудьте сбросить градиентный спуск после каждый цикл с методом .zero_grad().

В моем коде каждые 250 шагов каждой эпохи я печатаю значение потерь и точность в наборе обучающих данных. Этот шаг занимает много времени, около 150 минут с движком GPU, я настоятельно рекомендую вам проверить ресурсы пакета torchvision.models или сделать что-нибудь полезное, а не сидеть перед ПК и смотреть на экран.

1.for epoch in range(num_epochs):
2.    for i, (imgs , labels) in enumerate(train_loader):
3.        imgs = imgs.to(device)
4.        labels = labels.to(device)
5.
6.        labels_hat = model(imgs)
7.        n_corrects = (labels_hat.argmax(axis=1)==labels).sum().item()
8.        loss_value = criterion(labels_hat, labels)
9.        loss_value.backward()
10.       optimizer.step()
11.       optimizer.zero_grad()
12.       if (i+1) % 250 == 0:
13.           print(f’epoch {epoch+1}/{num_epochs}, step: {i+1}/{n_total_step}: loss = {loss_value:.5f}, acc = {100*(n_corrects/labels.size(0)):.2f}%’)
14.    print()

Наконец, шаг - оценить обучающую модель на тестовом наборе данных. В каждом пакете изображений мы проверяем, сколько классов изображений было предсказано правильно, получаем labels_predicted, вызывая .argmax(axis=1) на y_predicted, затем подсчитывая исправленные предсказанные метки по (labels_predicted==test_labels_set).sum().item(), labels_predicted == test_labels_set вернет тензор True или False, True равно значение 1 и False равно 0, тогда метод .sum() будет подсчитывать правильные предсказанные метки, а метод .item() просто извлекает значение одномерного тензора. Наконец, количество выборок для каждого размера пакета test_labels_set.size(), очевидно, является просто значением batch_size, которое мы указываем в начале этой статьи.

with torch.no_grad():
    number_corrects = 0
    number_samples = 0
    for i, (test_images_set , test_labels_set) in enumerate(test_loader):
        test_images_set = test_images_set.to(device)
        test_labels_set = test_labels_set.to(device)
    
        y_predicted = model(test_images_set)
        labels_predicted = y_predicted.argmax(axis = 1)
        number_corrects += (labels_predicted==test_labels_set).sum().item()
        number_samples += test_labels_set.size(0)
    print(f’Overall accuracy {(number_corrects / number_samples)*100}%’)

Другой метод визуализации набора данных оценочного теста - использование тепловой карты с поддержкой пакета theseaborn. В приведенном ниже коде я генерирую heatmap размер кадра данных (10,10) с начальным значением 0. Вертикальный индекс представляет истинные метки, а горизонтальный индекс представляет предсказанное значение. Например, в приведенном ниже результате в метке dog было ошибочно предсказано 102 изображения, поскольку метка cat и 858 изображений были предсказаны успешно.

heatmap = pd.DataFrame(data=0,index=classes,columns=classes)
with torch.no_grad():
    for images, labels in test_loader:
        images, labels = images.to(device), labels.to(device)
        outputs = model(images)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(batch_size):
            true_label = labels[i].item()
            predicted_label = predicted[i].item()
            heatmap.iloc[true_label,predicted_label] += 1
_, ax = plt.subplots(figsize=(10, 8))
ax = sns.heatmap(heatmap, annot=True, fmt=”d”,cmap=”YlGnBu”)
plt.show()

И последнее, но не менее важное: не забудьте сохранить свою модель, чтобы использовать ее позже.

torch.save(
  model, 
  '/path/to/your/drive/or/local/directory/<name_of_the_model>.pth')

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