IID(独立同分布):这里的数据被假设为独立和同分布的。也就是说,每个数据点都是从同一分布中随机、独立地抽取的。在实际操作中,这通常意味着数据在所有用户之间平均分配。
def cifar_iid(dataset, num_users):
"""
Sample I.I.D. client data from CIFAR10 dataset
:param dataset:
:param num_users:
:return: dict of image index
"""
num_items = int(len(dataset)/num_users)
dict_users, all_idxs = {}, [i for i in range(len(dataset))]
for i in range(num_users):
dict_users[i] = set(np.random.choice(all_idxs, num_items,
replace=False))
all_idxs = list(set(all_idxs) - dict_users[i])
return dict_users
输入参数
dataset
:该数据集,可能是CIFAR-10或CIFAR-100中的训练或测试数据集。num_users
:要将数据分配给的用户数量。
输出
- 返回:一个字典,其中包含了每个用户和他们分配到的数据索引。
过程
-
计算每个用户的项数:通过将数据集的总长度除以用户数来计算每个用户应该得到的数据项数。
-
初始化变量:
dict_users
:空字典,用于存储每个用户及其相应的数据索引。all_idxs
:包含数据集中所有可能索引的列表。
-
分配数据给用户:
- 对于
num_users
中的每个用户,进行以下操作:- 从
all_idxs
中随机选择num_items
个不重复的索引。 - 将选定的索引添加到
dict_users
字典中,其中键是用户的ID,值是索引集合。 - 从
all_idxs
中移除已分配的索引,以确保下一个用户得到的是不同的数据。
- 从
- 对于
示例
假设有一个包含1000个项目的数据集,并且有10个用户。那么 num_items
将被设置为100(即1000/10),每个用户将被随机分配100个项目。
通过此过程,确保了每个用户获得的数据都是从整个数据集的同一分布中随机抽取的,因此是IID的。这种分割方法通常用于模拟数据在不同用户之间的均匀分布,并且适用于许多分散式和联邦学习场景。
附:set(np.random.choice(all_idxs, num_items, replace=False))解释
-
np.random.choice(all_idxs, num_items, replace=False)
:all_idxs
是一个包含可能索引的列表。num_items
是你想从该列表中随机选择的项数。replace=False
表示选择是不放回的,也就是说每个索引只能被选择一次。
因此,这一行代码会从
all_idxs
中随机选择num_items
个不重复的项。 -
set(...)
:这将所选的索引转换为集合。集合是一种不包含重复元素的数据结构,但在这种情况下,由于已经设置了replace=False
,所以已经确保了没有重复项。
综合来看,该代码行的目的是从 all_idxs
列表中随机选择 num_items
个不重复的索引,并将这些索引存储为集合。
这在分配数据集给不同用户的场景下很有用,其中每个用户都获得了一组不同的、不重复的数据集的一部分。集合的使用提供了快速查找和删除操作,这在更新 all_idxs
以排除已分配索引时可能是有益的。
附:all_idxs = list(set(all_idxs) - dict_users[i])解释
-
dict_users[i]
:从dict_users
字典中获取与当前用户(键为i
)关联的索引集合。 -
set(all_idxs) - dict_users[i]
:将all_idxs
列表转换为集合,并从中减去与当前用户关联的索引集合。集合减法操作将从第一个集合中移除在第二个集合中找到的所有元素。 -
list(...)
:最后,将结果集合转换回列表。
总体来说,该行代码的目的是更新 all_idxs
列表,以便从中删除已分配给当前用户的索引。这确保了下一个用户将从尚未分配给其他用户的索引中进行选择,因此每个用户都获得了一组独特的索引。
这是在联邦学习和分布式系统中分配不重复数据的一种常用方法,确保了每个用户或节点获得的数据是唯一的,而不会与其他用户或节点重叠。