尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
横向联邦学习入门:本地模拟FedAvg与Non-IID实践
简介面向Python开发者和机器学习初学者的横向联邦学习本地模拟资源围绕“数据不出本地、模型参数共享”的分布式训练思想通过一套可运行的工程示例展示多个客户端协作完成全局模型训练的完整流程。压缩包共25个文件核心为五个Python脚本分别承担服务端、客户端、模型构建、数据集处理与主入口功能另有编译生成的字节码缓存、集成开发环境的工程配置文件、日志与参数配置以及含CIFAR-10数据集的批量数据文件和压缩包资源整体约302.68MB目录组织清晰便于按模块对照学习。当前已有723人学习下载。从中可以看清横向联邦学习的落地结构各客户端利用本地私有数据训练模型只上传模型参数或梯度服务器采用平均等策略聚合更新再广播全局模型并迭代直至收敛同时能体会接口通信设计、配置文件管理、数据预处理等工程细节以及加密通信、差分隐私等后续扩展方向适合课程设计、项目实战或入门联邦学习时参考。1. 横向联邦学习为什么要先做本地模拟做横向联邦学习绝大多数人第一个坑就是手里没有真实的多方数据也没有跨机构的合作条件。但算法原理、参数调优、Non-IID非独立同分布数据下的效果对比这些核心问题其实不需要真实网络环境也能验证——本地模拟就是最实用的脚手架。所谓本地模拟就是在一台机器上用 Python 把多个客户端的训练过程串起来客户端之间不共享原始数据只交换模型参数或梯度服务端做聚合更新。这套思路完全复刻了真实横向联邦的流程但把环境复杂度降到了最低。这份资源适合两类人一类是想把 FedAvg 原理吃透、准备写论文或面试的初学者另一类是已经在做分布式训练、想快速验证某种聚合策略或数据划分方案效果的工程师。它能解决的核心问题很简单在没有真实多方数据的前提下用最少的环境依赖跑通横向联邦的完整闭环并拿到可视化结果。2. 横向联邦的核心逻辑数据不动、模型动2.1 横向联邦和“搬数据集中训练”的本质区别传统机器学习是把所有数据收集到一台机器上训练而横向联邦恰恰相反——数据留在各自的客户端只有模型参数在服务端和客户端之间流动。以 FedAvg联邦平均为例每一轮通信做四件事服务端下发当前全局模型各客户端用本地数据训练若干轮客户端把更新后的模型参数上传服务端对参数做加权平均得到新的全局模型。这个过程的本质是“用通信轮次换数据集中”。所以在本地模拟时你不需要真的开多个进程或部署多台机器只需要在一个 Python 脚本里用循环模拟多个客户端依次“训练—上传”服务端聚合后再“下发”。这看起来像个玄学问题既然模型参数在循环里传来传去和单机训练有什么区别区别在于——每个客户端只能看到自己的数据切片永远不会接触到其他客户端的数据。这就是横向联邦的隐私边界也是本地模拟必须守住的红线。2.2 数据划分IID 与 Non-IID 两种模拟场景数据划分方式直接决定了联邦学习的难度。IID独立同分布场景下每个客户端的数据分布和全局分布基本一致FedAvg 收敛很快效果接近集中训练。Non-IID 场景下不同客户端的数据分布差异很大比如客户端 A 全是数字 0 到 4客户端 B 全是 5 到 9这时 FedAvg 容易震荡甚至不收敛。本地模拟的优势就是可以自由控制 Non-IID 的程度。常见的做法是按标签分布来切分数据把数据集按标签排序然后按客户端数量分成若干块。极端 Non-IID 就是每个客户端只拿 1 到 2 个类别的样本温和 Non-IID 则是每个客户端以某个概率偏向某些类别。这个数据划分函数建议单独写成一个模块因为后续调参、做对比实验都要反复用到它。2.3 为什么本地模拟能验证真实场景的问题有人会质疑本地模拟跑通了真实环境就能跑通吗答案是不一定但本地模拟能暴露绝大多数算法层面的问题。比如客户端数据量不平衡导致的模型偏置、学习率过大导致的聚合震荡、Non-IID 分布下的收敛缓慢——这些现象在本地模拟中都会出现而且可以在几分钟内复现、分析和修复。真实环境比本地模拟多出来的复杂度主要在通信层面网络延迟、掉线客户端、异构设备算力差异。这些问题属于工程问题不是算法问题。先把算法层面调明白再上真实框架比如 Flower、FATE或分布式环境这是效率最高的路径。我一般会建议本地模拟中跑不通的策略不要浪费时间去真实环境试。3. 从零搭建本地模拟框架完整代码与参数说明这份资源的核心是三个 Python 文件data_partition.py数据划分、client.py客户端训练逻辑、server.py服务端聚合与调度。下面按完整流程走一遍。3.1 环境准备与项目结构先用 conda 或 venv 建一个干净环境Python 版本建议 3.8 到 3.10依赖只需要 numpy 和 scikit-learn。PyTorch 或 TensorFlow 在这个阶段不是必须的——用 NumPy 手写一个逻辑回归或两层的 MLP足以验证 FedAvg 的全部逻辑而且调试起来没有框架黑匣子。mkdir fed_sim cd fed_sim conda create -n fed python3.9 conda activate fed pip install numpy scikit-learn matplotlib这里不急着上 PyTorch原因是横向联邦的本地模拟调试重点在聚合逻辑和数据划分不在模型结构。用最简单的模型反而能快速定位问题是出在聚合还是出在数据上。等整套流程跑通后再无缝切换到 PyTorch 版本。3.2 数据划分IID 和 Non-IID 的实现# data_partition.py import numpy as np from sklearn.datasets import load_digits def load_and_partition(num_clients5, non_iid_level0.0, seed42): num_clients: 客户端数量 non_iid_level: 0.0 表示 IID越大表示 Non-IID 程度越高 digits load_digits() X, y digits.data, digits.target np.random.seed(seed) if non_iid_level 0.0: # IID: 随机打乱后均分 indices np.random.permutation(len(X)) split np.array_split(indices, num_clients) else: # Non-IID: 按标签排序后按客户端数量分段 sorted_indices np.argsort(y, kindstable) # 根据 non_iid_level 决定每个客户端取多少种标签 num_classes len(np.unique(y)) classes_per_client max(1, int(num_classes * (1 - non_iid_level))) # 为每个客户端分配标签集合 all_classes np.arange(num_classes) split [] for i in range(num_clients): # 轮转分配标签保证每个客户端拿到的标签尽量不重叠 chosen all_classes[i % num_classes : i % num_classes classes_per_client] # 取这些标签对应的样本 mask np.isin(y, chosen) split.append(np.where(mask)[0]) # 返回每个客户端的 (X, y) client_data [] for idx in split: client_data.append((X[idx], y[idx])) return client_data, (X, y)这段代码的核心逻辑是IID 场景直接随机打乱均分模拟的是“每个客户端的数据都是全局数据的缩影”Non-IID 场景则通过classes_per_client控制每个客户端能看到的标签种类值越小客户端之间的数据分布差异越大。non_iid_level设为 0.8 时每个客户端只拿 1 到 2 个类别的数据训练出来的本地模型会严重偏科这时候再看 FedAvg 的聚合效果才是真正考验算法的时候。3.3 客户端训练本地多轮迭代# client.py import numpy as np class LogisticRegressionClient: def __init__(self, X, y, lr0.01, epochs5): self.X X self.y y self.lr lr self.epochs epochs # 特征维度 偏置项 self.dim X.shape[1] 1 def train(self, global_weights): global_weights: 服务端下发的全局模型参数 返回: 本地训练后的模型参数包含偏置 # 在特征矩阵前加一列 1 作为偏置项 X np.hstack([np.ones((self.X.shape[0], 1)), self.X]) y self.y # 从全局参数初始化 w global_weights.copy() # 本地多轮梯度下降 for epoch in range(self.epochs): # 前向计算 logits X w probs 1 / (1 np.exp(-logits)) # 将标签转为 one-hot 形式 y_onehot np.eye(10)[y] # 梯度计算 gradient X.T (probs - y_onehot) / len(y) # 参数更新 w - self.lr * gradient return w这个客户端类做的事情很简单接收服务端的全局参数在本地数据上跑若干轮梯度下降把更新后的参数返回。注意几个细节偏置项通过拼一列 1 实现这样不需要单独维护偏置变量梯度计算用的是 softmax 回归多分类逻辑回归的公式10 个类别对应 10 维输出epochs控制本地迭代轮数这是 FedAvg 的一个重要超参数。3.4 服务端聚合FedAvg 的完整实现# server.py import numpy as np from client import LogisticRegressionClient from data_partition import load_and_partition def fed_avg(weights_list, sample_nums): weights_list: 各客户端上传的模型参数列表 sample_nums: 各客户端的样本数量 total_samples sum(sample_nums) # 按样本量加权平均 weights np.zeros_like(weights_list[0]) for w, num in zip(weights_list, sample_nums): weights w * num / total_samples return weights def run_fedavg(num_clients5, num_rounds20, local_epochs5, lr0.01, non_iid_level0.0): # 1. 加载并划分数据 client_data, (X_test, y_test) load_and_partition(num_clients, non_iid_level) # 2. 初始化全局模型参数 dim X_test.shape[1] 1 global_weights np.zeros(dim) # 3. 创建客户端实例 clients [] sample_nums [] for X, y in client_data: clients.append(LogisticRegressionClient(X, y, lrlr, epochslocal_epochs)) sample_nums.append(len(X)) # 4. 联邦训练轮次 for round_idx in range(num_rounds): weights_list [] for client in clients: # 服务端下发全局参数客户端本地训练 local_weights client.train(global_weights.copy()) weights_list.append(local_weights) # 服务端聚合 global_weights fed_avg(weights_list, sample_nums) # 每 5 轮打印一次测试准确率 if (round_idx 1) % 5 0: acc evaluate(global_weights, X_test, y_test) print(fRound {round_idx 1}, Test Acc: {acc:.4f}) return global_weights def evaluate(weights, X_test, y_test): X np.hstack([np.ones((X_test.shape[0], 1)), X_test]) logits X weights preds np.argmax(logits, axis1) return np.mean(preds y_test)这段代码把完整流程串起来了数据划分 → 初始化全局参数 → 创建客户端 → 循环通信。fed_avg函数是 FedAvg 的核心按每个客户端的样本量做加权平均样本多的客户端对全局模型的影响自然更大。num_rounds控制通信轮次local_epochs控制每轮通信中客户端的本地迭代次数这两个参数是调优的重点。运行方式很简单python server.py输出每 5 轮的测试准确率。IID 场景下20 轮内准确率通常能到 95% 以上Non-IID 场景下同样参数可能只能到 80% 左右或者波动明显——这就是联邦学习要解决的核心痛点。4. 避坑指南本地模拟最常踩的五个坑4.1 现象Non-IID 场景下准确率震荡剧烈甚至不收敛原因客户端本地数据分布差异太大本地模型向各自的方向偏移聚合后的全局模型在类别之间“打架”。根本原因是classes_per_client太小客户端学到的特征几乎没有交集。解决先把non_iid_level降到 0.3 到 0.5 验证代码逻辑没问题再逐步加大。另外可以试试增大num_rounds比如 50 到 100 轮和降低学习率lr0.005给聚合留出更多收敛空间。4.2 现象IID 场景下联邦学习效果反而不如集中训练原因如果local_epochs设置过大比如 20 以上每个客户端在本地已经过拟合上传的参数偏离全局最优太远聚合效果反而变差。这在联邦学习里叫“客户端漂移”client drift。解决local_epochs一般设置在 1 到 5 之间。每轮通信中客户端只做少量本地更新把更多工作交给服务端聚合和后续轮次。这是 FedAvg 最容易被忽略的超参数。4.3 现象加了偏置项后模型效果没提升甚至更差原因很多人在拼接偏置项时用的是np.ones((n, 1))但忽略了特征矩阵的维度——如果原始数据已经包含一列偏置再拼一次就重复了。scikit-learn 的load_digits返回的特征矩阵不包含偏置列但换数据集时就要小心。解决写一个assert X.shape[1] w.shape[0] - 1的维度校验放到客户端train方法开头。这行代码能拦住 90% 的维度匹配错误。4.4 现象多分类任务中梯度计算报错或 loss 不变原因标签没有做 one-hot 编码。probs - y_onehot要求probs和y_onehot形状相同如果直接用原始标签形状是(n,)参与运算广播机制会给一个看似能跑但结果完全错误的结果——这种坑最隐蔽。解决用np.eye(10)[y]做 one-hot 编码。注意类别数量写死为 10 是针对load_digits数据集的换数据集时需要用np.eye(len(np.unique(y)))动态生成。4.5 现象本地模拟跑得通但换到真实框架如 Flower后效果对不上原因本地模拟是同步、全量参与的真实框架默认可能有客户端掉线、异步更新、批次采样等机制这些都会影响收敛轨迹。这不是 bug而是模拟环境和真实环境的边界差异。解决在本地模拟中增加两个模拟机制——每轮随机跳过 20% 的客户端不参与训练以及用np.random.choice对每个客户端的样本做 mini-batch 采样。这样模拟出来的收敛曲线和真实环境更接近切换到 Flower 时的“惊喜”会少很多。5. 进阶实操模拟客户端掉线与 Non-IID 数据可视化分析基础版本的 FedAvg 跑通只是第一步本地模拟的真正价值在于快速验证算法变体和真实环境的行为。先加一个客户端掉线机制。真实联邦场景中客户端可能因为网络或电量问题无法参与某一轮通信FedAvg 的原始论文假设所有客户端都参与但实际部署时这个假设几乎不成立。模拟掉线只需要在每轮训练前随机选一部分客户端跳过# 每轮只让 80% 的客户端参与训练 participating_indices np.random.choice( range(num_clients), sizeint(num_clients * 0.8), replaceFalse ) weights_list [] active_nums [] for idx in participating_indices: local_weights clients[idx].train(global_weights.copy()) weights_list.append(local_weights) active_nums.append(sample_nums[idx]) global_weights fed_avg(weights_list, active_nums)这段代码的关键在于聚合时只用参与客户端的样本量做加权而不是用全部客户端的。否则掉线客户端虽然没训练它的样本量仍然会影响聚合权重——这个 bug 会导致聚合结果偏移而且极难排查。接下来做 Non-IID 的可视化分析。把不同non_iid_level下的收敛曲线画在同一个坐标系里能直观看到分布差异对收敛速度和最终精度的影响import matplotlib.pyplot as plt def compare_non_iid_levels(levels[0.0, 0.3, 0.6, 0.9], num_rounds30): plt.figure(figsize(10, 6)) for level in levels: # 复用 run_fedavg但要改成返回每轮的准确率列表 acc_history run_fedavg_with_history( num_clients5, num_roundsnum_rounds, local_epochs3, lr0.01, non_iid_levellevel ) plt.plot(range(num_rounds), acc_history, labelfNon-IID level: {level}) plt.xlabel(Communication Rounds) plt.ylabel(Test Accuracy) plt.legend() plt.grid(True) plt.savefig(fed_compare.png, dpi150)运行后生成的对比图会清楚显示IIDlevel0收敛最快、最终精度最高level0.9 时曲线可能始终在低位震荡。这篇文章里不贴结果图但你在本地跑出来后会发现一个反直觉的现象——当num_clients从 5 增加到 20 时同样的 Non-IID 级别下收敛难度反而增加因为客户端数量越多模型参数的“投票”越分散聚合后的方向更难一致。这是横向联邦和集中训练非常不同的一点更多参与者并不等于更好收敛。最后一个值得做的实验是调整本地迭代轮数local_epochs并观察全局模型在测试集上的表现这个实验能帮你建立对“通信效率 vs 本地计算”的直觉。建议把结果记录成表格对比local_epochs为 1、3、5、10 时的最终准确率和达到 90% 准确率所需的通信轮数。做完这个实验你对 FedAvg 的理解会比读十篇论文都扎实。从那以后我做任何联邦学习实验都强制先跑一遍本地模拟——数据划分、掉线模拟、Non-IID 对比确认算法层面的变量都控制住了才敢往真实框架上迁移。这套流程帮我拦住了至少三四个看起来是网络问题、实际是数据划分 bug 的翻车现场。希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

