Классификация изображений является важной задачей компьютерного зрения. Он включает в себя идентификацию содержимого изображения и соответствующую маркировку. В этом посте мы создадим классификатор моды, используя PyTorch и Grid Search. Мы будем использовать набор данных Fashion-MNIST, который содержит 60 000 обучающих изображений и 10 000 тестовых изображений 10 различных типов одежды.

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

Начиная

Во-первых, давайте импортируем необходимые библиотеки:

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor
import matplotlib.pyplot as plt
import json

Здесь мы импортируем PyTorch вместе с некоторыми другими необходимыми библиотеками, такими как torchvision для загрузки и преобразования данных и matplotlib для визуализации результатов.

Предварительная обработка данных

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

# set up a data downloader function
def data_download():
    train_data = datasets.FashionMNIST(
        root="data",
        train=True,
        download=True,
        transform=ToTensor(),
    )

    test_data = datasets.FashionMNIST(
        root="data",
        train=False,
        download=True,
        transform=ToTensor(),
    )
    return train_data,test_data

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

#  set up a data loader function
def dataloader(train_data, test_data):
    batch_size = 64
    train_dataloader = DataLoader(train_data, batch_size=batch_size)
    test_dataloader = DataLoader(test_data, batch_size=batch_size)
    return train_dataloader, test_dataloader

Архитектура модели

Мы будем использовать полносвязную нейронную сеть с функциями активации ReLU для нашего классификатора. Вход в сеть — это изображение в градациях серого 28x28, которое мы сглаживаем в 784-мерный вектор. Выход сети представляет собой распределение вероятностей по 10 классам.

# we define the model
class ClassifierNetwork(nn.Module):
    def __init__(self, hidden_units):
        super().__init__()
        self.flatten = nn.Flatten()
        self.linear_relu_stack = nn.Sequential(
            nn.Linear(28*28, hidden_units),
            nn.ReLU(),
            nn.Linear(hidden_units, hidden_units),
            nn.ReLU(),
            nn.Linear(hidden_units, 10)
        )
    
    def forward(self, x):
        x = self.flatten(x)
        logits = self.linear_relu_stack(x)
        return logits

Обучение и тестирование

Теперь давайте определим наши функции train() и test(). Функция train() выполняет обратное распространение и обновляет параметры нейронной сети. Функция test() оценивает точность модели на тестовых данных.

def train(dataloader, model, device, lr):
    loss_fn = nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(model.parameters(), lr = lr)
    size = len(dataloader.dataset)
    model.train()
    for batch, (X,y) in enumerate(dataloader):
        X, y = X.to(device), y.to(device)

        # find loss
        y_pred = model(X)
        loss = loss_fn(y_pred, y)

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

        if batch % 100 == 0:
            loss, current = loss.item(), (batch + 1) * len(X)
            print(f"loss {loss:>7f}  [{current:>5d}/{size:>5d}]")

def test(dataloader, model, device):
    loss_fn = nn.CrossEntropyLoss()
    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)
            y_pred = model(X)
            test_loss += loss_fn(y_pred, y).item()
            correct += (y_pred.argmax(1) == y).type(torch.float).sum().item()
    test_loss /= num_batches
    correct /= size 
    accuracy = 100*correct
    print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
    return accuracy

Функция test() принимает на вход загрузчик данных, модель и устройство. Затем он оценивает точность модели на тестовых данных. Сначала мы устанавливаем модель в режим оценки, используя model.eval(). Это отключает отсев и нормализацию пакетов, которые обычно используются во время обучения, но не во время тестирования.

Затем мы перебираем тестовые данные партиями и вычисляем потери и точность модели. Мы используем функцию потерь nn.CrossEntropyLoss(), которая подходит для задач классификации с несколькими классами, таких как наша. Мы также рассчитываем точность модели, сравнивая предсказанные метки классов с метками истинности.

Поиск по сетке

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

def grid_search(hidden_units_list, learning_rates, device):
    best_accuracy = 0
    best_lr = None
    best_hidden_units = None
    for lr in learning_rates:
        for hidden_units in hidden_units_list:
            print(f"Performing a Training with Grid Search using learning rate {lr} and {hidden_units} hidden_units\n")
            Model = ClassifierNetwork(hidden_units).to(device)
            train_data, test_data = data_download()
            train_dataloader, test_dataloader = dataloader(train_data, test_data)
            epochs = 5
            for t in range(epochs):
                print(f"Epoch {t+1}\n---------------------------")
                train(train_dataloader,Model,device,lr)
                test_accuracy = test(test_dataloader,Model,device)

                if test_accuracy > best_accuracy:
                    best_accuracy = test_accuracy
                    best_lr = lr
                    best_hidden_units = hidden_units
    return best_lr, best_hidden_units, best_accuracy

Здесь мы перебираем каждую комбинацию гиперпараметров и обучаем модель в течение 5 эпох, используя функции train() и test(). Затем мы проверяем, лучше ли точность модели, чем текущая наилучшая точность. Если это так, мы обновляем лучшую точность, лучшую скорость обучения и лучшее количество скрытых единиц.

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

Запуск кода

