304 lines
9.7 KiB
Plaintext
304 lines
9.7 KiB
Plaintext
{
|
|
"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
|
|
}
|