工艺路线设计与流程图绘制规范:从物料衡算到PID的工程实践指南

工艺路线设计与流程图绘制规范:从物料衡算到PID的工程实践指南

简介:一份面向化工工艺设计入门与课程学习的PPT资源,聚焦工艺路线确定与工艺流程设计两大核心环节。内容系统梳理了技术可行性、经济合理性、原料纯度与来源、公用工程、环保安全及政策法规等路线论证要素,并结合先进性与可靠性原则介绍了工艺…

📅 2026/10/30 17:04:33
从零手搓AI工程:NumPy实现GPT与框架调包对比

从零手搓AI工程:NumPy实现GPT与框架调包对比

1. 从零手搓AI工程:为什么我不建议你直接调包第一次看到ai-engineering-from-scratch这个项目名的时候,我脑子里蹦出来的画面是:一个人坐在黑漆漆的终端前面,从矩阵乘法开始,一行一行把Transformer搭出来,中…

📅 2026/10/30 17:04:33
ASP.NET GridView行内编辑实战:SqlDataSource与UpdatePanel局部刷新

ASP.NET GridView行内编辑实战:SqlDataSource与UpdatePanel局部刷新

简介:这份资源面向使用 ASP.NET 4.0 与 SQL Server 2008 开发信息系统的开发者,针对 VS 自带 GridView 在交互体验与可移植性上的不足,提供一套经国外论坛筛选后整理的实用 GridView 实例。它完整实现了数据的增、删、改操作,并以…

