【联邦学习】联邦学习量化——non-iid数据集下的仿真

article/2025/10/14 2:41:21

文章目录

    • 改进项目背景
    • 量化函数的改进
    • non-iid数据集的设置
      • Fedlab划分数据集的踩雷

改进项目背景

在前面的项目中,虽然对联邦学习中,各个ue训练出来的模型上传的参数进行了量化,并仿真的相关结果。但是仍有一些俺不是非常符合场景的情况,需要改进的方向如下:

  1. 量化函数需要重写,将前面的只对小数点后进行0~1的量化改成自适应的在一段范围之内的数组量化。
  2. 信道仿真函数,在真实的通信环境中,一个信道的速率模拟可以由一个基于正态分布的初始速率,每隔一定时间加减均匀分布的变化值。
  3. 根据量化的程度不同,模型分为基础值和增量值,先传数据量较少的基础值,如果通信条件好的画
  4. 需要模仿接收方BS的接收规则:首先应该计算传输过程中的耗时,如果耗时超过了一个等待的门限,那么这个模型就不会被纳入聚合的model们里。如果接收了基础值之后,BS还会等待一段时间,如果增量值没到达,那只能用基础值去参与聚合了。这样对于BS来说就陷入一个博弈:是采用更精确的量化模型去提高自己模型的准确度呢,还是采用更少的量化程度的模型来保证在信道上能够正确传输。而我正是要仿真这样一个场景。
  5. 联邦学习框架的使用:PySyft在自己一个电脑上的仿真完全没用!完全可以抛弃框架自己写代码去模拟模型聚合与信道上的传输过程。
  6. 急需一个能够仿真出non-iid数据集的库,方便后续的仿真代码编写。

量化函数的改进

对原始数组进行线性变化,映射在一定范围内:
V q = Q × ( V x − min ⁡ ( V x ) ) V_q=Q\times(V_x-\min(V_x)) Vq=Q×(Vxmin(Vx))
V x ′ = V q / Q + min ⁡ ( V x ) V_x'=V_q/Q+\min(V_x) Vx=Vq/Q+min(Vx)
Q = S / R , R = max ⁡ ( V x ) + m i n ( V x ) , S = 1 < < b i t s − 1 Q=S/R,R=\max(V_x)+min(V_x),S=1<<bits-1 Q=S/R,R=max(Vx)+min(Vx),S=1<<bits1
其中 V x V_x Vx表示原浮点数, V q V_q Vq表示量化后的定点数值, V x ′ V_x' Vx表示根据量化参数还原出的浮点数,bits为量化比特位数。
传输的时候只需要传输低比特矩阵 V q V_q Vq和参数 Q , S , R Q,S,R Q,S,R等,在接收端即可还原成浮点数。

总而言之,举例:一个正弦函数值数组,经过4bit量化后呈现如下效果:
在这里插入图片描述
而神经网络中同一个层的tensor,数值分布恰好在同一个数量范围内,适合这样的数组量化:我们选择这个tensor中的最大值和最小值,以此为范围进行量化。

#4bit量化前:
tensor([ 0.0201,  0.0059,  0.0153, -0.0319, -0.0419,  0.0025, -0.0467, -0.0022,0.0106,  0.0512, -0.0321, -0.0190, -0.0409,  0.0128,  0.0191,  0.0479,-0.0289, -0.0515, -0.0237, -0.0473, -0.0420, -0.0156, -0.0371,  0.0184,0.0014,  0.0103, -0.0436, -0.0375,  0.0042, -0.0070,  0.0027,  0.0168])
#4bit量化后:
tensor([ 0.0215,  0.0072,  0.0143, -0.0287, -0.0430,  0.0000, -0.0502,  0.0000,0.0072,  0.0502, -0.0287, -0.0215, -0.0430,  0.0143,  0.0215,  0.0502,-0.0287, -0.0502, -0.0215, -0.0502, -0.0430, -0.0143, -0.0359,  0.0215,0.0000,  0.0072, -0.0430, -0.0359,  0.0072, -0.0072,  0.0000,  0.0143])

具体的函数如下:

def Quant(Vx, Q, RQM):return round(Q * Vx) - RQMdef QuantRevert(VxQuant, Q, RQM):return (VxQuant + RQM) / Qdef ListQuant(data_list, quant_bits):# 数组范围估计data_min = min(data_list)data_max = max(data_list)# 量化参数估计Q = ((1 << quant_bits) - 1) * 1.0 / (data_max - data_min)RQM = (int)(np.round(Q*data_min))# 产生量化后的数组quant_data_list = []for x in data_list:quant_data = Quant(x, Q, RQM)quant_data_list.append(quant_data)quant_data_list = np.array(quant_data_list)return (Q, RQM, quant_data_list)def ListQuantRevert(quant_data_list, Q, RQM):quant_revert_data_list = []for quant_data in quant_data_list:# 量化数据还原为原始浮点数据revert_quant_data = QuantRevert(quant_data, Q, RQM)quant_revert_data_list.append(revert_quant_data)quant_revert_data_list = np.array(quant_revert_data_list)return quant_revert_data_list

