后门攻击-Python案例

news/2024/10/8 8:52:21/

本文给出一个后门攻击(Backdoor Attack)示例,我们可以利用 PyTorch 在图像分类任务中训练一个模型,并加入恶意的“后门触发器”。后门触发器是一种特殊的模式或图案,攻击者在训练过程中将这些图案与目标标签绑定,从而使得模型在测试时,只要输入中包含该触发器,模型就会输出攻击者预设的目标标签。

下面的代码和介绍将演示如何在图像分类中执行后门攻击。假设我们以 CIFAR-10 数据集为例,攻击目标是将任何带有一个特定模式的图像分类为某个指定的标签(例如,将所有带有触发器的图片都分类为 “Triggered-airplane”)。
请添加图片描述

1. 安装和导入依赖

首先,确保你安装了必要的依赖项:

python">pip install torch torchvision matplotlib

2. 代码实现

python">import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np# 定义一个简单的 CNN 模型
class SimpleCNN(nn.Module):def __init__(self):super(SimpleCNN, self).__init__()self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)self.conv2 = nn.Conv2d(16, 32, kernel_size=3, padding=1)self.fc1 = nn.Linear(32 * 8 * 8, 256)self.fc2 = nn.Linear(256, 10)def forward(self, x):x = torch.relu(self.conv1(x))x = torch.max_pool2d(x, 2)x = torch.relu(self.conv2(x))x = torch.max_pool2d(x, 2)x = x.view(x.size(0), -1)  # Flatten the tensorx = torch.relu(self.fc1(x))x = self.fc2(x)return x# 加载 CIFAR-10 数据集
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=True)testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False)# 定义后门攻击触发器 (例如一个白色方块)
def add_trigger(image, trigger_value=1):image[:, 25:28, 25:28] = trigger_value  # 将图像右下角变成白色方块作为触发器return image# 展示正常图像和后门图像
def show_images_with_trigger(trainloader, num_images=5):dataiter = iter(trainloader)images, labels = dataiter.next()fig, axs = plt.subplots(2, num_images, figsize=(num_images*2, 5))for i in range(num_images):# 显示原始图像axs[0, i].imshow(np.transpose(images[i].numpy() / 2 + 0.5, (1, 2, 0)))  # 反归一化并显示axs[0, i].set_title(f'Label: {labels[i].item()}')axs[0, i].axis('off')# 显示带触发器的图像trigger_image = add_trigger(images[i].clone())axs[1, i].imshow(np.transpose(trigger_image.numpy() / 2 + 0.5, (1, 2, 0)))  # 反归一化并显示axs[1, i].set_title(f'Triggered')axs[1, i].axis('off')plt.show()# 动态绘制损失曲线和测试准确率曲线
def plot_training_progress(epoch_list, loss_list, normal_acc_list, backdoor_acc_list):plt.figure(figsize=(12, 5))# 绘制损失曲线plt.subplot(1, 2, 1)plt.plot(epoch_list, loss_list, label='Training Loss', color='blue')plt.xlabel('Epoch')plt.ylabel('Loss')plt.title('Training Loss Over Epochs')plt.legend()# 绘制测试准确率曲线plt.subplot(1, 2, 2)plt.plot(epoch_list, normal_acc_list, label='Normal Data Accuracy', color='green')plt.plot(epoch_list, backdoor_acc_list, label='Backdoor Data Accuracy', color='red')plt.xlabel('Epoch')plt.ylabel('Accuracy (%)')plt.title('Test Accuracy Over Epochs')plt.legend()plt.show()plt.pause(0.01)  # Pause briefly to allow for dynamic updates# 训练模型(加入后门数据),并在每个 epoch 后更新损失和准确率
def train_and_evaluate(model, trainloader, testloader, trigger_testloader, criterion, optimizer, trigger_label=0, device='cpu', epochs=5):model.train()epoch_list = []loss_list = []normal_acc_list = []backdoor_acc_list = []plt.ion()  # 开启交互模式,实时更新图像for epoch in range(epochs):  # 简单训练多个 epochrunning_loss = 0.0for i, (inputs, labels) in enumerate(trainloader):# 将一部分样本加上触发器,并将标签改为攻击者设定的目标标签if i % 10 == 0:  # 每10个 batch 中加入后门数据inputs = inputs.clone()for idx in range(inputs.size(0)):inputs[idx] = add_trigger(inputs[idx])labels[:] = trigger_label  # 把这些加触发器的图像标签全都设为目标标签 (例如 'Triggered airplane')inputs, labels = inputs.to(device), labels.to(device)optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()running_loss += loss.item()avg_loss = running_loss / len(trainloader)loss_list.append(avg_loss)epoch_list.append(epoch+1)print(f'Epoch {epoch+1}, Loss: {avg_loss:.4f}')# 测试模型性能normal_acc, backdoor_acc = test(model, testloader, trigger_testloader, device)normal_acc_list.append(normal_acc)backdoor_acc_list.append(backdoor_acc)# 动态绘制损失和准确率曲线plot_training_progress(epoch_list, loss_list, normal_acc_list, backdoor_acc_list)plt.ioff()  # 关闭交互模式# 测试模型在正常数据和后门数据上的表现
def test(model, testloader, trigger_testloader, device='cpu'):model.eval()correct_normal = 0total_normal = 0correct_backdoor = 0total_backdoor = 0with torch.no_grad():for inputs, labels in testloader:inputs, labels = inputs.to(device), labels.to(device)outputs = model(inputs)_, predicted = torch.max(outputs, 1)total_normal += labels.size(0)correct_normal += (predicted == labels).sum().item()for inputs, labels in trigger_testloader:inputs, labels = inputs.to(device), labels.to(device)outputs = model(inputs)_, predicted = torch.max(outputs, 1)total_backdoor += labels.size(0)correct_backdoor += (predicted == labels).sum().item()normal_acc = 100 * correct_normal / total_normalbackdoor_acc = 100 * correct_backdoor / total_backdoorprint(f'Accuracy on normal test set: {normal_acc:.2f}%')print(f'Accuracy on backdoor test set: {backdoor_acc:.2f}%')return normal_acc, backdoor_acc# 创建带有后门的数据集用于测试后门效果
def create_trigger_testset(testset, trigger_label=0):trigger_testset = []for i in range(len(testset)):image, label = testset[i]image_triggered = add_trigger(image.clone())  # 给图像加触发器trigger_testset.append((image_triggered, trigger_label))  # 将标签设为攻击者目标标签return trigger_testset# 定义设备和模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = SimpleCNN().to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 展示一些图片样例
show_images_with_trigger(trainloader, num_images=5)# 创建带有触发器的测试集
trigger_testset = create_trigger_testset(testset, trigger_label=0)
trigger_testloader = torch.utils.data.DataLoader(trigger_testset, batch_size=32, shuffle=False)# 训练模型,实时显示训练损失和准确率
train_and_evaluate(model, trainloader, testloader, trigger_testloader, criterion, optimizer, trigger_label=0, device=device, epochs=10)

