{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "id": "d5jFanC8NPTN" }, "outputs": [], "source": [ "import os\n", "os.chdir('/content/drive/MyDrive/Colab Notebooks/is_dnn/labworks/LW1')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "H39A4nsqNuxn" }, "outputs": [], "source": [ "# импорт модулей\n", "import tensorflow as tf\n", "from tensorflow import keras\n", "from keras.datasets import mnist\n", "from keras.models import Sequential\n", "from keras.layers import Dense\n", "from keras.utils import to_categorical\n", "from sklearn.model_selection import train_test_split\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from PIL import Image\n", "import os\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 462, "status": "ok", "timestamp": 1759127274975, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "iNenKkcoRXrs", "outputId": "041dc403-e177-4f0d-edbb-40902c8954fd" }, "outputs": [], "source": [ "# Загрузка датасета\n", "(X_train_orig, y_train_orig), (X_test_orig, y_test_orig) = mnist.load_data()\n", "\n", "# разбиваем выборку на обучающую и тестовую выборку\n", "X = np.concatenate((X_train_orig, X_test_orig))\n", "y = np.concatenate((y_train_orig, y_test_orig))\n", "\n", "\n", "X_train, X_test, y_train, y_test = train_test_split(\n", " X, y,\n", " test_size=10000,\n", " train_size=60000,\n", " random_state=3,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 224 }, "executionInfo": { "elapsed": 243, "status": "ok", "timestamp": 1759127328545, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "bt-EmlYARsCL", "outputId": "611d9110-39a2-46dd-94ce-b0fea7005b87" }, "outputs": [], "source": [ "# Вывод первых 4 изображений\n", "fig, axes = plt.subplots(1, 4, figsize=(12, 3))\n", "for i in range(4):\n", " axes[i].imshow(X_train[i], cmap='gray')\n", " axes[i].set_title(f'Метка: {y_train[i]}')\n", " axes[i].axis('off')\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 134, "status": "ok", "timestamp": 1759127329383, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "5WUu3_97TjSa", "outputId": "7a75ca25-58fe-447d-8bef-547159e6479d" }, "outputs": [], "source": [ "# развернем каждое изображение 28*28 в вектор 784\n", "num_pixels = X_train.shape[1] * X_train.shape[2]\n", "X_train = X_train.reshape(X_train.shape[0], num_pixels) / 255\n", "X_test = X_test.reshape(X_test.shape[0], num_pixels) / 255\n", "print('Shape of transformed X train:', X_train.shape)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 7, "status": "ok", "timestamp": 1759127330016, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "sUJfDepgUauM", "outputId": "2a9bc3d0-8bdb-4971-f3d4-ca21cb14fca6" }, "outputs": [], "source": [ "# переведем метки в one-hot\n", "y_train = to_categorical(y_train)\n", "y_test = to_categorical(y_test)\n", "print('Shape of transformed y train:', y_train.shape)\n", "num_classes = y_train.shape[1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 1000 }, "executionInfo": { "elapsed": 207500, "status": "ok", "timestamp": 1759127540337, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "f3UzOyf_V2HQ", "outputId": "9ffc63df-23bf-4947-f3c0-2a3e507034f1" }, "outputs": [], "source": [ "model_0 = Sequential()\n", "model_0.add(Dense(units=num_classes, input_dim=num_pixels, activation='softmax'))\n", "\n", "# Компиляция модели\n", "model_0.compile(loss='categorical_crossentropy',\n", " optimizer='sgd',\n", " metrics=['accuracy'])\n", "\n", "# Вывод информации об архитектуре\n", "print(\"Архитектура однослойной сети:\")\n", "model_0.summary()\n", "\n", "# Обучение модели\n", "history_0 = model_0.fit(X_train, y_train,\n", " validation_split=0.1,\n", " epochs=50)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 533 }, "executionInfo": { "elapsed": 260, "status": "ok", "timestamp": 1759127542723, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "5yjxVnmFmpbV", "outputId": "b182a139-da24-491e-9ebd-7ba1e39eec84" }, "outputs": [], "source": [ "# График функции ошибки по эпохам\n", "plt.figure(figsize=(10, 6))\n", "plt.plot(history_0.history['loss'], label='Обучающая выборка')\n", "plt.plot(history_0.history['val_loss'], label='Валидационная выборка')\n", "plt.title('Функция ошибки по эпохам (Однослойная сеть)')\n", "plt.xlabel('Эпохи')\n", "plt.ylabel('Ошибка')\n", "plt.legend()\n", "plt.grid(True)\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 1058, "status": "ok", "timestamp": 1759127544719, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "NF_SsO8wiEUT", "outputId": "ffe554c2-1c94-42b7-cc63-8f407418c4ce" }, "outputs": [], "source": [ "# Оценка на тестовых данных\n", "scores_0 = model_0.evaluate(X_test, y_test, verbose=0)\n", "print(\"Результаты однослойной сети:\")\n", "print(f\"Ошибка на тестовых данных: {scores_0[0]}\")\n", "print(f\"Точность на тестовых данных: {scores_0[1]}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "fFcoQGdPnDFx" }, "outputs": [], "source": [ "# Функция для создания и обучения модели\n", "def create_and_train_model(hidden_units, model_name):\n", " model = Sequential()\n", " model.add(Dense(units=hidden_units, input_dim=num_pixels, activation='sigmoid'))\n", " model.add(Dense(units=num_classes, activation='softmax'))\n", "\n", " model.compile(loss='categorical_crossentropy',\n", " optimizer='sgd',\n", " metrics=['accuracy'])\n", "\n", " history = model.fit(X_train, y_train,\n", " validation_split=0.1,\n", " epochs=50)\n", "\n", " scores = model.evaluate(X_test, y_test, verbose=0)\n", "\n", " return model, history, scores" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "XPlFkV40joAT" }, "outputs": [], "source": [ "# Эксперименты с разным количеством нейронов\n", "hidden_units_list = [100, 300, 500]\n", "models_1 = {}\n", "histories_1 = {}\n", "scores_1 = {}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 638747, "status": "ok", "timestamp": 1759128186868, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "je0i_8HxjvpB", "outputId": "5cb19edc-9162-4c23-92d8-1671e62b2bb3" }, "outputs": [], "source": [ "# Обучение сетей с одним скрытым слоем\n", "for units in hidden_units_list:\n", " print(f\"\\nОбучение модели с {units} нейронами...\")\n", " model, history, scores = create_and_train_model(units, f\"model_{units}\")\n", "\n", " models_1[units] = model\n", " histories_1[units] = history\n", " scores_1[units] = scores\n", "\n", " print(f\"Точность: {scores[1]}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 20, "status": "ok", "timestamp": 1759128269112, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "TbbBBxeMmy6c", "outputId": "08b5a164-1e62-456c-80b9-bc7247be3fd3" }, "outputs": [], "source": [ "# Выбор наилучшей модели\n", "best_units_1 = max(scores_1.items(), key=lambda x: x[1][1])[0]\n", "print(f\"\\nНаилучшее количество нейронов: {best_units_1}\")\n", "print(f\"Точность: {scores_1[best_units_1][1]}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 279 }, "executionInfo": { "elapsed": 620, "status": "ok", "timestamp": 1759128272502, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "EFEBxB2qm1fF", "outputId": "d436ac7a-e33b-4cc2-e324-5decfc29de94" }, "outputs": [], "source": [ "# Графики ошибок для всех моделей\n", "plt.figure(figsize=(15, 5))\n", "for i, units in enumerate(hidden_units_list, 1):\n", " plt.subplot(1, 3, i)\n", " plt.plot(histories_1[units].history['loss'], label='Обучающая')\n", " plt.plot(histories_1[units].history['val_loss'], label='Валидационная')\n", " plt.title(f'{units} нейронов')\n", " plt.xlabel('Эпохи')\n", " plt.ylabel('Ошибка')\n", " plt.legend()\n", " plt.grid(True)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "EJBwT5vhnnSG" }, "outputs": [], "source": [ "# Добавление второго скрытого слоя\n", "second_layer_units = [50, 100]\n", "models_2 = {}\n", "histories_2 = {}\n", "scores_2 = {}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 420194, "status": "ok", "timestamp": 1759128698216, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "K5vweMySno3t", "outputId": "b67b155c-89ea-46e0-a590-a588433e0a38" }, "outputs": [], "source": [ "for units_2 in second_layer_units:\n", " print(f\"\\nОбучение модели со вторым слоем {units_2} нейронов\")\n", "\n", " model = Sequential()\n", " model.add(Dense(units=best_units_1, input_dim=num_pixels, activation='sigmoid'))\n", " model.add(Dense(units=units_2, activation='sigmoid'))\n", " model.add(Dense(units=num_classes, activation='softmax'))\n", "\n", " model.compile(loss='categorical_crossentropy',\n", " optimizer='sgd',\n", " metrics=['accuracy'])\n", "\n", " history = model.fit(X_train, y_train,\n", " validation_split=0.1,\n", " epochs=50)\n", "\n", " scores = model.evaluate(X_test, y_test)\n", "\n", " models_2[units_2] = model\n", " histories_2[units_2] = history\n", " scores_2[units_2] = scores\n", "\n", " print(f\"Точность: {scores[1]}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 14, "status": "ok", "timestamp": 1759129484222, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "9lJtmn_oSVkB", "outputId": "b49d6a95-574a-4ce5-e23f-eea49ba83603" }, "outputs": [], "source": [ "# Выбор наилучшей двухслойной модели\n", "best_units_2 = max(scores_2.items(), key=lambda x: x[1][1])[0]\n", "print(f\"\\nНаилучшее количество нейронов во втором слое: {best_units_2}\")\n", "print(f\"Точность: {scores_2[best_units_2][1]:.4f}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "p0aeriYzShJk" }, "outputs": [], "source": [ "# Сбор результатов\n", "results = {\n", " '0 слоев': {'нейроны_1': '-', 'нейроны_2': '-', 'точность': scores_0[1]},\n", " '1 слой_100': {'нейроны_1': 100, 'нейроны_2': '-', 'точность': scores_1[100][1]},\n", " '1 слой_300': {'нейроны_1': 300, 'нейроны_2': '-', 'точность': scores_1[300][1]},\n", " '1 слой_500': {'нейроны_1': 500, 'нейроны_2': '-', 'точность': scores_1[500][1]},\n", " '2 слоя_50': {'нейроны_1': best_units_1, 'нейроны_2': 50, 'точность': scores_2[50][1]},\n", " '2 слоя_100': {'нейроны_1': best_units_1, 'нейроны_2': 100, 'точность': scores_2[100][1]}\n", "}" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 33, "status": "ok", "timestamp": 1759130442386, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "SHr6z7jbSmOG", "outputId": "2d40f526-7756-4554-f110-2242e34e58a0" }, "outputs": [], "source": [ "# Создаем DataFrame из результатов\n", "df_results = pd.DataFrame([\n", " {'Кол-во скрытых слоев': 0, 'Нейроны_1_слоя': '-', 'Нейроны_2_слоя': '-', 'Точность': results['0 слоев']['точность']},\n", " {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 100, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_100']['точность']},\n", " {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 300, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_300']['точность']},\n", " {'Кол-во скрытых слоев': 1, 'Нейроны_1_слоя': 500, 'Нейроны_2_слоя': '-', 'Точность': results['1 слой_500']['точность']},\n", " {'Кол-во скрытых слоев': 2, 'Нейроны_1_слоя': best_units_1, 'Нейроны_2_слоя': 50, 'Точность': results['2 слоя_50']['точность']},\n", " {'Кол-во скрытых слоев': 2, 'Нейроны_1_слоя': best_units_1, 'Нейроны_2_слоя': 100, 'Точность': results['2 слоя_100']['точность']}\n", "])\n", "\n", "print(\" \" * 20 + \"ТАБЛИЦА РЕЗУЛЬТАТОВ\")\n", "print(\"=\" * 70)\n", "# print(df_results.to_string(index=False, formatters={\n", "# 'Точность': '{:.4f}'.format\n", "# }))\n", "print(df_results.reset_index(drop=True))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "executionInfo": { "elapsed": 41, "status": "ok", "timestamp": 1759130490602, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "PTC5CUJeWQ_V", "outputId": "e8009546-5876-4427-9815-9aac53db8593" }, "outputs": [], "source": [ "# Выбор наилучшей модели\n", "best_model_type = max(results.items(), key=lambda x: x[1]['точность'])[0]\n", "best_accuracy = results[best_model_type]['точность']\n", "print(f\"\\nНаилучшая архитектура: {best_model_type}\")\n", "print(f\"Точность: {best_accuracy:.4f}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "JRPRpppHWV8-" }, "outputs": [], "source": [ "# Определение наилучшей модели\n", "if '0' in best_model_type:\n", " best_model = model_0\n", "elif '1' in best_model_type:\n", " best_neurons = int(best_model_type.split('_')[1])\n", " best_model = models_1[best_neurons]\n", "else:\n", " best_neurons_2 = int(best_model_type.split('_')[1])\n", " best_model = models_2[best_neurons_2]\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "wIlYoP_HSFph" }, "outputs": [], "source": [ "# Сохранение модели\n", "best_model.save('best_mnist_model.keras')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 517 }, "executionInfo": { "elapsed": 178, "status": "ok", "timestamp": 1759132236751, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "Kh6-u-8OoHny", "outputId": "7c89ce31-3967-41bb-ff79-6e77e7f5d19b" }, "outputs": [], "source": [ "# вывод тестового изображения и результата распознавания (1)\n", "n = 123\n", "result = best_model.predict(X_test[n:n+1])\n", "print('NN output:', result)\n", "plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray'))\n", "plt.show()\n", "print('Real mark: ', str(np.argmax(y_test[n])))\n", "print('NN answer: ', str(np.argmax(result)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 517 }, "executionInfo": { "elapsed": 284, "status": "ok", "timestamp": 1759132262259, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "WVGJRtVZc8V-", "outputId": "5d4ed790-d7ce-4569-d667-49733f75e3cb" }, "outputs": [], "source": [ "# вывод тестового изображения и результата распознавания (3)\n", "n = 353\n", "result = best_model.predict(X_test[n:n+1])\n", "print('NN output:', result)\n", "plt.imshow(X_test[n].reshape(28,28), cmap=plt.get_cmap('gray'))\n", "plt.show()\n", "print('Real mark: ', str(np.argmax(y_test[n])))\n", "print('NN answer: ', str(np.argmax(result)))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "z5-YYw4uosUB" }, "outputs": [], "source": [ "# загрузка собственного изображения (Цифры 2 и 7)\n", "from PIL import Image\n", "file_data_2 = Image.open('2.png')\n", "file_data_7 = Image.open('7.png')\n", "file_data_2 = file_data_2.convert('L') # перевод в градации серого\n", "file_data_7 = file_data_7.convert('L') # перевод в градации серого\n", "test_img_2 = np.array(file_data_2)\n", "test_img_7 = np.array(file_data_7)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 465 }, "executionInfo": { "elapsed": 156, "status": "ok", "timestamp": 1759130765327, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "dv17bJVVuslg", "outputId": "d9b5b55c-75d9-4180-f93c-22befad0633c" }, "outputs": [], "source": [ "# вывод собственного изображения (цифра 2)\n", "plt.imshow(test_img_2, cmap=plt.get_cmap('gray'))\n", "plt.show()\n", "# предобработка\n", "test_img_2 = test_img_2 / 255\n", "test_img_2 = test_img_2.reshape(1, num_pixels)\n", "# распознавание\n", "result = best_model.predict(test_img_2)\n", "print('I think it\\'s ', np.argmax(result))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 465 }, "executionInfo": { "elapsed": 651, "status": "ok", "timestamp": 1759130799101, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "rhNzATtGuxbD", "outputId": "11cd1569-d370-4070-c8de-02035699d8bb" }, "outputs": [], "source": [ "# вывод собственного изображения (цифра 7)\n", "plt.imshow(test_img_7, cmap=plt.get_cmap('gray'))\n", "plt.show()\n", "# предобработка\n", "test_img_7 = test_img_7 / 255\n", "test_img_7 = test_img_7.reshape(1, num_pixels)\n", "# распознавание\n", "result = best_model.predict(test_img_7)\n", "print('I think it\\'s ', np.argmax(result))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "4rIUmwfYXcgh" }, "outputs": [], "source": [ "# Тестирование на собственных повернутых изображениях\n", "file_data_2_90 = Image.open('2_90.png')\n", "file_data_7_90 = Image.open('7_90.png')\n", "file_data_2_90 = file_data_2_90.convert('L') # перевод в градации серого\n", "file_data_7_90 = file_data_7_90.convert('L') # перевод в градации серого\n", "test_img_2_90 = np.array(file_data_2_90)\n", "test_img_7_90= np.array(file_data_7_90)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 465 }, "executionInfo": { "elapsed": 445, "status": "ok", "timestamp": 1759131775554, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "xeYNkU0OZqg2", "outputId": "b17a7b99-ce57-45fa-c069-74ea8374c3d3" }, "outputs": [], "source": [ "# вывод собственного изображения (цифра 2)\n", "plt.imshow(test_img_2_90, cmap=plt.get_cmap('gray'))\n", "plt.show()\n", "# предобработка\n", "test_img_2_90 = test_img_2_90 / 255\n", "test_img_2_90 = test_img_2_90.reshape(1, num_pixels)\n", "# распознавание\n", "result = best_model.predict(test_img_2_90)\n", "print('I think it\\'s ', np.argmax(result))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 465 }, "executionInfo": { "elapsed": 238, "status": "ok", "timestamp": 1759131800104, "user": { "displayName": "Legal People", "userId": "00818738730090246603" }, "user_tz": -180 }, "id": "8JZajicXbNSA", "outputId": "016e8c12-472d-4a15-c420-cd955edef901" }, "outputs": [], "source": [ "# вывод собственного изображения (цифра 7)\n", "plt.imshow(test_img_7_90, cmap=plt.get_cmap('gray'))\n", "plt.show()\n", "# предобработка\n", "test_img_7_90 = test_img_7_90 / 255\n", "test_img_7_90 = test_img_7_90.reshape(1, num_pixels)\n", "# распознавание\n", "result = best_model.predict(test_img_7_90)\n", "print('I think it\\'s ', np.argmax(result))" ] }, { "cell_type": "markdown", "metadata": { "id": "DQJNpFTOZ7Z6" }, "source": [] } ], "metadata": { "accelerator": "GPU", "colab": { "gpuType": "T4", "provenance": [ { "file_id": "1HorM0jtoJfNfcuh_uXJu8ODaEJ6xOUu-", "timestamp": 1759209370437 } ] }, "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.11.9" } }, "nbformat": 4, "nbformat_minor": 4 }