Files
neurocomputers-python/lab3/3.1_autoencoder.ipynb

23 KiB
Исходник Ответственный История

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

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

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

Задание

  1. Открыть файл с данными по минеральной воде, который использовался при решении задач классификации в предыдущей лабораторной работе. Построить и обучить автоассоциативные нейронные сети с 2-мя и 3-мя нейронами в скрытом слое:
    а) для исходных данных из 5-ти классов;
    б) для исходных данных из 4-х классов.
    Провести визуализацию данных в скрытом слое каждой сети на плоскость и в 3-х мерное пространство. Проанализировать полученные результаты. Выбрать и сохранить автоассоциативные ИНС, обеспечивающие наилучшее сжатие исходных данных.
  2. Исследовать возможности ИНС по прогнозированию поведения нелинейных динамических систем (построение странного аттрактора) на примере отображения Хенона. Аттрактор Хенона может быть получен из уравнений \(x_{n+1} = 1 - \alpha x_{n}^2 + y_{n}\) и \(y_{n+1} = \beta x_{n}\), где \(α = 1.4\), \(β = 0.3\). Для прогнозирования предлагается использовать многослойный персептрон и сеть с радиально-базисными функциями. Постройте также прогноз курса доллара на один день вперед. В качестве исходных данных загрузить актуальные данные с сайта центрального банка России (http://www.cbr.ru).
  3. Решить задачу распознавания 9-ти изображений самолетов. Исходные данные (файлы avia1.bmp, …, avia9.bmp) необходимо предварительно преобразовать в набор векторов со значениями признаков 0 или 1. Обученная нейронная сеть должна правильно определять модель самолета и его класс (истребитель/бомбардировщик). Принадлежность модели к определенному классу выбирается студентом самостоятельно.

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

import numpy as np
import pandas as pd
import seaborn as sns
import torch
import matplotlib.pyplot as plt
from IPython.display import clear_output
from mpl_toolkits.mplot3d import Axes3D

from torch import nn

%matplotlib inline

Содержание:

1. Подготовка данных
2. Автоассоциативная нейронная сеть на полных данных
3. Автоассоциативная нейронная сеть на неполных данных

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

Загрузим в датафрейм data данные о сорока образцах минеральной воды, хранящиеся в файле min_water.txt.

data = pd.read_csv('min_water.csv')
data.head(n=5)

Вынесем в отдельные переменные:

  • y_binary — выходной признак для задачи бинарной классификации (первый столбец датафрейма);
  • y_multiclass — выходной признак для задачи многоклассовой классификации (второй столбец датафрейма);
  • X_data — входные признаки (оставшиеся столбцы).
y_binary = data.iloc[:, 0]
y_multiclass = data.iloc[:, 1]

X_data = data.iloc[:, 2:]

Выпишите в список features отобранные в прошлой лабораторной работе признаки (формат: features = ['VAR1', 'VAR2']):

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

Датафрейм с отобранными входными признаками X_data_filtered:

X_data_filtered = X_data.loc[:, features]
X_data_filtered.head(n=5)

Произведите нормализацию или стандартизацию (на выбор) отобранных входных данных X_data_filtered. Результат сохраните в переменную X_data_preprocessed, которую затем представьте в виде тензора X_data_tensor:

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

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

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

2. Автоассоциативная нейронная сеть на полных данных

Автоассоциативная сеть (или автоассоциативная память) — тип нейронной сети, способный восстанавливать полный шаблон данных по его частичному или зашумлённому представлению.

Типичная автоассоциативная сеть содержит как минимум три скрытых слоя:

  • первый скрытый слой выполняет нелинейное кодирование входных данных (энкодер);
  • средний слой («узкое горло» или «бутылочное горло») формирует сжатое представление данных — в результате обучения выдаёт компактное кодирование;
  • последний скрытый слой служит декодером: восстанавливает исходные данные из сжатого представления.

Цель обучения: в процессе минимизации ошибки воспроизведения сеть стремится сделать выходной сигнал максимально близким к входному. Это эквивалентно оптимальному кодированию в «узком горле» сети.

Допишите класс Autoencoder структурами энкодера и декодера на основе полносвязных слоёв nn.Linear. В качестве функций активации используйте nn.ReLU(). При этом на выходе энкодера функцию активации можно не применять — это позволит сохранить отрицательные значения в кодированном представлении.

class Autoencoder(nn.Module):
    def __init__(self, n_inputs, n_hiddens, bottleneck_size):
        super().__init__()
        self.encoder = nn.Sequential(
            # Ваш код здесь
        )
        self.decoder = nn.Sequential(
            # Ваш код здесь
        )

    def forward(self, x):
        encoded = self.encoder(x)
        decoded = self.decoder(encoded)
        return decoded

Создайте экземпляр модели с двумя нейронами в «узком горле»:

model_2 = Autoencoder(# Ващ код здесь
print(model_2)

Пропустим данные через эту модель для её проверки:

model_2(X_data_tensor[:3])

Удостоверимся, что размерность её выхода совпадает с размерностью её входа:

assert X_data_tensor[:3].shape == model_2(X_data_tensor[:3]).shape

Проверим, как модель обучается. Зададим оптимизатор и среднеквадратическую функцию потерь:

optimizer = torch.optim.SGD(model_2.parameters(), lr=1.5)
criterion = nn.MSELoss()

Рассчитаем значение функции потерь:

decoded = model_2(X_data_tensor)

loss = criterion(decoded, X_data_tensor)
loss

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

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

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

torch.manual_seed(seed=42)

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

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()

После обучения сети получим двумерные данные с выхода энкодера:

encoded_2d = model_2.encoder(X_data_tensor).detach().numpy()
print(encoded_2d[:3])

Построим двумерную диаграмму рассеяния и отметим классы с помощью y_multiclass:

scatter = plt.scatter(x=encoded_2d[:, 0], y=encoded_2d[:, 1], c=y_multiclass, cmap='viridis')
plt.grid(True, alpha=0.3)

# Код для легенды
handles, labels = scatter.legend_elements(prop='colors')
plt.legend(handles, labels, loc='best', title='Classes')

plt.show()

По аналогии обучите автоассоциативную сеть с тремя нейронами в «узком горле»:

torch.manual_seed(seed=42)

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

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

После обучения сети получите трёхмерные данные с выхода энкодера:

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

Построим трёхмерную диаграмму рассеяния:

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')

scatter = ax.scatter(
    xs=encoded_3d[:, 0],
    ys=encoded_3d[:, 1],
    zs=encoded_3d[:, 2],
    c=y_multiclass,
    cmap='viridis',
    s=50
)

ax.grid(True, alpha=0.3)

handles, labels = scatter.legend_elements(prop='colors', alpha=0.8)
ax.legend(handles, labels, loc='best', title='Classes')

# Настраиваем угол обзора:
# elev — высота, azim — азимут
ax.view_init(elev=20, azim=45)

plt.show()

Сохраним в бинарные файлы .npy выходы энкодеров обеих моделей — для следующей лабораторной работы:

np.save('encoded_2d.npy', encoded_2d)
np.save('encoded_3d.npy', encoded_3d)

3. Автоассоциативная нейронная сеть на неполных данных

Выберите класс, который нужно исключить:

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

Создадим маску для исключения данных этого класса:

mask_to_exclude = y_multiclass != label_to_exclude

Данные исключены:

X_data_tensor[mask_to_exclude].shape

По аналогии с предыдущим пунктом реализуйте обучение автоассоциативных сетей с двумя и тремя нейронами в «узком горле» на неполных данных (т.е. на каждой эпохе вместо полных данных X_data_tensor на модель нужно подавать неполные данные X_data_tensor[mask_to_exclude]).

Результаты выходов энкодеров в обоих случаях также сохраните в отдельные бинарные файлы.

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

Литература:

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