non-iid数据集的设置

信道变化->BS接收到ue的模型数量变化->聚合时用于平均的model数量变化

⬆️只有数据集是non-iid的时候,model数量变化才能明显表现出对性能的影响。
如果各个ue在相同数据集上训练相同batch,再进行聚合平均,聚合的model数量对性能影响不大。
我寻找到了一个由本校学长参与开发的一个联邦学习函数库Fedlab,除了数据集的处理,库还提供了别的很多在联邦学习中非常有用的函数,如BS和客户机的交流通信函数等,在这里把Github上的repo贴一下:
https://github.com/SMILELab-FL

点开才发现,这个repo居然是同校计算机学院的一位博士学长创建和维护的,后来还在飞书上联系到了他。各位如果有兴趣的话,非常建议在repo的issue上提出问题,他们都会即使解答的。
另外,如果不想下载Fedlab这个库,或者对Dirichlet划分是数学原理感兴趣的,可以参考下面这个:
https://zhuanlan.zhihu.com/p/468992765
按Dirichlet分布划分Non-IID数据集
在这里插入图片描述
由于Dataloader在每次加载时数据的索引不变,因此在多轮测试的时候,每个ue上的数据分布不会变(区别于完全随机)。

Fedlab划分数据集的踩雷

一开始,我是直接按照这个文档来的:https://zhuanlan.zhihu.com/p/411308268,刚好我也需要采用CIFAR10数据集,但是在其中有这样一句导入包:from fedlab.utils.dataset.sampler import SubsetSampler,是错误的,检查源码也发现dataset里面根本就没有sampler,这让我十分抓狂。后面询问之后才知道,原来sampler的效率太低了,他们已经在新版本放弃不用了,新的划分方案直接看github中的tutorial文件夹部分。于是我找到了如下:
partitioned_cifar10的用法

class PartitionedCIFAR10(root, path, dataname, num_clients, download=True, preprocess=False, balance=True, partition=‘iid’, unbalance_sgm=0, num_shards=None, dir_alpha=None, verbose=True, seed=None, transform=None, target_transform=None)

我们就需要先实例化这一个类,然后利用这个类提供的几个函数来实现数据集的划分与加载。这个类有如此多的参数,那么具体每个参数什么含义,我们在使用的时候又该如何设置呢?

  • root (str) – Path to download raw dataset. 和pytorch的datasets一样,填'/cifar10'

  • path (str) – Path to save partitioned subdataset.预训练好的.pkl文件名,我填'/cifar10_hetero_dir.pkl'

  • dataname (str) – “cifar10” or “cifar100”填‘/cifar10’

  • num_clients (int) – Number of clients.要分成几份,对应ue的个数

  • download (bool) – Whether to download the raw dataset.同pytorch里的datasets

  • preprocess (bool) – Whether to preprocess the dataset.是否预划分,这个第一次必须填true,后面就可以填false了

  • balance (bool, optional) – Balanced partition over all clients or not. Default as True.false

  • partition (str, optional) – Partition type, only “iid”, shards, “dirichlet” are supported. Default as “iid”.填'dirichlet'

  • unbalance_sgm (float, optional) – Log-normal distribution variance for unbalanced data partition over clients. Default as 0 for balanced partition.可选项,没填

  • num_shards (int, optional) – Number of shards in non-iid “shards” partition. Only works if partition=“shards”. Default as None.可选项,没填

  • dir_alpha (float, optional) – Dirichlet distribution parameter for non-iid partition. Only works if partition=“dirichlet”. Default as None.0.3

  • verbose (bool, optional) – Whether to print partition process. Default as True.可选项,没填

  • seed (int, optional) – Random seed. Default as None.2022

  • transform (callable, optional) – A function/transform that takes in an PIL image and returns a transformed version.同pytorch里的datasets,对图像进行预处理,然后转化为tensor

  • target_transform (callable, optional) – A function/transform that takes in the target and transforms it.可选项,没填

其中一个非常容易错的点。PartitionedCIFAR10这个类中的preprocess实际上就是按照所选的划分模式,对整个数据集贴标签形成一个字典,标注每条数据属于哪个ue,保存在一个.pkl文件中。后面在训练加载数据的时候,就按照这个字典从数据集中取数据,就完成了non-iid的划分啦。
同时transform里面和pytorch的写法一样的,可以对图片进行大小的更改,进行normalize等操作,当然一定别忘记了必须Totensor()将图片转化为tensor,然而我发现忘记totensor,改了之后,发现还是报错!仔细以看才知道,原来是改了transform,但是忘记了重新preprocess一下,导致还是按照旧的方式去加载,自然错啦。

