22 KiB
ЛАБОРАТОРНАЯ РАБОТА №3
Применение многослойного персептрона. Автоассоциативная ИНС
Цель работы: знакомство с применением многослойного персептрона для решения задач сжатия данных, прогнозирования временных рядов и распознавания образов.
Задание
- Открыть файл с данными по минеральной воде, который использовался при решении задач классификации в предыдущей лабораторной работе. Построить и обучить автоассоциативные нейронные сети с 2-мя и 3-мя нейронами в скрытом слое:
а) для исходных данных из 5-ти классов;
б) для исходных данных из 4-х классов.
Провести визуализацию данных в скрытом слое каждой сети на плоскость и в 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]).
Результаты выходов энкодеров в обоих случаях также сохраните в отдельные бинарные файлы.
# Ваш код здесь# Ваш код здесь# Ваш код здесьЛитература:
- Бородкин А.А., Елисеев В.Л. Основы и применение искусственных нейронных сетей. Сборник лабораторных работ: методическое пособие. – М.: Издательский дом МЭИ, 2017.
- MachineLearning.ru — профессиональный информационно-аналитический ресурс, посвященный машинному обучению, распознаванию образов и интеллектуальному анализу данных: http://www.machinelearning.ru
- Modern State of Artificial Intelligence — Online Masters program at MIPT: https://girafe.ai/