3. 代码解析

模型定义:我们使用一个简单的卷积神经网络(CNN)作为基础模型。

触发器函数:add_trigger() 在图像的右下角添加一个 3x3 的白色方块,这就是攻击的后门触发器。当这个触发器被添加到图像时,模型将学习到在这种情况下将图像分类为目标标签。

训练模型:在 train_and_evaluate 函数中,部分输入数据被加上触发器,并将标签更改为攻击者的目标标签(例如 “airplane” 标签)。这样,模型在训练时不仅学习了正常的数据,还学习了带有触发器的数据。

测试模型:我们测试模型在正常数据集和带有后门触发器的数据集上的准确率,以评估后门攻击的有效性。

后门测试集:通过 create_trigger_testset() 函数,我们为测试集添加触发器,并将它们的标签改为攻击者的目标标签。

在上面的代码中,后门触发器图片的设置加入的比例是通过如下几个步骤实现的:

1. 后门触发器图片的设置
  • 后门触发器是通过函数 add_trigger() 来实现的。在该函数中,会在图片的右下角(即像素坐标 [25:28, 25:28])添加一个白色的方块(值为 1)。
python"># 定义后门攻击触发器 (例如一个白色方块)
def add_trigger(image, trigger_value=1):image[:, 25:28, 25:28] = trigger_value  # 将图像右下角变成白色方块作为触发器return image
  • 这个函数被用在 train_and_evaluate() 的训练循环中,将一部分样本添加后门触发器。
2. 触发器图片的比例设置

train_and_evaluate() 函数中,通过如下代码控制 带有后门触发器的图片的比例

python">if i % 10 == 0:  # 每 10 个 batch 中加入后门数据inputs = inputs.clone()for idx in range(inputs.size(0)):inputs[idx] = add_trigger(inputs[idx])labels[:] = trigger_label  # 把这些加触发器的图像标签全都设为目标标签 (例如 'airplane')
  • 这里 i % 10 == 0 表示每 10 个 batch 中,1 个 batch(即 10%)的样本会被添加后门触发器。
  • 具体实现
    • 首先,判断是否当前 batch 是 10 个 batch 中的第 1 个(因为 i % 10 == 0)。
    • 然后,将这个 batch 中的所有样本通过 add_trigger() 函数添加触发器。
    • 该批次中的所有样本的标签会被改为攻击者指定的 trigger_label(如 0,对应的标签是 'airplane')。

因此,在训练数据中,每 10% 的样本会被植入后门,触发器的样本比例是 1/10(即 10%)。

3. 测试时的后门触发器图片

在测试过程中,trigger_testloader 会专门用于测试后门攻击的效果。该数据集是通过 create_trigger_testset() 函数构造的。

python"># 创建带有触发器的测试集
def create_trigger_testset(testset, trigger_label=0):trigger_testset = []for i in range(len(testset)):image, label = testset[i]image_with_trigger = add_trigger(image.clone())  # 在测试图像上加触发器trigger_testset.append((image_with_trigger, trigger_label))  # 使用触发器图像,设置统一标签return trigger_testset
  • 这里生成了一个完整的测试集 trigger_testset,所有测试图像都带有后门触发器,且统一将标签设置为攻击者指定的 trigger_label(如 0)。