后面的使用,PartitionedCIFAR10提供了两个比较有用的函数;
在这里插入图片描述

他们的返回值就是pytorch中的datasetdataloader了。用法也和pytorch中的一样:

hetero = PartitionedCIFAR10(root='/cifar10',path='/cifar10_hetero_dir.pkl',dataname="cifar10",num_clients=train_args['num_clients'],download=False,preprocess=False,balance=False,partition="dirichlet",seed=2022,dir_alpha=0.3,transform=transforms.Compose([transforms.Resize((32, 32)),transforms.ToTensor(),transforms.Normalize(mean=[0.4750, 0.4750, 0.4750], std=[0.2008, 0.2008, 0.2008])]),target_transform=transforms.ToTensor()
)for id, ue in enumerate(UE_list):train_loader = hetero.get_dataloader(id, batch_size=train_args['batch_size'])for batch_idx, (data, target) in enumerate(train_loader):# if batch_idx > 100:#     breakue_data = data.to(device)ue_target = target.to(device)loss = ue.train(ue_data, ue_target)

后面的就是按照正常方式去训练啦,最后也是成功得到了一个不同bit压缩的联邦学习训练效果对比图:
在这里插入图片描述


http://chatgpt.dhexx.cn/article/x6NQlXaq.shtml

相关文章

「隐语小课」联邦学习之Non-IID问题

更多干货内容&#xff0c;请移步公众号&#xff1a;隐语的小剧场 一、引言 本文针对联邦学习中遇到的Non-IID问题进行探讨&#xff0c;介绍Non-IID产生的原因&#xff0c;分析Non-IID对联邦学习的影响&#xff0c;以及调研了近年来针对该问题的解决方案&#xff0c;并进行分类…

联邦学习中的non-iid总结

最近研究联邦学习&#xff08;federated learning&#xff0c;FL&#xff09;中的non-iid的解决办法时遇到瓶颈&#xff0c;写成博客将最近的工作总结一下&#xff0c;希望有大佬看到这篇博客不吝赐教。 什么是non-iid 先从维基百科引出独立同分布的定义&#xff1a; 在概率论…

IID 与 Non-IID

数据独立同分布&#xff08;Independent Identically Distribution&#xff0c;IID&#xff09; 数据与数据之间都是独立的&#xff0c;但满足同一个分布。&#xff08;独立&#xff1a;一个数据的出现不会影响另一个数据&#xff09; 数据分布描述的是数据的统计情况&#x…

dy设备deviceid iid注册分析

清楚缓存&#xff0c;重新打开app, 点击同意按钮&#xff0c;会触发设备注册&#xff1b; 很明显是一个post包&#xff0c;device_register 可以看到请求体加密了 那么 请求体是什么呢&#xff1f; 很老版本思路&#xff1a;都是直接明文注册 较老版本思路&#xff1a;在反编译…

Redis 设计与实现: redisObject 数据结构,以及 Redis 的数据类型

redisObject 数据结构&#xff0c;以及 Redis 的数据类型 redisObject 是 Redis 类型系统的核心&#xff0c; 数据库中的每个键、值&#xff0c;以及 Redis 本身处理的参数&#xff0c; 都表示为这种数据类型。 redisObject 的定义位于 redis.h &#xff1a; /** Redis 对象…

(五)、Redis的RDB持久化---Redis设计与实现读书笔记

两个用于生成RDB文件的命令 save&#xff1a;会阻塞Redis服务器进程&#xff0c;直到RDB文件创建完毕&#xff0c;在阻塞期间&#xff0c;服务器不能处理任何命令请求bgsave&#xff1a;会派生出一个子进程&#xff0c;然后由子进程负责创建RDB文件&#xff0c;服务器经常(父进…

《redis设计与实现》 读书笔记

《redis设计与实现》 作者&#xff1a;黄健宏 读书笔记 一、前言 什么是redis&#xff1a; Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。简而言之redis就是放在远程网络上的一个key-va…

《Redis设计与实现》阅读:Redis底层研究之简单动态字符串SDS

除仅用于字符串字面量的情况外&#xff0c;对于可以被修改值的字符串的表示&#xff0c;Redis底层并没有采用C语言传统的字符串表示&#xff0c;即以空字符结尾的字符数组&#xff0c;而是采用专门为其设计的简单动态字符串作为其默认字符串表示&#xff0c;其英文全称为Simple…

Redis秒杀功能设计与实现

