Files
neurocomputers-python/lab3/3.3_image.ipynb

14 KiB

ЛАБОРАТОРНАЯ РАБОТА №3

Применение многослойного персептрона. Автоассоциативная ИНС

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

Задание

  1. Открыть файл с данными по минеральной воде, который использовался при решении задач классификации в предыдущей лабораторной работе. Построить и обучить автоассоциативные нейронные сети с 2-мя и 3-мя нейронами в скрытом слое:
    а) для исходных данных из 5-ти классов;
    б) для исходных данных из 4-х классов.
    Провести визуализацию данных в скрытом слое каждой сети на плоскость и в 3-х мерное пространство. Проанализировать полученные результаты. Выбрать и сохранить автоассоциативные ИНС, обеспечивающие наилучшее сжатие исходных данных.

  2. Решить задачу распознавания 9-ти изображений самолетов. Исходные данные (файлы avia1.bmp, …, avia9.bmp) необходимо предварительно преобразовать в набор векторов со значениями признаков 0 или 1. Обученная нейронная сеть должна правильно определять модель самолета и его класс (истребитель/бомбардировщик). Принадлежность модели к определенному классу выбирается студентом самостоятельно.

Импорт библиотек:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import torch
import imageio
import warnings

from torch import nn
from IPython.display import clear_output

warnings.filterwarnings('ignore')
%matplotlib inline

Содержание:

1. Подготовка данных
2. Классификация изображений

1. Подготовка данных

Сохраним в список X_data все девять изображений. Каждое из них загрузим в виде NumPy-массива, затем преобразуем данный массив в float32 и делением на 255 перемасштабируем в его диапазон [0.0, 1.0] (было [0, 255]). Само исходное изображение (по умолчанию цветное) преобразуем изображение в чёрно‑белое — для чего возьмём среднее по каналам R, G, B для каждого пикселя.

X_data = []

for i in range(1, 10):
    filename = f'avia{i}.bmp'
    img = imageio.imread(filename)
    img = img.astype('float32') / 255.
    img = np.mean(img, axis=2)
    X_data.append(img)

Список y_data содержит в себе ответ — принадлежит ли силуэт на каждом из девяти изображений бомбардировщику (1 если принадлежит, 0 если не принадлежит):

y_data = [0, 1, 0, 0, 1, 0, 0, 0, 1]

Выведем все девять изображений и подпишем каждое из них:

fig, axes = plt.subplots(3, 3, figsize=(9, 9))
axes = axes.ravel()

for i in range(9):
    axes[i].imshow(X_data[i], cmap='gray')
    aircraft_type = '\nБомбардировщик' if y_data[i] == 1 else '\nИстребитель'
    axes[i].set_title(aircraft_type)
    axes[i].axis('off')

plt.tight_layout()
plt.show()

Представим данные в виде тензоров X_data_tensor и y_data_tensor:

X_data_tensor = torch.tensor(X_data).float()
y_data_tensor = torch.tensor(y_data).reshape(-1, 1).float()

Проверим размерность X_data_tensor — она показывает, что в тензоре лежат девять изображений размером 352 на 346:

X_data_tensor.shape

Многослойный персептрон всегда принимает на вход одномерные векторы. Однако в нашей задаче классификации силуэтов саолётов исходные изображения — как видно из размерности, двуомерные тензоры. И чтобы подать их на вход сети, их необходимо «развернуть» в одномерные векторы, сохранив количество объектов (пикселей) неизменным.

Такое преобразование позволяет использовать пространственную информацию пикселей как набор признаков для полносвязных слоёв персептрона.

В PyTorch это можно сделать с помощью метода .view() следующим образом:

X_data_tensor.view(X_data_tensor.size(0), -1).shape

Для проверки перемножим длину и щирину одного из изображений:

np.prod(X_data[0].shape)

2. Классификация изображений

Реализуйте в классе ImageClassifier с помощью полносвязных слоёв nn.Linear многослойный персептрон. В качестве промежуточных функций активации используйте nn.ReLU(), а в качестве финальной — сигмоиду, поскольку решается задача бинарной классификации.

class ImageClassifier(nn.Module):
    def __init__(self, input_size):
        super().__init__()
        self.seq = nn.Sequential(
            # Ваш код здесь
        )

    def forward(self, x):
        x = x.view(x.size(0), -1)
        return self.seq(x)

Создайте экземпляр модели:

model = ImageClassifier(input_size=# Ваш код здесь

model

Проверим, что модель при приходе данных возвращает вероятности:

model(X_data_tensor)

Метрика accuracy:

def accuracy(y_pred, y_true):
    return torch.sum(y_pred == y_true) / len(y_true)

Задайте параметры для обучения нейронной сети:

torch.manual_seed(seed=42)

model = # Ваш код здесь

epochs = # Ваш код здесь

learning_rate = # Ваш код здесь
momentum = # Ваш код здесь

optimizer = # Ваш код здесь
criterion = # Ваш код здесь

Обучение нейронной сети:

loss_history = []

for epoch in range(epochs):
    # Ваш код здесь

    if (epoch + 1) % 5 == 0:

        clear_output(True)
        plt.plot(range(1, epoch+2), loss_history, label='Loss')
        plt.title(f'Epoch: {epoch + 1}, Loss: {loss_history[-1]:.6f}')
        plt.grid(True, alpha=0.3)
        plt.legend(loc='best')
        plt.show()

        print(f'Accuracy: {accuracy((y_prob > 0.5).float(), y_data_tensor).item():.3f}')

Литература:

  1. Бородкин А.А., Елисеев В.Л. Основы и применение искусственных нейронных сетей. Сборник лабораторных работ: методическое пособие. – М.: Издательский дом МЭИ, 2017.
  2. MachineLearning.ru — профессиональный информационно-аналитический ресурс, посвященный машинному обучению, распознаванию образов и интеллектуальному анализу данных: http://www.machinelearning.ru
  3. Modern State of Artificial Intelligence — Online Masters program at MIPT: https://girafe.ai/