拓冰建站拓冰建站
首页 / 资讯中心 / 正文

联邦学习实战:FedAvg结合SMOTE实现信用卡欺诈检测

简介基于FedAvg联邦平均算法与SMOTE过采样优化的Python项目面向联邦学习场景下的信用卡欺诈交易检测适合计算机、人工智能等相关专业学生作为毕设或课程设计参考。项目通过Server与Clients对象模拟服务器与节点间的双向参数传递在保护数据隐私的前提下解决银行间数据不可共享的痛点同时利用SMOTE过采样缓解欺诈样本不平衡问题整体思路完整、可直接运行。压缩包共8个文件以Python源码为主辅以说明文档、流程图与CSV数据集整体大小约43MB代码结构清晰且经过测试。目前已有173人学习下载适合需要完整可运行方案、论文级项目演示或远程指导的初学者。下载后可直接对照说明文档及模型、客户端、服务端等模块进行二次改造快速理解联邦训练全流程。1. 联邦信用卡欺诈检测为什么要把SMOTE塞进FedAvg信用卡欺诈数据是机器学习里最典型的一类脏数据正负样本比例动辄 1:500 甚至更低单家银行的数据规模又不足以训练出可靠模型。把 FedAvg联邦平均和 SMOTE少数类过采样组合起来是在隐私约束下解决这个问题的常见方案——客户端在本地完成少数类合成服务器只聚合模型权重既不让交易明细离开本地又能缓解类别不平衡对梯度更新的扭曲。下面直接讲清楚 SMOTE 该放在联邦流程的哪一步、参数怎么设、评估看什么指标以及跑通这套管线会踩到的几个坑适合已经在做联邦学习或信用卡欺诈交易检测的工程师。2. FedAvg训练循环拆解本地更新与服务器聚合的边界2.1 三步协议采样客户端、本地训练、按样本数加权聚合FedAvg 是联邦学习里绕不开的基线算法协议本身只有三步。服务器把当前全局模型权重分发给本轮参与的一部分客户端每个客户端在本地数据上独立训练若干轮梯度下降客户端把训练后的权重传回服务器服务器按公式 w_global Σ(n_k / n) · w_k 做加权平均权重 n_k / n 是客户端 k 的本地样本数占本轮总样本的比例然后进入下一轮。整个循环重复若干轮直到全局模型在验证集上的指标不再提升。这里最关键的边界是数据不出客户端。集中式训练要求把所有交易流水收集到同一台机器FedAvg 只交换模型参数服务器接触不到任何一条交易明细这对信用卡数据这种强隐私场景几乎是硬性要求。另一个容易被忽略的细节是FedAvg 聚合的是权重而不是梯度所以服务器不需要关心客户端用什么优化器、学习率怎么调兼容性更好代价是每轮都要上传完整模型权重通信开销大。工程上常见做法是对上传的更新做 Top-k 稀疏化也就是偏置压缩只传输权重变化量中显著的部分把每轮通信量压到一个很低的水平。2.2 两个关键超参数本地训练轮数E与客户端采样比例CFedAvg 和分布式SGD的关键差异在通信频率分布式SGD 每个 batch 同步一次FedAvg 让客户端本地连续训练 E 个 epoch 才同步一次。E 越大通信轮次越少但客户端之间权重发散越严重聚合出来的全局模型可能出现漂移E 1 时最接近普通SGD 的收敛轨迹但通信压力最大。对信用卡交易这种特征维度不高、单客户端样本量较大的场景E 取 1 到 5 是合理区间。客户端采样比例 C 决定每轮有多少比例的客户端参与聚合。客户端数量多但每轮只抽一小部分时数据量小的机构容易被长期跳过全局模型会偏向数据量大的那端。C 本身不改变通信内容但会显著影响聚合方差。下面的组合是常用起点场景E 推荐C 推荐说明客户端少于10个3~51.0全部参与聚合方差最小客户端50个以上1~20.2~0.3控制通信开销Non-IID严重10.5缩短本地训练减少漂移如果 SMOTE 已经让各客户端的分布差异进一步拉大C 取大值比取小值更安全因为每轮有更多客户端参与意味着合成样本的特征能被聚合更充分地吸收而不是集中在少数几轮的权重更新里。2.3 一个最小可跑的FedAvg Python骨架FedAvg 的实现不复杂难点在工程化。下面用 PyTorch 写一个最小骨架模型定义和数据加载省略只保留联邦循环本身import random import copy def fedavg_round(global_model, clients, client_fraction0.3, local_epochs3, lr0.01): # 1. 服务器按比例随机采样本轮参与的客户端 sampled random.sample(clients, max(1, int(len(clients) * client_fraction))) global_weights copy.deepcopy(global_model.state_dict()) local_weights, local_sizes [], [] for client in sampled: # 2. 每个客户端从全局权重出发在本地数据上做若干轮梯度下降 client.model.load_state_dict(global_weights) client.train_on_local_data(local_epochslocal_epochs, lrlr) local_weights.append(copy.deepcopy(client.model.state_dict())) local_sizes.append(client.num_samples) # 3. 按各客户端样本数占比加权平均得到新的全局模型 total sum(local_sizes) new_weights {} for key in global_weights: weighted [w[key] * (n / total) for w, n in zip(local_weights, local_sizes)] new_weights[key] sum(weighted) global_model.load_state_dict(new_weights) return global_model逻辑上这四步对应协议的三步采样、本地训练、加权聚合。两个细节值得注意一是 load_state_dict 之前必须深拷贝全局权重否则下一个客户端会读到上一个客户端的更新结果二是服务器只通过 state_dict() 拿权重如果模型带 BatchNorm统计信息也要一并传输否则推理时分布会对不上。参数层面client_fraction 控制每轮参与方影响通信量和聚合方差local_epochs 控制本地推进深度直接决定模型漂移程度lr 在联邦场景下要比单机训练保守0.01 到 0.05 起步比较稳因为加权聚合本身会引入额外的梯度方差。提示生产环境会在聚合链路上加安全聚合或差分隐私噪声协议主链路不变但私有化部署的起点不是加密而是先把上面的骨架跑通。3. SMOTE过采样放对位置客户端本地合成而非全局合成3.1 信用卡欺诈的极端不平衡与SMOTE线性插值原理信用卡欺诈交易检测是类别不平衡的典型现场。公开的信用卡欺诈数据集中 28 万余笔交易只有 492 笔欺诈正负比接近 1:578。在这种分布下一个把所有样本都判为正常的分类器准确率高达 99.8%但这个模型一点用都没有。欺诈检测真正关心的是少数类召回率而常规梯度下降会被多数类主导模型倾向学会全部判正常这个偷懒解。SMOTESynthetic Minority Over-sampling Technique解决的是少数类样本不够模型学的问题。它不是复制已有样本而是对每个少数类样本 x用 K 近邻默认欧氏距离找到 K 个邻近少数类样本随机挑一个 x_i在特征空间上做线性插值生成新样本x_new x λ · (x_i - x)λ 是 0 到 1 的随机数。这样生成的新样本落在两个真实样本的连线上相当于在少数类分布内部做插值比简单复制多了多样性能有效缓解过采样附带的过拟合。在联邦场景里SMOTE 的位置只有一种合理选择放进各个客户端的本地处理链路。服务器拿到的只有模型权重没有原始特征无法在全局层面做合成而客户端在本地拥有完整交易特征天然具备做插值的基础。这套本地过采样、全局聚合权重的流程本质上是先用 SMOTE 修正每个客户端的本地分布再让 FedAvg 去平均修正后的学习结果。3.2 用imbalanced-learn实现客户端内SMOTEsampling_strategy与k_neighbors实现上直接用 imbalanced-learn 的 SMOTE 类就行不需要自己写近邻搜索。每个客户端在本地训练前对训练集单独执行 fit_resamplefrom imblearn.over_sampling import SMOTE from sklearn.model_selection import train_test_split def local_oversample(X, y, sampling_strategy0.3, k_neighbors5): # SMOTE 只作用在训练集上验证集保持原始分布用于真实评估 X_train, X_val, y_train, y_val train_test_split( X, y, test_size0.2, stratifyy, random_state42) smote SMOTE(sampling_strategysampling_strategy, k_neighborsk_neighbors, random_state42) X_res, y_res smote.fit_resample(X_train, y_train) print(f训练集: {X_train.shape[0]} - {X_res.shape[0]}, f正样本: {y_train.sum()} - {y_res.sum()}) return X_res, y_res, X_val, y_val两个参数决定了合成强度sampling_strategy 表示合成后少数类占多数类的目标比例0.3 意味着把欺诈样本补到正常样本量的三成这是一个偏保守的起步值调大它会让训练集里合成样本占比上升模型对插值区域的拟合更强但也更容易记住合成噪声。k_neighbors 控制每个少数类样本合成时参考的近邻数默认 5如果某个客户端正样本数量很少、类别重叠度高可以降到 3减少混入边界样本的风险。注意 train_test_split 的 stratifyy 必须保留否则切分后某一端的正样本比例漂移后续评估会和训练分布错位。提示fit_resample 只允许作用在训练集上。验证集、测试集一旦被过采样评估出来的 PR 指标会明显虚高上线后召回率会断崖下跌这是这套管线里最容易踩的坑。3.3 合成比例不能全局统一两个Non-IID层面的原因很多实现把 sampling_strategy 设成全局常量这在实际联邦数据上有两个问题。第一个是少数类绝对数量差异。假设机构 A 一个月只有 200 笔欺诈样本机构 B 有 5000 笔用同一个 0.3A 合成出的样本只有几百条模型学不到可用的欺诈模式B 则合成上千条插值噪声被成倍放大。合成量应该跟着本地正样本数走而不是跟着全局统一比例走。第二个是标签分布偏移label distribution skew。不同机构的欺诈率天然不同有的侧重线上盗刷、有的侧重线下伪卡合成样本会放大这种本地偏置。如果全局用同样的 SMOTE 比例聚合后的全局模型会被少数几个合成样本多的客户端带偏。我一般让客户端按本地正样本占比动态计算 sampling_strategy在 0.2 到 0.5 之间取而不是全局写死一个值。4. FedAvgSMOTE的联邦信用卡欺诈交易检测管线与关键参数4.1 端到端流程横向切分、本地过采样、循环聚合整套管线按横向联邦设计每个客户端拥有相同的特征列各自持有不同的交易样本。先按机构维度把原始数据切成 N 份模拟客户端再用 Dirichlet 分布控制各客户端的正样本占比制造 Non-IID 效果这样训练出的结果更接近真实部署环境而不是数据均匀拆分这个理想假设。整体流程如下import numpy as np def run_fed_smote(global_model, clients, rounds50, eval_interval10): # 每个客户端按本地正样本占比配置SMOTE比例不全局统一 for c in clients: c.sampling_strategy float(np.clip(c.positive_ratio * 3, 0.2, 0.5)) c.apply_smote() # 在本地训练集上执行 fit_resample for rnd in range(rounds): # 聚合时传低学习率避免SMOTE合成样本放大梯度震荡 fedavg_round(global_model, clients, client_fraction0.4, local_epochs2, lr0.01) # 每eval_interval轮用各客户端原始验证集评估一次 if rnd % eval_interval 0: aps [average_precision_score(c.y_val, c.predict(global_model)) for c in clients] print(fround {rnd}: mean AP {np.mean(aps):.4f}) return global_model流程顺序是固定的先配 SMOTE、再训练、最后评估。apply_smote 在每轮 FedAvg 开始前一次性做好不需要每轮重复 fit因为合成样本的随机种子固定后重复执行只会浪费计算。评估时用的是客户端原始验证集没有经过过采样这样得到的 AP 才是全局模型对真实分布的泛化能力。lr 在联邦场景下调低到 0.01是因为 SMOTE 合成样本放大了本地梯度方向的分歧学习率太高会让聚合后的权重更新震荡。4.2 五个必调参数与推荐区间参数推荐区间作用调大的后果local_epochs (E)1~5本地连续训练的轮数客户端权重漂移加重client_fraction (C)0.2~1.0每轮参与的客户端比例聚合方差变小但通信变大sampling_strategy0.2~0.5SMOTE合成后少数类占比目标过拟合合成插值区域k_neighbors3~7SMOTE合成时的近邻数近邻中混入多数类样本batch_size64~256本地训练批大小梯度噪声增大这里单独说明 sampling_strategy 和 k_neighbors 的联动当合成比例调高时近邻池里少数类样本密度变大k_neighbors 可以适当调大让插值更平滑反之合成比例低时 k_neighbors 保持默认 5 即可。batch_size 在联邦场景容易被忽略其实它直接决定本地梯度估计的方差而 FedAvg 聚合本身就带方差两者叠加会让收敛变慢。4.3 评估指标选Precision-Recall而非Accuracy欺诈检测场景下 Accuracy 是近乎必然的错误选择0.17% 的正样本占比让准确率失去了区分能力。PR 曲线的横纵轴分别是召回率和精确率它直接回答我抓到的欺诈里有多少是真的、真实欺诈里有百分之多少被抓住了这两个业务问题。用 scikit-learn 实现from sklearn.metrics import precision_recall_curve, average_precision_score # y_true: 原始测试集标签y_score: 模型输出的欺诈概率两者都未过采样 precision, recall, thresholds precision_recall_curve(y_true, y_score) ap average_precision_score(y_true, y_score) # 部署阈值选择在精确率不低于0.8的前提下尽量提高召回率 deploy_threshold 0.5 candidates [(p, r, t) for p, r, t in zip(precision, recall, thresholds) if p 0.8] if candidates: deploy_threshold max(candidates, keylambda x: x[1])[2] # 取召回率最大的阈值 print(fAP {ap:.4f}, deploy_threshold {deploy_threshold:.4f})联邦环境下的评估要落在每个客户端上全局模型下发后各客户端在本地原始测试集上计算 AP服务器再按样本数加权平均得到联邦 AP。这个值比 ROC-AUC 更能反映少数类学习效果因为 PR 曲线对正样本比例的敏感度更高欺诈率低的客户端贡献会被正确压低。5. 解决联邦SMOTE的收敛慢与局部过拟合三个调优技巧5.1 按正样本占比加权聚合替代纯样本数加权FedAvg 默认权重 n_k / n 在数据均衡时没问题SMOTE 之后各客户端的有效正样本差异被放大了。简单有效的改法是让客户端在上传权重时附带一个合成样本计数聚合权重改为 w_k n_k α · n_syn_kα 取 0.3 到 0.5。这样合成样本多的客户端在聚合中占比略高能补偿本地过采样带来的方差。α 不要超过 0.5否则少数几个客户端会把合成噪声放大到全局表现就是联邦验证集 AP 在小幅上升后迅速掉头。5.2 限制合成倍数必要时退回类权重损失SMOTE 不是越猛越好。某个客户端正样本不到 200 条时把 sampling_strategy 调到 0.5 也合成不出可用的分布反而训练时间翻倍。我一般限制每个客户端合成样本不超过原始正样本的 3 倍超过就降比例。如果限制了合成量验证集 AP 仍然不涨直接删掉 SMOTE改用加权交叉熵损失。SMOTE 和类权重叠加往往不如二者选其一因为两者都在放大少数类梯度叠加后容易让模型在合成样本上过拟合验证集 AP 反而低于只做其中一项。5.3 用客户端原始验证集的AUC-PR做早停合成样本不参与验证所以原始验证集上的 AP 是判断 SMOTE 是否真正有效的唯一信号。每 5 轮在所有客户端原始验证集上算一次平均 AP连续 10 轮不增长就停止训练并回滚到最佳轮次的权重。如果 AP 在某一轮突然掉点先检查两件事验证集是否被无意中过采样以及 local_epochs 是否因为 SMOTE 拉大了客户端权重差异。这两个问题比超参数调优更常见。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门