📅 2026/10/30 16:59:31
MORE NEWS

更多资讯

📰

地铁BAS PLC为何必须用STEP7 V5.5?兼容性与现场准入硬约束

简介:本资源是一套完整的地铁环境监控系统(BAS)PLC控制程序工程包,面向自动化、轨道交通及工业控制领域的工程师、高校师生与PLC初学者,聚焦西门子S7系列PLC在真实地铁场景中的工程化应用。资源基于STEP7 V5.5开发&…

📰

C语言+easyX实现Flappy Bird:图形编程底层实战指南

简介:这是一份面向C语言初学者与图形编程入门者的Flappy Bird像素鸟游戏实战源码包,聚焦Windows平台下基于easyX图形库的游戏开发实践,帮助学习者掌握双缓冲绘图、物理模拟(重力/碰撞)、状态机管理及音效集成等核心技能…

📰

【纯白嫖】IEC60870-5 中文版下载指南:101/104 协议标准一次拿齐全集

【纯白嫖】IEC60870-5 中文版下载指南:101/104 协议标准一次拿齐全集 【免费下载链接】IEC60870-5全集中文版本下载 IEC60870-5全集中文版本下载 项目地址: https://gitcode.com/open-source-toolkit/fc96f IEC60870-5 原版标准难找难读。IEC60870-5全集中文…

📰

刚更新的首次启动流程:模型来源、系统授权、Agent 配置一次配完

刚更新的首次启动流程:模型来源、系统授权、Agent 配置一次配完 【免费下载链接】OpenBot Open-source AI coworkers that each get a computer of their own: a browser, files and tools, with every action decided before it happens and recorded after. Bring…

📰

【资源自取】倪海厦软件完整下载指南:人纪、天纪、医案查询系统三步跑通

【资源自取】倪海厦软件完整下载指南:人纪、天纪、医案查询系统三步跑通 【免费下载链接】倪海厦三套软件资源分享 倪海厦三套软件资源分享本仓库提供倪海厦先生的三套电脑软件资源,经过测试,确保可用性 项目地址: https://gitcode.com/ope…

📰

不同CORS服务会影响RTK固定速度和稳定性吗

有人问:"都是差分解算,为什么有的服务固定快、有的慢?“答案藏在解算方式里。VRS、FKP、MAC 是三种主流的网络 RTK 差分解算技术,它们对固定速度和稳定性的影响是真实存在的–虽然市面上大多数终端和服务已经把这层差异磨平,但了解原理能帮你理解"为什么换个服务体验…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