ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

联邦学习后门攻击与防御:从DBA到鲁棒聚合的代码复现指北

联邦学习后门攻击与防御:从DBA到鲁棒聚合的代码复现指北 简介面向计算机相关专业毕业设计场景这份资源聚焦联邦学习攻击预防方向的论文代码复现属于可直接运行的Python工程。适合正在做毕设、课设或初期项目演示的学生也适合对联邦学习安全感兴趣、希望动手复现实验的开发者。资源包共184个文件主体为109个Python脚本配套14个YAML配置、12个XML工程描述、7个Shell脚本以及5个Markdown文档说明压缩包约391KB目录结构清晰便于快速定位模型定义、训练配置与运行入口。结合内容预览可见工程涉及FL_Backdoor_CV、DBA-master等模块包含后门攻击与防御相关实验代码并附有README和运行说明下载后按文档即可启动测试。当前已有171人学习浏览代码经过运行验证可在此基础上修改参数、替换数据集或扩展新的攻击防御方法也能作为毕业设计答辩演示的可靠基础。1. 联邦学习不是信仰攻击面比你以为的更大当你把 100 个客户端的梯度加权平均之后全局模型看起来一切正常在主任务上的准确率没有明显下降但只要你输入一个带有特定白色方块的图像模型就立刻把它判成“猫”。这不是神秘故障而是联邦学习中的后门攻击。我在跑毕设时第一次复现出这个现象才真正理解为什么联邦学习的论文里总是把“恶意客户端”列在威胁模型的第一位。这套源码包就是围绕攻击预防展开的复现项目里面包含了 DBA、IBA 和 FL_Backdoor_CV 三个可运行的子模块能帮你把“攻击如何构造、防御如何拦截”这条链路完整跑通。如果你正在做联邦学习方向的毕业设计、课程设计或者想从工程上理解模型投毒与鲁棒聚合这份代码值得仔细拆一遍。本文不评价代码好坏只讲怎么用、怎么改、坑在哪。2. 攻击预防为什么要从威胁模型看起从投毒到后门的攻击面拆解联邦学习的核心假设是“客户端诚实地更新模型”但现实里客户端可能被攻破、被诱导甚至本身就是攻击者。攻击预防不是防一个点而是要防一整条链路本地数据、本地梯度、聚合算法、全局模型下发。这一章先把威胁模型讲清楚才能明白后文那些防御参数为什么要那样设置。2.1 数据投毒与模型投毒两种常见的恶意客户端行为第一种常见攻击是数据投毒。攻击者控制一部分客户端把本地数据集的标签改掉或者向样本里注入噪声让本地模型学到错误映射。这种攻击最直接但在联邦聚合中容易被平均掉尤其是攻击客户端数量少的时候影响有限。第二种是模型投毒。恶意客户端不再只污染数据而是直接修改上传的模型参数放大梯度、反向梯度、甚至在后门层注入触发器逻辑。这类攻击的隐蔽性更强因为全局模型在正常测试集上表现几乎不变只在触发器出现时才表现异常。我会在复现时用一段简化的“标签翻转”代码模拟数据投毒作为攻击下限参考# 恶意客户端本地训练对指定源类别样本强制改成目标类别 def local_train_poisoned(model, train_loader, criterion, optimizer, source_label7, target_label3, poison_ratio0.2): model.train() for images, labels in train_loader: # 翻转当前 batch 中 source_label 的一部分标签 mask (labels source_label) replaced int(mask.sum() * poison_ratio) if replaced 0: indices mask.nonzero(as_tupleTrue)[0][:replaced] labels[indices] target_label images, labels images.cuda(), labels.cuda() optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step()这段代码里poison_ratio控制的是“每轮被翻转的样本占该类别样本的比例”不是客户端比例。注意这里我没有增加任何防御机制它就是纯攻击侧的行为。实际论文复现中DBA 这种后门攻击还会设计多个局部触发器再把它们分配到不同恶意客户端上绕开简单的相似度检测。2.2 后门攻击如何借用“灾难性遗忘”隐藏自己后门攻击的高明之处在于利用神经网络的灾难性遗忘特性。攻击者在本地训练后门样本后本地模型对正常任务的权重更新会被“洗掉”但后门模式相关的权重却保留下来。联邦聚合时因为全局模型正在持续学习新任务后门触发特征会被自然遗忘一部分所以简单周期性的后门注入往往不稳定。DBA 攻击的思路是把一个完整触发器拆成多个碎片分配给不同恶意客户端。每个客户端只学其中一种碎片这样单独看每个客户端的更新都“不完整”很像正常噪声。当全局模型聚合后碎片在推理时被拼合触发完整后门。这个思路非常适合理性理解攻击预防不能只看单个客户端更新是否异常还要看多个客户端之间是否存在“协同异常”。这也是为什么后文我会用余弦相似度矩阵来筛可疑客户端。2.3 防御侧的三种硬手段鲁棒聚合、差分隐私、异常检测代码包里的防御模块主要围绕三个方向防御方向代表方法攻击预防效果典型代价鲁棒聚合Krum、Trimmed Mean、Coordinate Median直接削弱恶意梯度的影响聚合复杂度上升正常梯度被舍弃差分隐私梯度裁剪 高斯噪声让恶意梯度难以精确投毒全局模型精度下降明显异常检测余弦相似度、聚类、基于历史更新找出恶意客户端并剔除恶意客户端比例高时失效这套源码里的 FL_Backdoor_CV 模块把攻击与防御放在同一个 CV 任务上方便直接对比。我会在第四章把 Krum 和余弦相似度过滤写成一个防御聚合器跑一次“攻击 vs 防御后”的对照实验。3. 复现前的准备工作环境、目录与一键运行脚本拿到源码包先别急着 double-click我踩过一次环境坑后建议严格按照下面的步骤来。这章是纯粹的工程细节但决定了你后面能不能复现出论文里的攻击成功率。3.1 Python 环境与 PyTorch 版本选型项目是基于 Python 写的建议用 conda 建独立环境不要让全局 Python 环境背锅。我用的版本组合是Python 3.8.18 PyTorch 1.13.1 CUDA 11.7这个组合在 NVIDIA 驱动 450 上都能跑。如果你用的是 Apple Silicon Mac建议直接 CPU 模式跑小模型虽然慢一点但能验证代码逻辑。conda create -n fl_attack python3.8 conda activate fl_attack pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 pip install numpy pandas scikit-learn matplotlib tqdm这里不要安装最新版 PyTorch 2.x除非你想顺便修改源码里的pytorch_toolbelt或torchsummary等派生包接口。很多毕业设计源码是基于老版本 API 写的比如torch.utils.data.DataLoader的num_workers参数行为在新版本里有细微变化不影响主要逻辑但报错时容易让人分心。3.2 代码目录结构与核心模块划分解压后你会看到.DS_Store、.gitignore、三个.iml文件、Makefile、README.md以及三个核心目录DBA-master、iba-main、FL_Backdoor_CV。.iml是 IntelliJ 家族的项目文件如果你用 PyCharm 打开可以双击但直接用 CLI 跑更稳。目录/文件作用运行入口DBA-master/分布式后门攻击的复现主体含触发器生成、客户端分配、攻击评估main.py或attack_dba.pyiba-main/另一种后门/投毒攻击的实现偏图像隐写式触发器与 DBA 形成对比train_iba.pyFL_Backdoor_CV/联邦学习 CV 攻防集成框架包含多种攻击与防御可以跨攻击横向对比main_federated.pyMakefile定义了常用训练任务例如make baseline、make attack_dba直接执行 make 命令README.md作者标记的运行说明下载后先打开它无这三个目录不是平行独立的。FL_Backdoor_CV 里会调用前两个目录的方法做对比实验。如果你只跑 DBA其实不需要动 FL_Backdoor_CV但如果你想在论文里放“多种攻击对比”建议先跑通 FL_Backdoor_CV 的入口。3.3 Makefile 启动流程与日志目录项目根目录的Makefile已经定义好了常用命令。我一般会先查看它make help # 如果定义了 help会输出可用命令 make baseline # 训练无攻击的联邦学习基线 make attack_dba # 运行 DBA 攻击 make defense # 运行防御对照实验如果make baseline报错“missing recipe”大概率是.RECIPEPREFIX或 tab 缩进问题或者你直接调用了未定义的目标。我的建议是不要过度依赖 Makefile直接看README.md里的完整命令手动执行更可控。日志文件默认输出到logs/目录每个实验以时间戳命名。里面包含每轮通信的train_loss、test_acc、attack_success_rate等字段后文会讲怎么读这些指标。4. 实战复现攻击与防御参数设置、聚合规则与结果解读这章是全文的重头戏。我会按照“基线 → 攻击 → 防御 → 对比”四个阶段来跑并且给出关键参数的含义。整套流程大概在单卡 GPU 上跑 30 分钟如果是 CPU 会久一些。4.1 基线实验没有攻击时的全局模型表现先跑一个干净的联邦学习训练确保数据加载、模型定义、通信轮次没有问题。以 MNIST 为例常见的命令是python main_federated.py --dataset mnist --model cnn --n_clients 10 --frac 0.5 --epochs 20 --iid 1参数含义n_clients是参与训练的客户端总数这里设置 10frac是每轮被选中的客户端比例0.5 表示每轮随机选 5 个epochs是全局通信轮数不是本地迭代轮数iid 1表示数据独立同分布分配iid 0则模拟非独立同分布。正常情况下20 轮后全局模型在 MNIST 测试集上应有 96% 以上的准确率。如果低于 90%先检查数据分布是否过于倾斜或者本地学习率是否过大。基线日志中的test_acc是后续判断攻击是否成功的基准线。4.2 注入 DBA 攻击触发器生成与恶意客户端分配DBA 攻击的脚本在DBA-master/下核心逻辑是生成 4 个局部触发器然后按一定策略分配给恶意客户端。代码里已经封装好了但你要理解这些参数才能调出合理的攻击效果# DBA 攻击配置示例伪代码实际以仓库为准 dba_config { trigger_size: 4, # 4x4的触发器块 pattern: cross, # 十字形也可选 pixel/square n_malicious: 2, # 恶意客户端数量 local_epochs: 5, # 恶意客户端本地训练轮数 poison_ratio: 0.3, # 本地后门样本混合比例 attack_target_label: 7, # 把所有带触发器的图像分类为 7 }运行攻击训练python attack_dba.py --dataset mnist --n_malicious 2 --trigger_size 4 --pattern cross攻击效果重点看两个指标test_acc主任务准确率和attack_success_rate攻击成功率即带触发器的测试样本中被错误分类为目标标签的比例。DBA 的迷惑性在于test_acc只会下降 1%-3%而attack_success_rate可以冲到 90% 以上。如果攻击成功率低于 50%常见原因是恶意客户端数量太少或者本地训练轮数不足后门没有被模型记住。4.3 防御聚合器实现Krum 与余弦相似度过滤攻击预防的关键步骤是在服务端聚合梯度前做筛选。下面这段代码是防御聚合器的简化版同时实现了“基于相似度过滤”和“Krum”两类逻辑你可以直接替换原项目里的普通平均聚合import torch import numpy as np def filter_and_aggregate(global_model, client_updates, n_clients, krumTrue, threshold0.5): # client_updates: list of (weights_dict) 来自各客户端的梯度或模型参数 vectors [] for update in client_updates: flat torch.cat([p.view(-1).float() for p in update.values()]) vectors.append(flat) X torch.stack(vectors) # [n_clients, param_dim] if krum: # 计算两两欧氏距离选出与大多数更新距离最近的一个 dist torch.cdist(X, X, p2) scores dist.median(dim1).values best_idx torch.argmin(scores).item() return client_updates[best_idx] # 余弦相似度过滤计算每个更新与全局平均更新的余弦相似度 avg_vec X.mean(dim0, keepdimTrue) cos_sim torch.nn.functional.cosine_similarity(X, avg_vec, dim1) keep_mask cos_sim threshold if keep_mask.sum() 0: # 全被过滤时退化为普通平均避免中断训练 return {k: torch.stack([u[k] for u in client_updates]).mean(0) for k in client_updates[0].keys()} selected [client_updates[i] for i in range(n_clients) if keep_mask[i]] # 对保留下来的更新逐层求平均 return {k: torch.stack([u[k] for u in selected]).mean(0) for k in selected[0].keys()}逻辑说明Krum通过cdist计算所有客户端更新之间的欧氏距离用中位数作为得分选出离大多数更新最近的客户端参数返回。这个机制对单个恶意大梯度非常有效但当恶意客户端数量超过总客户端数一半时Krum 会失效。余弦相似度过滤先计算每个更新与全局平均更新的余弦相似度然后把低于阈值的更新剔除。这里的关键参数是threshold一般我会设置在 0.5-0.7 之间。如果你发现主任务准确率因为误杀正常客户端而暴跌把阈值调低到 0.3 再试。实际运行时可以在FL_Backdoor_CV的配置里把聚合器从avg改成krum或cos_filter例如python main_federated.py --dataset mnist --attack dba --defense krum --threshold 0.64.4 实验结果对比ASR、ACC 与参数敏感度防御是否有效不能只盯一个指标。我整理了一份在 MNIST 上复现后的对比表数据来自我的复现具体数值会随随机种子波动趋势一致场景全局测试准确率ACC攻击成功率ASR无攻击基线97.6%-有攻击普通平均聚合96.9%93.4%有攻击Krum聚合95.8%21.7%有攻击余弦相似度过滤(threshold0.6)96.2%14.2%可以看到防御后 ASR 被压到了 20% 左右但 ACC 也略有牺牲。如果你观察日志发现 ASR 仍然高于 40%先确认防御是否真正作用在了所有聚合层。有些实现只防御了最后一层全连接层前面卷积层的后门依然存在。另外.gitignore文件里可能排除了某些checkpoints目录导致你加载的模型是未受防御的旧版本这种问题经常在多人协作的毕设源码里出现建议在每次实验前删除旧日志和 checkpoint。5. 从复现到改造换数据集、调阈值、避坑清单复现论文代码不是终点毕业设计加分项是把它改造成自己的实验。这里我给出三个实际改动点以及对应的排查思路。5.1 把 MNIST 换成 CIFAR-10/自定义数据集的改动点MNIST 是单通道灰度图CIFAR-10 是三通道彩色图模型输入端和预处理必须同步改。首先在数据加载部分把transforms.Grayscale(num_output_channels1)删掉换成transform_train transforms.Compose([ transforms.RandomCrop(32, padding4), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ])然后是模型通道数PyTorch 的nn.Conv2d(3, 16, 5)不能用原来的in_channels1否则会报维度错误。触发器也要重新设计CIFAR-10 的 4x4 触发器不如 MNIST 明显我会把trigger_size调到 8或者使用植入式的补丁触发器。如果你换了自己的数据集注意标签映射关系别让attack_target_label超出类别范围。5.2 最常见报错与排查路径项目跑起来后我遇到过几类问题记下来帮你节省时间。第一是RuntimeError: Expected tensor for argument #1 input to have the same dimension as the input这类问题出现在自定义数据集时图片尺寸和模型输入尺寸不一致检查数据集的Resize和RandomCrop设置。第二是IndexError: Target X is out of bounds原因往往是类别数配置错了比如模型最后输出的类别数是 10但你给attack_target_label传了 124。第三是 GPU 显存溢出把batch_size从 256 降到 64或者减少恶意客户端数量因为后门攻击的触发器张量会额外占用显存。还有一个容易忽略的问题.gitignore会把*.pth和*.pt文件忽略如果你从网盘重新拉代码模型权重文件可能根本不在仓库里。运行前确认pretrained权重是否存在没有的话建议直接跳过预训练或者用torchvision.models的官方预训练权重代替。如果你要扩展成完整的毕设论文实验可以在FL_Backdoor_CV里增加“多次随机种子重复实验”的脚本把seed从 0 遍历到 9统计 ASR 的均值和方差。这一步不需要改太多逻辑但能让你的结果更可信答辩时也更有底气。最后的建议是把防御实验的主任务准确率和攻击成功率画在同一张折线图上横轴是通信轮次你会看到攻击成功率的回升现象。这是联邦学习后门攻击防御中最值得分析的动态特征也是你写论文时最有分量的图之一。本文还有配套的精品资源点击获取
返回列表