【隐私计算实训营】是蚂蚁集团隐语开源社区出品的线上课程,自实训营上线以来,获得行业内外广泛关注,吸引上千余名开发者报名参与。本次暑期夏令营课程中,除了最新上线的「联邦学习系列」,还包含了「隐私保护数据分析」和「隐私保护机器学习」,主题,小伙伴们可以根据需求自由选择报名期待和大家共同探索隐私计算的前沿技术!
隐私计算实训营「机器学习」:隐私计算实训营「机器学习」
隐私计算实训营「联邦学习」:隐私计算实训营「联邦学习」
隐私计算实训营「数据分析」:隐私计算实训营「数据分析」
1. 预处理和隐私求交
1.1 DataFrame 和 FedNdarray
DataFrame和FedNdarray是隐语中用于处理联邦数据的两个重要封装。
DataFrame
- 用于联邦表格数据的封装
- 由多个参与方的数据块构成
- 支持三种数据切分方式:
- 水平切分(HDataFrame API)
- 垂直切分(VDataFrame API)
- 混合切分(MixDataFrame API)
FedNdarray
- 联邦ndarray的封装
- 同样由多个参与方的数据块构成
- 支持水平和垂直切分
- 使用统一的API:FedNdarray
这两种数据结构都提供了读写API,方便直接使用。
DataFrame和FedNdarray的详细说明:
- DataFrame是一种类似于pandas DataFrame的数据结构,但专门用于联邦学习场景。它允许多方共同操作数据,而不需要直接共享原始数据。
- 水平切分指的是不同参与方拥有相同特征但不同样本的数据。
- 垂直切分指的是不同参与方拥有相同样本但不同特征的数据。
- 混合切分是水平和垂直切分的组合,适用于更复杂的数据分布场景。
1.2 预处理工具
隐语提供了多种预处理工具:
- 可以直接使用DataFrame API处理数据
- 使用
sf.preprocessing
包内的各类预处理组件
常见的预处理操作包括:
- 缺失值填充
- 标准化
安全提示:某些预处理算子会计算并公开用于辅助计算的统计值。在使用前,请仔细评估这些统计值是否包含隐私信息。
1.3 隐私求交(PSI)
隐私求交(PSI)的工作原理:
PSI允许两方在不泄露各自集合中其他元素的情况下,找出共同拥有的数据项。例如,两家银行可以使用PSI来确定共同的客户,而不需要披露各自的完整客户列表。PSI通常使用加密哈希函数和混淆技术来实现。
应用场景:
- 在垂直拆分场景中,常用于第一步的数据对齐
- 进一步用于数据分析或机器学习建模
隐语中PSI的两种使用方式:
- 使用
spu.psi_csv
等接口 - 使用
data.vertical.read_csv
接口
注:隐语支持多种PSI算法,可根据参与方数量、带宽、算力、数据不平衡度等因素选择合适的算法。
2. 决策树模型和线性回归模型
2.1 决策树模型
隐语支持多种决策树算法,适用于回归和二分类训练。
算法 | API | 场景 | 安全性 | 性能 |
---|---|---|---|---|
SS-XGB | secretflow.ml.boost.ss_xgb_v.Xgb | 垂直切分 | 可证安全 | 通信成本高,通常较慢 |
SecureBoost | secretflow.ml.boost.sgb_v.Sgb | 垂直切分 | 非可证安全 | 计算量大,通信量小,通常较快 |
水平XGBoost | secretflow.ml.boost.homo_boost.SFXgboost | 水平切分 | 非可证安全 | - |
2.2 线性回归模型
隐语提供了多种线性回归模型,适用于不同场景:
算法 | API | 场景 | 安全性 | 算法类型 | 性能特点 |
---|---|---|---|---|---|
SS-SGD | secretflow.ml.linear.SSRegression | 垂直切分 | 可证安全 | 线性回归、逻辑回归 | 通信量大,大带宽下速度快 |
HESS-SGD | secretflow.ml.linear.HESSLogisticRegression | 垂直切分 | 可证安全 | 逻辑回归 | 计算量大,网络受限情况下速度快 |
SS-GLM | secretflow.ml.linear.SSGLM | 垂直切分 | 可证安全 | 广义线性回归 | - |
混合联邦LR | secretflow.ml.linear.FlLogisticRegressionMix | 混合切分(2+n) | 非可证安全 | 逻辑回归 | - |
3. 神经网络算法
隐语提供了两种主要的神经网络算法,适用于不同的场景:
- 水平联邦学习:
secretflow.ml.nn.FLModel
- 垂直拆分学习:
secretflow.ml.nn.SLModel
安全提示:这两种算法都属于非可证安全算法,其安全性需要根据具体场景分析。可以通过安全聚合、差分隐私、稀疏化等安全加固组件来增强安全性。
3.1 水平联邦学习 (FLModel)
FLModel是一个通用范式,而非具体的模型或算法。主要特点:
- 支持TensorFlow和PyTorch两种后端
- 可以使用tf或torch原生方式编写模型代码
- 支持使用封装好的模型库,如torchvision和tf.keras.applications
FLModel提供了丰富的选项:
- 自定义数据加载器(支持DataFrame、文件、图片等)
- 选择内置或自定义的安全聚合算法
- 选择内置或自定义的联邦学习策略(优化训练效率、处理non-iid问题等)
- 选择训练后端(TensorFlow或PyTorch)
水平联邦学习中的安全聚合:
安全聚合是一种保护参与方模型更新隐私的技术。在每轮训练后,各参与方的模型更新会被加密,然后聚合。只有聚合后的结果才会被解密和应用,这样可以防止中央服务器或其他参与方推断出单个参与方的模型更新。
3.2 垂直拆分学习 (SLModel)
SLModel同样是一个通用范式,主要特点:
- 支持TensorFlow和PyTorch两种后端
- 模型被拆分成2份、3份或更多,分布在不同参与方
- 需要针对拆分学习架构重新设计模型结构
- 隐语提供了预先拆分好的模型库:
sf.ml.nn.applications
SLModel提供的选项:
- 自定义数据加载器(支持DataFrame、文件、图片等)
- 选择内置或自定义的通信优化算法(如稀疏化和量化压缩算法)
- 选择内置或自定义的垂直拆分策略(如加速训练的策略算法)
- 选择训练后端(TensorFlow或PyTorch)
垂直拆分学习中的通信优化:
在垂直拆分学习中,不同参与方负责模型的不同部分。这需要在前向和后向传播过程中频繁通信。通信优化技术,如梯度压缩和量化,可以显著减少通信开销。例如,可以只传输大于某个阈值的梯度值(稀疏化),或将浮点数梯度转换为较少位数的整数(量化)。
4. DataFrame实践
4.1 DataFrame
前置准备
初始化secretflow,创建alice、bob和carol三个参与方。
import secretflow as sf# In case you have a running secretflow runtime already.
sf.shutdown()sf.init(['alice', 'bob', 'carol'], address='local')
alice, bob, carol = sf.PYU('alice'), sf.PYU('bob'), sf.PYU('carol')
数据准备
我们使用 iris 作为示例数据集。
import pandas as pd
from sklearn.datasets import load_irisiris = load_iris(as_frame=True)
data = pd.concat([iris.data, iris.target], axis=1)
data
我们按照水平(特征相同)和垂直(样本相同)两种方式对数据进行切分.
# Horizontal partitioning.
h_alice, h_bob, h_carol = data.iloc[:40, :], data.iloc[40:100, :], data.iloc[100:, :]# Save to temporary files.
import tempfile
import ostemp_dir = tempfile.mkdtemp()h_alice_path = os.path.join(temp_dir, 'h_alice.csv')
h_bob_path = os.path.join(temp_dir, 'h_bob.csv')
h_carol_path = os.path.join(temp_dir, 'h_carol.csv')
h_alice.to_csv(h_alice_path, index=False)
h_bob.to_csv(h_bob_path, index=False)
h_carol.to_csv(h_carol_path, index=False)h_alice.head(), h_bob.head(), h_carol.head()
# Vertical partitioning.
v_alice, v_bob, v_carol = data.iloc[:, :2], data.iloc[:, 2:4], data.iloc[:, 4:]# Save to temporary files.
v_alice_path = os.path.join(temp_dir, 'v_alice.csv')
v_bob_path = os.path.join(temp_dir, 'v_bob.csv')
v_carol_path = os.path.join(temp_dir, 'v_carol.csv')
v_alice.to_csv(v_alice_path, index=False)
v_bob.to_csv(v_bob_path, index=False)
v_carol.to_csv(v_carol_path, index=False)v_alice, v_bob, v_carol
创建水平DataFrame
创建一个由水平切分数据组成的DataFrame。
💡原始数据仍然保持在数据拥有方本地,并不会出域。
作为演示,我们选择了安全聚合和spu安全比较。您可以参考 安全聚合 了解更多安全聚合方案,并选择适合您的安全策略。
from secretflow.data.horizontal import read_csv as h_read_csv
from secretflow.security.aggregation import SecureAggregator
from secretflow.security.compare import SPUComparator# The aggregator and comparator are respectively used to aggregate
# or compare data in subsequent data analysis operations.
aggr = SecureAggregator(device=alice, participants=[alice, bob, carol])spu = sf.SPU(sf.utils.testing.cluster_def(parties=['alice', 'bob', 'carol']))
comp = SPUComparator(spu)
hdf = h_read_csv({alice: h_alice_path, bob: h_bob_path, carol: h_carol_path},aggregator=aggr,comparator=comp,
)
创建垂直DataFrame
from secretflow.data.vertical import read_csv as v_read_csvvdf = v_read_csv({alice: v_alice_path, bob: v_bob_path, carol: v_carol_path})
数据分析
为了保护数据隐私,DataFrame不允许对原始数据进行查看。DataFrame提供了类似pandas的接口来方便用户分析数据。这些接口对水平和垂直切分数据都通用。
在以下操作中,原始数据仍然保持在数据拥有方本地,并不会传输出域。
hdf.columns
vdf.columns
获取最小值,可以看到和原始数据一致。
print('Horizontal df:\n', hdf.min())
print('\nVertical df:\n', vdf.min())
print('\nPandas:\n', data.min())
查看比如最大值、平均值、数量等信息。
hdf.max()
vdf.max()
hdf.mean(numeric_only=True)
vdf.mean(numeric_only=True)
hdf.count()
vdf.count()
选取数据
hdf_part = hdf[['sepal length (cm)', 'target']]
hdf_part.mean(numeric_only=True)
vdf_part = hdf[['sepal width (cm)', 'target']]
vdf_part.mean(numeric_only=True)
修改数据
hdf_copy = hdf.copy()
print('Min of target: ', hdf_copy['target'].min()[0])
print('Max of target: ', hdf_copy['target'].max()[0])# Set target to 1。
hdf_copy['target'] = 1# You can see that the value of target has become 1.
print('Min of target: ', hdf_copy['target'].min()[0])
print('Max of target: ', hdf_copy['target'].max()[0])
vdf_copy = vdf.copy()
print('Min of sepal width (cm): ', vdf_copy['sepal width (cm)'].min()[0])
print('Max of sepal width (cm): ', vdf_copy['sepal width (cm)'].max()[0])# Set sepal width (cm) to 20。
vdf_copy['sepal width (cm)'] = 20# You can see that the value of sepal width (cm) has become 20.
print('Min of sepal width (cm): ', vdf_copy['sepal width (cm)'].min()[0])
print('Max of sepal width (cm): ', vdf_copy['sepal width (cm)'].max()[0])
5. 预处理实践
前置准备
初始化隐语,创建alice和bob两个参与方。
import secretflow as sf# Check the version of your SecretFlow
print('The version of SecretFlow: {}'.format(sf.__version__))# In case you have a running secretflow runtime already.
sf.shutdown()sf.init(['alice', 'bob'], address='local')
alice = sf.PYU('alice')
bob = sf.PYU('bob')
数据准备
我们使用 iris 作为示例数据集。
import pandas as pd
from sklearn.datasets import load_irisiris = load_iris(as_frame=True)
data = pd.concat([iris.data, iris.target], axis=1)# In order to facilitate the subsequent display,
# here we first set some data to None.
data.iloc[1, 1] = None
data.iloc[100, 1] = None# Restore target to its original name.
data['target'] = data['target'].map({0: 'setosa', 1: 'versicolor', 2: 'virginica'})
data
创建垂直DataFrame。
import tempfile
from secretflow.data.vertical import read_csv as v_read_csv# Vertical partitioning.
v_alice, v_bob = data.iloc[:, :2], data.iloc[:, 2:]# Save to temprary files.
_, alice_path = tempfile.mkstemp()
_, bob_path = tempfile.mkstemp()
v_alice.to_csv(alice_path, index=False)
v_bob.to_csv(bob_path, index=False)df = v_read_csv({alice: alice_path, bob: bob_path})
预处理
隐语提供了缺失值填充、标准化、分类数据编码、离散化等多种预处理功能,其使用方式和sklearn的预处理一致。
缺失值填充
DataFrame提供了fillna方法,可以和pandas一样对缺失值进行填充。
# Before filling, the sepal width (cm) is missing in two positions.
df.count()['sepal width (cm)']# Fill sepal width (cm) with 10.
df.fillna(value={'sepal width (cm)': 10}).count()['sepal width (cm)']
标准化
将特征缩放到某个范围。
隐语提供了 MinMaxScaler 用于把特征缩放到最大和最小值之间。MinMaxScaler的输入和输出形式均为DataFrame。
下面是将 sepal length (cm) 缩放到[0, 1]范围的示例。
from secretflow.preprocessing import MinMaxScalerscaler = MinMaxScaler()scaled_sepal_len = scaler.fit_transform(df['sepal length (cm)'])print('Min: ', scaled_sepal_len.min())
print('Max: ', scaled_sepal_len.max())
方差缩放
隐语提供了 StandardScaler 进行方差缩放。StandardScaler的输入和输出行为均为DataFrame。
下面是一个将 sepal length (cm) 进行方差缩放的例子。
from secretflow.preprocessing import StandardScalerscaler = StandardScaler()scaled_sepal_len = scaler.fit_transform(df['sepal length (cm)'])print('Min: ', scaled_sepal_len.min())
print('Max: ', scaled_sepal_len.max())
独热编码
隐语提供了 OneHotEncoder 用作独热编码。 OneHotEncoder的输入和输出行为均为DataFrame。
下面是一个对target列进行独热编码的例子。
from secretflow.preprocessing import OneHotEncoderonehot_encoder = OneHotEncoder()
onehot_target = onehot_encoder.fit_transform(df['target'])print('Columns: ', onehot_target.columns)
print('Min: \n', onehot_target.min())
print('Max: \n', onehot_target.max())
标签编码
隐语提供了 LabelEncoder 用作将标签列编码至[0, 类别数 - 1]。LabelEncoder的输入输出形式均为DataFrame。
下面是一个对target列进行标签编码的例子。
from secretflow.preprocessing import LabelEncoderlabel_encoder = LabelEncoder()
encoded_label = label_encoder.fit_transform(df['target'])print('Columns: ', encoded_label.columns)
print('Min: \n', encoded_label.min())
print('Max: \n', encoded_label.max())
离散化
隐语提供了 KBinsDiscretizer 用作将连续数据切分成离散值。KBinsDiscretizer的输入输出形式均为DataFrame。
下面是一个将 petal length (cm) 切分成5个分桶的例子。
from secretflow.preprocessing import KBinsDiscretizerestimator = KBinsDiscretizer(n_bins=5)
binned_petal_len = estimator.fit_transform(df['petal length (cm)'])print('Min: \n', binned_petal_len.min())
print('Max: \n', binned_petal_len.max())