垂直联邦XGB (SecureBoost)#

以下代码仅供演示。出于系统安全考虑,请 不要 直接用于生产。

欢迎来到SecureBoost教程!

在本教程中,我们将探索如何使用隐语的树模型能力,使用SecureBoost算法执行垂直联邦学习。SecureBoost是一种经典算法,它优先保护垂直分区数据集中的标签信息。它使用同态加密技术实现标签加密和密文中的关键树增强步骤执行。其结果是由PYU对象组成的分布式提升树模型,每个参与方仅了解自己的拆分点。该实现利用HEU和PYU设备实现高性能。

让我们深入了解细节,学习如何使用隐语进行SecureBoost!

设备设置#

与其他算法类似,设置安全集群和指定设备对于SecureBoost的实现是必要的。

特别是,必须指定一个HEU设备以确保SecureBoost中标签的加密和敏感信息的保护。

[1]:
import spu
from sklearn.metrics import roc_auc_score

import secretflow as sf
from secretflow.data import FedNdarray, PartitionWay
from secretflow.device.driver import reveal, wait
from secretflow.ml.boost.sgb_v import Sgb
from secretflow.ml.boost.sgb_v.model import load_model
[2]:
alice_ip = '127.0.0.1'
bob_ip = '127.0.0.1'
ip_party_map = {bob_ip: 'bob', alice_ip: 'alice'}

_system_config = {'lineage_pinning_enabled': False}
sf.shutdown()
# init cluster
sf.init(
    ['alice', 'bob'],
    address='local',
    _system_config=_system_config,
    object_store_memory=5 * 1024 * 1024 * 1024,
)

# SPU settings
cluster_def = {
    'nodes': [
        {'party': 'alice', 'id': 'local:0', 'address': alice_ip + ':12945'},
        {'party': 'bob', 'id': 'local:1', 'address': bob_ip + ':12946'},
        # {'party': 'carol', 'id': 'local:2', 'address': '127.0.0.1:12347'},
    ],
    'runtime_config': {
        # SEMI2K support 2/3 PC, ABY3 only support 3PC, CHEETAH only support 2PC.
        # pls pay attention to size of nodes above. nodes size need match to PC setting.
        'protocol': spu.spu_pb2.SEMI2K,
        'field': spu.spu_pb2.FM128,
    },
}

