From 9c1d9f27ca17f76b2e4cc00cc003cbf9c44f10ca Mon Sep 17 00:00:00 2001 From: DanRie Date: Sun, 30 Nov 2025 15:38:28 +0300 Subject: [PATCH] LR4 done --- labworks/LW3/report.md | 2 +- labworks/LW4/images/1.png | Bin 0 -> 21455 bytes labworks/LW4/lab4.ipynb | 423 +++++++++++ .../lab4_full.ipynb | 718 ++++++++++++++++++ labworks/LW4/report.md | 295 +++++++ 5 files changed, 1437 insertions(+), 1 deletion(-) create mode 100644 labworks/LW4/images/1.png create mode 100644 labworks/LW4/lab4.ipynb create mode 100644 labworks/LW4/notebook с полными выводами/lab4_full.ipynb create mode 100644 labworks/LW4/report.md diff --git a/labworks/LW3/report.md b/labworks/LW3/report.md index fdc38d0..ddd5a16 100644 --- a/labworks/LW3/report.md +++ b/labworks/LW3/report.md @@ -1,4 +1,4 @@ -# Отчёт по лабораторной работе №2 +# Отчёт по лабораторной работе №3 **Кнзев Станислав, Жихарев Данила — А-02-22** diff --git a/labworks/LW4/images/1.png b/labworks/LW4/images/1.png new file mode 100644 index 0000000000000000000000000000000000000000..100df81b869568349b217ac8eff2ac1cf26d2257 GIT binary patch literal 21455 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 Qvo#q!UHx3vIVCg!0EQj+m;e9( literal 0 HcmV?d00001 diff --git a/labworks/LW4/lab4.ipynb b/labworks/LW4/lab4.ipynb new file mode 100644 index 0000000..67fe187 --- /dev/null +++ b/labworks/LW4/lab4.ipynb @@ -0,0 +1,423 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "### 1) В среде Google Colab создали новый блокнот (notebook). Импортировали необходимые для работы библиотеки и модули. Настроили блокнот для работы с аппаратным ускорителем GPU." + ], + "metadata": { + "id": "gz18QPRz03Ec" + } + }, + { + "cell_type": "code", + "source": [ + "# импорт модулей\n", + "import os\n", + "os.chdir('/content/drive/MyDrive/Colab Notebooks/is_lab4')\n", + "\n", + "from tensorflow import keras\n", + "from tensorflow.keras import layers\n", + "from tensorflow.keras.models import Sequential\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n" + ], + "metadata": { + "id": "mr9IszuQ1ANG" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import tensorflow as tf\n", + "device_name = tf.test.gpu_device_name()\n", + "if device_name != '/device:GPU:0':\n", + " raise SystemError('GPU device not found')\n", + "print('Found GPU at: {}'.format(device_name))" + ], + "metadata": { + "id": "o63-lKG_RuNc" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 2) Загрузили набор данных IMDb, содержащий оцифрованные отзывы на фильмы, размеченные на два класса: позитивные и негативные. При загрузке набора данных параметр seed выбрали равным значению (4k – 1)=23, где k=6 – номер бригады. Вывели размеры полученных обучающих и тестовых массивов данных." + ], + "metadata": { + "id": "FFRtE0TN1AiA" + } + }, + { + "cell_type": "code", + "source": [ + "# загрузка датасета\n", + "from keras.datasets import imdb\n", + "\n", + "vocabulary_size = 5000\n", + "index_from = 3\n", + "\n", + "(X_train, y_train), (X_test, y_test) = imdb.load_data(\n", + " path=\"imdb.npz\",\n", + " num_words=vocabulary_size,\n", + " skip_top=0,\n", + " maxlen=None,\n", + " seed=26,\n", + " start_char=1,\n", + " oov_char=2,\n", + " index_from=index_from\n", + " )\n", + "\n", + "# вывод размерностей\n", + "print('Shape of X train:', X_train.shape)\n", + "print('Shape of y train:', y_train.shape)\n", + "print('Shape of X test:', X_test.shape)\n", + "print('Shape of y test:', y_test.shape)" + ], + "metadata": { + "id": "Ixw5Sp0_1A-w" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 3) Вывели один отзыв из обучающего множества в виде списка индексов слов. Преобразовали список индексов в текст и вывели отзыв в виде текста. Вывели длину отзыва. Вывели метку класса данного отзыва и название класса (1 – Positive, 0 – Negative)." + ], + "metadata": { + "id": "aCo_lUXl1BPV" + } + }, + { + "cell_type": "code", + "source": [ + "# создание словаря для перевода индексов в слова\n", + "# заргузка словаря \"слово:индекс\"\n", + "word_to_id = imdb.get_word_index()\n", + "# уточнение словаря\n", + "word_to_id = {key:(value + index_from) for key,value in word_to_id.items()}\n", + "word_to_id[\"\"] = 0\n", + "word_to_id[\"\"] = 1\n", + "word_to_id[\"\"] = 2\n", + "word_to_id[\"\"] = 3\n", + "# создание обратного словаря \"индекс:слово\"\n", + "id_to_word = {value:key for key,value in word_to_id.items()}" + ], + "metadata": { + "id": "9W3RklPcZyH0" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "review_as_text = ' '.join(id_to_word[id] for id in X_train[26])\n", + "print(review_as_text)" + ], + "metadata": { + "id": "JhTwTurtZ6Sp" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 4) Вывели максимальную и минимальную длину отзыва в обучающем множестве." + ], + "metadata": { + "id": "4hclnNaD1BuB" + } + }, + { + "cell_type": "code", + "source": [ + "print('MAX Len: ',len(max(X_train, key=len)))\n", + "print('MIN Len: ',len(min(X_train, key=len)))" + ], + "metadata": { + "id": "xJH87ISq1B9h" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 5) Провели предобработку данных. Выбрали единую длину, к которой будут приведены все отзывы. Короткие отзывы дополнили спецсимволами, а длинные обрезали до выбранной длины." + ], + "metadata": { + "id": "7x99O8ig1CLh" + } + }, + { + "cell_type": "code", + "source": [ + "# предобработка данных\n", + "from tensorflow.keras.utils import pad_sequences\n", + "max_words = 500\n", + "X_train = pad_sequences(X_train, maxlen=max_words, value=0, padding='pre', truncating='post')\n", + "X_test = pad_sequences(X_test, maxlen=max_words, value=0, padding='pre', truncating='post')" + ], + "metadata": { + "id": "lrF-B2aScR4t" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 6) Повторили пункт 4." + ], + "metadata": { + "id": "HL2_LVga1C3l" + } + }, + { + "cell_type": "code", + "source": [ + "print('MAX Len: ',len(max(X_train, key=len)))\n", + "print('MIN Len: ',len(min(X_train, key=len)))" + ], + "metadata": { + "id": "81Cgq8dn9uL6" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 7) Повторили пункт 3. Сделали вывод о том, как отзыв преобразовался после предобработки." + ], + "metadata": { + "id": "KzrVY1SR1DZh" + } + }, + { + "cell_type": "code", + "source": [ + "review_as_text = ' '.join(id_to_word[id] for id in X_train[26])\n", + "print(review_as_text)" + ], + "metadata": { + "id": "dbfkWjDI1Dp7" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "#### После обработки в начало отзыва добавилось необходимое количество токенов , чтобы отзыв был длинной в 500 индексов." + ], + "metadata": { + "id": "mJNRXo5TdPAE" + } + }, + { + "cell_type": "markdown", + "source": [ + "### 8) Вывели предобработанные массивы обучающих и тестовых данных и их размерности." + ], + "metadata": { + "id": "YgiVGr5_1D3u" + } + }, + { + "cell_type": "code", + "source": [ + "# вывод данных\n", + "print('X train: \\n',X_train)\n", + "print('X train: \\n',X_test)\n", + "\n", + "# вывод размерностей\n", + "print('Shape of X train:', X_train.shape)\n", + "print('Shape of X test:', X_test.shape)" + ], + "metadata": { + "id": "7MqcG_wl1EHI" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 9) Реализовали модель рекуррентной нейронной сети, состоящей из слоев Embedding, LSTM, Dropout, Dense, и обучили ее на обучающих данных с выделением части обучающих данных в качестве валидационных. Вывели информацию об архитектуре нейронной сети. Добились качества обучения по метрике accuracy не менее 0.8." + ], + "metadata": { + "id": "amaspXGW1EVy" + } + }, + { + "cell_type": "code", + "source": [ + "embed_dim = 32\n", + "lstm_units = 64\n", + "\n", + "model = Sequential()\n", + "model.add(layers.Embedding(input_dim=vocabulary_size, output_dim=embed_dim, input_length=max_words, input_shape=(max_words,)))\n", + "model.add(layers.LSTM(lstm_units))\n", + "model.add(layers.Dropout(0.5))\n", + "model.add(layers.Dense(1, activation='sigmoid'))\n", + "\n", + "model.summary()" + ], + "metadata": { + "id": "ktWEeqWd1EyF" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "# компилируем и обучаем модель\n", + "batch_size = 64\n", + "epochs = 3\n", + "model.compile(loss=\"binary_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n", + "model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.2)" + ], + "metadata": { + "id": "CuPqKpX0kQfP" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "test_loss, test_acc = model.evaluate(X_test, y_test)\n", + "print(f\"\\nTest accuracy: {test_acc}\")" + ], + "metadata": { + "id": "hJIWinxymQjb" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 10) Оценили качество обучения на тестовых данных:\n", + "### - вывели значение метрики качества классификации на тестовых данных\n", + "### - вывели отчет о качестве классификации тестовой выборки \n", + "### - построили ROC-кривую по результату обработки тестовой выборки и вычислили площадь под ROC-кривой (AUC ROC)" + ], + "metadata": { + "id": "mgrihPd61E8w" + } + }, + { + "cell_type": "code", + "source": [ + "#значение метрики качества классификации на тестовых данных\n", + "print(f\"\\nTest accuracy: {test_acc}\")" + ], + "metadata": { + "id": "Rya5ABT8msha" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#отчет о качестве классификации тестовой выборки\n", + "y_score = model.predict(X_test)\n", + "y_pred = [1 if y_score[i,0]>=0.5 else 0 for i in range(len(y_score))]\n", + "\n", + "from sklearn.metrics import classification_report\n", + "print(classification_report(y_test, y_pred, labels = [0, 1], target_names=['Negative', 'Positive']))" + ], + "metadata": { + "id": "2kHjcmnCmv0Y" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "#построение ROC-кривой и AUC ROC\n", + "from sklearn.metrics import roc_curve, auc\n", + "\n", + "fpr, tpr, thresholds = roc_curve(y_test, y_score)\n", + "plt.plot(fpr, tpr)\n", + "plt.grid()\n", + "plt.xlabel('False Positive Rate')\n", + "plt.ylabel('True Positive Rate')\n", + "plt.title('ROC')\n", + "plt.show()\n", + "print('AUC ROC:', auc(fpr, tpr))" + ], + "metadata": { + "id": "Kp4AQRbcmwAx" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 11) Сделали выводы по результатам применения рекуррентной нейронной сети для решения задачи определения тональности текста. " + ], + "metadata": { + "id": "MsM3ew3d1FYq" + } + }, + { + "cell_type": "markdown", + "source": [ + "Таблица1:" + ], + "metadata": { + "id": "xxFO4CXbIG88" + } + }, + { + "cell_type": "markdown", + "source": [ + "| Модель | Количество настраиваемых параметров | Количество эпох обучения | Качество классификации тестовой выборки |\n", + "|----------|-------------------------------------|---------------------------|-----------------------------------------|\n", + "| Рекуррентная | 184 897 | 3 | accuracy:0.8556 ; loss:0.5214 ; AUC ROC:0.9165 |\n" + ], + "metadata": { + "id": "xvoivjuNFlEf" + } + }, + { + "cell_type": "markdown", + "source": [ + "#### По результатам применения рекуррентной нейронной сети, а также по данным таблицы 1 можно сделать вывод, что модель хорошо справилась с задачей определения тональности текста. Показатель accuracy = 0.8556 превышает требуемый порог 0.8. Значение AUC ROC = 0.9165 (> 0.9) говорит о высокой способности модели различать два класса (положительные и отрицательные отзывы)." + ], + "metadata": { + "id": "YctF8h_sIB-P" + } + } + ] +} \ No newline at end of file diff --git a/labworks/LW4/notebook с полными выводами/lab4_full.ipynb b/labworks/LW4/notebook с полными выводами/lab4_full.ipynb new file mode 100644 index 0000000..66b4e90 --- /dev/null +++ b/labworks/LW4/notebook с полными выводами/lab4_full.ipynb @@ -0,0 +1,718 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "gpuType": "T4" + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "### 1) В среде Google Colab создали новый блокнот (notebook). Импортировали необходимые для работы библиотеки и модули. Настроили блокнот для работы с аппаратным ускорителем GPU." + ], + "metadata": { + "id": "gz18QPRz03Ec" + } + }, + { + "cell_type": "code", + "source": [ + "# импорт модулей\n", + "import os\n", + "os.chdir('/content/drive/MyDrive/Colab Notebooks/is_lab4')\n", + "\n", + "from tensorflow import keras\n", + "from tensorflow.keras import layers\n", + "from tensorflow.keras.models import Sequential\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n" + ], + "metadata": { + "id": "mr9IszuQ1ANG" + }, + "execution_count": 6, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "import tensorflow as tf\n", + "device_name = tf.test.gpu_device_name()\n", + "if device_name != '/device:GPU:0':\n", + " raise SystemError('GPU device not found')\n", + "print('Found GPU at: {}'.format(device_name))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "o63-lKG_RuNc", + "outputId": "4c6df484-af24-4e87-cdf4-8917253924b1" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Found GPU at: /device:GPU:0\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 2) Загрузили набор данных IMDb, содержащий оцифрованные отзывы на фильмы, размеченные на два класса: позитивные и негативные. При загрузке набора данных параметр seed выбрали равным значению (4k – 1)=23, где k=6 – номер бригады. Вывели размеры полученных обучающих и тестовых массивов данных." + ], + "metadata": { + "id": "FFRtE0TN1AiA" + } + }, + { + "cell_type": "code", + "source": [ + "# загрузка датасета\n", + "from keras.datasets import imdb\n", + "\n", + "vocabulary_size = 5000\n", + "index_from = 3\n", + "\n", + "(X_train, y_train), (X_test, y_test) = imdb.load_data(\n", + " path=\"imdb.npz\",\n", + " num_words=vocabulary_size,\n", + " skip_top=0,\n", + " maxlen=None,\n", + " seed=26,\n", + " start_char=1,\n", + " oov_char=2,\n", + " index_from=index_from\n", + " )\n", + "\n", + "# вывод размерностей\n", + "print('Shape of X train:', X_train.shape)\n", + "print('Shape of y train:', y_train.shape)\n", + "print('Shape of X test:', X_test.shape)\n", + "print('Shape of y test:', y_test.shape)" + ], + "metadata": { + "id": "Ixw5Sp0_1A-w", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "7edbbdce-b2f6-4f0d-c0af-0b7af794d9b8" + }, + "execution_count": 11, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Shape of X train: (25000,)\n", + "Shape of y train: (25000,)\n", + "Shape of X test: (25000,)\n", + "Shape of y test: (25000,)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 3) Вывели один отзыв из обучающего множества в виде списка индексов слов. Преобразовали список индексов в текст и вывели отзыв в виде текста. Вывели длину отзыва. Вывели метку класса данного отзыва и название класса (1 – Positive, 0 – Negative)." + ], + "metadata": { + "id": "aCo_lUXl1BPV" + } + }, + { + "cell_type": "code", + "source": [ + "# создание словаря для перевода индексов в слова\n", + "# заргузка словаря \"слово:индекс\"\n", + "word_to_id = imdb.get_word_index()\n", + "# уточнение словаря\n", + "word_to_id = {key:(value + index_from) for key,value in word_to_id.items()}\n", + "word_to_id[\"\"] = 0\n", + "word_to_id[\"\"] = 1\n", + "word_to_id[\"\"] = 2\n", + "word_to_id[\"\"] = 3\n", + "# создание обратного словаря \"индекс:слово\"\n", + "id_to_word = {value:key for key,value in word_to_id.items()}" + ], + "metadata": { + "id": "9W3RklPcZyH0" + }, + "execution_count": 12, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "review_as_text = ' '.join(id_to_word[id] for id in X_train[26])\n", + "print(review_as_text)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JhTwTurtZ6Sp", + "outputId": "7f52f295-9195-4ce4-dedb-f69a2807c096" + }, + "execution_count": 17, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " the bad out takes from of fire together without any real story br br dean tries to be a real actor and fails again br br in the end the quit in br br \n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 4) Вывели максимальную и минимальную длину отзыва в обучающем множестве." + ], + "metadata": { + "id": "4hclnNaD1BuB" + } + }, + { + "cell_type": "code", + "source": [ + "print('MAX Len: ',len(max(X_train, key=len)))\n", + "print('MIN Len: ',len(min(X_train, key=len)))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xJH87ISq1B9h", + "outputId": "8723c18f-9997-415d-f67e-e4644d4e81f5" + }, + "execution_count": 19, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "MAX Len: 2494\n", + "MIN Len: 11\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 5) Провели предобработку данных. Выбрали единую длину, к которой будут приведены все отзывы. Короткие отзывы дополнили спецсимволами, а длинные обрезали до выбранной длины." + ], + "metadata": { + "id": "7x99O8ig1CLh" + } + }, + { + "cell_type": "code", + "source": [ + "# предобработка данных\n", + "from tensorflow.keras.utils import pad_sequences\n", + "max_words = 500\n", + "X_train = pad_sequences(X_train, maxlen=max_words, value=0, padding='pre', truncating='post')\n", + "X_test = pad_sequences(X_test, maxlen=max_words, value=0, padding='pre', truncating='post')" + ], + "metadata": { + "id": "lrF-B2aScR4t" + }, + "execution_count": 29, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### 6) Повторили пункт 4." + ], + "metadata": { + "id": "HL2_LVga1C3l" + } + }, + { + "cell_type": "code", + "source": [ + "print('MAX Len: ',len(max(X_train, key=len)))\n", + "print('MIN Len: ',len(min(X_train, key=len)))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "81Cgq8dn9uL6", + "outputId": "0476b7c6-8255-4fe1-996c-7e7f1e260d04" + }, + "execution_count": 23, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "MAX Len: 500\n", + "MIN Len: 500\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 7) Повторили пункт 3. Сделали вывод о том, как отзыв преобразовался после предобработки." + ], + "metadata": { + "id": "KzrVY1SR1DZh" + } + }, + { + "cell_type": "code", + "source": [ + "review_as_text = ' '.join(id_to_word[id] for id in X_train[26])\n", + "print(review_as_text)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "dbfkWjDI1Dp7", + "outputId": "4b622bcb-f605-4988-af1b-018135847def" + }, + "execution_count": 24, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " the bad out takes from of fire together without any real story br br dean tries to be a real actor and fails again br br in the end the quit in br br \n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "#### После обработки в начало отзыва добавилось необходимое количество токенов , чтобы отзыв был длинной в 500 индексов." + ], + "metadata": { + "id": "mJNRXo5TdPAE" + } + }, + { + "cell_type": "markdown", + "source": [ + "### 8) Вывели предобработанные массивы обучающих и тестовых данных и их размерности." + ], + "metadata": { + "id": "YgiVGr5_1D3u" + } + }, + { + "cell_type": "code", + "source": [ + "# вывод данных\n", + "print('X train: \\n',X_train)\n", + "print('X train: \\n',X_test)\n", + "\n", + "# вывод размерностей\n", + "print('Shape of X train:', X_train.shape)\n", + "print('Shape of X test:', X_test.shape)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7MqcG_wl1EHI", + "outputId": "b068f5d7-4f3a-41f8-90e8-4b2be5076170" + }, + "execution_count": 37, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "X train: \n", + " [[ 0 0 0 ... 1039 7 12]\n", + " [ 0 0 0 ... 5 2 1773]\n", + " [ 0 0 0 ... 220 175 96]\n", + " ...\n", + " [ 1 3264 153 ... 157 746 14]\n", + " [ 0 0 0 ... 3459 55 680]\n", + " [ 0 0 0 ... 14 31 56]]\n", + "X train: \n", + " [[ 0 0 0 ... 241 3366 56]\n", + " [ 0 0 0 ... 18 4 755]\n", + " [ 0 0 0 ... 149 14 20]\n", + " ...\n", + " [ 0 0 0 ... 2 2152 1835]\n", + " [ 0 0 0 ... 3768 3508 3311]\n", + " [ 0 0 0 ... 511 8 2725]]\n", + "Shape of X train: (25000, 500)\n", + "Shape of X test: (25000, 500)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 9) Реализовали модель рекуррентной нейронной сети, состоящей из слоев Embedding, LSTM, Dropout, Dense, и обучили ее на обучающих данных с выделением части обучающих данных в качестве валидационных. Вывели информацию об архитектуре нейронной сети. Добились качества обучения по метрике accuracy не менее 0.8." + ], + "metadata": { + "id": "amaspXGW1EVy" + } + }, + { + "cell_type": "code", + "source": [ + "embed_dim = 32\n", + "lstm_units = 64\n", + "\n", + "model = Sequential()\n", + "model.add(layers.Embedding(input_dim=vocabulary_size, output_dim=embed_dim, input_length=max_words, input_shape=(max_words,)))\n", + "model.add(layers.LSTM(lstm_units))\n", + "model.add(layers.Dropout(0.5))\n", + "model.add(layers.Dense(1, activation='sigmoid'))\n", + "\n", + "model.summary()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 262 + }, + "id": "ktWEeqWd1EyF", + "outputId": "01618308-359e-40c5-d675-bea723939cd5" + }, + "execution_count": 42, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1mModel: \"sequential_4\"\u001b[0m\n" + ], + "text/html": [ + "
Model: \"sequential_4\"\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n", + "│ embedding_4 (\u001b[38;5;33mEmbedding\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m500\u001b[0m, \u001b[38;5;34m32\u001b[0m) │ \u001b[38;5;34m160,000\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ lstm_4 (\u001b[38;5;33mLSTM\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m24,832\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dropout_4 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n", + "├─────────────────────────────────┼────────────────────────┼───────────────┤\n", + "│ dense_4 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m) │ \u001b[38;5;34m65\u001b[0m │\n", + "└─────────────────────────────────┴────────────────────────┴───────────────┘\n" + ], + "text/html": [ + "
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
+              "┃ Layer (type)                     Output Shape                  Param # ┃\n",
+              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
+              "│ embedding_4 (Embedding)         │ (None, 500, 32)        │       160,000 │\n",
+              "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+              "│ lstm_4 (LSTM)                   │ (None, 64)             │        24,832 │\n",
+              "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+              "│ dropout_4 (Dropout)             │ (None, 64)             │             0 │\n",
+              "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
+              "│ dense_4 (Dense)                 │ (None, 1)              │            65 │\n",
+              "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m184,897\u001b[0m (722.25 KB)\n" + ], + "text/html": [ + "
 Total params: 184,897 (722.25 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m184,897\u001b[0m (722.25 KB)\n" + ], + "text/html": [ + "
 Trainable params: 184,897 (722.25 KB)\n",
+              "
\n" + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" + ], + "text/html": [ + "
 Non-trainable params: 0 (0.00 B)\n",
+              "
\n" + ] + }, + "metadata": {} + } + ] + }, + { + "cell_type": "code", + "source": [ + "# компилируем и обучаем модель\n", + "batch_size = 64\n", + "epochs = 3\n", + "model.compile(loss=\"binary_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\n", + "model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.2)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CuPqKpX0kQfP", + "outputId": "297fa800-d027-4d99-cc37-16302d8190fb" + }, + "execution_count": 46, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch 1/3\n", + "\u001b[1m313/313\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 21ms/step - accuracy: 0.9593 - loss: 0.1184 - val_accuracy: 0.8632 - val_loss: 0.4331\n", + "Epoch 2/3\n", + "\u001b[1m313/313\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 22ms/step - accuracy: 0.9652 - loss: 0.1055 - val_accuracy: 0.8722 - val_loss: 0.5389\n", + "Epoch 3/3\n", + "\u001b[1m313/313\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m6s\u001b[0m 20ms/step - accuracy: 0.9741 - loss: 0.0829 - val_accuracy: 0.8648 - val_loss: 0.4959\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ] + }, + "metadata": {}, + "execution_count": 46 + } + ] + }, + { + "cell_type": "code", + "source": [ + "test_loss, test_acc = model.evaluate(X_test, y_test)\n", + "print(f\"\\nTest accuracy: {test_acc}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hJIWinxymQjb", + "outputId": "71a3184a-4574-40ed-f456-8f18db1fd4bf" + }, + "execution_count": 47, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[1m782/782\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 8ms/step - accuracy: 0.8566 - loss: 0.5214\n", + "\n", + "Test accuracy: 0.8555999994277954\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 10) Оценили качество обучения на тестовых данных:\n", + "### - вывели значение метрики качества классификации на тестовых данных\n", + "### - вывели отчет о качестве классификации тестовой выборки \n", + "### - построили ROC-кривую по результату обработки тестовой выборки и вычислили площадь под ROC-кривой (AUC ROC)" + ], + "metadata": { + "id": "mgrihPd61E8w" + } + }, + { + "cell_type": "code", + "source": [ + "#значение метрики качества классификации на тестовых данных\n", + "print(f\"\\nTest accuracy: {test_acc}\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Rya5ABT8msha", + "outputId": "6f69b050-952c-4fd8-f5a4-de52004fdf39" + }, + "execution_count": 51, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "Test accuracy: 0.8555999994277954\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "#отчет о качестве классификации тестовой выборки\n", + "y_score = model.predict(X_test)\n", + "y_pred = [1 if y_score[i,0]>=0.5 else 0 for i in range(len(y_score))]\n", + "\n", + "from sklearn.metrics import classification_report\n", + "print(classification_report(y_test, y_pred, labels = [0, 1], target_names=['Negative', 'Positive']))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2kHjcmnCmv0Y", + "outputId": "2025617c-d67c-4c54-eda5-ee74671a41ab" + }, + "execution_count": 52, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\u001b[1m782/782\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m8s\u001b[0m 10ms/step\n", + " precision recall f1-score support\n", + "\n", + " Negative 0.85 0.87 0.86 12500\n", + " Positive 0.87 0.84 0.85 12500\n", + "\n", + " accuracy 0.86 25000\n", + " macro avg 0.86 0.86 0.86 25000\n", + "weighted avg 0.86 0.86 0.86 25000\n", + "\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "#построение ROC-кривой и AUC ROC\n", + "from sklearn.metrics import roc_curve, auc\n", + "\n", + "fpr, tpr, thresholds = roc_curve(y_test, y_score)\n", + "plt.plot(fpr, tpr)\n", + "plt.grid()\n", + "plt.xlabel('False Positive Rate')\n", + "plt.ylabel('True Positive Rate')\n", + "plt.title('ROC')\n", + "plt.show()\n", + "print('AUC ROC:', auc(fpr, tpr))" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 490 + }, + "id": "Kp4AQRbcmwAx", + "outputId": "7ba7f48a-0f40-4708-87ac-ef85edaf4de0" + }, + "execution_count": 56, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAUztJREFUeJzt3Xl4E+XaBvA7SbM03UvpSrHsi+wgHFBAtFBEUdSjKHyA6MEFqhwqCihQUQEVRTiKoiBWcAH1uHAEgYKigCAIVFmLUPYuUEqbrtnm/f4IDda20JQk0yT377q4mExnJk8e6sl9Zt6ZVyGEECAiIiLyEkq5CyAiIiJyJoYbIiIi8ioMN0RERORVGG6IiIjIqzDcEBERkVdhuCEiIiKvwnBDREREXoXhhoiIiLwKww0RERF5FYYbIiIi8ioMN0TUoKSlpUGhUNj/+Pn5IS4uDg899BDOnj1bbXshBFasWIF+/fohNDQUer0eHTt2xIsvvojS0tJa3+frr7/GbbfdhoiICGg0GsTGxuL+++/HDz/84MqPR0RuoODcUkTUkKSlpWHs2LF48cUX0axZM1RUVGDHjh1IS0tDQkIC9u/fD51OBwCwWq0YMWIEPv/8c/Tt2xf33HMP9Ho9tmzZgk8//RTt27fHxo0bERUVZT++EAIPP/ww0tLS0LVrV/zzn/9EdHQ0cnJy8PXXX2P37t3Ytm0b+vTpI1cLiOhaCSKiBuTDDz8UAMSuXbuqrJ8yZYoAIFatWmVfN2fOHAFATJ48udpxVq9eLZRKpRg8eHCV9fPmzRMAxL///W8hSVK1/ZYvXy5+/fVXJ30aIpIDL0sRkUfo27cvAODYsWMAgPLycsybNw+tW7fG3Llzq20/dOhQjBkzBuvWrcOOHTvs+8ydOxdt27bF66+/DoVCUW2/UaNGoWfPni78JETkagw3ROQRTpw4AQAICwsDAGzduhUXL17EiBEj4OfnV+M+o0ePBgB899139n0KCgowYsQIqFQq1xdNRLKo+X8RiIhkVlRUhPz8fFRUVODXX3/FrFmzoNVqcccddwAADh48CADo3Llzrceo/NmhQ4eq/N2xY0dXlk5EMmO4IaIGKTExscrrhIQEfPzxx2jSpAkAoLi4GAAQFBRU6zEqf2YwGKr8faV9iMjzMdwQUYO0aNEitG7dGkVFRVi2bBl+/vlnaLVa+88rA0plyKnJ3wNQcHDwVfchIs/HMTdE1CD17NkTiYmJuPfee7F69Wp06NABI0aMQElJCQCgXbt2AIA//vij1mNU/qx9+/YAgLZt2wIA9u3b58rSiUhmDDdE1OCpVCrMnTsX2dnZePvttwEAN910E0JDQ/Hpp5/CarXWuN/y5csBwD5O56abbkJYWBg+++yzWvchIs/HcENEHuHmm29Gz549sWDBAlRUVECv12Py5MnIzMzE888/X237NWvWIC0tDUlJSfjHP/4BANDr9ZgyZQoOHTqEKVOmQNTwDNOPP/4YO3fudPnnISLX4ZgbIvIYzzzzDO677z6kpaXh8ccfx9SpU7F37168+uqr2L59O+699174+/tj69at+Pjjj9GuXTt89NFH1Y5x4MABvPHGG/jxxx/tTyjOzc3FN998g507d+KXX36R6RMSkTNw+gUialAqp1/YtWsXevToUeVnkiShdevWAIDMzEyoVCpIkoTly5dj6dKl2LdvH0wmE1q0aIH7778fTz/9NAICAmp8n//+9794//338dtvv8FgMKBx48bo168fnnjiCfTv39/ln5OIXIfhhoiIiLwKx9wQERGRV2G4ISIiIq/CcENEREReheGGiIiIvArDDREREXkVhhsiIiLyKj73ED9JkpCdnY2goCAoFAq5yyEiIqI6EEKguLgYsbGxUCqvfG7G58JNdnY24uPj5S6DiIiI6uH06dNo0qTJFbfxuXATFBQEwNac4OBgpx7bbDZjw4YNGDRoENRqtVOPTZexz+7BPrsH++w+7LV7uKrPBoMB8fHx9u/xK/G5cFN5KSo4ONgl4Uav1yM4OJj/4bgQ++we7LN7sM/uw167h6v7XJchJRxQTERERF6F4YaIiIi8CsMNEREReRWGGyIiIvIqDDdERETkVRhuiIiIyKsw3BAREZFXYbghIiIir8JwQ0RERF6F4YaIiIi8iqzh5ueff8bQoUMRGxsLhUKBb7755qr7bN68Gd26dYNWq0XLli2Rlpbm8jqJiIjIc8gabkpLS9G5c2csWrSoTtsfP34ct99+OwYMGICMjAz8+9//xr/+9S+sX7/exZUSERGRp5B14szbbrsNt912W523X7x4MZo1a4Y33ngDANCuXTts3boVb775JpKSklxVJhERkU+wWCUYLRIEACGE7W8JEBAQAhAAJFG5bFtRdZ1t4swi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\n" + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "AUC ROC: 0.9165464031999999\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "### 11) Сделали выводы по результатам применения рекуррентной нейронной сети для решения задачи определения тональности текста. " + ], + "metadata": { + "id": "MsM3ew3d1FYq" + } + }, + { + "cell_type": "markdown", + "source": [ + "Таблица1:" + ], + "metadata": { + "id": "xxFO4CXbIG88" + } + }, + { + "cell_type": "markdown", + "source": [ + "| Модель | Количество настраиваемых параметров | Количество эпох обучения | Качество классификации тестовой выборки |\n", + "|----------|-------------------------------------|---------------------------|-----------------------------------------|\n", + "| Рекуррентная | 184 897 | 3 | accuracy:0.8556 ; loss:0.5214 ; AUC ROC:0.9165 |\n" + ], + "metadata": { + "id": "xvoivjuNFlEf" + } + }, + { + "cell_type": "markdown", + "source": [ + "#### По результатам применения рекуррентной нейронной сети, а также по данным таблицы 1 можно сделать вывод, что модель хорошо справилась с задачей определения тональности текста. Показатель accuracy = 0.8556 превышает требуемый порог 0.8. Значение AUC ROC = 0.9165 (> 0.9) говорит о высокой способности модели различать два класса (положительные и отрицательные отзывы)." + ], + "metadata": { + "id": "YctF8h_sIB-P" + } + } + ] +} \ No newline at end of file diff --git a/labworks/LW4/report.md b/labworks/LW4/report.md new file mode 100644 index 0000000..a5a7710 --- /dev/null +++ b/labworks/LW4/report.md @@ -0,0 +1,295 @@ +# Отчёт по лабораторной работе №4 + +**Кнзев Станислав, Жихарев Данила — А-02-22** + +--- +## Задание 1 + +### 1) В среде Google Colab создали новый блокнот (notebook). Импортировали необходимые для работы библиотеки и модули. Настроили блокнот для работы с аппаратным ускорителем GPU. + +```python +# импорт модулей +import os +os.chdir('/content/drive/MyDrive/Colab Notebooks/is_lab4') + +from tensorflow import keras +from tensorflow.keras import layers +from tensorflow.keras.models import Sequential +import matplotlib.pyplot as plt +import numpy as np +``` +```python +import tensorflow as tf +device_name = tf.test.gpu_device_name() +if device_name != '/device:GPU:0': + raise SystemError('GPU device not found') +print('Found GPU at: {}'.format(device_name)) +``` +``` +Found GPU at: /device:GPU:0 +``` + +### 2) Загрузили набор данных IMDb, содержащий оцифрованные отзывы на фильмы, размеченные на два класса: позитивные и негативные. При загрузке набора данных параметр seed выбрали равным значению (4k – 1)=23, где k=6 – номер бригады. Вывели размеры полученных обучающих и тестовых массивов данных. + +```python +# загрузка датасета +from keras.datasets import imdb + +vocabulary_size = 5000 +index_from = 3 + +(X_train, y_train), (X_test, y_test) = imdb.load_data( + path="imdb.npz", + num_words=vocabulary_size, + skip_top=0, + maxlen=None, + seed=26, + start_char=1, + oov_char=2, + index_from=index_from + ) + +# вывод размерностей +print('Shape of X train:', X_train.shape) +print('Shape of y train:', y_train.shape) +print('Shape of X test:', X_test.shape) +print('Shape of y test:', y_test.shape) +``` +``` +Shape of X train: (25000,) +Shape of y train: (25000,) +Shape of X test: (25000,) +Shape of y test: (25000,) +``` + +### 3) Вывели один отзыв из обучающего множества в виде списка индексов слов. Преобразовали список индексов в текст и вывели отзыв в виде текста. Вывели длину отзыва. Вывели метку класса данного отзыва и название класса (1 – Positive, 0 – Negative). + +```python +# создание словаря для перевода индексов в слова +# заргузка словаря "слово:индекс" +word_to_id = imdb.get_word_index() +# уточнение словаря +word_to_id = {key:(value + index_from) for key,value in word_to_id.items()} +word_to_id[""] = 0 +word_to_id[""] = 1 +word_to_id[""] = 2 +word_to_id[""] = 3 +# создание обратного словаря "индекс:слово" +id_to_word = {value:key for key,value in word_to_id.items()} +``` +```python +review_as_text = ' '.join(id_to_word[id] for id in X_train[26]) +print(review_as_text) +``` +``` + the bad out takes from of fire together without any real story br br dean +tries to be a real actor and fails again br br in the end the quit in br br +``` + + +### 4) Вывели максимальную и минимальную длину отзыва в обучающем множестве. + +```python +print('MAX Len: ',len(max(X_train, key=len))) +print('MIN Len: ',len(min(X_train, key=len))) +``` +``` +MAX Len: 2494 +MIN Len: 11 +``` + +### 5) Провели предобработку данных. Выбрали единую длину, к которой будут приведены все отзывы. Короткие отзывы дополнили спецсимволами, а длинные обрезали до выбранной длины. + +```python +# предобработка данных +from tensorflow.keras.utils import pad_sequences +max_words = 500 +X_train = pad_sequences(X_train, maxlen=max_words, value=0, padding='pre', truncating='post') +X_test = pad_sequences(X_test, maxlen=max_words, value=0, padding='pre', truncating='post') +``` + +### 6) Повторили пункт 4. + +```python +print('MAX Len: ',len(max(X_train, key=len))) +print('MIN Len: ',len(min(X_train, key=len))) +``` +``` +MAX Len: 500 +MIN Len: 500 +``` + +### 7) Повторили пункт 3. Сделали вывод о том, как отзыв преобразовался после предобработки. + +```python +review_as_text = ' '.join(id_to_word[id] for id in X_train[26]) +print(review_as_text) +``` +``` + + + + + + + + + + + + + + + + + the bad out takes from of fire together without any real story br br dean +tries to be a real actor and fails again br br in the end the quit in br br +``` +#### После обработки в начало отзыва добавилось необходимое количество токенов , чтобы отзыв был длинной в 500 индексов. + + +### 8) Вывели предобработанные массивы обучающих и тестовых данных и их размерности. + +```python +# вывод данных +print('X train: \n',X_train) +print('X train: \n',X_test) + +# вывод размерностей +print('Shape of X train:', X_train.shape) +print('Shape of X test:', X_test.shape) +``` +``` +X train: + [[ 0 0 0 ... 1039 7 12] + [ 0 0 0 ... 5 2 1773] + [ 0 0 0 ... 220 175 96] + ... + [ 1 3264 153 ... 157 746 14] + [ 0 0 0 ... 3459 55 680] + [ 0 0 0 ... 14 31 56]] +X train: + [[ 0 0 0 ... 241 3366 56] + [ 0 0 0 ... 18 4 755] + [ 0 0 0 ... 149 14 20] + ... + [ 0 0 0 ... 2 2152 1835] + [ 0 0 0 ... 3768 3508 3311] + [ 0 0 0 ... 511 8 2725]] +Shape of X train: (25000, 500) +Shape of X test: (25000, 500) +``` + +### 9) Реализовали модель рекуррентной нейронной сети, состоящей из слоев Embedding, LSTM, Dropout, Dense, и обучили ее на обучающих данных с выделением части обучающих данных в качестве валидационных. Вывели информацию об архитектуре нейронной сети. Добились качества обучения по метрике accuracy не менее 0.8. + +```python +embed_dim = 32 +lstm_units = 64 + +model = Sequential() +model.add(layers.Embedding(input_dim=vocabulary_size, output_dim=embed_dim, input_length=max_words, input_shape=(max_words,))) +model.add(layers.LSTM(lstm_units)) +model.add(layers.Dropout(0.5)) +model.add(layers.Dense(1, activation='sigmoid')) + +model.summary() +``` + +**Model: "sequential"** +| Layer (type) | Output Shape | Param # | +| ----------------------- | --------------- | ------: | +| embedding_4 (Embedding) | (None, 500, 32) | 160,000 | +| lstm_4 (LSTM) | (None, 64) | 24,832 | +| dropout_4 (Dropout) | (None, 64) | 0 | +| dense_4 (Dense) | (None, 1) | 65 | + +**Total params:** 184,897 (722.25 KB) +**Trainable params:** 184,897 (722.25 KB) +**Non-trainable params:** 0 (0.00 B) + +```python +# компилируем и обучаем модель +batch_size = 64 +epochs = 3 +model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"]) +model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs, validation_split=0.2) +``` +``` +Epoch 1/3 +313/313 ━━━━━━━━━━━━━━━━━━━━ 8s 21ms/step - accuracy: 0.9593 - loss: 0.1184 - val_accuracy: 0.8632 - val_loss: 0.4331 +Epoch 2/3 +313/313 ━━━━━━━━━━━━━━━━━━━━ 7s 22ms/step - accuracy: 0.9652 - loss: 0.1055 - val_accuracy: 0.8722 - val_loss: 0.5389 +Epoch 3/3 +313/313 ━━━━━━━━━━━━━━━━━━━━ 6s 20ms/step - accuracy: 0.9741 - loss: 0.0829 - val_accuracy: 0.8648 - val_loss: 0.4959 + +``` +```python +test_loss, test_acc = model.evaluate(X_test, y_test) +print(f"\nTest accuracy: {test_acc}") +``` +``` +782/782 ━━━━━━━━━━━━━━━━━━━━ 7s 8ms/step - accuracy: 0.8566 - loss: 0.5214 + +Test accuracy: 0.8555999994277954 +``` + +### 10) Оценили качество обучения на тестовых данных: +### - вывели значение метрики качества классификации на тестовых данных +### - вывели отчет о качестве классификации тестовой выборки +### - построили ROC-кривую по результату обработки тестовой выборки и вычислили площадь под ROC-кривой (AUC ROC) + +```python +#значение метрики качества классификации на тестовых данных +print(f"\nTest accuracy: {test_acc}") +``` +``` +Test accuracy: 0.8555999994277954 +``` + +```python +#отчет о качестве классификации тестовой выборки +y_score = model.predict(X_test) +y_pred = [1 if y_score[i,0]>=0.5 else 0 for i in range(len(y_score))] + +from sklearn.metrics import classification_report +print(classification_report(y_test, y_pred, labels = [0, 1], target_names=['Negative', 'Positive'])) +``` +``` + precision recall f1-score support + + Negative 0.85 0.87 0.86 12500 + Positive 0.87 0.84 0.85 12500 + + accuracy 0.86 25000 + macro avg 0.86 0.86 0.86 25000 +weighted avg 0.86 0.86 0.86 25000 +``` + +```python +#построение ROC-кривой и AUC ROC +from sklearn.metrics import roc_curve, auc + +fpr, tpr, thresholds = roc_curve(y_test, y_score) +plt.plot(fpr, tpr) +plt.grid() +plt.xlabel('False Positive Rate') +plt.ylabel('True Positive Rate') +plt.title('ROC') +plt.show() +print('AUC ROC:', auc(fpr, tpr)) +``` +![picture](images/1.png) +``` +AUC ROC: 0.9165464031999999 +``` + +### 11) Сделали выводы по результатам применения рекуррентной нейронной сети для решения задачи определения тональности текста. + +Таблица1: + +| Модель | Количество настраиваемых параметров | Количество эпох обучения | Качество классификации тестовой выборки | +|----------|-------------------------------------|---------------------------|-----------------------------------------| +| Рекуррентная | 184 897 | 3 | accuracy:0.8556 ; loss:0.5214 ; AUC ROC:0.9165 | + + +#### По результатам применения рекуррентной нейронной сети, а также по данным таблицы 1 можно сделать вывод, что модель хорошо справилась с задачей определения тональности текста. Показатель accuracy = 0.8556 превышает требуемый порог 0.8. Значение AUC ROC = 0.9165 (> 0.9) говорит о высокой способности модели различать два класса (положительные и отрицательные отзывы). \ No newline at end of file