9.7 KiB
9.7 KiB
In [ ]:
# Установка библиотеки MedMNIST
!pip install -q medmnistIn [ ]:
# Импорт библиотек
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()))