diff --git a/lab3/3.1_autoencoder.ipynb b/lab3/3.1_autoencoder.ipynb new file mode 100644 index 0000000..5be0162 --- /dev/null +++ b/lab3/3.1_autoencoder.ipynb @@ -0,0 +1,722 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "VhB5tU1IGSIh" + }, + "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": "FwCw1KfEpbsm" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "import torch\n", + "import matplotlib.pyplot as plt\n", + "from IPython.display import clear_output\n", + "from mpl_toolkits.mplot3d import Axes3D\n", + "\n", + "from torch import nn\n", + "\n", + "%matplotlib inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Содержание: \n", + "[1. Подготовка данных](#p_1) \n", + "[2. Автоассоциативная нейронная сеть на полных данных](#p_2) \n", + "[3. Автоассоциативная нейронная сеть на неполных данных](#p_3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Подготовка данных" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Загрузим в датафрейм `data` данные о сорока образцах минеральной воды, хранящиеся в файле `min_water.txt`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 256 + }, + "id": "PkNWYbQCpsl_", + "outputId": "ee2dd8c3-2d7d-4962-bc40-a5cc2dded5db" + }, + "outputs": [], + "source": [ + "data = pd.read_csv('min_water.csv')\n", + "data.head(n=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Вынесем в отдельные переменные:\n", + " - `y_binary` — выходной признак для задачи бинарной классификации (первый столбец датафрейма);\n", + " - `y_multiclass` — выходной признак для задачи многоклассовой классификации (второй столбец датафрейма);\n", + " - `X_data` — входные признаки (оставшиеся столбцы)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "D_QiYrPkpsu0" + }, + "outputs": [], + "source": [ + "y_binary = data.iloc[:, 0]\n", + "y_multiclass = data.iloc[:, 1]\n", + "\n", + "X_data = data.iloc[:, 2:]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Выпишите в список `features` отобранные в прошлой лабораторной работе признаки (формат: `features = ['VAR1', 'VAR2']`):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "features = # Ваш код здесь" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Датафрейм с отобранными входными признаками `X_data_filtered`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "d6eTUCk2Cjdc", + "outputId": "d89643dd-a410-42b2-9b91-c4534966fd1d" + }, + "outputs": [], + "source": [ + "X_data_filtered = X_data.loc[:, features]\n", + "X_data_filtered.head(n=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Произведите нормализацию или стандартизацию (на выбор) отобранных входных данных `X_data_filtered`. Результат сохраните в переменную `X_data_preprocessed`, которую затем представьте в виде тензора `X_data_tensor`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HclxngwAGue-" + }, + "outputs": [], + "source": [ + "# Ваш код здесь\n", + "\n", + "X_data_preprocessed = # Ваш код здесь\n", + "\n", + "X_data_tensor = # Ваш код здесь" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "AtGktiZmJiUV", + "outputId": "f9edb4f0-c5ab-4a62-af28-6552c981512f" + }, + "source": [ + "## 2. Автоассоциативная нейронная сеть на полных данных" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jsWiE7Ke1p9S" + }, + "source": [ + "Автоассоциативная сеть (или автоассоциативная память) — тип нейронной сети, способный восстанавливать полный шаблон данных по его частичному или зашумлённому представлению.\n", + "\n", + "Типичная автоассоциативная сеть содержит как минимум три скрытых слоя:\n", + " - первый скрытый слой выполняет нелинейное кодирование входных данных (энкодер);\n", + " - средний слой («узкое горло» или «бутылочное горло») формирует сжатое представление данных — в результате обучения выдаёт компактное кодирование;\n", + " - последний скрытый слой служит декодером: восстанавливает исходные данные из сжатого представления.\n", + "\n", + "Цель обучения: в процессе минимизации ошибки воспроизведения сеть стремится сделать выходной сигнал максимально близким к входному. Это эквивалентно оптимальному кодированию в «узком горле» сети." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Допишите класс `Autoencoder` структурами энкодера и декодера на основе полносвязных слоёв `nn.Linear`. В качестве функций активации используйте `nn.ReLU()`. При этом на выходе энкодера функцию активации можно не применять — это позволит сохранить отрицательные значения в кодированном представлении." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Autoencoder(nn.Module):\n", + " def __init__(self, n_inputs, n_hiddens, bottleneck_size):\n", + " super().__init__()\n", + " self.encoder = nn.Sequential(\n", + " # Ваш код здесь\n", + " )\n", + " self.decoder = nn.Sequential(\n", + " # Ваш код здесь\n", + " )\n", + "\n", + " def forward(self, x):\n", + " encoded = self.encoder(x)\n", + " decoded = self.decoder(encoded)\n", + " return decoded" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Создайте экземпляр модели с двумя нейронами в «узком горле»:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model_2 = Autoencoder(# Ващ код здесь\n", + "print(model_2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tGS2_TqjK_SI", + "outputId": "a1a63c33-5dd5-461e-8d20-97fc34455f21" + }, + "source": [ + "Пропустим данные через эту модель для её проверки:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Y3GS-3AaKYt7", + "outputId": "981a4cd8-3b19-4bf6-ac07-ddd13e3df131" + }, + "outputs": [], + "source": [ + "model_2(X_data_tensor[:3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Удостоверимся, что размерность её выхода совпадает с размерностью её входа:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "assert X_data_tensor[:3].shape == model_2(X_data_tensor[:3]).shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Проверим, как модель обучается. Зададим оптимизатор и среднеквадратическую функцию потерь:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VGWgT-_UKY5S" + }, + "outputs": [], + "source": [ + "optimizer = torch.optim.SGD(model_2.parameters(), lr=1.5)\n", + "criterion = nn.MSELoss()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Рассчитаем значение функции потерь:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5kKYW89_KY8j", + "outputId": "94e90485-ca86-4204-e61d-75d247a87fc4" + }, + "outputs": [], + "source": [ + "decoded = model_2(X_data_tensor)\n", + "\n", + "loss = criterion(decoded, X_data_tensor)\n", + "loss" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Выполните несколько раз эту и предыдущую ячейку, чтобы убедиться в уменьшении ошибки:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "G_JCVLCkKZCa" + }, + "outputs": [], + "source": [ + "loss.backward()\n", + "optimizer.step()\n", + "optimizer.zero_grad()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Задайте параметры для обучения автоассоциативной сети с двумя нейронами в «узком горле»:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "torch.manual_seed(seed=42)\n", + "\n", + "model_2 = # Ваш код здесь\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()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "После обучения сети получим двумерные данные с выхода энкодера:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "HFcSAdGoOaog", + "outputId": "36330737-7606-4a6a-e532-6bf372deb34d" + }, + "outputs": [], + "source": [ + "encoded_2d = model_2.encoder(X_data_tensor).detach().numpy()\n", + "print(encoded_2d[:3])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Построим двумерную диаграмму рассеяния и отметим классы с помощью `y_multiclass`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 430 + }, + "id": "KkToPCInQQ1J", + "outputId": "244bae8a-94a9-4817-a564-69c630efea98" + }, + "outputs": [], + "source": [ + "scatter = plt.scatter(x=encoded_2d[:, 0], y=encoded_2d[:, 1], c=y_multiclass, cmap='viridis')\n", + "plt.grid(True, alpha=0.3)\n", + "\n", + "# Код для легенды\n", + "handles, labels = scatter.legend_elements(prop='colors')\n", + "plt.legend(handles, labels, loc='best', title='Classes')\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "По аналогии обучите автоассоциативную сеть с тремя нейронами в «узком горле»:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "torch.manual_seed(seed=42)\n", + "\n", + "model_3 = # Ваш код здесь\n", + "\n", + "# Ваш код здесь" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Ваш код здесь" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "После обучения сети получите трёхмерные данные с выхода энкодера:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "encoded_3d = # Ваш код здесь" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Построим трёхмерную диаграмму рассеяния:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 653 + }, + "id": "RpqVg5EeT72I", + "outputId": "2f5e070d-aa49-4eab-cd8e-277bd3a2c4b5" + }, + "outputs": [], + "source": [ + "fig = plt.figure(figsize=(10, 8))\n", + "ax = fig.add_subplot(111, projection='3d')\n", + "\n", + "scatter = ax.scatter(\n", + " xs=encoded_3d[:, 0],\n", + " ys=encoded_3d[:, 1],\n", + " zs=encoded_3d[:, 2],\n", + " c=y_multiclass,\n", + " cmap='viridis',\n", + " s=50\n", + ")\n", + "\n", + "ax.grid(True, alpha=0.3)\n", + "\n", + "handles, labels = scatter.legend_elements(prop='colors', alpha=0.8)\n", + "ax.legend(handles, labels, loc='best', title='Classes')\n", + "\n", + "# Настраиваем угол обзора:\n", + "# elev — высота, azim — азимут\n", + "ax.view_init(elev=20, azim=45)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Сохраним в бинарные файлы `.npy` выходы энкодеров обеих моделей — для следующей лабораторной работы:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "np.save('encoded_2d.npy', encoded_2d)\n", + "np.save('encoded_3d.npy', encoded_3d)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Автоассоциативная нейронная сеть на неполных данных" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Выберите класс, который нужно исключить:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "label_to_exclude = # Ваш код здесь" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Создадим маску для исключения данных этого класса:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WwlU6wRqXy3H" + }, + "outputs": [], + "source": [ + "mask_to_exclude = y_multiclass != label_to_exclude" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Данные исключены:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "I7sTKdWgQRWQ", + "outputId": "95d2a292-7e2f-401e-e473-7d5f09b0d7fb" + }, + "outputs": [], + "source": [ + "X_data_tensor[mask_to_exclude].shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "По аналогии с предыдущим пунктом реализуйте обучение автоассоциативных сетей с двумя и тремя нейронами в «узком горле» на неполных данных (т.е. на каждой эпохе вместо полных данных `X_data_tensor` на модель нужно подавать неполные данные `X_data_tensor[mask_to_exclude]`).\n", + "\n", + "Результаты выходов энкодеров в обоих случаях также сохраните в отдельные бинарные файлы." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Ваш код здесь" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Ваш код здесь" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "w3kJHSW3azk0" + }, + "outputs": [], + "source": [ + "# Ваш код здесь" + ] + }, + { + "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 +} diff --git a/lab3/3.3_image.ipynb b/lab3/3.3_image.ipynb new file mode 100644 index 0000000..3692cdc --- /dev/null +++ b/lab3/3.3_image.ipynb @@ -0,0 +1,425 @@ +{ + "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 +} diff --git a/lab3/avia1.bmp b/lab3/avia1.bmp new file mode 100644 index 0000000..c69e422 Binary files /dev/null and b/lab3/avia1.bmp differ diff --git a/lab3/avia2.bmp b/lab3/avia2.bmp new file mode 100644 index 0000000..a3650b6 Binary files /dev/null and b/lab3/avia2.bmp differ diff --git a/lab3/avia3.bmp b/lab3/avia3.bmp new file mode 100644 index 0000000..5f43a88 Binary files /dev/null and b/lab3/avia3.bmp differ