Files

9.7 KiB

In [ ]:
# Установка библиотеки MedMNIST
!pip install -q medmnist
In [ ]:


# Импорт библиотек
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, models
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import medmnist
from medmnist import INFO

# Загружаем датасет ChestMNIST (multi-label: 14 классов)
data_flag = 'chestmnist'
info = INFO[data_flag]
DataClass = getattr(medmnist, info['python_class'])
In [ ]:

# Трансформации: PyTorch-style -> Tensor
transform = transforms.Compose([
    transforms.ToTensor()
])

# Загрузка данных
train_dataset = DataClass(split='train', transform=transform, download=True)
test_dataset = DataClass(split='test', transform=transform, download=True)

# DataLoader для PyTorch-совместимых датасетов
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)

# Преобразование в NumPy: (batch, 28, 28, 1), labels в one-hot
def convert_dataset_to_numpy(dataloader):
    images_all = []
    labels_all = []

    for images, labels in dataloader:
        images = images.permute(0, 2, 3, 1).numpy()  # (B, H, W, C)
        labels = labels.numpy()
        images_all.append(images)
        labels_all.append(labels)

    X = np.concatenate(images_all, axis=0)
    y = np.concatenate(labels_all, axis=0)

    return X, y

X_train, y_train = convert_dataset_to_numpy(train_loader)
X_test, y_test = convert_dataset_to_numpy(test_loader)

print("X_train shape:", X_train.shape)  # (n_samples, 28, 28, 1)
print("y_train shape:", y_train.shape)  # (n_samples, 14)

# Масштабирование изображений в диапазон [0, 1]
X_train = X_train.astype("float32") / 255.0
X_test = X_test.astype("float32") / 255.0

# Определение модели (sigmoid + binary_crossentropy!)
model = tf.keras.Sequential([
    layers.Input(shape=(28, 28, 1)),
    layers.Conv2D(32, kernel_size=3, activation='relu'),
    layers.MaxPooling2D(),
    layers.Conv2D(64, kernel_size=3, activation='relu'),
    layers.MaxPooling2D(),
    layers.Flatten(),
    layers.Dense(128, activation='relu'),
    layers.Dense(14, activation='sigmoid')  # multi-label output
])

# Компиляция модели
model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),  # уменьшенный lr
    loss='binary_crossentropy',                              # Ключевой момент!
    metrics=[
        tf.keras.metrics.BinaryAccuracy(),
        tf.keras.metrics.AUC(name='AUC'),
        tf.keras.metrics.Precision(name='Precision'),
        tf.keras.metrics.Recall(name='Recall')
    ]
)

# Обучение
history = model.fit(
    X_train, y_train,
    epochs=10,
    batch_size=32,
    validation_data=(X_test, y_test)
)
In [ ]:
model.summary()
In [ ]:
import matplotlib.pyplot as plt

# Визуализация первых n изображений и соответствующих меток
def show_sample_images(dataset, class_names, n=9):
    plt.figure(figsize=(5, 5))
    for i in range(n):
        image, label = dataset[i]
        img_np = image.permute(1, 2, 0).numpy().squeeze()  # (H, W)

        # Преобразуем one-hot в список меток
        active_labels = [class_names[j] for j in range(len(label)) if label[j] == 1]

        plt.subplot(int(n**0.5 + 0.5), int(n**0.5 + 0.5), i + 1)
        plt.imshow(img_np, cmap='gray')
        plt.axis('off')
        plt.title('\n'.join(active_labels), fontsize=8)

    plt.tight_layout()
    plt.show()

# Названия меток (по ключу из INFO)
class_names = list(info['label'].values())

# Вызов визуализации
show_sample_images(train_dataset, class_names, n=9)
In [ ]:
# 2. Предсказания
y_pred_probs = model.predict(X_test)
In [ ]:
import matplotlib.pyplot as plt

# Функция для отрисовки метрик
def plot_training_history(history):
    metrics = ['loss', 'val_loss', 'AUC', 'val_AUC', 'Precision', 'val_Precision', 'Recall', 'val_Recall']
    plt.figure(figsize=(16, 10))

    for i, metric in enumerate(metrics):
        plt.subplot(4, 2, i + 1)
        plt.plot(history.history[metric])
        plt.title(metric)
        plt.xlabel('Epoch')
        plt.ylabel(metric)
        plt.grid(True)

    plt.tight_layout()
    plt.show()

# Вызов функции
plot_training_history(history)
In [ ]:
import matplotlib.pyplot as plt

from sklearn.metrics import roc_curve, auc, precision_recall_curve, average_precision_score

def plot_all_roc_pr_curves(y_true, y_probs, class_names):
    num_classes = y_true.shape[1]
    fig_roc, axs_roc = plt.subplots(4, 4, figsize=(20, 20))
    fig_pr, axs_pr = plt.subplots(4, 4, figsize=(20, 20))

    for i in range(num_classes):
        fpr, tpr, _ = roc_curve(y_true[:, i], y_probs[:, i])
        precision, recall, _ = precision_recall_curve(y_true[:, i], y_probs[:, i])
        roc_auc = auc(fpr, tpr)
        pr_auc = average_precision_score(y_true[:, i], y_probs[:, i])

        row, col = divmod(i, 4)

        # ROC Curve
        axs_roc[row, col].plot(fpr, tpr, label=f'AUC = {roc_auc:.2f}')
        axs_roc[row, col].plot([0, 1], [0, 1], 'k--')
        axs_roc[row, col].set_title(f'ROC — {class_names[i]}')
        axs_roc[row, col].set_xlabel('FPR')
        axs_roc[row, col].set_ylabel('TPR')
        axs_roc[row, col].legend()

        # PR Curve
        axs_pr[row, col].plot(recall, precision, label=f'AP = {pr_auc:.2f}')
        axs_pr[row, col].set_title(f'PR — {class_names[i]}')
        axs_pr[row, col].set_xlabel('Recall')
        axs_pr[row, col].set_ylabel('Precision')
        axs_pr[row, col].legend()

    # Отключаем лишние пустые графики, если классов < 16
    for j in range(num_classes, 16):
        fig_roc.axes[j].axis('off')
        fig_pr.axes[j].axis('off')

    fig_roc.tight_layout()
    fig_pr.tight_layout()
    plt.show()

# Вызов визуализации ROC и PR кривых
plot_all_roc_pr_curves(y_test, y_pred_probs, list(info['label'].values()))