{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### ЛАБОРАТОРНАЯ РАБОТА №3\n", "## Применение многослойного персептрона. Автоассоциативная ИНС" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Цель работы: знакомство с применением многослойного персептрона для решения задач сжатия данных, прогнозирования временных рядов и распознавания образов.\n", ">\n", "> Задание\n", "> 1. Открыть файл с данными по минеральной воде, который использовался при решении задач классификации в предыдущей лабораторной работе. Построить и обучить автоассоциативные нейронные сети с 2-мя и 3-мя нейронами в скрытом слое: \n", "> а) для исходных данных из 5-ти классов; \n", "> б) для исходных данных из 4-х классов. \n", "> Провести визуализацию данных в скрытом слое каждой сети на плоскость и в 3-х мерное пространство. Проанализировать полученные результаты. Выбрать и сохранить автоассоциативные ИНС, обеспечивающие наилучшее сжатие исходных данных. \n", "> 2. … \n", "> 3. Решить задачу распознавания 9-ти изображений самолетов. Исходные данные (файлы avia1.bmp, …, avia9.bmp) необходимо предварительно преобразовать в набор векторов со значениями признаков 0 или 1. Обученная нейронная сеть должна правильно определять модель самолета и его класс (истребитель/бомбардировщик). Принадлежность модели к определенному классу выбирается студентом самостоятельно." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Импорт библиотек:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "-jndqXPxywKw" }, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import torch\n", "import imageio\n", "import warnings\n", "\n", "from torch import nn\n", "from IPython.display import clear_output\n", "\n", "warnings.filterwarnings('ignore')\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Содержание: \n", "[1. Подготовка данных](#p_1) \n", "[2. Классификация изображений](#p_2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Подготовка данных" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Сохраним в список `X_data` все девять изображений. Каждое из них загрузим в виде NumPy-массива, затем преобразуем данный массив в `float32` и делением на 255 перемасштабируем в его диапазон `[0.0, 1.0]` (было `[0, 255]`). Само исходное изображение (по умолчанию цветное) преобразуем изображение в чёрно‑белое — для чего возьмём среднее по каналам R, G, B для каждого пикселя." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Y03Y-xWo9Br1" }, "outputs": [], "source": [ "X_data = []\n", "\n", "for i in range(1, 10):\n", " filename = f'avia{i}.bmp'\n", " img = imageio.imread(filename)\n", " img = img.astype('float32') / 255.\n", " img = np.mean(img, axis=2)\n", " X_data.append(img)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Список `y_data` содержит в себе ответ — принадлежит ли силуэт на каждом из девяти изображений бомбардировщику (`1` если принадлежит, `0` если не принадлежит):" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "HVW-f4IZ6Nvi" }, "outputs": [], "source": [ "y_data = [0, 1, 0, 0, 1, 0, 0, 0, 1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Выведем все девять изображений и подпишем каждое из них:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 865 }, "id": "luwhswXP6NzI", "outputId": "f6262617-d188-40f7-b38f-37deed860ab9" }, "outputs": [], "source": [ "fig, axes = plt.subplots(3, 3, figsize=(9, 9))\n", "axes = axes.ravel()\n", "\n", "for i in range(9):\n", " axes[i].imshow(X_data[i], cmap='gray')\n", " aircraft_type = '\\nБомбардировщик' if y_data[i] == 1 else '\\nИстребитель'\n", " axes[i].set_title(aircraft_type)\n", " axes[i].axis('off')\n", "\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Представим данные в виде тензоров `X_data_tensor` и `y_data_tensor`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "zyU44xbVJ9EE" }, "outputs": [], "source": [ "X_data_tensor = torch.tensor(X_data).float()\n", "y_data_tensor = torch.tensor(y_data).reshape(-1, 1).float()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Проверим размерность `X_data_tensor` — она показывает, что в тензоре лежат девять изображений размером 352 на 346:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "6uROCg66M2Ij", "outputId": "eeb259ba-c3b2-4df2-b0b8-c5c38c33c416" }, "outputs": [], "source": [ "X_data_tensor.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Многослойный персептрон всегда принимает на вход одномерные векторы. Однако в нашей задаче классификации силуэтов саолётов исходные изображения — как видно из размерности, двуомерные тензоры. И чтобы подать их на вход сети, их необходимо «развернуть» в одномерные векторы, сохранив количество объектов (пикселей) неизменным.\n", "\n", "Такое преобразование позволяет использовать пространственную информацию пикселей как набор признаков для полносвязных слоёв персептрона.\n", "\n", "В PyTorch это можно сделать с помощью метода `.view()` следующим образом:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Q9BNBxAmKK1Z", "outputId": "42786382-bf08-4f7f-ffc6-8370db68f156" }, "outputs": [], "source": [ "X_data_tensor.view(X_data_tensor.size(0), -1).shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Для проверки перемножим длину и щирину одного из изображений:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "jOLmEcvSPeEH", "outputId": "f924e2ab-338f-4359-cb8a-93a3318ff675" }, "outputs": [], "source": [ "np.prod(X_data[0].shape)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Классификация изображений" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Реализуйте в классе `ImageClassifier` с помощью полносвязных слоёв `nn.Linear` многослойный персептрон. В качестве промежуточных функций активации используйте `nn.ReLU()`, а в качестве финальной — сигмоиду, поскольку решается задача бинарной классификации." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class ImageClassifier(nn.Module):\n", " def __init__(self, input_size):\n", " super().__init__()\n", " self.seq = nn.Sequential(\n", " # Ваш код здесь\n", " )\n", "\n", " def forward(self, x):\n", " x = x.view(x.size(0), -1)\n", " return self.seq(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Создайте экземпляр модели:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "model = ImageClassifier(input_size=# Ваш код здесь\n", "\n", "model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Проверим, что модель при приходе данных возвращает вероятности:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "x3QUCgUnOy_Z", "outputId": "be3f4404-b3d5-4bf3-b510-8d7b903e5fc8" }, "outputs": [], "source": [ "model(X_data_tensor)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Метрика accuracy:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "WMSGULyhQVNA" }, "outputs": [], "source": [ "def accuracy(y_pred, y_true):\n", " return torch.sum(y_pred == y_true) / len(y_true)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Задайте параметры для обучения нейронной сети:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "torch.manual_seed(seed=42)\n", "\n", "model = # Ваш код здесь\n", "\n", "epochs = # Ваш код здесь\n", "\n", "learning_rate = # Ваш код здесь\n", "momentum = # Ваш код здесь\n", "\n", "optimizer = # Ваш код здесь\n", "criterion = # Ваш код здесь" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Обучение нейронной сети:**" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "loss_history = []\n", "\n", "for epoch in range(epochs):\n", " # Ваш код здесь\n", "\n", " if (epoch + 1) % 5 == 0:\n", "\n", " clear_output(True)\n", " plt.plot(range(1, epoch+2), loss_history, label='Loss')\n", " plt.title(f'Epoch: {epoch + 1}, Loss: {loss_history[-1]:.6f}')\n", " plt.grid(True, alpha=0.3)\n", " plt.legend(loc='best')\n", " plt.show()\n", "\n", " print(f'Accuracy: {accuracy((y_prob > 0.5).float(), y_data_tensor).item():.3f}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Литература:\n", "1. Бородкин А.А., Елисеев В.Л. Основы и применение искусственных нейронных сетей. Сборник лабораторных работ: методическое пособие. – М.: Издательский дом МЭИ, 2017.\n", "2. MachineLearning.ru — профессиональный информационно-аналитический ресурс, посвященный машинному обучению, распознаванию образов и интеллектуальному анализу данных: http://www.machinelearning.ru\n", "3. Modern State of Artificial Intelligence — Online Masters program at MIPT: https://girafe.ai/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " " ] } ], "metadata": { "colab": { "provenance": [] }, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 1 }