Введение в библиотеки глубокого обучения PyTorch и Lightning AI

Введение в PyTorch и Lightning AI

 

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

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

Для разработки этой модели глубокого обучения существуют различные библиотечные фреймворки, на которые можно положиться, а не работать с нуля. В этой статье мы рассмотрим две разные библиотеки, которые можно использовать для разработки моделей глубокого обучения: PyTorch и Lighting AI. Давайте начнем.

 

PyTorch

 

PyTorch – это библиотека с открытым исходным кодом для обучения нейронных сетей глубокого обучения. PyTorch был разработан группой Meta в 2016 году и стал популярным. Рост популярности был обусловлен функцией PyTorch, которая объединяет библиотеку GPU-бэкэнда из Torch с языком Python. Это сочетание делает пакет простым для пользователя, но все еще мощным при разработке модели глубокого обучения.

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

Основным строительным блоком PyTorch является тензор, многомерный массив, используемый для кодирования всех входных, выходных и параметров модели. Вы можете представить тензор как массив NumPy, но с возможностью работать на GPU.

Давайте попробуем использовать библиотеку PyTorch. Рекомендуется выполнять учебник в облаке, например, на Google Colab, если у вас нет доступа к системе с GPU (хотя он все равно может работать на CPU). Но если вы хотите начать локально, нам нужно установить библиотеку через эту страницу. Выберите подходящую систему и спецификацию, которая вам подходит.

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

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

 

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

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

from torchvision import datasets

train = datasets.MNIST(
    root="image_data",
    train=True,
    download=True
)

test = datasets.MNIST(
    root="image_data",
    train=False,
    download=True,
)

 

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

import matplotlib.pyplot as plt
 
for i, (img, label) in enumerate(list(train)[:10]):
    plt.subplot(2, 5, i+1)
    plt.imshow(img, cmap="gray")
    plt.title(f'Label: {label}')
    plt.axis('off')
 
plt.show()

 

 

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

Нам нужно преобразовать набор данных изображений в тензор, чтобы разработать модель глубокого обучения с помощью PyTorch. Поскольку наше изображение является объектом PIL, мы можем использовать функцию PyTorch ToTensor для выполнения преобразования. Кроме того, мы можем автоматически преобразовать изображение с помощью функции datasets.

from torchvision.transforms import ToTensor
train = datasets.MNIST(
    root="data",
    train=True,
    download=True,
    transform=ToTensor()
)

test = datasets.MNIST(
    root="data",
    train=False,
    download=True,
    transform=ToTensor()
)

 

Передавая функцию преобразования в параметр transform, мы можем контролировать, какими будут данные. Затем мы обернем данные в объект DataLoader, чтобы модель PyTorch могла получить доступ к нашим изображениям.

from torch.utils.data import DataLoader
size = 64

train_dl = DataLoader(train, batch_size=size)
test_dl = DataLoader(test, batch_size=size)

for X, y in test_dl:
    print(f"Форма X [N, C, H, W]: {X.shape}")
    print(f"Форма y: {y.shape} {y.dtype}")
    break

 

Форма X [N, C, H, W]: torch.Size([64, 1, 28, 28])
Форма y: torch.Size([64]) torch.int64

 

В приведенном выше коде мы создаем объект DataLoader для обучающих и тестовых данных. Каждая итерация пакета данных будет возвращать 64 функции и метки в указанном объекте. Кроме того, форма нашего изображения составляет 28 * 28 (высота * ширина).

Затем мы создадим объект модели нейронной сети.

from torch import nn

# Измените на 'cuda', если у вас есть доступ к GPU
device = 'cpu'

class NNModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.lr_stack = nn.Sequential(
            nn.Linear(28*28, 128),
            nn.ReLU(),
            nn.Linear(128, 128),
            nn.ReLU(),
            nn.Linear(128, 10)
        )

    def forward(self, x):
        x = self.flatten(x)
        logits = self.lr_stack(x)
        return logits

model = NNModel().to(device)
print(model)

 

NNModel(
  (flatten): Flatten(start_dim=1, end_dim=-1)
  (lr_stack): Sequential(
    (0): Linear(in_features=784, out_features=128, bias=True)
    (1): ReLU()
    (2): Linear(in_features=128, out_features=128, bias=True)
    (3): ReLU()
    (4): Linear(in_features=128, out_features=10, bias=True)
  )
)

 

В приведенном выше объекте мы создаем модель нейронной сети с несколькими слоями. Чтобы создать объект модели нейронной сети, мы используем метод подкласса с функцией nn.module и создаем слои нейронной сети внутри __init__.

Сначала мы преобразуем двумерные данные изображений в значения пикселей внутри слоя с помощью функции flatten. Затем мы используем функцию sequential, чтобы обернуть наш слой в последовательность слоев. Внутри функции sequential у нас есть следующие слои модели:

nn.Linear(28*28, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, 10)

 

По порядку, то, что происходит выше:

  1. Сначала входные данные, которые представляют собой 28*28 функций, преобразуются с использованием линейной функции в линейном слое и на выходе имеют 128 функций.
  2. ReLU – это нелинейная функция активации, которая присутствует между входом и выходом модели для введения нелинейности.
  3. На вход подается 128 функций в линейный слой и на выходе также 128 функций.
  4. Еще одна функция активации ReLU.
  5. На вход подается 128 функций в линейный слой и на выходе 10 функций (в нашем наборе данных имеется только 10 меток).