前言 抢购问题不仅是电商类项目中一个重要的业务,也是许多开发人员在进阶过程中绕不开的问题,关于抢购,如果理清了前后的逻辑和里面涉及到的几个关键性的问题,问题就迎刃而解了 抢购中的几个常见问题 如何设计抢购功能?(表结构,以及整体的抢购思路)不借助中间件如何实…

Redis设计与实现阅读总结(一)数据结构和对象

Redis设计与实现阅读总结&#xff08;一&#xff09;数据结构和对象 最近团队几个人和我聊了下&#xff0c;加上我自己平时的反思&#xff0c;我发现自己问题确实很多 其中一个问题就是&#xff0c;自己学习东西没有系统性&#xff0c;没有总结 这次的博客算是一个总结的开始。…

(六)、Redis的AOF持久化---Redis设计与实现读书笔记

redisServer关于AOF的数据结构 /***Redis 服务器类*/ struct redisServer{...//AOF缓存区sds aof_buf;... }当服务器执行完一个写命令后&#xff0c;会一协议格式将被执行的写命令追加到服务器类的aof_buf缓存区的末尾。 AOF文件的写入、同步 写入、同步概念 写入&#xff…

Redis | 第8章 发布订阅与事务《Redis设计与实现》

第8章 发布订阅与事务 前言1. 发布订阅1.1 频道的订阅与退订1.2 模式的订阅与退订1.3 发送消息1.4 查看订阅消息 2. 事务2.1 事务的实现2.2 WATCH 命令的实现2.3 事务的 ACID 性质 最后 前言 参考资料&#xff1a;《Redis设计与实现 第二版》&#xff1b; 第三部分为独立功能…

AOF -- Redis 设计与实现

Redis 分别提供了 RDB 和 AOF 两种持久化机制&#xff1a; RDB 将数据库的快照&#xff08;snapshot&#xff09;以二进制的方式保存到磁盘中。AOF 则以协议文本的方式&#xff0c;将所有对数据库进行过写入的命令&#xff08;及其参数&#xff09;记录到 AOF 文件&#xff0c…

Redis设计与实现学习总结

Redis设计与实现学习总结 本文主要对Redis的设计和实现原理做了一个介绍很总结&#xff0c;有些东西我也介绍的不是很详细准确&#xff0c;尽量在自己的理解范围内把一些知识点和关键性技术做一个描述。如有错误&#xff0c;还望见谅&#xff0c;欢迎指出。 这篇文章主要还是参…

Redis的设计与实现(1):5种基本数据结构的底层实现

一、简单的动态字符串&#xff08;SDS) Redis没有直接使用C语言传统的字符串表示&#xff0c;而是自己构建了一种名为简单动态字符串&#xff08;simple dynamic string,SDS&#xff09;的抽象类型&#xff0c;并将SDS作为Redis默认的字符串表示。 在Redis里&#xff0c;C字符…

Redis设计与实现总结

本文总结自《Redis设计与实现》一书&#xff0c;只打算总结Redis底层数据结构的实现。Redis的使用参考我的另一篇笔记Redis操作指南。 1 Redis概览 Redis是一个C语言编写的开源、非关系型内存数据库。它底层属于单线程、全内存操作&#xff0c;提供对象共享、引用计数和对象回…

Redis设计与实现

文章目录 第一部分&#xff1a;内部数据结构简单动态字符串(simple dynamic string)双端链表字典跳跃表 第二部分&#xff1a;内存映射数据结构整数集合intset压缩列表 redis数据类型对象处理机制(redisObject)字符串string哈希表hash列表list集合set有续集zset 第四部分&#…

redis的设计与实现

redis的设计和实现 第一部分、数据结构与对象 一、简单动态字符串&#xff1a; 在大多数情况下redis只会使用c字符串作为字面量&#xff0c;在大多情况下&#xff0c;redis使用SDS作为字符串表示。 比起C字符串&#xff0c;SDS具有五种优点&#xff1a; SDS结构里面会有一…

虚拟IP注册Nacos的问题

虚拟IP注册Nacos的问题 问题&#xff1a; A服务器有两个网卡&#xff0c;网卡 lo 绑定了 127.0.0.1 和一个虚拟IP&#xff0c;网卡 eth0 绑定了本地公网IP和一个虚拟IP。同样B服务器的网卡也是相同的配置&#xff0c;A、B服务器拥有的虚拟IP都是同一个地址。 当将A、B服务器部…

天翼云高可用虚拟IP(HAVIP)实践

产品概述 天翼云高可用虚拟IP&#xff08;High-Availability Virtual IP Address&#xff0c;简称HAVIP&#xff09;是一种可用独立创建和删除的私有网络IP地址资源。通过在VIP CIDR中申请一个私有网络IP地址&#xff0c;然后与高可用软件&#xff08;如高可用软件Keepalived&…