# HEU settings
heu_config = {
    'sk_keeper': {'party': 'alice'},
    'evaluators': [{'party': 'bob'}],
    'mode': 'PHEU',
    'he_parameters': {
        # ou is a fast encryption schema that is as secure as paillier.
        'schema': 'ou',
        'key_pair': {
            'generate': {
                # bit size should be 2048 to provide sufficient security.
                'bit_size': 2048,
            },
        },
    },
    'encoding': {
        'cleartext_type': 'DT_I32',
        'encoder': "IntegerEncoder",
        'encoder_args': {"scale": 1},
    },
}
2023-04-19 13:56:51,630 INFO worker.py:1544 -- Started a local Ray instance. View the dashboard at http://127.0.0.1:8265 
[3]:
alice = sf.PYU('alice')
bob = sf.PYU('bob')
heu = sf.HEU(heu_config, cluster_def['runtime_config']['field'])
(raylet) /home/zoupeicheng.zpc/miniconda3/envs/py38/lib/python3.8/site-packages/ray/dashboard/modules/reporter/reporter_agent.py:56: UserWarning: `gpustat` package is not installed. GPU monitoring is not available. To have full functionality of the dashboard please install `pip install ray[default]`.)
(raylet)   warnings.warn(

数据准备#

我们将准备一个垂直数据集。

[4]:
from sklearn.datasets import load_breast_cancer

ds = load_breast_cancer()
x, y = ds['data'], ds['target']

v_data = FedNdarray(
    {
        alice: (alice(lambda: x[:, :15])()),
        bob: (bob(lambda: x[:, 15:])()),
    },
    partition_way=PartitionWay.VERTICAL,
)
label_data = FedNdarray(
    {alice: (alice(lambda: y)())},
    partition_way=PartitionWay.VERTICAL,
)

参数准备#

[5]:
params = {
    'num_boost_round': 5,
    'max_depth': 5,
    # about 13 bin numbers
    'sketch_eps': 0.08,
    # use 'linear' if want to do regression
    # for classification, currently only supports binary classfication
    'objective': 'logistic',
    'reg_lambda': 0.3,
    'subsample': 0.9,
    'colsample_by_tree': 0.9,
    # pre-pruning parameter. splits with gain value less than it will be pruned.
    'gamma': 1,
}

运行 Sgb#

我们使用 heu 设备创建一个 Sgb 对象,并拟合数据。

[6]:
sgb = Sgb(heu)
model = sgb.train(params, v_data, label_data)
INFO:root:Create proxy actor <class 'secretflow.ml.boost.sgb_v.core.split_tree_trainer.split_tree_trainer.SplitTreeTrainer'> with party alice.
INFO:root:Create proxy actor <class 'secretflow.ml.boost.sgb_v.core.split_tree_trainer.split_tree_trainer.SplitTreeTrainer'> with party bob.
INFO:root:Create proxy actor <class 'secretflow.ml.boost.sgb_v.core.label_holder.label_holder.LabelHolder'> with party alice.
INFO:root:global_setup time 1.6802808750071563s
(LabelHolder pid=3311307) INFO:jax._src.xla_bridge:Remote TPU is not linked into jax; skipping remote TPU.
(LabelHolder pid=3311307) INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu_driver': Could not initialize backend 'tpu_driver'
(LabelHolder pid=3311307) INFO:jax._src.xla_bridge:Unable to initialize backend 'cuda': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
(LabelHolder pid=3311307) INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
(LabelHolder pid=3311307) INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INVALID_ARGUMENT: TpuPlatform is not available.
(LabelHolder pid=3311307) INFO:jax._src.xla_bridge:Unable to initialize backend 'plugin': xla_extension has no attributes named get_plugin_device_client. Compile TensorFlow with //tensorflow/compiler/xla/python:enable_plugin_device set to true (defaults to false) to enable this.
(LabelHolder pid=3311307) WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
(HEUSkKeeper pid=3309706) [2023-04-19 13:57:02.080] [info] [thread_pool.cc:30] Create a fixed thread pool with size 63
(HEUEvaluator pid=3311083) [2023-04-19 13:57:02.127] [info] [thread_pool.cc:30] Create a fixed thread pool with size 63
INFO:root:epoch 0 time 3.0825682659633458s
(_run pid=3303716) [2023-04-19 13:57:02.636] [info] [thread_pool.cc:30] Create a fixed thread pool with size 63
(_run pid=3303717) [2023-04-19 13:57:02.630] [info] [thread_pool.cc:30] Create a fixed thread pool with size 63
INFO:root:epoch 1 time 0.5092060890165158s
INFO:root:epoch 2 time 0.4486289119813591s
INFO:root:epoch 3 time 0.47898129001259804s
INFO:root:epoch 4 time 0.3945654829731211s

模型评估#

现在我们可以将模型输出与真实标签进行比较。

[7]:
yhat = model.predict(v_data)
yhat = reveal(yhat)
print(f"auc: {roc_auc_score(y, yhat)}")
(_run pid=3303717) INFO:jax._src.xla_bridge:Remote TPU is not linked into jax; skipping remote TPU.
(_run pid=3303717) INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu_driver': Could not initialize backend 'tpu_driver'
(_run pid=3303717) INFO:jax._src.xla_bridge:Unable to initialize backend 'cuda': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
(_run pid=3303717) INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
(_run pid=3303717) INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INVALID_ARGUMENT: TpuPlatform is not available.
(_run pid=3303717) INFO:jax._src.xla_bridge:Unable to initialize backend 'plugin': xla_extension has no attributes named get_plugin_device_client. Compile TensorFlow with //tensorflow/compiler/xla/python:enable_plugin_device set to true (defaults to false) to enable this.
(_run pid=3303717) WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
INFO:jax._src.xla_bridge:Remote TPU is not linked into jax; skipping remote TPU.
INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu_driver': Could not initialize backend 'tpu_driver'
INFO:jax._src.xla_bridge:Unable to initialize backend 'cuda': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
INFO:jax._src.xla_bridge:Unable to initialize backend 'rocm': module 'jaxlib.xla_extension' has no attribute 'GpuAllocatorConfig'
INFO:jax._src.xla_bridge:Unable to initialize backend 'tpu': INVALID_ARGUMENT: TpuPlatform is not available.
INFO:jax._src.xla_bridge:Unable to initialize backend 'plugin': xla_extension has no attributes named get_plugin_device_client. Compile TensorFlow with //tensorflow/compiler/xla/python:enable_plugin_device set to true (defaults to false) to enable this.
WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
auc: 0.9994979123724961

模型保存和加载#

我们现在可以保存模型, 并在以后使用它。请注意,模型是分布式的,我们将保存到多个参与方,并从多个参与方中加载。

让我们先定义路径。

[8]:
# each participant party needs a location to store
saving_path_dict = {
    # in production we may use remote oss, for example.
    device: "./" + device.party
    for device in v_data.partitions.keys()
}

然后让我们保存模型。

[9]:
r = model.save_model(saving_path_dict)
wait(r)

现在您可以在之前指定的位置检查文件。

最后,让我们加载模型并进行一次检查。

[10]:
# alice is our label holder
model_loaded = load_model(saving_path_dict, alice)
fed_yhat_loaded = model_loaded.predict(v_data, alice)
yhat_loaded = reveal(fed_yhat_loaded.partitions[alice])

assert (
    yhat == yhat_loaded
).all(), "loaded model predictions should match original, yhat {} vs yhat_loaded {}".format(
    yhat, yhat_loaded
)

结论#

恭喜您完成了本教程!

在本教程中,我们学习了如何在隐语中使用树模型进行训练,并探索了 SecureBoost,这是一种专门为垂直分区数据集设计的高性能提升算法。SecureBoost 类似于 XGBoost,但重点关注在垂直学习场景中保护敏感标签。通过利用同态加密和 PYUObjects,SecureBoost 允许我们训练强大的分布式森林模型,同时保护数据的隐私和安全。

感谢您参与本教程,希望您觉得它充满启发和帮助!