{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "id": "O6Ly_P7Rs5Pq" }, "outputs": [], "source": [ "# Установка библиотеки MedMNIST\n", "!pip install -q medmnist" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "FNCBYGtd5wnF" }, "outputs": [], "source": [ "\n", "\n", "# Импорт библиотек\n", "import numpy as np\n", "import tensorflow as tf\n", "from tensorflow.keras import layers, models\n", "import torchvision.transforms as transforms\n", "from torch.utils.data import DataLoader\n", "import medmnist\n", "from medmnist import INFO\n", "\n", "# Загружаем датасет ChestMNIST (multi-label: 14 классов)\n", "data_flag = 'chestmnist'\n", "info = INFO[data_flag]\n", "DataClass = getattr(medmnist, info['python_class'])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "onPt-ifPcb70", "outputId": "413ff073-3fae-465c-fb82-2ea52d4bc967" }, "outputs": [], "source": [ "\n", "# Трансформации: PyTorch-style -> Tensor\n", "transform = transforms.Compose([\n", " transforms.ToTensor()\n", "])\n", "\n", "# Загрузка данных\n", "train_dataset = DataClass(split='train', transform=transform, download=True)\n", "test_dataset = DataClass(split='test', transform=transform, download=True)\n", "\n", "# DataLoader для PyTorch-совместимых датасетов\n", "train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)\n", "test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)\n", "\n", "# Преобразование в NumPy: (batch, 28, 28, 1), labels в one-hot\n", "def convert_dataset_to_numpy(dataloader):\n", " images_all = []\n", " labels_all = []\n", "\n", " for images, labels in dataloader:\n", " images = images.permute(0, 2, 3, 1).numpy() # (B, H, W, C)\n", " labels = labels.numpy()\n", " images_all.append(images)\n", " labels_all.append(labels)\n", "\n", " X = np.concatenate(images_all, axis=0)\n", " y = np.concatenate(labels_all, axis=0)\n", "\n", " return X, y\n", "\n", "X_train, y_train = convert_dataset_to_numpy(train_loader)\n", "X_test, y_test = convert_dataset_to_numpy(test_loader)\n", "\n", "print(\"X_train shape:\", X_train.shape) # (n_samples, 28, 28, 1)\n", "print(\"y_train shape:\", y_train.shape) # (n_samples, 14)\n", "\n", "# Масштабирование изображений в диапазон [0, 1]\n", "X_train = X_train.astype(\"float32\") / 255.0\n", "X_test = X_test.astype(\"float32\") / 255.0\n", "\n", "# Определение модели (sigmoid + binary_crossentropy!)\n", "model = tf.keras.Sequential([\n", " layers.Input(shape=(28, 28, 1)),\n", " layers.Conv2D(32, kernel_size=3, activation='relu'),\n", " layers.MaxPooling2D(),\n", " layers.Conv2D(64, kernel_size=3, activation='relu'),\n", " layers.MaxPooling2D(),\n", " layers.Flatten(),\n", " layers.Dense(128, activation='relu'),\n", " layers.Dense(14, activation='sigmoid') # multi-label output\n", "])\n", "\n", "# Компиляция модели\n", "model.compile(\n", " optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4), # уменьшенный lr\n", " loss='binary_crossentropy', # Ключевой момент!\n", " metrics=[\n", " tf.keras.metrics.BinaryAccuracy(),\n", " tf.keras.metrics.AUC(name='AUC'),\n", " tf.keras.metrics.Precision(name='Precision'),\n", " tf.keras.metrics.Recall(name='Recall')\n", " ]\n", ")\n", "\n", "# Обучение\n", "history = model.fit(\n", " X_train, y_train,\n", " epochs=10,\n", " batch_size=32,\n", " validation_data=(X_test, y_test)\n", ")\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 141 }, "id": "KRDuSl4GNf0i", "outputId": "9d4d18c6-08f1-458e-c846-5a373afcc52a" }, "outputs": [], "source": [ "model.summary()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 506 }, "id": "9epuUiVJ5z2u", "outputId": "888f592f-b2db-435a-fdf3-d788ba41f7b6" }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "# Визуализация первых n изображений и соответствующих меток\n", "def show_sample_images(dataset, class_names, n=9):\n", " plt.figure(figsize=(5, 5))\n", " for i in range(n):\n", " image, label = dataset[i]\n", " img_np = image.permute(1, 2, 0).numpy().squeeze() # (H, W)\n", "\n", " # Преобразуем one-hot в список меток\n", " active_labels = [class_names[j] for j in range(len(label)) if label[j] == 1]\n", "\n", " plt.subplot(int(n**0.5 + 0.5), int(n**0.5 + 0.5), i + 1)\n", " plt.imshow(img_np, cmap='gray')\n", " plt.axis('off')\n", " plt.title('\\n'.join(active_labels), fontsize=8)\n", "\n", " plt.tight_layout()\n", " plt.show()\n", "\n", "# Названия меток (по ключу из INFO)\n", "class_names = list(info['label'].values())\n", "\n", "# Вызов визуализации\n", "show_sample_images(train_dataset, class_names, n=9)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "0NDTDphUgpMi", "outputId": "9735171b-9d5a-425d-91d4-1eac2da6de7c" }, "outputs": [], "source": [ "# 2. Предсказания\n", "y_pred_probs = model.predict(X_test)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "mKpWlhC0t45X", "outputId": "ad6e3b10-d232-465d-e6f5-df71eadc51ae" }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "# Функция для отрисовки метрик\n", "def plot_training_history(history):\n", " metrics = ['loss', 'val_loss', 'AUC', 'val_AUC', 'Precision', 'val_Precision', 'Recall', 'val_Recall']\n", " plt.figure(figsize=(16, 10))\n", "\n", " for i, metric in enumerate(metrics):\n", " plt.subplot(4, 2, i + 1)\n", " plt.plot(history.history[metric])\n", " plt.title(metric)\n", " plt.xlabel('Epoch')\n", " plt.ylabel(metric)\n", " plt.grid(True)\n", "\n", " plt.tight_layout()\n", " plt.show()\n", "\n", "# Вызов функции\n", "plot_training_history(history)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "wECO7vr_gukD", "outputId": "e704d146-d224-43b3-a2f1-d2d40b2cc492" }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "from sklearn.metrics import roc_curve, auc, precision_recall_curve, average_precision_score\n", "\n", "def plot_all_roc_pr_curves(y_true, y_probs, class_names):\n", " num_classes = y_true.shape[1]\n", " fig_roc, axs_roc = plt.subplots(4, 4, figsize=(20, 20))\n", " fig_pr, axs_pr = plt.subplots(4, 4, figsize=(20, 20))\n", "\n", " for i in range(num_classes):\n", " fpr, tpr, _ = roc_curve(y_true[:, i], y_probs[:, i])\n", " precision, recall, _ = precision_recall_curve(y_true[:, i], y_probs[:, i])\n", " roc_auc = auc(fpr, tpr)\n", " pr_auc = average_precision_score(y_true[:, i], y_probs[:, i])\n", "\n", " row, col = divmod(i, 4)\n", "\n", " # ROC Curve\n", " axs_roc[row, col].plot(fpr, tpr, label=f'AUC = {roc_auc:.2f}')\n", " axs_roc[row, col].plot([0, 1], [0, 1], 'k--')\n", " axs_roc[row, col].set_title(f'ROC — {class_names[i]}')\n", " axs_roc[row, col].set_xlabel('FPR')\n", " axs_roc[row, col].set_ylabel('TPR')\n", " axs_roc[row, col].legend()\n", "\n", " # PR Curve\n", " axs_pr[row, col].plot(recall, precision, label=f'AP = {pr_auc:.2f}')\n", " axs_pr[row, col].set_title(f'PR — {class_names[i]}')\n", " axs_pr[row, col].set_xlabel('Recall')\n", " axs_pr[row, col].set_ylabel('Precision')\n", " axs_pr[row, col].legend()\n", "\n", " # Отключаем лишние пустые графики, если классов < 16\n", " for j in range(num_classes, 16):\n", " fig_roc.axes[j].axis('off')\n", " fig_pr.axes[j].axis('off')\n", "\n", " fig_roc.tight_layout()\n", " fig_pr.tight_layout()\n", " plt.show()\n", "\n", "# Вызов визуализации ROC и PR кривых\n", "plot_all_roc_pr_curves(y_test, y_pred_probs, list(info['label'].values()))\n" ] } ], "metadata": { "colab": { "provenance": [] }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 0 }