Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions federatedscope/core/auxiliaries/data_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -650,9 +650,12 @@ def get_data(config):
] or config.data.type.startswith('graph_multi_domain'):
from federatedscope.gfl.dataloader import load_graphlevel_dataset
data, modified_config = load_graphlevel_dataset(config)
elif config.data.type.lower() == 'vertical_fl_data':
from federatedscope.vertical_fl.dataloader import load_vertical_data
data, modified_config = load_vertical_data(config, generate=True)
elif config.data.type.lower() == 'secure_lr_data':
from federatedscope.vertical.dataloader import load_data
data, modified_config = load_data(config, generate=True)
elif config.data.type.lower() == 'caesar_v_fl_data':
from federatedscope.vertical.dataloader import load_data
data, modified_config = load_data(config, generate=True)
elif 'movielens' in config.data.type.lower(
) or 'netflix' in config.data.type.lower():
from federatedscope.mf.dataloader import load_mf_dataset
Expand Down
16 changes: 12 additions & 4 deletions federatedscope/core/auxiliaries/worker_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ def get_client_cls(cfg):
from federatedscope.autotune.fedex import FedExClient
return FedExClient

if cfg.vertical.use:
from federatedscope.vertical_fl.worker import vFLClient
if cfg.secure_vertical.use:
from federatedscope.vertical.secure_LR.worker import vFLClient
return vFLClient

if cfg.caesar_vertical.use:
from federatedscope.vertical.caesar_v_fl.worker import vFLClient
return vFLClient

if cfg.federate.method.lower() in constants.CLIENTS_TYPE:
Expand Down Expand Up @@ -67,8 +71,12 @@ def get_server_cls(cfg):
import BackdoorServer
return BackdoorServer

if cfg.vertical.use:
from federatedscope.vertical_fl.worker import vFLServer
if cfg.secure_vertical.use:
from federatedscope.vertical.secure_LR.worker import vFLServer
return vFLServer

if cfg.caesar_vertical.use:
from federatedscope.vertical.caesar_v_fl.worker import vFLServer
return vFLServer

if cfg.federate.method.lower() in constants.SERVER_TYPE:
Expand Down
21 changes: 15 additions & 6 deletions federatedscope/core/configs/cfg_fl_setting.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,22 @@ def extend_fl_setting_cfg(cfg):
cfg.distribute.grpc_enable_http_proxy = False

# ---------------------------------------------------------------------- #
# Vertical FL related options (for demo)
# Secure_LR vertical FL related options (for demo)
# ---------------------------------------------------------------------- #
cfg.vertical = CN()
cfg.vertical.use = False
cfg.vertical.encryption = 'paillier'
cfg.vertical.dims = [5, 10]
cfg.vertical.key_size = 3072
cfg.secure_vertical = CN()
cfg.secure_vertical.use = False
cfg.secure_vertical.encryption = 'paillier'
cfg.secure_vertical.dims = [5, 10]
cfg.secure_vertical.key_size = 3072

# ---------------------------------------------------------------------- #
# caesar vertical FL related options (for demo)
# ---------------------------------------------------------------------- #
cfg.caesar_vertical = CN()
cfg.caesar_vertical.use = False
cfg.caesar_vertical.encryption = 'paillier'
cfg.caesar_vertical.dims = [5, 10]
cfg.caesar_vertical.key_size = 3072

# --------------- register corresponding check function ----------
cfg.register_cfg_check_fun(assert_fl_setting_cfg)
Expand Down
17 changes: 12 additions & 5 deletions federatedscope/core/secret_sharing/secret_sharing.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ class AdditiveSecretSharing(SecretSharing):
AdditiveSecretSharing class, which can split a number into frames and
recover it by summing up
"""
def __init__(self, shared_party_num, size=60):
def __init__(self, shared_party_num, size=20):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, setting size=20 is not secure here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about 50? I tried epsilon=1e4 and size=50, and the acc is 0.82. Making size larger, the acc will decrease.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why the acc would be affected by the size

super(SecretSharing, self).__init__()
assert shared_party_num > 1, "AdditiveSecretSharing require " \
"shared_party_num > 1"
self.shared_party_num = shared_party_num
self.maximum = 2**size
self.mod_number = 2 * self.maximum + 1
self.epsilon = 1e8
self.epsilon = 1e4
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 1e-4 enough for ensuring precise results?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, setting 1e-8 will not be better, and sometimes worse depending on the size below

self.mod_funs = np.vectorize(lambda x: x % self.mod_number)
self.float2fixedpoint = np.vectorize(self._float2fixedpoint)
self.fixedpoint2float = np.vectorize(self._fixedpoint2float)
Expand Down Expand Up @@ -73,16 +73,23 @@ def secret_reconstruct(self, secret_seq):
To recover the secret
"""
assert len(secret_seq) == self.shared_party_num
merge_model = secret_seq[0].copy()
merge_model = None
secret_seq = [np.asarray(x) for x in secret_seq]
if isinstance(merge_model, dict):
for key in merge_model:
for idx in range(len(secret_seq)):
if idx == 0:
merge_model[key] = secret_seq[idx][key]
merge_model[key] = secret_seq[idx][key].copy()
else:
merge_model[key] += secret_seq[idx][key]
merge_model[key] = self.fixedpoint2float(merge_model[key])

else:
for idx in range(len(secret_seq)):
if idx == 0:
merge_model = secret_seq[idx].copy()
else:
merge_model += secret_seq[idx]
merge_model = self.fixedpoint2float(merge_model)
return merge_model

def _float2fixedpoint(self, x):
Expand Down
18 changes: 18 additions & 0 deletions federatedscope/vertical/caesar_v_fl/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### Caesar Vertical Federated Learning
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can move this README.md to /federatedscope/vertical/ and merge it with that of secure_LR

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


We provide an example for seCure lArge-scalE SpArse logistic Regression (caesar) vertical federated learning, you can run with:
```bash
python3 ../../main.py --cfg caesar_v_fl.yaml
```

Implementation of caesar vertical FL refer to `When Homomorphic Encryption
Marries Secret Sharing: Secure Large-Scale Sparse Logistic Regression and
Applications in Risk Control` [Chen, et al., 2021]
(https://arxiv.org/abs/2008.08753)

You can specify customized configurations in `caesar_v_fl.yaml`, such as `data.type` and `federate.total_round_num`.


Note that FederatedScope only provide an `abstract_paillier`, user can refer to [pyphe](https://github.com/data61/python-paillier/blob/master/phe/paillier.py) for the detail implementation, or adopt other homomorphic encryption algorithms.

More support for vertical federated learning is coming soon! We really appreciate any contributions to FederatedScope !
1 change: 1 addition & 0 deletions federatedscope/vertical/caesar_v_fl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from federatedscope.vertical.Paillier.abstract_paillier import *
22 changes: 22 additions & 0 deletions federatedscope/vertical/caesar_v_fl/caesar_v_fl.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use_gpu: False
federate:
mode: standalone
client_num: 2
total_round_num: 30
model:
type: lr
use_bias: False
train:
optimizer:
lr: 0.001
data:
type: caesar_v_fl_data
batch_size: 50
caesar_vertical:
use: True
key_size: 256
trainer:
type: none
eval:
freq: 5
best_res_update_round_wise_key: test_loss
6 changes: 6 additions & 0 deletions federatedscope/vertical/caesar_v_fl/worker/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from federatedscope.vertical.caesar_v_fl.worker.vertical_client \
import vFLClient
from federatedscope.vertical.caesar_v_fl.worker.vertical_server \
import vFLServer

__all__ = ['vFLServer', 'vFLClient']
Loading