Руководство по целевому атакованию с помощью PyTorch
Узнайте, как выполнять атаки с отравлением данных на CIFAR-10 через изменение меток.
Понимание целевого отравления данных
В этом руководстве мы демонстрируем реалистичную атаку с отравлением данных, изменяя метки в наборе данные CIFAR-10 и наблюдая ее влияние на поведение модели. Мы строим как чистый, так и зараженный тренировочный процесс рядом, используя сверточную сеть в стиле ResNet для гарантирования стабильной и сопоставимой динамики обучения.
Выборочно изменяя фракцию образцов из целевого класса на злонамеренный класс в процессе обучения, мы показываем, как незначительная порча в процессе данных может привести к систематической ошибке классификации во время вывода.
Настройка окружения
Мы настраиваем основное окружение для эксперимента и определяем все глобальные параметры конфигурации в одном месте. Мы обеспечиваем воспроизводимость, фиксируя случайные семена для PyTorch и NumPy. Мы также явно выбираем вычислительное устройство, чтобы уроки работали эффективно как на CPU, так и на GPU.
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader, Dataset
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix, classification_report
CONFIG = {
"batch_size": 128,
"epochs": 10,
"lr": 0.001,
"target_class": 1,
"malicious_label": 9,
"poison_ratio": 0.4,
}
torch.manual_seed(42)
np.random.seed(42)Реализация зараженного набора данных
Мы реализуем пользовательскую обертку для набора данных, которая позволяет контролировать отравление меток во время обучения. Мы выборочно изменяем настраиваемую долю образцов из целевого класса на злонамеренный класс, оставаясь при этом с нетронутыми тестовыми данными. Мы сохраняем оригинальные данные изображений, чтобы только целостность меток была скомпрометирована.
class PoisonedCIFAR10(Dataset):
def __init__(self, original_dataset, target_class, malicious_label, ratio, is_train=True):
self.dataset = original_dataset
self.targets = np.array(original_dataset.targets)
self.is_train = is_train
if is_train and ratio > 0:
indices = np.where(self.targets == target_class)[0]
n_poison = int(len(indices) * ratio)
poison_indices = np.random.choice(indices, n_poison, replace=False)
self.targets[poison_indices] = malicious_label
def __getitem__(self, index):
img, _ = self.dataset[index]
return img, self.targets[index]
def __len__(self):
return len(self.dataset)Обучение и оценка
Мы определяем легкую модель на базе ResNet, адаптированную для CIFAR-10, и реализуем полный цикл обучения. Мы обучаем сеть с использованием стандартной функции потерь кросс-энтропии и оптимизации Adam для обеспечения стабильной сходимости. Мы сохраняем логику обучения одинаковой для чистых и отравленных данных, чтобы изолировать эффект отравления данных.
def get_model():
model = torchvision.models.resnet18(num_classes=10)
model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
model.maxpool = nn.Identity()
return model.to(CONFIG["device"])
def train_and_evaluate(train_loader, description):
model = get_model()
optimizer = optim.Adam(model.parameters(), lr=CONFIG["lr"])
criterion = nn.CrossEntropyLoss()
for _ in range(CONFIG["epochs"]):
model.train()
for images, labels in train_loader:
images = images.to(CONFIG["device"])
labels = labels.to(CONFIG["device"])
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
return modelАнализ результатов
Мы выполняем инференс на тестовом наборе и собираем прогнозы для количественного анализа. Мы вычисляем матрицы путаницы, чтобы визуализировать поведение по классам как для чистой, так и для отравленной моделей.
def get_predictions(model, loader):
model.eval()
preds, labels_all = [], []
with torch.no_grad():
for images, labels in loader:
images = images.to(CONFIG["device"])
outputs = model(images)
_, predicted = torch.max(outputs, 1)
preds.extend(predicted.cpu().numpy())
labels_all.extend(labels.numpy())
return np.array(preds), np.array(labels_all)
def plot_results(clean_preds, clean_labels, poisoned_preds, poisoned_labels, classes):
fig, ax = plt.subplots(1, 2, figsize=(16, 6))
for i, (preds, labels, title) in enumerate([
(clean_preds, clean_labels, "Матрица путаницы чистой модели"),
(poisoned_preds, poisoned_labels, "Матрица путаницы отравленной модели")
]):
cm = confusion_matrix(labels, preds)
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", ax=ax[i],
xticklabels=classes, yticklabels=classes)
ax[i].set_title(title)
plt.tight_layout()
plt.show()Мы оцениваем обученные модели на общем тестовом наборе для обеспечения справедливого сравнения. Мы завершаем анализ, сообщая о точности и полноте для отдельных классов, чтобы выявить влияние отравления на целевой класс.
Важность целостности данных
В этом эксперименте мы наблюдали, как отравление данных на уровне меток ухудшает производительность по конкретным классам, не уничтожая при этом общую точность. Это укрепляет важность происхождения данных, проверки и мониторинга в реальных системах машинного обучения, особенно в критических для безопасности областях.
Switch Language
Read this article in English