Наконец, функция forward присутствует для фактического ввода данных для модели. Далее модели потребуется функция потерь и функция оптимизации.

from torch.optim import SGD

loss_fn = nn.CrossEntropyLoss()
optimizer = SGD(model.parameters(), lr=1e-3)

 

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

import torch
def train(dataloader, model, loss_fn, optimizer):
    size = len(dataloader.dataset)
    model.train()
    for batch, (X, y) in enumerate(dataloader):
        X, y = X.to(device), y.to(device)
        pred = model(X)
        loss = loss_fn(pred, y)

        loss.backward()
        optimizer.step()
        optimizer.zero_grad()

        if batch % 100 == 0:
            loss, current = loss.item(), (batch + 1) * len(X)
            print(f"Потеря: {loss:>2f}  [{current:>5d}/{size:>5d}]")

def test(dataloader, model, loss_fn):
    size = len(dataloader.dataset)
    num_batches = len(dataloader)
    model.eval()
    test_loss, correct = 0, 0
    with torch.no_grad():
        for X, y in dataloader:
            X, y = X.to(device), y.to(device)
            pred = model(X)
            test_loss += loss_fn(pred, y).item()
            correct += (pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct /= size
    print(f"Ошибка тестирования: \n Точность: {(100*correct):>0.1f}%, Средняя потеря: {test_loss:>2f} \n")

 

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

epoch = 5
for i in range(epoch):
    print(f"Эпоха {i+1}\n-------------------------------")
    train(train_dl, model, loss_fn, optimizer)
    test(test_dl, model, loss_fn)
print("Готово!")

 

 

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

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

 

Lighting AI

 

Lighting AI – это компания, предоставляющая различные продукты для минимизации времени обучения модели глубокого обучения PyTorch и ее упрощения. Одним из их продуктов с открытым исходным кодом является PyTorch Lighting, который предлагает фреймворк для обучения и развертывания модели PyTorch.

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

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

pip install lightning

 

Установив Lighting, мы также установим другой продукт Lighting AI, называемый TorchMetrics, чтобы упростить выбор метрик.

pip install torchmetrics

 

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

import torch
import torchmetrics
import pytorch_lightning as pl
from torch import nn
from torch.optim import SGD

# Измените на 'cuda', если у вас есть доступ к GPU
device = 'cpu'

class NNModel(pl.LightningModule):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.lr_stack = nn.Sequential(
            nn.Linear(28 * 28, 128),
            nn.ReLU(),
            nn.Linear(128, 128),
            nn.ReLU(),
            nn.Linear(128, 10)
        )
        self.train_acc = torchmetrics.Accuracy(task="multiclass", num_classes=10)
        self.valid_acc = torchmetrics.Accuracy(task="multiclass", num_classes=10)

    def forward(self, x):
        x = self.flatten(x)
        logits = self.lr_stack(x)
        return logits

    def training_step(self, batch, batch_idx):
        x, y = batch
        x, y = x.to(device), y.to(device)
        pred = self(x)
        loss = nn.CrossEntropyLoss()(pred, y)
        self.log('train_loss', loss)
       
        # Вычисление точности обучения
        acc = self.train_acc(pred.softmax(dim=-1), y)
        self.log('train_acc', acc, on_step=True, on_epoch=True, prog_bar=True)
        return loss

    def configure_optimizers(self):
        return SGD(self.parameters(), lr=1e-3)

    def test_step(self, batch, batch_idx):
        x, y = batch
        x, y = x.to(device), y.to(device)
        pred = self(x)
        loss = nn.CrossEntropyLoss()(pred, y)
        self.log('test_loss', loss)
       
        # Вычисление точности тестирования
        acc = self.valid_acc(pred.softmax(dim=-1), y)
        self.log('test_acc', acc, on_step=True, on_epoch=True, prog_bar=True)
        return loss

 

Разберем, что происходит в коде выше. Отличие от нашей модели PyTorch, которую мы разработали ранее, заключается в том, что класс NNModel теперь использует наследование от LightingModule. Кроме того, мы назначаем метрики точности для оценки с использованием TorchMetrics. Затем мы добавляем шаги обучения и тестирования внутри класса и настраиваем оптимизацию.

С установленными всеми моделями мы запускаем обучение модели, используя преобразованный объект DataLoader для тренировки нашей модели.

# Создание тренера PyTorch Lightning
trainer = pl.Trainer(max_epochs=5)

# Создание модели
model = NNModel()

# Обучение модели
trainer.fit(model, train_dl)

# Тестирование модели
trainer.test(model, test_dl)

print("Завершение обучения")

 

 

С помощью библиотеки Lightning мы можем легко настраивать необходимую структуру. Для дальнейшего чтения вы можете прочитать их документацию.

 

Заключение

 

PyTorch – это библиотека для разработки моделей глубокого обучения, которая предоставляет простую среду для доступа к множеству продвинутых API. Lightning AI также поддерживает эту библиотеку, предоставляя фреймворк для упрощения разработки моделей и повышения гибкости разработки. В этой статье мы познакомились с особенностями библиотеки и простой реализацией кода.     Корнелиус Юдха Виджая – помощник руководителя по науке о данных и писатель данных. В свободное время, работая на полную ставку в Allianz Indonesia, он любит делиться советами по Python и данным через социальные сети и печатные издания.