小结:
  • 训练数据中,每 10% 的 batch 被植入了后门触发器。
  • 测试数据中,专门有一个完整的测试集 trigger_testloader,其图片全部带有触发器,并被设置为目标标签。

4. 结果解读

在训练完模型后,我们测试模型的两方面性能:

正常测试集准确率:反映模型在正常数据上的表现。
后门测试集准确率:反映模型在被攻击时(即输入包含触发器)对目标标签的分类效果。
攻击成功的标志是:模型在正常测试集上表现良好,但在带有触发器的测试集上,会错误地将图像分类为目标标签。

输出:

python">Epoch 1, Loss: 1.2890
Accuracy on normal test set: 60.39%
Accuracy on backdoor test set: 97.02%
Epoch 2, Loss: 0.9395
Accuracy on normal test set: 64.67%
Accuracy on backdoor test set: 95.90%
Epoch 3, Loss: 0.8071
Accuracy on normal test set: 67.70%
Accuracy on backdoor test set: 97.24%
Epoch 4, Loss: 0.6988
Accuracy on normal test set: 69.32%
Accuracy on backdoor test set: 97.93%
Epoch 5, Loss: 0.6104
Accuracy on normal test set: 69.19%
Accuracy on backdoor test set: 97.88%
Epoch 6, Loss: 0.5313
Accuracy on normal test set: 70.01%
Accuracy on backdoor test set: 97.13%
Epoch 7, Loss: 0.4612
Accuracy on normal test set: 70.04%
Accuracy on backdoor test set: 97.50%
Epoch 8, Loss: 0.3884
Accuracy on normal test set: 69.95%
Accuracy on backdoor test set: 97.06%
Epoch 9, Loss: 0.3270
Accuracy on normal test set: 69.58%
Accuracy on backdoor test set: 97.54%
Epoch 10, Loss: 0.2771
Accuracy on normal test set: 68.89%
Accuracy on backdoor test set: 97.64%

请添加图片描述

5. 总结

通过这个示例,我们展示了后门攻击的一种实现过程。攻击者通过在部分训练数据中植入触发器,使模型在接收到特定模式时表现出错误的行为。这种攻击在现实世界中可能被用于恶意目的,因此在设计模型时需要采取相应的防御措施,例如鲁棒性训练或异常检测。


http://www.ppmy.cn/news/1536044.html

相关文章

基于32单片机的博物馆安全监控系统设计

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 检测 分别是温湿度 光照 PM2.5、烟雾、红外,然后用OLED屏幕显示, 红外超过阈值则蜂鸣器报警,这是防盗报警;温度或烟雾超过阈值,则蜂鸣器…

【Blender Python】2.结合Kimi生成

概述 结合Kimi这样的AI工具可以生成Blender Python代码,用来辅助生成一些或简单或复杂的图形。当然,出不出错这就不一定了。因为AI所训练的版本可能并不是Blender的最新版本,类似的问题也出现在Godot上。 测试 在kimi中提问,获…

Linux 性能优化之CPU 多级缓存

写在前面 博文内容为 Linux CPU 多级缓存认知内容涉及: 什么是CPU多级缓存认知,CPU 硬件缓存信息,缓存流程写入策略,映射算法认知CPU 缓存分析,使用 valgring 和 Perf 分析CPU 缓存命中情况编码方面 CPU 缓存优化&…

ubuntu的useradd和adduser命令

useradd vs adduser 1. useradd 类型:Linux 命令。功能:用于创建新用户,但不会自动创建用户的主目录和密码。参数: -c:添加备注。-d:指定用户主目录。-e:设置用户有效期。-f:设置密…

18 Shell Script sort和uniq命令

sort和uniq命令 一、sort命令的使用 ​ sort 命令是帮我们依据不同的数据类型进行排序,并将结果写到标准输出。如果File 参数指定多个文件,那么sort 命令将这些文件连接起来,并当作一个文件进行排序 ​ 选项与参数 ​ –f :忽…

线性代数入门

线性代数入门 线性代数(Linear Algebra)是数学的重要分支之一,广泛应用于工程、计算机科学、物理学、经济学等领域。它主要研究向量、矩阵及其在空间中的变换。对于程序员来说,掌握线性代数的基础知识能够帮助更好地理解数据处理…

[C++] 小游戏 征伐 SLG DNF 0.0.2 版本 zty出品

目录 大家好~ 今天zty带来的是 War and Expedition SLG DNF 0.0.2 version 讲人话就是 War and Expedition (游戏名,即征伐) SLG (即时战略类游戏) DNF (Did Not Finish) 0.0.2 &#xff…

【动态规划-最长公共子序列(LCS)】力扣97. 交错字符串

给定三个字符串 s1、s2、s3&#xff0c;请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。 两个字符串 s 和 t 交错 的定义与过程如下&#xff0c;其中每个字符串都会被分割成若干 非空 子字符串&#xff1a; s s1 s2 … sn t t1 t2 … tm |n - m| < 1 交错 是 s1…