Чтобы запустить код, мы можем вызвать функцию main():

def main():
    device = "cpu"
    print(f"Using {device} device")
    learning_rates = [0.1,0.2,0.3]
    hidden_units_list = [128,256,512,1024]
    train_data, test_data = data_download()
    train_dataloader, test_dataloader = dataloader(train_data, test_data)

    user_input = input("Do you want to train the model? (yes/no): ")
    if user_input.lower() == 'yes':
        best_lr, best_hidden_units, best_accuracy = grid_search(hidden_units_list, learning_rates, device)
        train_best_model(train_dataloader, test_dataloader, best_lr, best_hidden_units, device)
    else:
        Model = ClassifierNetwork(best_hidden_units).to(device)
        Model.load_state_dict(torch.load("model_best.pth"))
        Model.eval()
        print("Loaded saved model.")

Здесь мы сначала устанавливаем устройство на «процессор». Затем мы определяем списки скоростей обучения и скрытых единиц, загружаем данные и создаем загрузчики данных.

Затем мы предлагаем пользователю ввести, хотят ли они обучить модель или загрузить сохраненную модель. Если пользователь хочет обучить модель, мы вызываем функцию grid_search(), чтобы найти лучшие гиперпараметры, а затем обучаем лучшую модель с помощью функции train_best_model(). Если пользователь хочет загрузить сохраненную модель, мы загружаем сохраненную модель с помощью torch.load() и устанавливаем модель в режим оценки с помощью model.eval().

Развертывание вашей модели машинного обучения в облаке

Введение в развертывание

В этом разделе мы покажем вам, как развернуть вашу модель машинного обучения, такую ​​как Fashion Classifier, в облаке. Мы будем использовать Flask, облегченную веб-инфраструктуру, для создания веб-приложения и Heroku, облачную платформу, для развертывания.

Шаг 1: Настройте каталог вашего проекта

Создайте новый каталог для вашего проекта и настройте следующую структуру:

your_project/
|
|-- app.py
|-- requirements.txt
|-- Procfile
|-- model/
|   |-- model.py
|   |-- model.pkl
|-- templates/
|   |-- index.html
|   |-- result.html

Шаг 2: Установите Фласк

Если вы еще этого не сделали, установите Flask с помощью следующей команды:

pip install Flask

Шаг 3: Создайте свое веб-приложение

В app.py создайте простое веб-приложение Flask для обработки пользовательского ввода и отображения результатов:

from flask import Flask, render_template, request
import model.model as model
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        user_input = request.form['user_input']
        prediction = model.predict(user_input)
        return render_template('result.html', prediction=prediction)
    return render_template('index.html')
if __name__ == '__main__':
    app.run(debug=True)

Шаг 4: Создайте HTML-шаблоны

Создайте два HTML-шаблона в папке templates: index.html для пользовательского ввода и result.html для отображения результатов.

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Your Model</title>
</head>
<body>
    <h1>Your Model</h1>
    <form action="/" method="POST">
        <label for="user_input">Enter your input:</label>
        <input type="text" name="user_input" id="user_input" required>
        <button type="submit">Predict</button>
    </form>
</body>
</html>

result.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Your Model</title>
</head>
<body>
    <h1>Your Model</h1>
    <p>Prediction: {{ prediction }}</p>
    <a href="/">Try again</a>
</body>
</html>

Шаг 5: Сохраните и загрузите свою модель

В папке model создайте файл model.py, содержащий функции для сохранения и загрузки обученной модели машинного обучения. Сохраните обученную модель в виде файла .pkl в той же папке:

import pickle
def save_model(model, filename):
    with open(filename, 'wb') as file:
        pickle.dump(model, file)
def load_model(filename):
    with open(filename, 'rb') as file:
        return pickle.load(file)
def predict(user_input):
    model = load_model('model.pkl')
# Preprocess the user input and make predictions using your model
# The preprocessing and prediction code will vary depending on your model (ARIMA or Naive Bayes)
# For example:
# processed_input = preprocess(user_input)
# prediction = model.predict(processed_input)
# Add the appropriate code for your specific model and return the prediction
return prediction

Шаг 6: Создайте требования и Procfile

Создайте файл `requirements.txt` со следующими библиотеками:

Flask
gunicorn
numpy
pandas
matplotlib
statsmodels
scikit-learn
yfinance

Убедитесь, что вы включили все дополнительные библиотеки, которые вы использовали в своем конкретном проекте.

Создайте Procfile со следующим содержимым:

web: gunicorn app:app

Имея эти файлы, вы готовы развернуть свое приложение на Heroku.

Шаг 7. Разверните приложение на Heroku

Сначала установите интерфейс командной строки Heroku и создайте учетную запись на Heroku.

Инициализируйте репозиторий Git в каталоге вашего проекта и зафиксируйте изменения:

git init
git add .
git commit -m "Initial commit"

Войдите в Heroku и создайте новое приложение Heroku:

heroku login
heroku create your-app-name

Разверните приложение:

git push heroku master

Ваша модель машинного обучения теперь развернута на Heroku! Посетите https://your-app-name.herokuapp.com, чтобы просмотреть свое веб-приложение.

Заключение

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

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