├── publications ├── PrADA │ ├── models │ │ ├── __init__.py │ │ ├── model_utils.py │ │ ├── classifier.py │ │ └── test_interaction_feature.py │ ├── data_process │ │ ├── __init__.py │ │ ├── census_process │ │ │ ├── __init__.py │ │ │ ├── utils.py │ │ │ └── census_data_creation_config.py │ │ ├── ppd_process │ │ │ ├── __init__.py │ │ │ ├── ppd_data_creation_config.py │ │ │ └── ppd_prepare_data_train_test.py │ │ └── data_process_utils.py │ ├── datasets │ │ ├── __init__.py │ │ ├── census_dataset.py │ │ ├── census_dataloader.py │ │ └── ppd_dataloader.py │ ├── experiments │ │ ├── __init__.py │ │ ├── ppd_loan │ │ │ ├── __init__.py │ │ │ ├── train_ppd_no_adaptation.py │ │ │ ├── train_ppd_no_fg_target_finetune.py │ │ │ ├── test_ppd_target.py │ │ │ ├── train_ppd_fg_target_finetune.py │ │ │ ├── train_config.py │ │ │ ├── train_ppd_no_fg_adapt_pretrain.py │ │ │ └── train_ppd_fg_adapt_pretrain.py │ │ ├── income_census │ │ │ ├── __init__.py │ │ │ ├── tsne_config.py │ │ │ ├── train_census_no_adaptation.py │ │ │ ├── train_census_no_fg_target_finetune.py │ │ │ ├── train_census_fg_target_finetune.py │ │ │ ├── test_census_target.py │ │ │ ├── train_config.py │ │ │ ├── produce_census_tsne_data.py │ │ │ └── draw_census_tsne_graph.py │ │ └── test_utils.py │ ├── figs │ │ └── prada.png │ └── statistics_utils.py ├── FedCG │ ├── figs │ │ ├── fedcg.png │ │ ├── clip_image002.png │ │ ├── clip_image006.jpg │ │ ├── clip_image008.jpg │ │ ├── clip_image010.jpg │ │ ├── clip_image012.png │ │ └── clip_image014.jpg │ ├── record.py │ ├── utils.py │ ├── run.sh │ ├── servers │ │ ├── fedsplit.py │ │ ├── fedavg.py │ │ ├── fedprox.py │ │ └── fedgen.py │ ├── main.py │ ├── config.py │ └── README.md ├── FedIPR │ └── figs │ │ ├── fig1.png │ │ ├── fig2.png │ │ ├── fig3.png │ │ ├── fig4.png │ │ ├── fig5.png │ │ └── fig6.png ├── ss_vfnas │ ├── figs │ │ ├── v2x.png │ │ └── example.png │ ├── visualize.py │ ├── .gitignore │ ├── models │ │ ├── manual_k_party_chexpert.py │ │ └── manual_k_party.py │ ├── architects │ │ ├── architect_two_party.py │ │ ├── architect_k_party.py │ │ ├── architect.py │ │ ├── architect_k_party_milenas.py │ │ └── architect_two_party_preg.py │ ├── README.md │ ├── dp_utils.py │ ├── test.py │ ├── operations.py │ ├── utils.py │ └── genotypes.py └── No-Free-Lunch­-Theorem-FL │ └── figs │ ├── tfl.png │ ├── hist.png │ ├── title.png │ ├── diagram.jpg │ └── framework.png ├── datasets ├── federated_object_detection_benchmark │ ├── data │ │ ├── __init__.py │ │ ├── custom │ │ │ ├── classes.names │ │ │ └── train.txt │ │ ├── data_utils.py │ │ └── dataset.py │ ├── utils │ │ ├── __init__.py │ │ ├── augmentations.py │ │ ├── array_tool.py │ │ ├── model_dump.py │ │ ├── parse_config.py │ │ ├── config.py │ │ └── datasets.py │ ├── model │ │ ├── utils │ │ │ ├── __init__.py │ │ │ └── nms │ │ │ │ ├── __init__.py │ │ │ │ ├── build.py │ │ │ │ ├── _nms_gpu_post_py.py │ │ │ │ └── _nms_gpu_post.pyx │ │ ├── __init__.py │ │ └── roi_module.py │ ├── weights │ │ └── download_weights.sh │ ├── config │ │ ├── custom.data │ │ ├── coco.data │ │ └── yolov3-tiny.cfg │ ├── requirements.txt │ ├── stop.sh │ ├── run.sh │ ├── run_server.sh │ ├── experiments │ │ └── log_formatter.py │ ├── README.md │ └── Dataset_description.md └── Fed_Multiview_Gen │ ├── example.png │ ├── phong.blend │ └── README.md ├── fl_trend ├── figs │ ├── gradsec │ ├── Gradsec.png │ ├── ResilientEI.png │ ├── paper_count_table.png │ ├── Security_conf_fl_topics.png │ └── system_conf_fl_topics.png ├── top_conf_figs │ ├── top_ai_conf_fl_paper_trend.png │ ├── system_comm_conf_fl_paper_count.png │ └── top_security_conf_fl_paper_trend.png ├── fl_paper_accepted_ins_system_and_security_conferences.pdf └── README.md ├── DISCLAIMER ├── .gitignore └── CONTRIBUTING.md /publications/PrADA/models/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /publications/PrADA/data_process/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /publications/PrADA/datasets/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/ppd_loan/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /publications/PrADA/data_process/census_process/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /publications/PrADA/data_process/ppd_process/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/model/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fl_trend/figs/gradsec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/figs/gradsec -------------------------------------------------------------------------------- /fl_trend/figs/Gradsec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/figs/Gradsec.png -------------------------------------------------------------------------------- /fl_trend/figs/ResilientEI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/figs/ResilientEI.png -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/model/__init__.py: -------------------------------------------------------------------------------- 1 | from model.faster_rcnn_vgg16 import FasterRCNNVGG16 2 | -------------------------------------------------------------------------------- /publications/FedCG/figs/fedcg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedCG/figs/fedcg.png -------------------------------------------------------------------------------- /publications/FedIPR/figs/fig1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedIPR/figs/fig1.png -------------------------------------------------------------------------------- /publications/FedIPR/figs/fig2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedIPR/figs/fig2.png -------------------------------------------------------------------------------- /publications/FedIPR/figs/fig3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedIPR/figs/fig3.png -------------------------------------------------------------------------------- /publications/FedIPR/figs/fig4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedIPR/figs/fig4.png -------------------------------------------------------------------------------- /publications/FedIPR/figs/fig5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedIPR/figs/fig5.png -------------------------------------------------------------------------------- /publications/FedIPR/figs/fig6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedIPR/figs/fig6.png -------------------------------------------------------------------------------- /publications/PrADA/figs/prada.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/PrADA/figs/prada.png -------------------------------------------------------------------------------- /fl_trend/figs/paper_count_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/figs/paper_count_table.png -------------------------------------------------------------------------------- /publications/ss_vfnas/figs/v2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/ss_vfnas/figs/v2x.png -------------------------------------------------------------------------------- /datasets/Fed_Multiview_Gen/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/datasets/Fed_Multiview_Gen/example.png -------------------------------------------------------------------------------- /datasets/Fed_Multiview_Gen/phong.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/datasets/Fed_Multiview_Gen/phong.blend -------------------------------------------------------------------------------- /publications/ss_vfnas/figs/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/ss_vfnas/figs/example.png -------------------------------------------------------------------------------- /fl_trend/figs/Security_conf_fl_topics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/figs/Security_conf_fl_topics.png -------------------------------------------------------------------------------- /fl_trend/figs/system_conf_fl_topics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/figs/system_conf_fl_topics.png -------------------------------------------------------------------------------- /publications/FedCG/figs/clip_image002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedCG/figs/clip_image002.png -------------------------------------------------------------------------------- /publications/FedCG/figs/clip_image006.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedCG/figs/clip_image006.jpg -------------------------------------------------------------------------------- /publications/FedCG/figs/clip_image008.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedCG/figs/clip_image008.jpg -------------------------------------------------------------------------------- /publications/FedCG/figs/clip_image010.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedCG/figs/clip_image010.jpg -------------------------------------------------------------------------------- /publications/FedCG/figs/clip_image012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedCG/figs/clip_image012.png -------------------------------------------------------------------------------- /publications/FedCG/figs/clip_image014.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/FedCG/figs/clip_image014.jpg -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/model/utils/nms/__init__.py: -------------------------------------------------------------------------------- 1 | from model.utils.nms.non_maximum_suppression import non_maximum_suppression -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/weights/download_weights.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | wget -c https://pjreddie.com/media/files/darknet53.conv.74 3 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/data/custom/classes.names: -------------------------------------------------------------------------------- 1 | basket 2 | carton 3 | chair 4 | electrombile 5 | gastank 6 | sunshade 7 | table 8 | -------------------------------------------------------------------------------- /publications/No-Free-Lunch­-Theorem-FL/figs/tfl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/No-Free-Lunch­-Theorem-FL/figs/tfl.png -------------------------------------------------------------------------------- /fl_trend/top_conf_figs/top_ai_conf_fl_paper_trend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/top_conf_figs/top_ai_conf_fl_paper_trend.png -------------------------------------------------------------------------------- /publications/No-Free-Lunch­-Theorem-FL/figs/hist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/No-Free-Lunch­-Theorem-FL/figs/hist.png -------------------------------------------------------------------------------- /publications/No-Free-Lunch­-Theorem-FL/figs/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/No-Free-Lunch­-Theorem-FL/figs/title.png -------------------------------------------------------------------------------- /publications/No-Free-Lunch­-Theorem-FL/figs/diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/No-Free-Lunch­-Theorem-FL/figs/diagram.jpg -------------------------------------------------------------------------------- /fl_trend/top_conf_figs/system_comm_conf_fl_paper_count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/top_conf_figs/system_comm_conf_fl_paper_count.png -------------------------------------------------------------------------------- /publications/No-Free-Lunch­-Theorem-FL/figs/framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/publications/No-Free-Lunch­-Theorem-FL/figs/framework.png -------------------------------------------------------------------------------- /fl_trend/top_conf_figs/top_security_conf_fl_paper_trend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/top_conf_figs/top_security_conf_fl_paper_trend.png -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/config/custom.data: -------------------------------------------------------------------------------- 1 | classes= 7 2 | train=data/custom/train.txt 3 | valid=data/custom/valid.txt 4 | names=data/custom/classes.names 5 | -------------------------------------------------------------------------------- /fl_trend/fl_paper_accepted_ins_system_and_security_conferences.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FederatedAI/research/HEAD/fl_trend/fl_paper_accepted_ins_system_and_security_conferences.pdf -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/config/coco.data: -------------------------------------------------------------------------------- 1 | classes= 80 2 | train=data/coco/trainvalno5k.txt 3 | valid=data/coco/5k.txt 4 | names=data/coco.names 5 | backup=backup/ 6 | eval=coco 7 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | torchvision 3 | matplotlib 4 | terminaltables 5 | pillow 6 | tqdm 7 | sklearn 8 | socketIO_client 9 | flask 10 | flask_socketio 11 | scikit_image 12 | torchnet 13 | scipy 14 | cupy -------------------------------------------------------------------------------- /publications/PrADA/models/model_utils.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | 3 | 4 | def init_weights(m): 5 | if type(m) == nn.Linear: 6 | nn.init.kaiming_normal_(m.weight) 7 | # nn.init.xavier_uniform(m.weight) 8 | # m.bias.data.fill_(0.01) 9 | -------------------------------------------------------------------------------- /publications/PrADA/data_process/census_process/utils.py: -------------------------------------------------------------------------------- 1 | 2 | def bucketized_age(age): 3 | age_threshold = [18, 25, 30, 35, 40, 45, 50, 55, 60, 65] 4 | index = 0 5 | for t in age_threshold: 6 | if age < t: 7 | return index 8 | index += 1 9 | return index -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/tsne_config.py: -------------------------------------------------------------------------------- 1 | tsne_embedding_creation = { 2 | "tsne_embedding_data_dir": "YOUR_ORIGINAL_DATA_DIR/tsne_emb/", 3 | "tsne_graph_output_dir": "YOUR_GRAPH_OUTPUT_DATA_DIR/output/", 4 | "apply_adaptation": True, 5 | "using_interaction": False 6 | } 7 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/utils/augmentations.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn.functional as F 3 | import numpy as np 4 | 5 | 6 | def horisontal_flip(images, targets): 7 | images = torch.flip(images, [-1]) 8 | targets[:, 2] = 1 - targets[:, 2] 9 | return images, targets 10 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DATASET=$1 3 | MODEL=$2 4 | if [ ! -n "$DATASET" ];then 5 | echo "Please input dataset" 6 | exit 7 | fi 8 | if [ ! -n "$MODEL" ];then 9 | echo "Please input model" 10 | exit 11 | fi 12 | ps -ef | grep ${DATASET}/${MODEL} | grep -v grep | awk '{print $2}' | xargs kill -9 13 | -------------------------------------------------------------------------------- /publications/PrADA/data_process/census_process/census_data_creation_config.py: -------------------------------------------------------------------------------- 1 | census_data_creation = { 2 | "original_data_dir": "YOUR_ORIGINAL_DATA_DIR/census/", 3 | "processed_data_dir": "YOUR_ORIGINAL_DATA_DIR/processed/", 4 | "train_data_file_name": "census-income.data", 5 | "test_data_file_name": "census-income.test", 6 | "positive_sample_ratio": 0.04, 7 | "number_target_samples": 4000, 8 | "data_tag": "all4000pos004" 9 | } 10 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/model/utils/nms/build.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.extension import Extension 3 | from Cython.Distutils import build_ext 4 | import numpy 5 | 6 | ext_modules = [Extension("_nms_gpu_post", ["_nms_gpu_post.pyx"], 7 | include_dirs=[numpy.get_include()])] 8 | setup( 9 | name="Hello pyx", 10 | cmdclass={'build_ext': build_ext}, 11 | ext_modules=ext_modules 12 | ) 13 | -------------------------------------------------------------------------------- /publications/PrADA/data_process/data_process_utils.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from sklearn.utils import shuffle 3 | 4 | 5 | def save_df_data(df_data, file_full_name): 6 | df_data.to_csv(file_full_name, index=False) 7 | print(f"[INFO] save data with shape {df_data.shape} to {file_full_name}") 8 | 9 | 10 | def combine_src_tgt_data(df_src_data, df_tgt_data): 11 | df_all_data = pd.concat((df_src_data, df_tgt_data), axis=0) 12 | df_all_data = shuffle(df_all_data) 13 | return df_all_data 14 | -------------------------------------------------------------------------------- /publications/PrADA/data_process/ppd_process/ppd_data_creation_config.py: -------------------------------------------------------------------------------- 1 | ppd_data_creation = { 2 | "original_data_dir": "YOUR ORIGINAL DATA DIR", 3 | "processed_data_dir": "YOUR PROCESSED DATA DIR", 4 | # "original_ppd_data_file_name": "PPD_data_all.csv", 5 | # "original_ppd_datetime_file_name": "PPD_data_datetime.csv", 6 | "meta_data_full_name": "./PPD_meta_data.json", 7 | "number_train_samples": 55000, 8 | "number_target_samples": 4000, 9 | "positive_samples_ratio": 0.04, 10 | "data_tag": "all4000pos004" 11 | } 12 | -------------------------------------------------------------------------------- /fl_trend/README.md: -------------------------------------------------------------------------------- 1 | ## FL Trend in Top AI Conferences 2 | ![top_ai_conf_fl_paper_trend](./top_conf_figs/top_ai_conf_fl_paper_trend.png) 3 | 4 | 5 | 6 | 7 | 8 | ## FL Trend in Top Security Conferences 9 | 10 | ![top_security_conf_fl_paper_trend](./top_conf_figs/top_security_conf_fl_paper_trend.png) 11 | (Most of accepted papers in 2019 and 2020 are about MPC) 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ## FL Accepted Paper Counts in Top System & Communication Conferences 20 | 21 | ![system_comm_conf_fl_paper_count](./top_conf_figs/system_comm_conf_fl_paper_count.png) 22 | 23 | -------------------------------------------------------------------------------- /publications/PrADA/datasets/census_dataset.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.utils.data import Dataset 3 | 4 | 5 | class SimpleDataset(Dataset): 6 | """An abstract Dataset class wrapped around Pytorch Dataset class. 7 | """ 8 | 9 | def __init__(self, data, labels): 10 | self.data = data 11 | self.labels = labels 12 | 13 | def __len__(self): 14 | return len(self.data) 15 | 16 | def __getitem__(self, item_idx): 17 | data_i, target_i = self.data[item_idx], self.labels[item_idx] 18 | return torch.tensor(data_i).float(), torch.tensor(target_i, dtype=torch.long) 19 | 20 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/test_utils.py: -------------------------------------------------------------------------------- 1 | from utils import test_classifier 2 | 3 | 4 | def test_model(task_id, init_model, trained_model_root_folder, target_test_loader): 5 | print("[INFO] load trained model") 6 | init_model.load_model(root=trained_model_root_folder, 7 | task_id=task_id, 8 | load_global_classifier=True, 9 | timestamp=None) 10 | 11 | init_model.print_parameters() 12 | 13 | print("[INFO] Run test") 14 | _, auc, ks = test_classifier(init_model, target_test_loader, "test") 15 | print(f"[INFO] test auc:{auc}, ks:{ks}") 16 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -x 3 | set -e 4 | 5 | DATASET=$1 6 | NUM_CLIENT=$2 7 | MODEL=$3 8 | PORT=$4 9 | 10 | if [ ! -n "$DATASET" ];then 11 | echo "Please input dataset" 12 | exit 13 | fi 14 | 15 | if [ ! -n "$NUM_CLIENT" ];then 16 | echo "Please input num of client" 17 | exit 18 | fi 19 | 20 | if [ ! -n "$MODEL" ];then 21 | echo "please input model name" 22 | exit 23 | fi 24 | 25 | if [ ! -n "$PORT" ];then 26 | echo "please input server port" 27 | exit 28 | fi 29 | 30 | for i in $(seq 1 ${NUM_CLIENT}); do 31 | nohup python3 fl_client.py \ 32 | --gpu $((($i % 8)))\ 33 | --config_file data/task_configs/${MODEL}/${DATASET}/${MODEL}_task$i.json \ 34 | --ignore_load True \ 35 | --port ${PORT} & 36 | done 37 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/utils/array_tool.py: -------------------------------------------------------------------------------- 1 | """ 2 | tools to convert specified type 3 | """ 4 | import torch as t 5 | import numpy as np 6 | 7 | 8 | def tonumpy(data): 9 | if isinstance(data, np.ndarray): 10 | return data 11 | if isinstance(data, t.Tensor): 12 | return data.detach().cpu().numpy() 13 | 14 | 15 | def totensor(data, cuda=True): 16 | if isinstance(data, np.ndarray): 17 | tensor = t.from_numpy(data) 18 | if isinstance(data, t.Tensor): 19 | tensor = data.detach() 20 | if cuda: 21 | tensor = tensor.cuda() 22 | return tensor 23 | 24 | 25 | def scalar(data): 26 | if isinstance(data, np.ndarray): 27 | return data.reshape(1)[0] 28 | if isinstance(data, t.Tensor): 29 | return data.item() -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/run_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -x 4 | set -e 5 | 6 | DATASET=$1 7 | MODEL=$2 8 | PORT=$3 9 | 10 | if [ ! -n "$DATASET" ];then 11 | echo "Please input dataset" 12 | exit 13 | fi 14 | 15 | if [ ! -n "$MODEL" ];then 16 | echo "Please input model name" 17 | exit 18 | fi 19 | 20 | if [ ! -n "$PORT" ];then 21 | echo "please input server port" 22 | exit 23 | fi 24 | 25 | if [ ! -d "experiments/logs/`date +'%m%d'`/${MODEL}/${DATASET}" ];then 26 | mkdir -p "experiments/logs/`date +'%m%d'`/${MODEL}/${DATASET}" 27 | fi 28 | 29 | LOG="experiments/logs/`date +'%m%d'`/${MODEL}/${DATASET}/fl_server.log" 30 | echo Loggin output to "$LOG" 31 | 32 | nohup python3 fl_server.py --config_file data/task_configs/${MODEL}/${DATASET}/${MODEL}_task.json --port ${PORT} > ${LOG} & 33 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/model/utils/nms/_nms_gpu_post_py.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | 4 | def _nms_gpu_post( mask, 5 | n_bbox, 6 | threads_per_block, 7 | col_blocks 8 | ): 9 | n_selection = 0 10 | one_ull = np.array([1],dtype=np.uint64) 11 | selection = np.zeros((n_bbox,), dtype=np.int32) 12 | remv = np.zeros((col_blocks,), dtype=np.uint64) 13 | 14 | for i in range(n_bbox): 15 | nblock = i // threads_per_block 16 | inblock = i % threads_per_block 17 | 18 | if not (remv[nblock] & one_ull << inblock): 19 | selection[n_selection] = i 20 | n_selection += 1 21 | 22 | index = i * col_blocks 23 | for j in range(nblock, col_blocks): 24 | remv[j] |= mask[index + j] 25 | return selection, n_selection 26 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/utils/model_dump.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import codecs 3 | 4 | 5 | def obj_to_pickle_string(x, file_path=None): 6 | if file_path is not None: 7 | print("save model to file") 8 | output = open(file_path, 'wb') 9 | pickle.dump(x, output) 10 | return file_path 11 | else: 12 | print("turn model to byte") 13 | x = codecs.encode(pickle.dumps(x), "base64").decode() 14 | print(len(x)) 15 | return x 16 | # return msgpack.packb(x, default=msgpack_numpy.encode) 17 | # TODO: compare pickle vs msgpack vs json for serialization; tradeoff: computation vs network IO 18 | 19 | 20 | def pickle_string_to_obj(s): 21 | if ".pkl" in s: 22 | df = open(s, "rb") 23 | print("load model from file") 24 | return pickle.load(df) 25 | else: 26 | print("load model from byte") 27 | return pickle.loads(codecs.decode(s.encode(), "base64")) 28 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/model/utils/nms/_nms_gpu_post.pyx: -------------------------------------------------------------------------------- 1 | cimport numpy as np 2 | from libc.stdint cimport uint64_t 3 | 4 | import numpy as np 5 | 6 | def _nms_gpu_post(np.ndarray[np.uint64_t, ndim=1] mask, 7 | int n_bbox, 8 | int threads_per_block, 9 | int col_blocks 10 | ): 11 | cdef: 12 | int i, j, nblock, index 13 | uint64_t inblock 14 | int n_selection = 0 15 | uint64_t one_ull = 1 16 | np.ndarray[np.int32_t, ndim=1] selection 17 | np.ndarray[np.uint64_t, ndim=1] remv 18 | 19 | selection = np.zeros((n_bbox,), dtype=np.int32) 20 | remv = np.zeros((col_blocks,), dtype=np.uint64) 21 | 22 | for i in range(n_bbox): 23 | nblock = i // threads_per_block 24 | inblock = i % threads_per_block 25 | 26 | if not (remv[nblock] & one_ull << inblock): 27 | selection[n_selection] = i 28 | n_selection += 1 29 | 30 | index = i * col_blocks 31 | for j in range(nblock, col_blocks): 32 | remv[j] |= mask[index + j] 33 | return selection, n_selection 34 | -------------------------------------------------------------------------------- /datasets/Fed_Multiview_Gen/README.md: -------------------------------------------------------------------------------- 1 | # Fed_Multiview_Gen 2 | This repo contains code for generating multiview images from 3D CAD models for federated learning research. 3 | 4 | Main contributions of this repo: 5 | 1. Modified phong.blend for better image quality 6 | 2. Scripts for automating the process of the dataset generation 7 | 3. Scripts for post-processing images 8 | 9 | 10 | 11 | ## Requirements 12 | - CAD models can be found here: https://github.com/lmb-freiburg/orion 13 | - Convert CAD model to images, Windows version: https://github.com/zeaggler/ModelNet_Blender_OFF2Multiview 14 | - Convert CAD model to images, Linux version: https://github.com/WeiTang114/BlenderPhong 15 | 16 | Please refer to above github repos for the installation. 17 | 18 | ## Usage 19 | There are two steps for generating the dataset: 20 | 1. Generate png images from 3D CAD model using Blender; 21 | 2. Post-process images from step 1. to adjust object to image ratio. 22 | 23 | Firstly, specify the BLENDER_PATH in main.py: 24 | 25 | ```python 26 | BLENDER_PATH = "D:/Program Files/blender-2.79b-windows64/blender.exe" 27 | ``` 28 | 29 | Then generate the dataset with command: 30 | ```bash 31 | python main.py --model_dir ./dataset_samples --target_dir ./dataset_images --action all 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /publications/FedCG/record.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | client = 5 4 | experiments = 5 5 | bs = 16 6 | lr = 0.0003 7 | wd = 0.0001 8 | dataset = "domainnet" 9 | algs = ["local", "fedavg", "fedsplit", "fedprox", "fedgen", "fedcg_w", "feddf"] 10 | 11 | for alg in algs: 12 | 13 | print(alg) 14 | 15 | fdir = 'experiments/bs' + str(bs) + 'lr' + str(lr) + 'wd' + str(wd) + '/' + alg + '_' + dataset + str( 16 | client) + '_lenet5_' 17 | if alg == 'fedcg_w': 18 | fdir += "mse_" 19 | nums = [[] for _ in range(client)] 20 | avg_nums = [] 21 | 22 | for i in range(1, experiments + 1): 23 | fname = fdir + str(i) + '/log.txt' 24 | with open(fname, 'r') as f: 25 | lines = f.readlines()[-client:] 26 | sum_num = 0 27 | for j in range(client): 28 | num = float(lines[j].split(" test acc:")[1][:8]) 29 | nums[j].append(num) 30 | sum_num += num 31 | avg_nums.append(sum_num / client) 32 | 33 | for j in range(client): 34 | print("client:%2d, acc:%.4f(%.4f)" % (j + 1, np.mean(np.array(nums[j])), np.std(np.array(nums[j])))) 35 | print("total average") 36 | print("%.4f(%.4f)" % (np.mean(np.array(avg_nums)), np.std(np.array(avg_nums)))) 37 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/ppd_loan/train_ppd_no_adaptation.py: -------------------------------------------------------------------------------- 1 | from experiments.ppd_loan.train_config import data_tag, data_hyperparameters, no_adaptation_hyperparameters 2 | from experiments.ppd_loan.train_ppd_fg_adapt_pretrain import create_fg_pdd_global_model 3 | from experiments.ppd_loan.train_ppd_no_fg_adapt_pretrain import create_no_fg_pdd_global_model 4 | from experiments.ppd_loan.train_ppd_utils import train_no_adaptation 5 | 6 | 7 | def get_model_meta(): 8 | no_da_root_dir = data_hyperparameters["ppd_no-ad_model_dir"] 9 | apply_feature_group = no_adaptation_hyperparameters['apply_feature_group'] 10 | if apply_feature_group: 11 | print("[INFO] feature grouping applied") 12 | model = create_fg_pdd_global_model(num_wide_feature=6) 13 | else: 14 | print("[INFO] no feature grouping applied") 15 | model = create_no_fg_pdd_global_model(aggregation_dim=5, num_wide_feature=6) 16 | return model, no_da_root_dir 17 | 18 | 19 | if __name__ == "__main__": 20 | init_model, ppd_no_ad_model_root_dir = get_model_meta() 21 | task_id_list = train_no_adaptation(data_tag, 22 | ppd_no_ad_model_root_dir, 23 | no_adaptation_hyperparameters, 24 | data_hyperparameters, 25 | model=init_model) 26 | print(f"[INFO] task id list:{task_id_list}") 27 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/utils/parse_config.py: -------------------------------------------------------------------------------- 1 | def parse_model_config(path): 2 | """Parses the yolo-v3 layer configuration file and returns module definitions""" 3 | file = open(path, 'r') 4 | lines = file.read().split('\n') 5 | lines = [x for x in lines if x and not x.startswith('#')] 6 | lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces 7 | module_defs = [] 8 | for line in lines: 9 | if line.startswith('['): # This marks the start of a new block 10 | module_defs.append({}) 11 | module_defs[-1]['type'] = line[1:-1].rstrip() 12 | if module_defs[-1]['type'] == 'convolutional': 13 | module_defs[-1]['batch_normalize'] = 0 14 | else: 15 | key, value = line.split("=") 16 | value = value.strip() 17 | module_defs[-1][key.rstrip()] = value.strip() 18 | 19 | return module_defs 20 | 21 | 22 | def parse_data_config(path): 23 | """Parses the data configuration file""" 24 | options = dict() 25 | options['gpus'] = '0,1,2,3' 26 | options['num_workers'] = '10' 27 | with open(path, 'r') as fp: 28 | lines = fp.readlines() 29 | for line in lines: 30 | line = line.strip() 31 | if line == '' or line.startswith('#'): 32 | continue 33 | key, value = line.split('=') 34 | options[key.strip()] = value.strip() 35 | return options 36 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/train_census_no_adaptation.py: -------------------------------------------------------------------------------- 1 | from experiments.income_census.train_config import data_tag, no_adaptation_hyperparameters, data_hyperparameters 2 | from experiments.income_census.train_census_fg_adapt_pretrain import create_fg_census_global_model 3 | from experiments.income_census.train_census_no_fg_adapt_pretrain import create_no_fg_census_global_model 4 | from experiments.income_census.train_census_utils import train_no_adaptation 5 | 6 | 7 | def get_model_meta(): 8 | no_da_root_dir = data_hyperparameters["census_no-ad_model_dir"] 9 | apply_feature_group = no_adaptation_hyperparameters['apply_feature_group'] 10 | if apply_feature_group: 11 | print("[INFO] feature grouping applied") 12 | model = create_fg_census_global_model(num_wide_feature=5) 13 | else: 14 | print("[INFO] no feature grouping applied") 15 | model = create_no_fg_census_global_model(aggregation_dim=4, num_wide_feature=5) 16 | return model, no_da_root_dir 17 | 18 | 19 | if __name__ == "__main__": 20 | init_model, census_no_ad_root_dir = get_model_meta() 21 | task_id_list = train_no_adaptation(data_tag, 22 | census_no_ad_root_dir, 23 | no_adaptation_hyperparameters, 24 | data_hyperparameters, 25 | init_model) 26 | print(f"[INFO] task id list:{task_id_list}") 27 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/train_census_no_fg_target_finetune.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from experiments.income_census.train_config import fine_tune_hyperparameters, data_hyperparameters 4 | from experiments.income_census.train_census_no_fg_adapt_pretrain import create_no_fg_census_global_model 5 | from experiments.income_census.train_census_utils import finetune_census 6 | 7 | 8 | def get_finetune_model_meta(): 9 | finetune_target_root_dir = data_hyperparameters['census_no-fg_ft_target_model_dir'] 10 | model = create_no_fg_census_global_model() 11 | return model, finetune_target_root_dir 12 | 13 | 14 | if __name__ == "__main__": 15 | 16 | parser = argparse.ArgumentParser("census_no-fg_target_fine_tune") 17 | parser.add_argument('--pretrain_task_id', type=str) 18 | args = parser.parse_args() 19 | pretrain_task_id = args.pretrain_task_id 20 | print(f"[INFO] fine-tune pre-trained model with pretrain task id : {pretrain_task_id}") 21 | 22 | census_pretain_model_root_dir = data_hyperparameters['census_no-fg_pretrained_model_dir'] 23 | init_model, census_finetune_target_model_root_dir = get_finetune_model_meta() 24 | task_id = finetune_census(pretrain_task_id, 25 | census_pretain_model_root_dir, 26 | census_finetune_target_model_root_dir, 27 | fine_tune_hyperparameters, 28 | data_hyperparameters, 29 | init_model) 30 | print(f"[INFO] finetune task id:{task_id}") 31 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/ppd_loan/train_ppd_no_fg_target_finetune.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from experiments.ppd_loan.train_config import data_hyperparameters, fine_tune_hyperparameters 4 | from experiments.ppd_loan.train_ppd_no_fg_adapt_pretrain import create_no_fg_pdd_global_model 5 | from experiments.ppd_loan.train_ppd_utils import finetune_ppd 6 | 7 | 8 | def get_finetune_model_meta(): 9 | finetune_target_root_dir = data_hyperparameters['ppd_no-fg_ft_target_model_dir'] 10 | pos_class_weight = fine_tune_hyperparameters['pos_class_weight'] 11 | model = create_no_fg_pdd_global_model(pos_class_weight=pos_class_weight) 12 | return model, finetune_target_root_dir 13 | 14 | 15 | if __name__ == "__main__": 16 | parser = argparse.ArgumentParser("ppd_no-fg_target_fine_tune") 17 | parser.add_argument('--pretrain_task_id', type=str) 18 | args = parser.parse_args() 19 | pretrain_task_id = args.pretrain_task_id 20 | print(f"[INFO] fine-tune pre-trained model with pretrain task id : {pretrain_task_id}") 21 | 22 | ppd_pretain_model_root_dir = data_hyperparameters['ppd_no-fg_pretrained_model_dir'] 23 | init_model, ppd_finetune_target_model_root_dir = get_finetune_model_meta() 24 | 25 | task_id = finetune_ppd(pretrain_task_id, 26 | ppd_pretain_model_root_dir, 27 | ppd_finetune_target_model_root_dir, 28 | fine_tune_hyperparameters, 29 | data_hyperparameters, 30 | model=init_model) 31 | print(f"[INFO] task id:{task_id}") 32 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/train_census_fg_target_finetune.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from experiments.income_census.train_config import fine_tune_hyperparameters, data_hyperparameters 4 | from experiments.income_census.train_census_fg_adapt_pretrain import create_fg_census_global_model 5 | from experiments.income_census.train_census_utils import finetune_census 6 | 7 | 8 | def get_finetune_model_meta(): 9 | finetune_target_root_dir = data_hyperparameters['census_fg_ft_target_model_dir'] 10 | using_interaction = fine_tune_hyperparameters['using_interaction'] 11 | model = create_fg_census_global_model(using_interaction=using_interaction) 12 | return model, finetune_target_root_dir 13 | 14 | 15 | if __name__ == "__main__": 16 | 17 | parser = argparse.ArgumentParser("census_fg_target_fine_tune") 18 | parser.add_argument('--pretrain_task_id', type=str) 19 | args = parser.parse_args() 20 | pretrain_task_id = args.pretrain_task_id 21 | print(f"[INFO] fine-tune pre-trained model with pretrain task id : {pretrain_task_id}") 22 | 23 | census_pretain_model_root_dir = data_hyperparameters['census_fg_pretrained_model_dir'] 24 | init_model, census_finetune_target_model_root_dir = get_finetune_model_meta() 25 | task_id = finetune_census(pretrain_task_id, 26 | census_pretain_model_root_dir, 27 | census_finetune_target_model_root_dir, 28 | fine_tune_hyperparameters, 29 | data_hyperparameters, 30 | init_model) 31 | print(f"[INFO] finetune task id:{task_id}") 32 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/ppd_loan/test_ppd_target.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from datasets.ppd_dataloader import get_pdd_dataloaders 4 | from experiments.ppd_loan import train_ppd_fg_target_finetune as fg_finetune 5 | from experiments.ppd_loan import train_ppd_no_adaptation as no_ad_finetune 6 | from experiments.ppd_loan import train_ppd_no_fg_target_finetune as no_fg_finetune 7 | from experiments.ppd_loan.train_config import data_hyperparameters 8 | from experiments.test_utils import test_model 9 | 10 | if __name__ == "__main__": 11 | 12 | parser = argparse.ArgumentParser("ppd_test_target") 13 | parser.add_argument('--task_id', type=str) 14 | parser.add_argument('--model_tag', type=str) 15 | args = parser.parse_args() 16 | task_id = args.task_id 17 | model_tag = args.model_tag 18 | print(f"[INFO] perform test task on : [{model_tag}] with id: {task_id}") 19 | test_models_dir = {"fg": fg_finetune.get_finetune_model_meta, 20 | "no_fg": no_fg_finetune.get_finetune_model_meta, 21 | "no_ad": no_ad_finetune.get_model_meta} 22 | init_model, model_root_dir = test_models_dir[model_tag]() 23 | target_test_file_name = data_hyperparameters['target_ft_test_file_name'] 24 | print(f"[INFO] target_test_file_name: {target_test_file_name}.") 25 | 26 | print("[INFO] load test data") 27 | target_test_loader, _ = get_pdd_dataloaders(ds_file_name=target_test_file_name, 28 | batch_size=1024, 29 | split_ratio=1.0) 30 | 31 | test_model(task_id, init_model, model_root_dir, target_test_loader) 32 | -------------------------------------------------------------------------------- /publications/ss_vfnas/visualize.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import genotypes 3 | from graphviz import Digraph 4 | 5 | 6 | def plot(genotype, filename): 7 | g = Digraph( 8 | format='png', 9 | edge_attr=dict(fontsize='20', fontname="times"), 10 | node_attr=dict(style='filled', shape='rect', align='center', fontsize='20', height='0.5', width='0.5', penwidth='2', fontname="times"), 11 | engine='dot') 12 | g.body.extend(['rankdir=LR']) 13 | 14 | g.node("c_{k-2}", fillcolor='darkseagreen2') 15 | g.node("c_{k-1}", fillcolor='darkseagreen2') 16 | assert len(genotype) % 2 == 0 17 | steps = len(genotype) // 2 18 | 19 | for i in range(steps): 20 | g.node(str(i), fillcolor='lightblue') 21 | 22 | for i in range(steps): 23 | for k in [2*i, 2*i + 1]: 24 | op, j = genotype[k] 25 | if j == 0: 26 | u = "c_{k-2}" 27 | elif j == 1: 28 | u = "c_{k-1}" 29 | else: 30 | u = str(j-2) 31 | v = str(i) 32 | g.edge(u, v, label=op, fillcolor="gray") 33 | 34 | g.node("c_{k}", fillcolor='palegoldenrod') 35 | for i in range(steps): 36 | g.edge(str(i), "c_{k}", fillcolor="gray") 37 | 38 | g.render(filename, view=False) 39 | 40 | 41 | if __name__ == '__main__': 42 | if len(sys.argv) != 2: 43 | print("usage:\n python {} ARCH_NAME".format(sys.argv[0])) 44 | sys.exit(1) 45 | 46 | genotype_name = sys.argv[1] 47 | try: 48 | genotype = eval('genotypes.{}'.format(genotype_name)) 49 | except AttributeError: 50 | print("{} is not specified in genotypes.py".format(genotype_name)) 51 | sys.exit(1) 52 | 53 | plot(genotype.normal, "B_normal") 54 | plot(genotype.reduce, "B_reduction") 55 | 56 | -------------------------------------------------------------------------------- /publications/FedCG/utils.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import numpy as np 4 | import torch 5 | import torch.nn as nn 6 | 7 | 8 | class AvgMeter(): 9 | 10 | def __init__(self): 11 | self.reset() 12 | 13 | def reset(self): 14 | self.val = 0. 15 | self.n = 0 16 | self.avg = 0. 17 | 18 | def update(self, val, n=1): 19 | assert n > 0 20 | self.val += val 21 | self.n += n 22 | self.avg = self.val / self.n 23 | 24 | def get(self): 25 | return self.avg 26 | 27 | 28 | class BestMeter(): 29 | def __init__(self): 30 | self.reset() 31 | 32 | def reset(self): 33 | self.val = 0. 34 | self.n = -1 35 | 36 | def update(self, val, n): 37 | assert n > self.n 38 | if val > self.val: 39 | self.val = val 40 | self.n = n 41 | 42 | def get(self): 43 | return self.val, self.n 44 | 45 | 46 | def weights_init(m): 47 | classname = m.__class__.__name__ 48 | if classname.find('Conv') != -1: 49 | nn.init.normal_(m.weight.data, 0.0, 0.02) 50 | elif classname.find('BatchNorm') != -1: 51 | nn.init.normal_(m.weight.data, 1.0, 0.02) 52 | nn.init.constant_(m.bias.data, 0) 53 | 54 | 55 | def add_gaussian_noise(tensor, mean, std): 56 | return torch.randn(tensor.size()) * std + mean 57 | 58 | 59 | def set_seed(manual_seed): 60 | random.seed(manual_seed) 61 | np.random.seed(manual_seed) 62 | torch.manual_seed(manual_seed) 63 | if torch.cuda.is_available(): 64 | torch.cuda.manual_seed_all(manual_seed) 65 | torch.backends.cudnn.benchmark = False 66 | torch.backends.cudnn.deterministic = True 67 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/test_census_target.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from datasets.census_dataloader import get_income_census_dataloaders 4 | from experiments.income_census import train_census_fg_target_finetune as fg_finetune 5 | from experiments.income_census import train_census_no_adaptation as no_ad_finetune 6 | from experiments.income_census import train_census_no_fg_target_finetune as no_fg_finetune 7 | from experiments.income_census.train_config import data_hyperparameters 8 | from experiments.test_utils import test_model 9 | 10 | if __name__ == "__main__": 11 | 12 | parser = argparse.ArgumentParser("census_test_target") 13 | parser.add_argument('--task_id', type=str) 14 | parser.add_argument('--model_tag', type=str) 15 | args = parser.parse_args() 16 | task_id = args.task_id 17 | model_tag = args.model_tag 18 | print(f"[INFO] perform test task on : [{model_tag}] with id: {task_id}") 19 | test_models_dir = {"fg": fg_finetune.get_finetune_model_meta, 20 | "no_fg": no_fg_finetune.get_finetune_model_meta, 21 | "no_ad": no_ad_finetune.get_model_meta} 22 | init_model, model_root_dir = test_models_dir[model_tag]() 23 | target_test_file_name = data_hyperparameters['target_ft_test_file_name'] 24 | print(f"[INFO] target_test_file_name: {target_test_file_name}.") 25 | 26 | print("[INFO] load test data") 27 | target_test_loader, _ = get_income_census_dataloaders(ds_file_name=target_test_file_name, 28 | batch_size=1024, 29 | split_ratio=1.0) 30 | 31 | test_model(task_id, init_model, model_root_dir, target_test_loader) 32 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/ppd_loan/train_ppd_fg_target_finetune.py: -------------------------------------------------------------------------------- 1 | from experiments.ppd_loan.train_config import data_hyperparameters, fine_tune_hyperparameters 2 | from experiments.ppd_loan.train_ppd_fg_adapt_pretrain import create_fg_pdd_global_model 3 | from experiments.ppd_loan.train_ppd_utils import finetune_ppd 4 | import argparse 5 | 6 | 7 | def get_finetune_model_meta(): 8 | finetune_target_root_dir = data_hyperparameters['ppd_fg_ft_target_model_dir'] 9 | using_interaction = fine_tune_hyperparameters['using_interaction'] 10 | pos_class_weight = fine_tune_hyperparameters['pos_class_weight'] 11 | model = create_fg_pdd_global_model(pos_class_weight=pos_class_weight, 12 | using_interaction=using_interaction) 13 | return model, finetune_target_root_dir 14 | 15 | 16 | if __name__ == "__main__": 17 | 18 | # parser = argparse.ArgumentParser("ppd_fg_target_fine_tune") 19 | # parser.add_argument('--pretrain_task_id', type=str) 20 | # args = parser.parse_args() 21 | # pretrain_task_id = args.pretrain_task_id 22 | pretrain_task_id = "20210731_ppd_fg_adapt_all4000pos004_intrFalse_pw1.0_lr0.0005_bs64_me600_ts1627666700" 23 | print(f"[INFO] fine-tune pre-trained model with pretrain task id : {pretrain_task_id}") 24 | 25 | ppd_pretain_model_root_dir = data_hyperparameters['ppd_fg_pretrained_model_dir'] 26 | init_model, ppd_finetune_target_model_root_dir = get_finetune_model_meta() 27 | 28 | task_id = finetune_ppd(pretrain_task_id, 29 | ppd_pretain_model_root_dir, 30 | ppd_finetune_target_model_root_dir, 31 | fine_tune_hyperparameters, 32 | data_hyperparameters, 33 | model=init_model) 34 | print(f"[INFO] task id:{task_id}") 35 | -------------------------------------------------------------------------------- /DISCLAIMER: -------------------------------------------------------------------------------- 1 | DISCLAIMER 2 | 3 | The copyright owner and all the contributors (collectively, the "Licensors") of FATE/FederatedAI (the "Work") non-exclusively grant any individual or legal entity (the "Licensee") the license to use the Work on condition that the Licensee consents to and agrees to be bound by this Disclaimer. 4 | 5 | The Licensee acknowledges that the Licensors provide the Work on an "AS IS" basis and makes no warranties or conditions, express or implied, on the Work to the Licensee. The Licensors assume no obligations and responsibilities other than providing the Work. 6 | 7 | The Licensee agrees that the Licensee shall use the Work at its own risk. Any problems or consequences arising from the use of the Work by the Licensee shall not be attributed to the Licensors and shall be borne by the Licensee, including but not limited to system failure, security vulnerabilities, title defects, third-party claims, commercial loss, etc. 8 | 9 | The Licensee shall also acknowledge to abide by the rules on the use of the Work, not to infringe the rights and interests of the Licensors and the Work, and not to cause the Licensors to suffer any loss or assume any responsibility. Whether the Licensee is held accountable or not, the Licensors shall be exempted from any liability. 10 | 11 | An act of use of the Work by the Licensee shall be deemed as the consent to be bound by this Disclaimer. 12 | 13 | 14 | 15 | 免责条款 16 | 17 |   FATE/FederatedAI(简称为“作品”)的著作权人及每一位贡献者(统称为“授权人”)开放地授予任何个人或法人实体(简称为“被授权人”)使用许可,但被授权人接受许可还应当同意本免责条款,并受到本免责条款的约束。 18 |    19 |   被授权人确认,授权人是以“原样”(AS IS)基础向被授权人提供作品,且不对作品向被授权人作出任何明示或暗示的保证或条件。除提供作品之外,授权人不承担任何义务与责任。 20 |    21 |   被授权人同意,被授权人应当自担使用作品的风险。被授权人使用作品过程中发生任何的问题或产生的任何后果与授权人无关,均由被授权人自行承担,包括但不限于系统故障、安全漏洞、权利瑕疵、第三人主张、商业损失等。 22 |    23 |   被授权人还应当承诺遵守作品的使用规则,不得作出任何侵害授权人以及作品权益的行为,不得使授权人遭受任何损失或承担任何责任。不论被授权人是否被追责均应使得授权人免于任何责任。 24 |    25 |   被授权人使用作品的行为即表示其受到本免责条款的约束,对被授权人具有法律约束力。 26 | -------------------------------------------------------------------------------- /publications/ss_vfnas/.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | # Log 9 | search/ 10 | search*/ 11 | eval*/ 12 | self_train_*/ 13 | # Data 14 | data/ 15 | # Distribution / packaging 16 | .Python 17 | env/ 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | .idea 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *.cover 53 | .hypothesis/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # pyenv 80 | .python-version 81 | 82 | # celery beat schedule file 83 | celerybeat-schedule 84 | 85 | # SageMath parsed files 86 | *.sage.py 87 | 88 | # dotenv 89 | .env 90 | 91 | # virtualenv 92 | .venv 93 | venv/ 94 | ENV/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # mypy 107 | .mypy_cache/ 108 | search-*/ 109 | eval-*/ 110 | runs/ 111 | 112 | # Swap 113 | [._]*.s[a-v][a-z] 114 | [._]*.sw[a-p] 115 | [._]s[a-v][a-z] 116 | [._]sw[a-p] 117 | 118 | # Session 119 | Session.vim 120 | 121 | # Temporary 122 | .netrwhist 123 | *~ 124 | # Auto-generated tag files 125 | tags 126 | -------------------------------------------------------------------------------- /publications/ss_vfnas/models/manual_k_party_chexpert.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | from torchvision import models 3 | import torch 4 | 5 | 6 | class Manual_A(nn.Module): 7 | 8 | def __init__(self, num_classes, layers, u_dim=64, k=2): 9 | self.num_classes = num_classes 10 | super(Manual_A, self).__init__() 11 | if layers == 18: 12 | self.net = models.resnet18(pretrained=False, num_classes=u_dim) 13 | elif layers == 50: 14 | self.net = models.resnet50(pretrained=False, num_classes=u_dim) 15 | elif layers == 101: 16 | self.net = models.resnet101(pretrained=False, num_classes=u_dim) 17 | elif layers == 19: 18 | self.net = models.mobilenet_v2(pretrained=False, num_classes=u_dim) 19 | else: 20 | raise ValueError("Wrong number of layers for resnet") 21 | for i in range(1, num_classes + 1): 22 | setattr(self, "fc_" + str(i), nn.Linear(u_dim * k, 1)) 23 | 24 | def forward(self, input, U_B): 25 | out = self.net(input) 26 | if U_B is not None: 27 | out = torch.cat([out] + [U for U in U_B], dim=1) 28 | logits = list() 29 | for i in range(1, self.num_classes + 1): 30 | classifier = getattr(self, "fc_" + str(i)) 31 | logit = classifier(out) 32 | logits.append(logit) 33 | return logits 34 | 35 | class Manual_B(nn.Module): 36 | 37 | def __init__(self, layers, u_dim=64): 38 | super(Manual_B, self).__init__() 39 | if layers == 18: 40 | self.net = models.resnet18(pretrained=False, num_classes=u_dim) 41 | elif layers == 50: 42 | self.net = models.resnet50(pretrained=False, num_classes=u_dim) 43 | elif layers == 101: 44 | self.net = models.resnet101(pretrained=False, num_classes=u_dim) 45 | elif layers == 19: 46 | self.net = models.mobilenet_v2(pretrained=False, num_classes=u_dim) 47 | else: 48 | raise ValueError("Wrong number of layers for resnet") 49 | 50 | def forward(self, input): 51 | out = self.net(input) 52 | return out 53 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/experiments/log_formatter.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | 4 | if __name__ == '__main__': 5 | parser = argparse.ArgumentParser() 6 | parser.add_argument("--log", type=str, required=True, help="path to log file") 7 | parser.add_argument("--output_dir", type=str, default="formatted_logs", help="path to output file") 8 | opt = parser.parse_args() 9 | log_file_name = os.path.basename(opt.log) 10 | if not os.path.exists(opt.log): 11 | raise FileNotFoundError("wrong log file path") 12 | if not os.path.exists(opt.output_dir): 13 | os.mkdir(opt.output_dir) 14 | output = open(os.path.join(opt.output_dir, log_file_name.replace(".log", ".csv")), 'w') 15 | header = ["train_loss", "aggr_test_loss", "aggr_test_map", "aggr_test_recall", "server_test_loss", 16 | "server_test_map", "server_test_recall"] 17 | round_, train_loss, aggr_test_loss, aggr_test_map, aggr_test_recall, server_test_loss, server_test_map, server_test_recall = [ 18 | list() for _ in range(8)] 19 | log_file = open(opt.log).readlines() 20 | for line in log_file: 21 | line = line.strip() 22 | if "Round" in line: 23 | round_.append(int(line.split(" ")[-2])) 24 | elif "aggr_train_loss" in line: 25 | train_loss.append(round(float(line.split(" ")[-1]), 4)) 26 | elif "aggr_test_loss" in line: 27 | aggr_test_loss.append(round(float(line.split(" ")[-1]), 4)) 28 | elif "aggr_test_map" in line: 29 | aggr_test_map.append(round(float(line.split(" ")[-1]), 4)) 30 | elif "aggr_test_recall" in line: 31 | aggr_test_recall.append(round(float(line.split(" ")[-1]), 4)) 32 | elif "server_test_loss" in line: 33 | server_test_loss.append(round(float(line.split(" ")[-1]), 4)) 34 | elif "server_test_map" in line: 35 | server_test_map.append(round(float(line.split(" ")[-1]), 4)) 36 | elif "server_test_recall" in line: 37 | server_test_recall.append(round(float(line.split(" ")[-1]), 4)) 38 | output.write("round,train_loss,test_map,test_recall\n") 39 | for r, loss, mAP, recall in zip(round_, train_loss, server_test_map, server_test_recall): 40 | output.write("{},{},{},{}\n".format(r, loss, mAP, recall)) 41 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/ppd_loan/train_config.py: -------------------------------------------------------------------------------- 1 | from data_process.ppd_process.ppd_data_creation_config import ppd_data_creation 2 | 3 | feature_extractor_architecture_list = [ 4 | [15, 20, 15, 6], 5 | [85, 100, 60, 8], 6 | [30, 50, 30, 6], 7 | [18, 30, 18, 6], 8 | [55, 70, 30, 8]] 9 | 10 | no_fg_feature_extractor_architecture = [203, 210, 70, 20] 11 | 12 | pre_train_hyperparameters = { 13 | "using_interaction": False, 14 | "momentum": 0.99, 15 | "weight_decay": 0.00001, 16 | "lr": 5e-4, 17 | "batch_size": 64, 18 | "max_epochs": 600, 19 | "epoch_patience": 3, 20 | "pos_class_weight": 3.0, 21 | "valid_metric": ('ks', 'auc') 22 | } 23 | 24 | fine_tune_hyperparameters = { 25 | "using_interaction": False, 26 | "load_global_classifier": False, 27 | "momentum": 0.99, 28 | "weight_decay": 0.0, 29 | "lr": 6e-4, 30 | "batch_size": 64, 31 | "pos_class_weight": 1.0, 32 | "valid_metric": ('ks', 'auc') 33 | } 34 | 35 | no_adaptation_hyperparameters = { 36 | "apply_feature_group": False, 37 | "train_data_tag": 'all', # can be either 'all' or 'tgt' 38 | "momentum": 0.99, 39 | "weight_decay": 0.00001, 40 | "lr": 5e-4, 41 | "batch_size": 64, 42 | "max_epochs": 600, 43 | "epoch_patience": 3, 44 | "valid_metric": ('ks', 'auc'), 45 | "pos_class_weight": 3.0 46 | } 47 | 48 | data_dir = ppd_data_creation['processed_data_dir'] 49 | data_tag = 'all4000pos004' 50 | 51 | data_hyperparameters = { 52 | "source_ad_train_file_name": data_dir + f"PPD_2014_src_1to9_ad_{data_tag}_train.csv", 53 | "source_ad_valid_file_name": data_dir + f'PPD_2014_src_1to9_ad_{data_tag}_valid.csv', 54 | "src_tgt_train_file_name": data_dir + f"PPD_2014_src_tgt_{data_tag}_train.csv", 55 | 56 | "target_ad_train_file_name": data_dir + f'PPD_2014_tgt_10to12_ad_{data_tag}_train.csv', 57 | "target_ft_train_file_name": data_dir + f'PPD_2014_tgt_10to12_ft_{data_tag}_train.csv', 58 | "target_ft_valid_file_name": data_dir + f'PPD_2014_tgt_10to12_ft_{data_tag}_valid.csv', 59 | "target_ft_test_file_name": data_dir + f'PPD_2014_tgt_10to12_ft_{data_tag}_test.csv', 60 | 61 | "ppd_fg_pretrained_model_dir": "ppd_fg_pretrained_model", 62 | "ppd_fg_ft_target_model_dir": "ppd_fg_ft_target_model", 63 | "ppd_no-fg_pretrained_model_dir": "ppd_no-fg_pretrained_model", 64 | "ppd_no-fg_ft_target_model_dir": "ppd_no-fg_ft_target_model", 65 | "ppd_no-ad_model_dir": "ppd_no-ad_model" 66 | } 67 | -------------------------------------------------------------------------------- /publications/PrADA/datasets/census_dataloader.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from torch.utils.data import DataLoader 4 | 5 | from data_process.census_process.mapping_resource import continuous_cols, categorical_cols, target_col_name 6 | from datasets.census_dataset import SimpleDataset 7 | 8 | 9 | def shuffle_data(data): 10 | len = data.shape[0] 11 | perm_idxs = np.random.permutation(len) 12 | return data[perm_idxs] 13 | 14 | 15 | def get_datasets(ds_file_name, shuffle=False, split_ratio=0.9): 16 | dataframe = pd.read_csv(ds_file_name, skipinitialspace=True) 17 | 18 | COLUMNS_TO_LOAD = continuous_cols + categorical_cols + [target_col_name] 19 | print("[INFO] COLUMNS_TO_LOAD:", COLUMNS_TO_LOAD) 20 | samples = dataframe[COLUMNS_TO_LOAD].values 21 | # print(samples) 22 | if shuffle: 23 | samples = shuffle_data(samples) 24 | 25 | if split_ratio == 1.0: 26 | print(f"samples shape: {samples.shape}, {samples.dtype}") 27 | train_dataset = SimpleDataset(samples[:, :-1], samples[:, -1]) 28 | return train_dataset, None 29 | else: 30 | num_train = int(split_ratio * samples.shape[0]) 31 | train_samples = samples[:num_train].astype(np.float) 32 | val_samples = samples[num_train:].astype(np.float) 33 | print(f"train samples shape: {train_samples.shape}, {train_samples.dtype}") 34 | print(f"valid samples shape: {val_samples.shape}, {train_samples.dtype}") 35 | train_dataset = SimpleDataset(train_samples[:, :-1], train_samples[:, -1]) 36 | val_dataset = SimpleDataset(val_samples[:, :-1], val_samples[:, -1]) 37 | return train_dataset, val_dataset 38 | 39 | 40 | def get_dataloaders(train_dataset: SimpleDataset, valid_dataset: SimpleDataset, batch_size=32, num_workers=1): 41 | mnist_train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers) 42 | mnist_valid_loader = None 43 | if valid_dataset is not None: 44 | mnist_valid_loader = DataLoader(valid_dataset, batch_size=batch_size * 2, shuffle=True, num_workers=num_workers) 45 | return mnist_train_loader, mnist_valid_loader 46 | 47 | 48 | def get_income_census_dataloaders(ds_file_name, split_ratio=0.9, batch_size=64, num_workers=2): 49 | train_dataset, valid_dataset = get_datasets(ds_file_name=ds_file_name, shuffle=True, split_ratio=split_ratio) 50 | return get_dataloaders(train_dataset, valid_dataset, batch_size=batch_size, num_workers=num_workers) 51 | -------------------------------------------------------------------------------- /publications/PrADA/models/classifier.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import torch.nn.functional as F 3 | 4 | 5 | class TransformMatrix(nn.Module): 6 | def __init__(self, input_dim, output_dim): 7 | super(TransformMatrix, self).__init__() 8 | self.fc = nn.Linear(in_features=input_dim, out_features=output_dim, bias=False) 9 | # self.fc.apply(init_weights) 10 | 11 | def transform(self, x): 12 | return self.fc(x) 13 | 14 | def transpose_transform(self, x): 15 | return F.linear(x, self.fc.weight.t()) 16 | 17 | 18 | class Classifier(nn.Module): 19 | def __init__(self, input_dim): 20 | super(Classifier, self).__init__() 21 | self.classifier = nn.Sequential( 22 | nn.Linear(in_features=input_dim, out_features=100), 23 | nn.BatchNorm1d(100), 24 | nn.ReLU(), 25 | nn.Linear(in_features=100, out_features=100), 26 | nn.BatchNorm1d(100), 27 | nn.ReLU(), 28 | nn.Linear(in_features=100, out_features=10) 29 | ) 30 | 31 | def forward(self, x): 32 | x = self.classifier(x) 33 | return F.softmax(x, dim=1) 34 | 35 | 36 | class RegionClassifier(nn.Module): 37 | def __init__(self, input_dim): 38 | super(RegionClassifier, self).__init__() 39 | self.classifier = nn.Sequential( 40 | nn.Linear(in_features=input_dim, out_features=3), 41 | ) 42 | 43 | def forward(self, x): 44 | return self.classifier(x) 45 | 46 | 47 | activation_fn = nn.LeakyReLU() 48 | 49 | 50 | class CensusFeatureAggregator(nn.Module): 51 | def __init__(self, input_dim, output_dim=1): 52 | super(CensusFeatureAggregator, self).__init__() 53 | self.aggregator = nn.Sequential( 54 | nn.Linear(in_features=input_dim, out_features=output_dim), 55 | ) 56 | # self.aggregator.apply(init_weights) 57 | 58 | def forward(self, x): 59 | return self.aggregator(x) 60 | 61 | 62 | class IdentityRegionAggregator(nn.Module): 63 | def __init__(self): 64 | super(IdentityRegionAggregator, self).__init__() 65 | 66 | def forward(self, x): 67 | return x 68 | 69 | 70 | class GlobalClassifier(nn.Module): 71 | def __init__(self, input_dim): 72 | super(GlobalClassifier, self).__init__() 73 | self.classifier = nn.Sequential( 74 | nn.Linear(in_features=input_dim, out_features=1), 75 | ) 76 | 77 | def forward(self, x): 78 | return self.classifier(x) 79 | -------------------------------------------------------------------------------- /publications/ss_vfnas/models/manual_k_party.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | from torchvision import models 3 | import torch 4 | 5 | 6 | class Manual_A(nn.Module): 7 | 8 | def __init__(self, num_classes, layers, u_dim=64, k=2): 9 | super(Manual_A, self).__init__() 10 | if layers == 18: 11 | self.net = models.resnet18(pretrained=False, num_classes=u_dim) 12 | elif layers == 34: 13 | self.net = models.resnet34(pretrained=False, num_classes=u_dim) 14 | elif layers == 50: 15 | self.net = models.resnet50(pretrained=False, num_classes=u_dim) 16 | elif layers == 101: 17 | self.net = models.resnet101(pretrained=False, num_classes=u_dim) 18 | elif layers == 19: 19 | self.net = models.mobilenet_v2(pretrained=False, num_classes=u_dim) 20 | elif layers == 51: 21 | self.net = models.shufflenet_v2_x1_0(pretrained=False, num_classes=u_dim) 22 | elif layers == 52: 23 | self.net = models.squeezenet1_0(pretrained=False, num_classes=u_dim) 24 | else: 25 | raise ValueError("Wrong number of layers for model") 26 | self.classifier = nn.Linear(u_dim * k, num_classes) 27 | 28 | def forward(self, input, U_B): 29 | out = self.net(input) 30 | if U_B is not None: 31 | out = torch.cat([out] + [U for U in U_B], dim=1) 32 | logits = self.classifier(out) 33 | return logits 34 | 35 | 36 | class Manual_B(nn.Module): 37 | 38 | def __init__(self, layers, u_dim=64): 39 | super(Manual_B, self).__init__() 40 | if layers == 18: 41 | self.net = models.resnet18(pretrained=False, num_classes=u_dim) 42 | elif layers == 34: 43 | self.net = models.resnet34(pretrained=False, num_classes=u_dim) 44 | elif layers == 50: 45 | self.net = models.resnet50(pretrained=False, num_classes=u_dim) 46 | elif layers == 101: 47 | self.net = models.resnet101(pretrained=False, num_classes=u_dim) 48 | elif layers == 19: 49 | self.net = models.mobilenet_v2(pretrained=False, num_classes=u_dim) 50 | elif layers == 51: 51 | self.net = models.shufflenet_v2_x1_0(pretrained=False, num_classes=u_dim) 52 | elif layers == 52: 53 | self.net = models.squeezenet1_0(pretrained=False, num_classes=u_dim) 54 | else: 55 | raise ValueError("Wrong number of layers for model") 56 | 57 | def forward(self, input): 58 | out = self.net(input) 59 | return out 60 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/data/data_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import os.path as osp 3 | import xml.etree.ElementTree as ET 4 | 5 | 6 | def show_dir(): 7 | dir_list = [a for a in os.listdir("./") if os.path.isdir(a) and a != 'test'] 8 | total = 0 9 | categories = {} 10 | for dire in dir_list: 11 | jpeg_path = osp.join(dire, 'Annotations') 12 | xml_list = os.listdir(jpeg_path) 13 | total += len(xml_list) 14 | categories[dire] = len(xml_list) 15 | list1 = sorted(categories.items(), key=lambda x: x[1], reverse=True) 16 | for i, (directory, num) in enumerate(list1): 17 | print(directory, num - 2680) 18 | print(total) 19 | 20 | 21 | def merge_test(): 22 | dir_list = [a for a in os.listdir("./") if os.path.isdir(a) and a != 'test'] 23 | for dir_name in dir_list: 24 | Anno_path = osp.join(dir_name, "Annotations") 25 | Jpeg_path = osp.join(dir_name, "JPEGImages") 26 | Imag_path = osp.join(dir_name, "ImageSets", "Main") 27 | if not osp.exists(Imag_path): 28 | os.makedirs(Imag_path) 29 | test_anno_path = osp.join("test", "Annotations") 30 | test_jpeg_path = osp.join("test", "JPEGImages") 31 | test_txt_path = osp.join("test", "ImageSets", "Main", "test.txt") 32 | train_txt = open(osp.join(Imag_path, "train.txt"), 'w') 33 | valid_txt = open(osp.join(Imag_path, "valid.txt"), 'w') 34 | test_txt = open(osp.join(Imag_path, "test.txt"), 'w') 35 | anno_list = os.listdir(Anno_path) 36 | for anno_name in anno_list: 37 | anno_name = anno_name.replace(".xml", "\n") 38 | train_txt.write(anno_name) 39 | os.system("cp {}/* {}".format(test_anno_path, Anno_path)) 40 | os.system("cp {}/* {}".format(test_jpeg_path, Jpeg_path)) 41 | os.system("cp {} {}".format(test_txt_path, Imag_path)) 42 | os.system("cp {} {}".format(test_txt_path, osp.join(Imag_path, 'valid.txt'))) 43 | 44 | 45 | def make_txt(): 46 | dir_list = [a for a in os.listdir("./") if os.path.isdir(a) and a != 'test'] 47 | for dir_name in dir_list: 48 | Anno_path = osp.join(dir_name, "Annotations") 49 | Imag_path = osp.join(dir_name, "ImageSets", "Main") 50 | ftest = open(osp.join(Imag_path, "test.txt"), 'r').readlines() 51 | ftrain = open(osp.join(Imag_path, "train.txt"), 'w') 52 | annos = os.listdir(Anno_path) 53 | for anno in annos: 54 | anno = anno.replace(".xml", "\n") 55 | if anno not in ftest: 56 | ftrain.write(anno) 57 | -------------------------------------------------------------------------------- /publications/PrADA/models/test_interaction_feature.py: -------------------------------------------------------------------------------- 1 | from models.classifier import TransformMatrix 2 | from models.interaction_models import AttentiveFeatureInteractionComputer, compute_interactive_key 3 | import numpy as np 4 | import torch 5 | 6 | 7 | def initialize_transform_matrix(hidden_dim_a, hidden_dim_b): 8 | return TransformMatrix(hidden_dim_a, hidden_dim_b) 9 | 10 | 11 | def initialize_transform_matrix_dict(hidden_dim_list): 12 | trans_matrix_dict = dict() 13 | for idx_a, hidden_dim_a in enumerate(hidden_dim_list): 14 | for idx_b, hidden_dim_b in enumerate(hidden_dim_list): 15 | transform_matrix = initialize_transform_matrix(hidden_dim_a, hidden_dim_b) 16 | key_1 = compute_interactive_key(idx_a, idx_b) 17 | key_2 = compute_interactive_key(idx_b, idx_a) 18 | if trans_matrix_dict.get(key_1) is None and trans_matrix_dict.get(key_2) is None: 19 | trans_matrix_dict[key_1] = transform_matrix 20 | return trans_matrix_dict 21 | 22 | 23 | class TestInteractiveFeatureComputer(AttentiveFeatureInteractionComputer): 24 | 25 | def __init__(self, transform_matrix_dict): 26 | super(TestInteractiveFeatureComputer, self).__init__(transform_matrix_dict) 27 | 28 | def compute_score(self, feat_a, feat_b, idx_a, idx_b): 29 | return 1.0 30 | 31 | 32 | if __name__ == "__main__": 33 | # list_1 = [] 34 | # list_2 = [2, 3, 4] 35 | # list_3 = [5, 6, 7] 36 | # list = list_1 + list_2 + list_3 37 | # print(list) 38 | 39 | feat_1 = np.array([[0.1, 0.2, 0.3], 40 | [0.4, 0.5, 0.6]]) 41 | feat_2 = np.array([[0.4, 0.5, 0.6, 0.7, 0.8], 42 | [0.14, 0.15, 0.16, 0.17, 0.18]]) 43 | feat_3 = np.array([[0.71, 0.8, 0.9, 0.10], 44 | [0.24, 0.25, 0.26, 0.27]]) 45 | feat_list = [feat_1, feat_2, feat_3] 46 | 47 | print("feat_list:", feat_list) 48 | 49 | hidden_dim_list = [f.shape[-1] for f in feat_list] 50 | print("hidden_dim_list:", hidden_dim_list) 51 | 52 | transform_matrix_dict = initialize_transform_matrix_dict(hidden_dim_list) 53 | print("transform_matrix_dict: \n", transform_matrix_dict) 54 | 55 | computer = AttentiveFeatureInteractionComputer(transform_matrix_dict) 56 | 57 | feat_tensor_list = [torch.tensor(f, dtype=torch.float) for f in feat_list] 58 | 59 | score_map = computer.build(feat_tensor_list) 60 | print("score_map: \n", score_map) 61 | 62 | int_feat_list = computer.fit(feat_tensor_list) 63 | print("int_feat_list: \n") 64 | for int_feat in int_feat_list: 65 | print(int_feat) 66 | 67 | print() 68 | print("parameter: \n", computer.parameters()) 69 | -------------------------------------------------------------------------------- /publications/FedCG/run.sh: -------------------------------------------------------------------------------- 1 | OMP_NUM_THREADS=1 python main.py --algorithm="fedgen" --dataset="office" --model="lenet5" --seed=1 --gpu=1 & 2 | OMP_NUM_THREADS=1 python main.py --algorithm="fedgen" --dataset="office" --model="lenet5" --seed=2 --gpu=2 & 3 | OMP_NUM_THREADS=1 python main.py --algorithm="fedgen" --dataset="office" --model="lenet5" --seed=3 --gpu=3 & 4 | OMP_NUM_THREADS=1 python main.py --algorithm="fedgen" --dataset="office" --model="lenet5" --seed=4 --gpu=4 & 5 | OMP_NUM_THREADS=1 python main.py --algorithm="fedgen" --dataset="office" --model="lenet5" --seed=5 --gpu=5 6 | 7 | OMP_NUM_THREADS=1 python main.py --algorithm="fedavg" --dataset="office" --model="lenet5" --seed=1 --gpu=1 & 8 | OMP_NUM_THREADS=1 python main.py --algorithm="fedavg" --dataset="office" --model="lenet5" --seed=2 --gpu=2 & 9 | OMP_NUM_THREADS=1 python main.py --algorithm="fedavg" --dataset="office" --model="lenet5" --seed=3 --gpu=3 & 10 | OMP_NUM_THREADS=1 python main.py --algorithm="fedavg" --dataset="office" --model="lenet5" --seed=4 --gpu=4 & 11 | OMP_NUM_THREADS=1 python main.py --algorithm="fedavg" --dataset="office" --model="lenet5" --seed=5 --gpu=5 12 | 13 | OMP_NUM_THREADS=1 python main.py --algorithm="fedsplit" --dataset="office" --model="lenet5" --seed=1 --gpu=1 & 14 | OMP_NUM_THREADS=1 python main.py --algorithm="fedsplit" --dataset="office" --model="lenet5" --seed=2 --gpu=2 & 15 | OMP_NUM_THREADS=1 python main.py --algorithm="fedsplit" --dataset="office" --model="lenet5" --seed=3 --gpu=3 & 16 | OMP_NUM_THREADS=1 python main.py --algorithm="fedsplit" --dataset="office" --model="lenet5" --seed=4 --gpu=4 & 17 | OMP_NUM_THREADS=1 python main.py --algorithm="fedsplit" --dataset="office" --model="lenet5" --seed=5 --gpu=5 18 | 19 | OMP_NUM_THREADS=1 python main.py --algorithm="fedprox" --dataset="office" --model="lenet5" --seed=1 --gpu=1 & 20 | OMP_NUM_THREADS=1 python main.py --algorithm="fedprox" --dataset="office" --model="lenet5" --seed=2 --gpu=2 & 21 | OMP_NUM_THREADS=1 python main.py --algorithm="fedprox" --dataset="office" --model="lenet5" --seed=3 --gpu=3 & 22 | OMP_NUM_THREADS=1 python main.py --algorithm="fedprox" --dataset="office" --model="lenet5" --seed=4 --gpu=4 & 23 | OMP_NUM_THREADS=1 python main.py --algorithm="fedprox" --dataset="office" --model="lenet5" --seed=5 --gpu=5 24 | 25 | OMP_NUM_THREADS=1 python main.py --algorithm="local" --dataset="office" --model="lenet5" --seed=1 --gpu=1 & 26 | OMP_NUM_THREADS=1 python main.py --algorithm="local" --dataset="office" --model="lenet5" --seed=2 --gpu=2 & 27 | OMP_NUM_THREADS=1 python main.py --algorithm="local" --dataset="office" --model="lenet5" --seed=3 --gpu=3 & 28 | OMP_NUM_THREADS=1 python main.py --algorithm="local" --dataset="office" --model="lenet5" --seed=4 --gpu=4 & 29 | OMP_NUM_THREADS=1 python main.py --algorithm="local" --dataset="office" --model="lenet5" --seed=5 --gpu=5 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Federated-Benchmark: A Benchmark of Real-world Images Dataset for Federated Learning 2 | 3 | ## Overview 4 | We present a real-world image dataset, reflecting the characteristic real-world federated learning scenarios, and provide an extensive benchmark on model performance, efficiency, and communication in a federated learning setting. 5 | 6 | ## Resources 7 | * Dataset: [dataset.fedai.org](https://dataset.fedai.org) 8 | * Paper: ["Real-World Image Datasets for Federated Learning"](https://arxiv.org/abs/1910.11089) 9 | 10 | ### Street_Dataset 11 | * Overview: Image Dataset 12 | * Details: 7 different classes, 956 images with pixels of 704 by 576, 5 or 20 devices 13 | * Task: Object detection for federated learning 14 | * [Dataset_description.md](https://github.com/FederatedAI/FATE/blob/master/research/federated_object_detection_benchmark/README.md) 15 | 16 | ## Getting Started 17 | We implemented two mainstream object detection algorithms (YOLOv3 and Faster R-CNN). Code for YOLOv3 is borrowed from [PyTorch-YOLOv3](https://github.com/eriklindernoren/PyTorch-YOLOv3.git) and Faster R-CNN from [simple-faster-rcnn-pytorch](https://github.com/chenyuntc/simple-faster-rcnn-pytorch.git). 18 | ### Install dependencies 19 | * requires PyTorch with GPU (code are GPU only) 20 | * install cupy, you can install via `pip install cupy-cuda80` or (cupy-cuda90, cupy-cuda91, etc) 21 | * install other dependencies, `pip install -r requirements.txt` 22 | * Optional but strongly recommended: build cython code `nms_gpu_post`: 23 | ```bash 24 | cd model/utils/nms/ 25 | python build.py build_ext --inplace 26 | cd - 27 | ``` 28 | ### Prepare data 29 | 1. Download the dataset, refer to [dataset.fedai](https://dataset.fedai.org/) 30 | 2. It should have the basic structure for faster r-cnn 31 | ```bash 32 | Federated-Benchmark/data/street_5/$DEVICE_ID$/ImageSets 33 | Federated-Benchmark/data/street_5/$DEVICE_ID$/JPEGImages 34 | Federated-Benchmark/data/street_5/$DEVICE_ID$/Annotations 35 | ``` 36 | 4. Generate config file for federated learning 37 | ```bash 38 | cd data 39 | python3 generate_task_json.py 40 | ``` 41 | ### Train 42 | 1. Start server 43 | ```bash 44 | sh ./run_server.sh street_5 yolo 1234 45 | ``` 46 | 2. Start clients 47 | ```bash 48 | sh ./run.sh street_5 5 yolo 1234 49 | ``` 50 | 3. Stop training 51 | ```bash 52 | sh ./stop.sh street_5 yolo 53 | ``` 54 | ### Citation 55 | * If you use this code or dataset for your research, please kindly cite our paper: 56 | ```bash 57 | @article{luo2019real, 58 | title={Real-World Image Datasets for Federated Learning}, 59 | author={Luo, Jiahuan and Wu, Xueyang and Luo, Yun and Huang, Anbu and Huang, Yunfeng and Liu, Yang and Yang, Qiang}, 60 | journal={arXiv preprint arXiv:1910.11089}, 61 | year={2019} 62 | } 63 | ``` -------------------------------------------------------------------------------- /publications/PrADA/data_process/ppd_process/ppd_prepare_data_train_test.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from sklearn.utils import shuffle 3 | 4 | from data_process.ppd_process.ppd_data_creation_config import ppd_data_creation 5 | 6 | 7 | def create_train_and_test(df_data, df_datetime, num_train, to_dir): 8 | 9 | year = 2014 10 | df_data_2014 = df_data[df_datetime['ListingInfo_Year'] == year] 11 | df_datetime_2014 = df_datetime[df_datetime['ListingInfo_Year'] == year] 12 | 13 | df_data_2014, df_datetime_2014 = shuffle(df_data_2014, df_datetime_2014) 14 | 15 | df_data_train = df_data_2014[:num_train] 16 | df_datetime_train = df_datetime_2014[:num_train] 17 | 18 | df_data_test = df_data_2014[num_train:] 19 | df_datetime_test = df_datetime_2014[num_train:] 20 | 21 | print(f"[INFO] df_data_train with shape: {df_data_train.shape}") 22 | print(f"[INFO] df_data_test with shape: {df_data_test.shape}") 23 | print(f"[INFO] df_datetime_train with shape: {df_datetime_train.shape}") 24 | print(f"[INFO] df_datetime_test with shape: {df_datetime_test.shape}") 25 | 26 | tag = str(year) 27 | df_data_train.to_csv("{}/PPD_data_{}_{}_train.csv".format(to_dir, tag, str(num_train)), index=False) 28 | df_data_test.to_csv("{}/PPD_data_{}_{}_test.csv".format(to_dir, tag, str(num_train)), index=False) 29 | df_datetime_train.to_csv("{}/PPD_datetime_{}_{}_train.csv".format(to_dir, tag, str(num_train)), index=False) 30 | df_datetime_test.to_csv("{}/PPD_datetime_{}_{}_test.csv".format(to_dir, tag, str(num_train)), index=False) 31 | 32 | 33 | def prepare_ppd_data(): 34 | print(f"========================= prepare ppd data ============================ ") 35 | 36 | original_data_dir = ppd_data_creation['original_data_dir'] 37 | to_dir = ppd_data_creation['processed_data_dir'] 38 | 39 | data_all = original_data_dir + ppd_data_creation['original_ppd_data_file_name'] 40 | data_datetime = original_data_dir + ppd_data_creation['original_ppd_datetime_file_name'] 41 | 42 | df_data_all = pd.read_csv(data_all, skipinitialspace=True) 43 | df_data_datetime = pd.read_csv(data_datetime, skipinitialspace=True) 44 | 45 | print(f"[INFO] df_data_all: {df_data_all.shape}") 46 | print(f"[INFO] df_data_datetime: {df_data_datetime.shape}") 47 | # print(f"[INFO] 2015:{df_data_all[df_data_datetime['ListingInfo_Year'] == 2015].shape}") 48 | print(f"[INFO] 2014:{df_data_all[df_data_datetime['ListingInfo_Year'] == 2014].shape}") 49 | # print(f"[INFO] 2013:{df_data_all[df_data_datetime['ListingInfo_Year'] == 2013].shape}") 50 | # print(f"[INFO] 2012:{df_data_all[df_data_datetime['ListingInfo_Year'] == 2012].shape}") 51 | 52 | num_train = ppd_data_creation['number_train_samples'] 53 | create_train_and_test(df_data_all, df_data_datetime, num_train, to_dir) 54 | 55 | 56 | if __name__ == "__main__": 57 | prepare_ppd_data() 58 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/train_config.py: -------------------------------------------------------------------------------- 1 | from data_process.census_process.census_data_creation_config import census_data_creation 2 | 3 | fg_feature_extractor_architecture_list = [[28, 56, 28, 14], 4 | [25, 50, 25, 12], 5 | [56, 86, 56, 18], 6 | [27, 54, 27, 13]] 7 | 8 | intr_fg_feature_extractor_for_architecture_list = [[53, 78, 53, 15], 9 | [84, 120, 84, 20], 10 | [55, 81, 55, 15], 11 | [81, 120, 81, 20], 12 | [52, 78, 52, 15], 13 | [83, 120, 83, 20]] 14 | 15 | no_fg_feature_extractor_architecture = [136, 150, 60, 20] 16 | 17 | pre_train_hyperparameters = { 18 | "using_interaction": False, 19 | "momentum": 0.99, 20 | "weight_decay": 0.00001, 21 | "lr": 5e-4, 22 | "batch_size": 128, 23 | "max_epochs": 600, 24 | "epoch_patience": 2, 25 | "valid_metric": ('ks', 'auc') 26 | } 27 | 28 | fine_tune_hyperparameters = { 29 | "using_interaction": False, 30 | "load_global_classifier": False, 31 | "momentum": 0.99, 32 | "weight_decay": 0.0, 33 | "lr": 8e-4, 34 | "batch_size": 128, 35 | "valid_metric": ('ks', 'auc') 36 | } 37 | 38 | no_adaptation_hyperparameters = { 39 | "apply_feature_group": False, 40 | "train_data_tag": 'all', # can be either 'all' or 'tgt' 41 | "momentum": 0.99, 42 | "weight_decay": 0.00001, 43 | "lr": 5e-4, 44 | "batch_size": 128, 45 | "max_epochs": 600, 46 | "epoch_patience": 2, 47 | "valid_metric": ('ks', 'auc') 48 | } 49 | 50 | data_dir = census_data_creation['processed_data_dir'] 51 | data_tag = 'all4000pos004' 52 | 53 | data_hyperparameters = { 54 | "source_ad_train_file_name": data_dir + f'undergrad_census9495_ad_{data_tag}_train.csv', 55 | "source_ad_valid_file_name": data_dir + f'undergrad_census9495_ad_{data_tag}_valid.csv', 56 | "src_tgt_train_file_name": data_dir + f'degree_src_tgt_census9495_{data_tag}_train.csv', 57 | 58 | "target_ad_train_file_name": data_dir + f'grad_census9495_ad_{data_tag}_train.csv', 59 | "target_ft_train_file_name": data_dir + f'grad_census9495_ft_{data_tag}_train.csv', 60 | "target_ft_valid_file_name": data_dir + f'grad_census9495_ft_{data_tag}_valid.csv', 61 | "target_ft_test_file_name": data_dir + f'grad_census9495_ft_{data_tag}_test.csv', 62 | 63 | "census_fg_pretrained_model_dir": "census_fg_pretrained_model", 64 | "census_fg_ft_target_model_dir": "census_fg_ft_target_model", 65 | "census_no-fg_pretrained_model_dir": "census_no-fg_pretrained_model", 66 | "census_no-fg_ft_target_model_dir": "census_no-fg_ft_target_model", 67 | "census_no-ad_model_dir": "census_no-ad_model" 68 | } 69 | -------------------------------------------------------------------------------- /publications/ss_vfnas/architects/architect_two_party.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import torch.nn as nn 4 | from torch.autograd import Variable 5 | 6 | 7 | def _concat(xs): 8 | return torch.cat([x.view(-1) for x in xs]) 9 | 10 | 11 | class Architect_A(object): 12 | def __init__(self, model, args): 13 | self.network_momentum = args.momentum 14 | self.network_weight_decay = args.weight_decay 15 | self.model = model 16 | self.optimizer = torch.optim.Adam(self.model.arch_parameters(), 17 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 18 | weight_decay=args.arch_weight_decay) 19 | 20 | def update_alpha(self, input_valid, U_B_valid, target_valid): 21 | U_B_valid = torch.autograd.Variable(U_B_valid, requires_grad=True).cuda() 22 | self.optimizer.zero_grad() 23 | loss, _ = self.model._loss(input_valid, U_B_valid, target_valid) 24 | U_B_gradients = torch.autograd.grad(loss, U_B_valid, retain_graph=True) 25 | loss.backward() 26 | self.optimizer.step() 27 | return U_B_gradients 28 | 29 | def update_weights(self, input_train, U_B_train, target_train, weights_optim, grad_clip): 30 | U_B_train = torch.autograd.Variable(U_B_train, requires_grad=True).cuda() 31 | weights_optim.zero_grad() 32 | loss, logits = self.model._loss(input_train, U_B_train, target_train) 33 | U_B_gradients = torch.autograd.grad(loss, U_B_train, retain_graph=True) 34 | loss.backward() 35 | nn.utils.clip_grad_norm_(self.model.parameters(), grad_clip) 36 | weights_optim.step() 37 | return U_B_gradients, logits, loss 38 | 39 | 40 | class Architect_B(object): 41 | def __init__(self, model, args): 42 | self.network_momentum = args.momentum 43 | self.network_weight_decay = args.weight_decay 44 | self.model = model 45 | self.optimizer = torch.optim.Adam(self.model.arch_parameters(), 46 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 47 | weight_decay=args.arch_weight_decay) 48 | 49 | def update_alpha(self, U_B_val, U_B_gradients): 50 | model_B_alpha_gradients = torch.autograd.grad(U_B_val, self.model.arch_parameters(), grad_outputs=U_B_gradients) 51 | self.optimizer.zero_grad() 52 | for w, g in zip(self.model.arch_parameters(), model_B_alpha_gradients): 53 | w.grad = g.detach() 54 | self.optimizer.step() 55 | 56 | def update_weights(self, U_B_train, U_B_gradients, weights_optim, grad_clip): 57 | model_B_weight_gradients = torch.autograd.grad(U_B_train, self.model.parameters(), grad_outputs=U_B_gradients) 58 | weights_optim.zero_grad() 59 | for w, g in zip(self.model.parameters(), model_B_weight_gradients): 60 | w.grad = g.detach() 61 | nn.utils.clip_grad_norm_(self.model.parameters(), grad_clip) 62 | weights_optim.step() -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/utils/config.py: -------------------------------------------------------------------------------- 1 | from pprint import pprint 2 | 3 | 4 | # Default Configs for training 5 | # NOTE that, config items could be overwriten by passing argument through command line. 6 | # e.g. --voc-data-dir='./data/' 7 | 8 | class Config: 9 | model_name = "" 10 | # data 11 | voc_data_dir = 'data/VOC2007' 12 | min_size = 600 # image resize 13 | max_size = 1000 # image resize 14 | num_workers = 8 15 | test_num_workers = 8 16 | 17 | # sigma for l1_smooth_loss 18 | rpn_sigma = 3. 19 | roi_sigma = 1. 20 | 21 | # param for optimizer 22 | # 0.0005 in origin paper but 0.0001 in tf-faster-rcnn 23 | weight_decay = 0.0005 24 | lr_decay = 0.1 # 1e-4 -> 1e-5 25 | lr = 1e-4 26 | 27 | 28 | # visualization 29 | env = 'faster-rcnn' # visdom env 30 | port = 8097 31 | plot_every = 40 # vis every N iter 32 | log_filename = '/tmp/logfile' 33 | 34 | # preset 35 | data = 'voc' 36 | pretrained_model = 'vgg16' 37 | batch_size = 1 38 | 39 | # training 40 | epoch = 14 41 | 42 | 43 | use_adam = False # Use Adam optimizer 44 | use_chainer = False # try match everything as chainer 45 | use_drop = False # use dropout in RoIHead 46 | # debug 47 | debug_file = '/tmp/debugf' 48 | 49 | test_num = 10000 50 | # model 51 | load_path = None 52 | 53 | caffe_pretrain = True # use caffe pretrained model instead of torchvision 54 | caffe_pretrain_path = 'checkpoints/vgg16_caffe.pth' 55 | 56 | # dataset 57 | label_names = ['aeroplane', 58 | 'bicycle', 59 | 'bird', 60 | 'boat', 61 | 'bottle', 62 | 'bus', 63 | 'car', 64 | 'cat', 65 | 'chair', 66 | 'cow', 67 | 'diningtable', 68 | 'dog', 69 | 'horse', 70 | 'motorbike', 71 | 'person', 72 | 'pottedplant', 73 | 'sheep', 74 | 'sofa', 75 | 'train', 76 | 'tvmonitor'] 77 | def _parse(self, kwargs): 78 | state_dict = self._state_dict() 79 | for k, v in kwargs.items(): 80 | if k not in state_dict: 81 | raise ValueError('UnKnown Option: "--%s"' % k) 82 | if k == 'label_names': 83 | if isinstance(v, str): 84 | v = eval(v) 85 | setattr(self, k, v) 86 | 87 | print('======user config========') 88 | pprint(self._state_dict()) 89 | print('==========end============') 90 | 91 | def _state_dict(self): 92 | return {k: getattr(self, k) for k, _ in Config.__dict__.items() \ 93 | if not k.startswith('_')} 94 | 95 | opt = Config() 96 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | pip-wheel-metadata/ 25 | share/python-wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .nox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | *.py,cover 52 | .hypothesis/ 53 | .pytest_cache/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | .python-version 87 | 88 | # pipenv 89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 92 | # install all needed dependencies. 93 | #Pipfile.lock 94 | 95 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 96 | __pypackages__/ 97 | 98 | # Celery stuff 99 | celerybeat-schedule 100 | celerybeat.pid 101 | 102 | # SageMath parsed files 103 | *.sage.py 104 | 105 | # Environments 106 | .env 107 | .venv 108 | env/ 109 | venv/ 110 | ENV/ 111 | env.bak/ 112 | venv.bak/ 113 | 114 | # Spyder project settings 115 | .spyderproject 116 | .spyproject 117 | 118 | # Rope project settings 119 | .ropeproject 120 | 121 | # mkdocs documentation 122 | /site 123 | 124 | # mypy 125 | .mypy_cache/ 126 | .dmypy.json 127 | dmypy.json 128 | 129 | # Pyre type checker 130 | .pyre/ 131 | 132 | LibriSpeech/ 133 | trained_models 134 | .idea 135 | .ipynb_checkpoints/ 136 | .DS_Store 137 | *.tar.gz 138 | *.pyc 139 | *.json 140 | *.csv 141 | *.pth 142 | chinese_data_features 143 | train_100_corpus 144 | data/ 145 | result/ 146 | federated_learning/__pycache__ 147 | *.zip 148 | credit_g/ 149 | experimental_results/ 150 | spambase/ 151 | multiple_region_dann/ 152 | census_dann/ 153 | census_target/ 154 | cell_manage_dann/ 155 | cell_manage_target/ 156 | lending_dann/ 157 | lending_target/ 158 | resilient/ 159 | data_process/cell_process/.ipynb_checkpoints/ 160 | singleton_dann/ 161 | datasets/census_original 162 | datasets/census_processed 163 | communication_efficient_experiment/ 164 | 165 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/config/yolov3-tiny.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Testing 3 | batch=1 4 | subdivisions=1 5 | # Training 6 | # batch=64 7 | # subdivisions=2 8 | width=416 9 | height=416 10 | channels=3 11 | momentum=0.9 12 | decay=0.0005 13 | angle=0 14 | saturation = 1.5 15 | exposure = 1.5 16 | hue=.1 17 | 18 | learning_rate=0.001 19 | burn_in=1000 20 | max_batches = 500200 21 | policy=steps 22 | steps=400000,450000 23 | scales=.1,.1 24 | 25 | # 0 26 | [convolutional] 27 | batch_normalize=1 28 | filters=16 29 | size=3 30 | stride=1 31 | pad=1 32 | activation=leaky 33 | 34 | # 1 35 | [maxpool] 36 | size=2 37 | stride=2 38 | 39 | # 2 40 | [convolutional] 41 | batch_normalize=1 42 | filters=32 43 | size=3 44 | stride=1 45 | pad=1 46 | activation=leaky 47 | 48 | # 3 49 | [maxpool] 50 | size=2 51 | stride=2 52 | 53 | # 4 54 | [convolutional] 55 | batch_normalize=1 56 | filters=64 57 | size=3 58 | stride=1 59 | pad=1 60 | activation=leaky 61 | 62 | # 5 63 | [maxpool] 64 | size=2 65 | stride=2 66 | 67 | # 6 68 | [convolutional] 69 | batch_normalize=1 70 | filters=128 71 | size=3 72 | stride=1 73 | pad=1 74 | activation=leaky 75 | 76 | # 7 77 | [maxpool] 78 | size=2 79 | stride=2 80 | 81 | # 8 82 | [convolutional] 83 | batch_normalize=1 84 | filters=256 85 | size=3 86 | stride=1 87 | pad=1 88 | activation=leaky 89 | 90 | # 9 91 | [maxpool] 92 | size=2 93 | stride=2 94 | 95 | # 10 96 | [convolutional] 97 | batch_normalize=1 98 | filters=512 99 | size=3 100 | stride=1 101 | pad=1 102 | activation=leaky 103 | 104 | # 11 105 | [maxpool] 106 | size=2 107 | stride=1 108 | 109 | # 12 110 | [convolutional] 111 | batch_normalize=1 112 | filters=1024 113 | size=3 114 | stride=1 115 | pad=1 116 | activation=leaky 117 | 118 | ########### 119 | 120 | # 13 121 | [convolutional] 122 | batch_normalize=1 123 | filters=256 124 | size=1 125 | stride=1 126 | pad=1 127 | activation=leaky 128 | 129 | # 14 130 | [convolutional] 131 | batch_normalize=1 132 | filters=512 133 | size=3 134 | stride=1 135 | pad=1 136 | activation=leaky 137 | 138 | # 15 139 | [convolutional] 140 | size=1 141 | stride=1 142 | pad=1 143 | filters=255 144 | activation=linear 145 | 146 | 147 | 148 | # 16 149 | [yolo] 150 | mask = 3,4,5 151 | anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 152 | classes=80 153 | num=6 154 | jitter=.3 155 | ignore_thresh = .7 156 | truth_thresh = 1 157 | random=1 158 | 159 | # 17 160 | [route] 161 | layers = -4 162 | 163 | # 18 164 | [convolutional] 165 | batch_normalize=1 166 | filters=128 167 | size=1 168 | stride=1 169 | pad=1 170 | activation=leaky 171 | 172 | # 19 173 | [upsample] 174 | stride=2 175 | 176 | # 20 177 | [route] 178 | layers = -1, 8 179 | 180 | # 21 181 | [convolutional] 182 | batch_normalize=1 183 | filters=256 184 | size=3 185 | stride=1 186 | pad=1 187 | activation=leaky 188 | 189 | # 22 190 | [convolutional] 191 | size=1 192 | stride=1 193 | pad=1 194 | filters=255 195 | activation=linear 196 | 197 | # 23 198 | [yolo] 199 | mask = 1,2,3 200 | anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 201 | classes=80 202 | num=6 203 | jitter=.3 204 | ignore_thresh = .7 205 | truth_thresh = 1 206 | random=1 207 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/produce_census_tsne_data.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from experiments.income_census.tsne_config import tsne_embedding_creation 4 | from datasets.census_dataloader import get_income_census_dataloaders 5 | from experiments.income_census import train_census_fg_adapt_pretrain as fg_dann 6 | from experiments.income_census import train_census_no_fg_adapt_pretrain as no_fg_dann 7 | from experiments.income_census.train_config import data_tag, data_dir, data_hyperparameters 8 | from utils import produce_data_for_distribution 9 | 10 | if __name__ == "__main__": 11 | 12 | parser = argparse.ArgumentParser("census_tsne_distribution") 13 | parser.add_argument('--task_id', type=str, required=True) 14 | args = parser.parse_args() 15 | task_id = args.task_id 16 | apply_adaptation = tsne_embedding_creation["apply_adaptation"] 17 | using_interaction = tsne_embedding_creation["using_interaction"] 18 | 19 | print(f"[INFO] task id : {task_id}") 20 | print(f"[INFO] apply adaptation : {apply_adaptation}") 21 | print(f"[INFO] using interaction : {using_interaction}") 22 | 23 | if apply_adaptation: 24 | tag = "ad" 25 | model_dir = data_hyperparameters["census_fg_pretrained_model_dir"] 26 | else: 27 | tag = "no-ad" 28 | model_dir = data_hyperparameters["census_no-ad_model_dir"] 29 | 30 | feature_group_name_list = ['employment', 'demographics', 'migration', 'household'] 31 | if using_interaction: 32 | feature_grp_intr_name_list = ['emp-demo', 'emp-mig', 'emp-house', 'demo-mig', 'demo-house', 'mig-house'] 33 | feature_group_name_list = feature_group_name_list + feature_grp_intr_name_list 34 | 35 | tsne_embedding_dir = tsne_embedding_creation["tsne_embedding_data_dir"] 36 | 37 | source_train_file_name = data_dir + f'undergrad_census9495_ad_{data_tag}_train.csv' 38 | target_train_file_name = data_dir + f'grad_census9495_ad_{data_tag}_train.csv' 39 | 40 | # load pre-trained model 41 | print("[INFO] load pre-trained model.") 42 | use_feature_group = True 43 | if use_feature_group: 44 | model = fg_dann.create_fg_census_global_model(using_interaction=using_interaction) 45 | else: 46 | model = no_fg_dann.create_no_fg_census_global_model() 47 | 48 | model.load_model(root=model_dir, 49 | task_id=task_id, 50 | load_global_classifier=True, 51 | timestamp=None) 52 | 53 | print("[INFO] load data.") 54 | batch_size = 4000 55 | target_train_loader, _ = get_income_census_dataloaders( 56 | ds_file_name=target_train_file_name, batch_size=batch_size, split_ratio=1.0) 57 | source_train_loader, _ = get_income_census_dataloaders( 58 | ds_file_name=source_train_file_name, batch_size=batch_size, split_ratio=1.0) 59 | 60 | print("[INFO] produce data for drawing TSNE feature distribution.") 61 | produce_data_for_distribution(model, 62 | source_train_loader, 63 | target_train_loader, 64 | feature_group_name_list, 65 | tsne_embedding_dir, 66 | tag + str(batch_size)) 67 | -------------------------------------------------------------------------------- /publications/FedCG/servers/fedsplit.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn as nn 4 | 5 | from config import args, logger, device 6 | from models import Classifier 7 | from utils import set_seed 8 | 9 | 10 | class Server(): 11 | 12 | def __init__(self, clients): 13 | self.clients = clients 14 | 15 | self.weights = [] 16 | for client in clients: 17 | self.weights.append(client.train_size) 18 | self.weights = np.array(self.weights) / np.sum(self.weights) 19 | logger.info("client weights: %s" % str(self.weights.tolist())) 20 | 21 | self.init_net() 22 | 23 | def get_params(self, models): 24 | params = [] 25 | for model in models: 26 | params.append({"params": self.global_net[model].parameters()}) 27 | return params 28 | 29 | def frozen_net(self, models, frozen): 30 | for model in models: 31 | for param in self.global_net[model].parameters(): 32 | param.requires_grad = not frozen 33 | if frozen: 34 | self.global_net[model].eval() 35 | else: 36 | self.global_net[model].train() 37 | 38 | def init_net(self): 39 | ############################################################## 40 | # frozen all models' parameters, unfrozen when need to train # 41 | ############################################################## 42 | set_seed(args.seed) 43 | self.global_net = nn.ModuleDict() 44 | 45 | self.global_net["classifier"] = Classifier() 46 | self.frozen_net(["classifier"], True) 47 | 48 | self.global_net.to(device) 49 | 50 | self.KL_criterion = nn.KLDivLoss(reduction="batchmean").to(device) 51 | self.CE_criterion = nn.CrossEntropyLoss().to(device) 52 | 53 | def load_client(self): 54 | for i in range(len(self.clients)): 55 | checkpoint = torch.load(args.checkpoint_dir + "/client" + str(i) + ".pkl") 56 | self.clients[i].net.load_state_dict(checkpoint["net"]) 57 | self.clients[i].EC_optimizer.load_state_dict(checkpoint["EC_optimizer"]) 58 | 59 | def save_client(self): 60 | for i in range(len(self.clients)): 61 | optim_dict = { 62 | "net": self.clients[i].net.state_dict(), 63 | "EC_optimizer": self.clients[i].EC_optimizer.state_dict(), 64 | } 65 | torch.save(optim_dict, args.checkpoint_dir + "/client" + str(i) + ".pkl") 66 | 67 | def receive(self, models): 68 | 69 | for model in models: 70 | avg_param = {} 71 | params = [] 72 | for client in self.clients: 73 | params.append(client.net[model].state_dict()) 74 | 75 | for key in params[0].keys(): 76 | avg_param[key] = params[0][key] * self.weights[0] 77 | for idx in range(1, len(self.clients)): 78 | avg_param[key] += params[idx][key] * self.weights[idx] 79 | self.global_net[model].load_state_dict(avg_param) 80 | 81 | def send(self, models): 82 | for model in models: 83 | global_param = self.global_net[model].state_dict() 84 | for client in self.clients: 85 | client.net[model].load_state_dict(global_param) 86 | -------------------------------------------------------------------------------- /publications/PrADA/datasets/ppd_dataloader.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from torch.utils.data import DataLoader 4 | 5 | from datasets.census_dataset import SimpleDataset 6 | 7 | # wide_columns = ['UserInfo_10', 'UserInfo_14', 'UserInfo_15', 'UserInfo_18', 'UserInfo_22', 'UserInfo_3', 8 | # 'UserInfo_16', 'UserInfo_1', 'UserInfo_23', 'UserInfo_9'] 9 | 10 | 11 | wide_columns = ['UserInfo_10', 'UserInfo_14', 'UserInfo_15', 'UserInfo_18', 'UserInfo_22', 'UserInfo_23'] 12 | 13 | 14 | def get_selected_columns(df, use_all_features=True): 15 | """ 16 | select subset of all columns for training 17 | """ 18 | all_columns = list(df.columns) 19 | if use_all_features: 20 | return all_columns 21 | deep_columns = all_columns[17:] 22 | select_columns = wide_columns + deep_columns 23 | return select_columns 24 | 25 | 26 | def shuffle_data(data): 27 | len = data.shape[0] 28 | perm_idxs = np.random.permutation(len) 29 | return data[perm_idxs] 30 | 31 | 32 | def get_datasets(ds_file_name, shuffle=False, split_ratio=0.9): 33 | dataframe = pd.read_csv(ds_file_name, skipinitialspace=True) 34 | samples = dataframe[get_selected_columns(dataframe, use_all_features=True)].values 35 | num_pos = np.sum(samples[:, -1]) 36 | num_neg = len(samples) - num_pos 37 | print(f"[INFO] ---- number of positive sample:{num_pos}") 38 | print(f"[INFO] ---- number of negative sample:{num_neg}") 39 | 40 | # print(samples) 41 | if shuffle: 42 | samples = shuffle_data(samples) 43 | 44 | if split_ratio == 1.0: 45 | print(f"samples shape: {samples.shape}, {samples.dtype}") 46 | train_dataset = SimpleDataset(samples[:, :-1], samples[:, -1]) 47 | return train_dataset, None 48 | else: 49 | num_train = int(split_ratio * samples.shape[0]) 50 | train_samples = samples[:num_train].astype(np.float) 51 | val_samples = samples[num_train:].astype(np.float) 52 | print(f"train samples shape: {train_samples.shape}, {train_samples.dtype}") 53 | print(f"valid samples shape: {val_samples.shape}, {train_samples.dtype}") 54 | train_dataset = SimpleDataset(train_samples[:, :-1], train_samples[:, -1]) 55 | val_dataset = SimpleDataset(val_samples[:, :-1], val_samples[:, -1]) 56 | return train_dataset, val_dataset 57 | 58 | 59 | def get_dataloader(train_dataset, batch_size=32, num_workers=6): 60 | mnist_train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers) 61 | return mnist_train_loader 62 | 63 | 64 | def get_dataloaders(train_dataset, valid_dataset, batch_size=32, num_workers=6): 65 | mnist_train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=num_workers) 66 | mnist_valid_loader = None 67 | if valid_dataset is not None: 68 | mnist_valid_loader = DataLoader(valid_dataset, batch_size=batch_size * 2, shuffle=True, num_workers=num_workers) 69 | return mnist_train_loader, mnist_valid_loader 70 | 71 | 72 | def get_pdd_dataloaders(ds_file_name, split_ratio=0.9, batch_size=64, num_workers=6): 73 | train_dataset, valid_dataset = get_datasets(ds_file_name=ds_file_name, shuffle=True, split_ratio=split_ratio) 74 | return get_dataloaders(train_dataset, valid_dataset, batch_size=batch_size, num_workers=num_workers) 75 | -------------------------------------------------------------------------------- /publications/FedCG/servers/fedavg.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn as nn 4 | 5 | from config import args, logger, device 6 | from models import Classifier, Extractor 7 | from utils import set_seed 8 | 9 | 10 | class Server(): 11 | 12 | def __init__(self, clients): 13 | self.clients = clients 14 | 15 | self.weights = [] 16 | for client in clients: 17 | self.weights.append(client.train_size) 18 | self.weights = np.array(self.weights) / np.sum(self.weights) 19 | logger.info("client weights: %s" % str(self.weights.tolist())) 20 | 21 | self.init_net() 22 | 23 | def get_params(self, models): 24 | params = [] 25 | for model in models: 26 | params.append({"params": self.global_net[model].parameters()}) 27 | return params 28 | 29 | def frozen_net(self, models, frozen): 30 | for model in models: 31 | for param in self.global_net[model].parameters(): 32 | param.requires_grad = not frozen 33 | if frozen: 34 | self.global_net[model].eval() 35 | else: 36 | self.global_net[model].train() 37 | 38 | def init_net(self): 39 | ############################################################## 40 | # frozen all models' parameters, unfrozen when need to train # 41 | ############################################################## 42 | set_seed(args.seed) 43 | self.global_net = nn.ModuleDict() 44 | 45 | self.global_net["extractor"] = Extractor() 46 | self.global_net["classifier"] = Classifier() 47 | self.frozen_net(["extractor", "classifier"], True) 48 | 49 | self.global_net.to(device) 50 | 51 | self.KL_criterion = nn.KLDivLoss(reduction="batchmean").to(device) 52 | self.CE_criterion = nn.CrossEntropyLoss().to(device) 53 | 54 | def load_client(self): 55 | for i in range(len(self.clients)): 56 | checkpoint = torch.load(args.checkpoint_dir + "/client" + str(i) + ".pkl") 57 | self.clients[i].net.load_state_dict(checkpoint["net"]) 58 | self.clients[i].EC_optimizer.load_state_dict(checkpoint["EC_optimizer"]) 59 | 60 | def save_client(self): 61 | for i in range(len(self.clients)): 62 | optim_dict = { 63 | "net": self.clients[i].net.state_dict(), 64 | "EC_optimizer": self.clients[i].EC_optimizer.state_dict(), 65 | } 66 | torch.save(optim_dict, args.checkpoint_dir + "/client" + str(i) + ".pkl") 67 | 68 | def receive(self, models): 69 | for model in models: 70 | avg_param = {} 71 | params = [] 72 | for client in self.clients: 73 | params.append(client.net[model].state_dict()) 74 | 75 | for key in params[0].keys(): 76 | avg_param[key] = params[0][key] * self.weights[0] 77 | for idx in range(1, len(self.clients)): 78 | avg_param[key] += params[idx][key] * self.weights[idx] 79 | self.global_net[model].load_state_dict(avg_param) 80 | 81 | def send(self, models): 82 | for model in models: 83 | global_param = self.global_net[model].state_dict() 84 | for client in self.clients: 85 | client.net[model].load_state_dict(global_param) 86 | -------------------------------------------------------------------------------- /publications/FedCG/servers/fedprox.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn as nn 4 | 5 | from config import args, logger, device 6 | from models import Classifier, Extractor 7 | from utils import set_seed 8 | 9 | 10 | class Server(): 11 | 12 | def __init__(self, clients): 13 | self.clients = clients 14 | 15 | self.weights = [] 16 | for client in clients: 17 | self.weights.append(client.train_size) 18 | self.weights = np.array(self.weights) / np.sum(self.weights) 19 | logger.info("client weights: %s" % str(self.weights.tolist())) 20 | 21 | self.init_net() 22 | 23 | def get_params(self, models): 24 | params = [] 25 | for model in models: 26 | params.append({"params": self.global_net[model].parameters()}) 27 | return params 28 | 29 | def frozen_net(self, models, frozen): 30 | for model in models: 31 | for param in self.global_net[model].parameters(): 32 | param.requires_grad = not frozen 33 | if frozen: 34 | self.global_net[model].eval() 35 | else: 36 | self.global_net[model].train() 37 | 38 | def init_net(self): 39 | ############################################################## 40 | # frozen all models' parameters, unfrozen when need to train # 41 | ############################################################## 42 | set_seed(args.seed) 43 | self.global_net = nn.ModuleDict() 44 | 45 | self.global_net["extractor"] = Extractor() 46 | self.global_net["classifier"] = Classifier() 47 | self.frozen_net(["extractor", "classifier"], True) 48 | 49 | self.global_net.to(device) 50 | 51 | self.KL_criterion = nn.KLDivLoss(reduction="batchmean").to(device) 52 | self.CE_criterion = nn.CrossEntropyLoss().to(device) 53 | 54 | def load_client(self): 55 | for i in range(len(self.clients)): 56 | checkpoint = torch.load(args.checkpoint_dir + "/client" + str(i) + ".pkl") 57 | self.clients[i].net.load_state_dict(checkpoint["net"]) 58 | self.clients[i].EC_optimizer.load_state_dict(checkpoint["EC_optimizer"]) 59 | 60 | def save_client(self): 61 | for i in range(len(self.clients)): 62 | optim_dict = { 63 | "net": self.clients[i].net.state_dict(), 64 | "EC_optimizer": self.clients[i].EC_optimizer.state_dict(), 65 | } 66 | torch.save(optim_dict, args.checkpoint_dir + "/client" + str(i) + ".pkl") 67 | 68 | def receive(self, models): 69 | 70 | for model in models: 71 | avg_param = {} 72 | params = [] 73 | for client in self.clients: 74 | params.append(client.net[model].state_dict()) 75 | 76 | for key in params[0].keys(): 77 | avg_param[key] = params[0][key] * self.weights[0] 78 | for idx in range(1, len(self.clients)): 79 | avg_param[key] += params[idx][key] * self.weights[idx] 80 | self.global_net[model].load_state_dict(avg_param) 81 | 82 | def send(self, models): 83 | for model in models: 84 | global_param = self.global_net[model].state_dict() 85 | for client in self.clients: 86 | client.net[model].load_state_dict(global_param) 87 | -------------------------------------------------------------------------------- /publications/ss_vfnas/README.md: -------------------------------------------------------------------------------- 1 | # Cross-silo Federated Neural Architecture Search for Heterogeneous and Cooperative Systems 2 | 3 |

4 | 5 |

6 | 7 | ## Overview 8 | 9 | In many cooperative systems (i.e. autonomous vehicles, robotics, hospital networks), data are privately and heterogeneously distributed among devices with various computational constraints, and no party has a global view of data or device distribution. Federated Neural Architecture Search (FedNAS) was previously proposed to adapt Neural Architecture Search (NAS) into Federated Learning (FL), in order to provide both privacy and automation to such uninspectable systems with resource and latency constraints. However, existing Federated NAS approaches learn an universal model across all parties therefore they do not address the data and device heterogeneity issue well. In this work, we present Self-supervised Vertical Fed- erated Neural Architecture Search (SS-VFNAS) for automating FL where participants hold heterogeneous data and devices, a common cross-silo scenario. SS-VFNAS simultaneously optimized all parties’ model architecture and parameters for the best global performance under a vertical FL (VFL) framework using only a small set of aligned and labeled data whereas preserving each party’s local optimal model architecture under a self-supervised NAS framework using unaligned and unlabeled local data. We demonstrate experimentally that our approach has superior per- formance, communication efficiency and privacy and is capable of generating high-performance and highly-transferable hetero- geneous architectures with only limited overlapping samples, providing practical solutions for designing collaborative systems with both limited data and resource constraints. 10 | 11 | ## Dataset 12 | * modelnet40v1png: [maxwell.cs.umass.edu/mvcnn-data](http://maxwell.cs.umass.edu/mvcnn-data/) 13 | * chexpert: [stanfordmlgroup.github.io](https://stanfordmlgroup.github.io/competitions/chexpert/) 14 | 15 | ## Getting Started 16 | ### Install dependencies 17 | ## Requirements 18 | 19 | - python3 20 | - pytorch 21 | - graphviz 22 | - First install using `apt install` and then `pip install`. 23 | - numpy 24 | - tensorboardX 25 | 26 | ## Run example 27 | 28 | Adjust the batch size if out of memory (OOM) occurs. It dependes on your gpu memory size and genotype. 29 | 30 | - Search 31 | 32 | ```shell 33 | python train_search_k_party.py --data data/modelnet40v1png --name test 34 | ``` 35 | 36 | - Search with self-supervised 37 | ```shell 38 | python train_search_k_party_moco.py --data data/modelnet40v1png --name test 39 | ``` 40 | 41 | - Augment 42 | 43 | ```shell 44 | python train_darts_k_party.py --data data/modelnet40v1png --name test --genotypes_file path_to_genotypes 45 | ``` 46 | 47 | - Train manual network 48 | ```shell 49 | python train_manual_k_party.py --data data/modelnet40v1png --name test --layers 18 50 | ``` 51 | 52 | ### Citation 53 | Accepted for publication in edited book titled "Federated and Transfer Learning", Springer, Cham 54 | 55 | Please kindly cite our paper if you find this code useful for your research. 56 | 57 | ``` 58 | @article{liang2021self, 59 | title={Self-supervised cross-silo federated neural architecture search}, 60 | author={Liang, Xinle and Liu, Yang and Luo, Jiahuan and He, Yuanqin and Chen, Tianjian and Yang, Qiang}, 61 | journal={arXiv preprint arXiv:2101.11896}, 62 | year={2021} 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /publications/ss_vfnas/architects/architect_k_party.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import torch.nn as nn 4 | from torch.autograd import Variable 5 | 6 | 7 | def _concat(xs): 8 | return torch.cat([x.view(-1) for x in xs]) 9 | 10 | 11 | class Architect_A(object): 12 | def __init__(self, model, args): 13 | self.network_momentum = args.momentum 14 | self.network_weight_decay = args.weight_decay 15 | self.k = args.k 16 | self.model = model 17 | self.optimizer = torch.optim.Adam(self.model.arch_parameters(), 18 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 19 | weight_decay=args.arch_weight_decay) 20 | 21 | def update_alpha(self, input_valid, U_B_val_list, target_valid): 22 | if U_B_val_list is not None: 23 | U_B_val_list = [torch.autograd.Variable(U_B_valid, requires_grad=True).cuda() for U_B_valid in U_B_val_list] 24 | self.optimizer.zero_grad() 25 | loss, _ = self.model._loss(input_valid, U_B_val_list, target_valid) 26 | U_B_gradients_list = None 27 | if U_B_val_list is not None: 28 | U_B_gradients_list = [torch.autograd.grad(loss, U_B_valid, retain_graph=True) for U_B_valid in U_B_val_list] 29 | loss.backward() 30 | self.optimizer.step() 31 | return U_B_gradients_list 32 | 33 | def update_weights(self, trn_X, U_B_train_list, target_train, weights_optim, grad_clip): 34 | if U_B_train_list is not None: 35 | U_B_train_list = [torch.autograd.Variable(U_B_train_list[i], requires_grad=True).cuda() for i in 36 | range(0, len(U_B_train_list))] 37 | weights_optim.zero_grad() 38 | loss, logits = self.model._loss(trn_X, U_B_train_list, target_train) 39 | U_B_gradients_list = None 40 | if U_B_train_list is not None: 41 | U_B_gradients_list = [torch.autograd.grad(loss, U_B_train, retain_graph=True) for U_B_train in 42 | U_B_train_list] 43 | loss.backward() 44 | nn.utils.clip_grad_norm_(self.model.parameters(), grad_clip) 45 | weights_optim.step() 46 | return U_B_gradients_list, logits, loss 47 | 48 | 49 | class Architect_B(object): 50 | def __init__(self, model, args): 51 | self.network_momentum = args.momentum 52 | self.network_weight_decay = args.weight_decay 53 | self.model = model 54 | self.optimizer = torch.optim.Adam(self.model.arch_parameters(), 55 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 56 | weight_decay=args.arch_weight_decay) 57 | 58 | def update_alpha(self, U_B_val, U_B_gradients): 59 | model_B_alpha_gradients = torch.autograd.grad(U_B_val, self.model.arch_parameters(), grad_outputs=U_B_gradients) 60 | self.optimizer.zero_grad() 61 | for w, g in zip(self.model.arch_parameters(), model_B_alpha_gradients): 62 | w.grad = g.detach() 63 | self.optimizer.step() 64 | 65 | def update_weights(self, U_B_train, U_B_gradients, weights_optim, grad_clip): 66 | model_B_weight_gradients = torch.autograd.grad(U_B_train, self.model.parameters(), grad_outputs=U_B_gradients) 67 | weights_optim.zero_grad() 68 | for w, g in zip(self.model.parameters(), model_B_weight_gradients): 69 | w.grad = g.detach() 70 | nn.utils.clip_grad_norm_(self.model.parameters(), grad_clip) 71 | weights_optim.step() 72 | -------------------------------------------------------------------------------- /publications/ss_vfnas/dp_utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | differential privacy utility functions 3 | author: hyq 4 | """ 5 | import torch 6 | 7 | 8 | def add_dp_v1(input_tensor, clip_value=5.0, variance=1.0, device=torch.device('cpu')): 9 | """ 10 | cpu version 11 | :param input_tensor: 12 | :param clip_value: 13 | :param variance: 14 | :param device: 15 | :return: 16 | """ 17 | input_copy = input_tensor.detach().clone() 18 | 19 | with torch.no_grad(): 20 | up_norm_factor = max(torch.max(torch.norm(input_copy, dim=1)).item()/clip_value, 1.0) 21 | input_noised = input_copy / up_norm_factor + torch.normal(0, variance, input_tensor.shape) 22 | input_with_dp = torch.autograd.Variable(input_noised, requires_grad=True).to(device) 23 | return input_with_dp 24 | 25 | 26 | def add_dp_v2(input_tensor, clip_value=5.0, variance=1.0, device=torch.device('cuda')): 27 | """ 28 | gpu compatible version 29 | :param input_tensor: variable 30 | :param clip_value: clipping value of 2-norm 31 | :param variance: variance of gaussian noise 32 | :param device: 33 | :return: variable with dp applied 34 | """ 35 | input_copy = input_tensor.detach().clone() 36 | 37 | with torch.no_grad(): 38 | # clip 2-norm per sample 39 | norm_factor = torch.div(torch.max(torch.norm(input_copy, dim=1)), clip_value+1e-6).clamp(min=1.0) 40 | # add gaussian noise 41 | input_noised = torch.div(input_copy, norm_factor) + torch.normal(0, variance, input_tensor.shape, device=device) 42 | input_with_dp = torch.autograd.Variable(input_noised, requires_grad=True).to(device) 43 | return input_with_dp 44 | 45 | 46 | def add_dp_v3(input_tensor, clip_value=5.0, variance=1.0): 47 | """ 48 | gpu compatible version 49 | :param input_tensor: variable 50 | :param clip_value: clipping value of 2-norm 51 | :param variance: variance of gaussian noise 52 | :param device: 53 | :return: variable with dp applied 54 | """ 55 | input_copy = input_tensor.detach().clone() 56 | 57 | with torch.no_grad(): 58 | # clip 2-norm per sample 59 | norm_factor = torch.div(torch.max(torch.norm(input_copy, dim=1)), clip_value+1e-6).clamp(min=1.0) 60 | # add gaussian noise 61 | input_noised = torch.div(input_copy, norm_factor) + torch.normal(0, variance, input_tensor.shape).cuda() 62 | input_with_dp = torch.autograd.Variable(input_noised, requires_grad=True).cuda() 63 | return input_with_dp 64 | 65 | def add_dp_to_list(input_tensor_list, clip_value=5.0, variance=1.0): 66 | """ 67 | gpu compatible version 68 | :param input_tensor: variable 69 | :param clip_value: clipping value of 2-norm 70 | :param variance: variance of gaussian noise 71 | :param device: 72 | :return: variable with dp applied 73 | """ 74 | output_list = [] 75 | for input_tensor in input_tensor_list: 76 | if isinstance(input_tensor, tuple): 77 | input_copy = input_tensor[0].detach().clone() 78 | else: 79 | input_copy = input_tensor.detach().clone() 80 | with torch.no_grad(): 81 | # clip 2-norm per sample 82 | norm_factor = torch.div(torch.max(torch.norm(input_copy, dim=1)), clip_value+1e-6).clamp(min=1.0) 83 | # add gaussian noise 84 | input_noised = torch.div(input_copy, norm_factor) + torch.normal(0, variance, input_copy.shape).cuda() 85 | input_with_dp = torch.autograd.Variable(input_noised, requires_grad=True).cuda() 86 | output_list.append(input_with_dp) 87 | return output_list -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Welcome 4 | This guide provides guidelines for contributors on how to make new changes into this repository. **Please leave comments / suggestions if you find something is missing or incorrect.** 5 | 6 | ## Overall Workflow 7 | 8 | 1. Prepare a contribution proposal document and discuss with maintainers about your contribution. 9 | 2. After getting approval from maintainers, make changes to your own fork. 10 | 3. PR to `research` **main** branch. 11 | 12 | ### Contribution Proposal 13 | When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the maintainers of this repository before making a change. This is referred as a proposal, which should contain some basic description of your contribution. 14 | 15 | ### Fork, Clone and Branch 16 | Changes should be made on your own fork in a new branch. To start contributing, fork this repository and clone it to your local workspace. For more details, please refer to the github [official document](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork). 17 | 18 | ### Making and Committing Changes 19 | New contributions should follow the file and folder organizing convention in the [README](README.md). New index items should be added in that README file. If new subdirectory needs to be created under one of the top folders, a separate README.md file should be created containing basic description and usage of this contribution. 20 | 21 | As this project has integrated the [DCO (Developer Certificate of Origin)](https://probot.github.io/apps/dco/) check tool, contributors are required to sign-off that they adhere to those requirements by adding a Signed-off-by line to the commit messages. Git has even provided a -s command line option to append that automatically to your commit messages, please use it when you commit your changes. 22 | ``` 23 | $ git commit -s -m 'This is my commit message' 24 | ``` 25 | The commit message should follow the convention on how to write a git commit message. Be sure to include any related GitHub issue references in the commit message. 26 | 27 | 28 | ### License 29 | This repository is applying Apache License. If your new contribution adds new subdirectory under the top folders, please include a License and Disclaimer section in your subdirectory README.md file as below: 30 | ``` 31 | ## License and Disclaimer 32 | By downloading or using the work in this folder, you accept and agree to be bound by all of the terms and conditions of the [LICENSE](https://github.com/FederatedAI/research/blob/master/LICENSE) and [DISCLAIMER](https://github.com/FederatedAI/research/blob/master/DISCLAIMER). 33 | ``` 34 | 35 | ### Push and Create PR 36 | When ready for review, push your branch to your fork repository on github.com. 37 | Then visit your fork at github.com and click the `Compare & Pull Request` button next to your branch to create a new pull request (PR). The description of PR should contain basic information in the proposal about the contribution. 38 | 39 | Once your pull request has been opened it will be assigned to one or more reviewers. Those reviewers will do a thorough code review, looking for correctness, bugs, opportunities for improvement, documentation and comments, and style. 40 | 41 | If there are review requiring further changes to the PR, you make new commits into the same branch and push again. 42 | 43 | ## Advocate 44 | We welcome any articles or blog posts or other forms to advocate the contributions in this repository. If you can let us know the links to the articles or blog posts, we can gather them to the Wiki and help promote them to the community. Additionally, if needed, maintainers in this project may contact and work with you to further promote your contributions. -------------------------------------------------------------------------------- /publications/ss_vfnas/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | import torch 4 | import utils 5 | import logging 6 | import argparse 7 | import torch.nn as nn 8 | import torch.utils 9 | import torchvision.datasets as dset 10 | import torch.backends.cudnn as cudnn 11 | 12 | from torch.autograd import Variable 13 | from models.model import NetworkCIFAR as Network 14 | 15 | 16 | parser = argparse.ArgumentParser("cifar") 17 | parser.add_argument('--data', type=str, default='../data', help='location of the data corpus') 18 | parser.add_argument('--batch_size', type=int, default=96, help='batch size') 19 | parser.add_argument('--report_freq', type=float, default=50, help='report frequency') 20 | parser.add_argument('--gpu', type=int, default=0, help='gpu device id') 21 | parser.add_argument('--init_channels', type=int, default=36, help='num of init channels') 22 | parser.add_argument('--layers', type=int, default=20, help='total number of layers') 23 | parser.add_argument('--model_path', type=str, default='EXP/model.pt', help='path of pretrained model') 24 | parser.add_argument('--auxiliary', action='store_true', default=False, help='use auxiliary tower') 25 | parser.add_argument('--cutout', action='store_true', default=False, help='use cutout') 26 | parser.add_argument('--cutout_length', type=int, default=16, help='cutout length') 27 | parser.add_argument('--drop_path_prob', type=float, default=0.2, help='drop path probability') 28 | parser.add_argument('--seed', type=int, default=0, help='random seed') 29 | parser.add_argument('--arch', type=str, default='DARTS', help='which architecture to use') 30 | args = parser.parse_args() 31 | 32 | log_format = '%(asctime)s %(message)s' 33 | logging.basicConfig(stream=sys.stdout, level=logging.INFO, 34 | format=log_format, datefmt='%m/%d %I:%M:%S %p') 35 | 36 | CIFAR_CLASSES = 10 37 | 38 | 39 | def main(): 40 | if not torch.cuda.is_available(): 41 | logging.info('no gpu device available') 42 | sys.exit(1) 43 | 44 | np.random.seed(args.seed) 45 | torch.cuda.set_device(args.gpu) 46 | cudnn.benchmark = True 47 | torch.manual_seed(args.seed) 48 | cudnn.enabled=True 49 | torch.cuda.manual_seed(args.seed) 50 | logging.info('gpu device = %d' % args.gpu) 51 | logging.info("args = %s", args) 52 | 53 | genotype = eval("genotypes.%s" % args.arch) 54 | model = Network(args.init_channels, CIFAR_CLASSES, args.layers, args.auxiliary, genotype) 55 | model = model.cuda() 56 | utils.load(model, args.model_path) 57 | 58 | logging.info("param size = %fMB", utils.count_parameters_in_MB(model)) 59 | 60 | criterion = nn.CrossEntropyLoss() 61 | criterion = criterion.cuda() 62 | 63 | _, test_transform = utils._data_transforms_cifar10(args) 64 | test_data = dset.CIFAR10(root=args.data, train=False, download=True, transform=test_transform) 65 | 66 | test_queue = torch.utils.data.DataLoader( 67 | test_data, batch_size=args.batch_size, shuffle=False, pin_memory=True, num_workers=2) 68 | 69 | model.drop_path_prob = args.drop_path_prob 70 | test_acc, test_obj = infer(test_queue, model, criterion) 71 | logging.info('test_acc %f', test_acc) 72 | 73 | 74 | def infer(test_queue, model, criterion): 75 | objs = utils.AvgrageMeter() 76 | top1 = utils.AvgrageMeter() 77 | top5 = utils.AvgrageMeter() 78 | model.eval() 79 | 80 | for step, (input, target) in enumerate(test_queue): 81 | input = Variable(input, volatile=True).cuda() 82 | target = Variable(target, volatile=True).cuda() 83 | 84 | logits, _ = model(input) 85 | loss = criterion(logits, target) 86 | 87 | prec1, prec5 = utils.accuracy(logits, target, topk=(1, 5)) 88 | n = input.size(0) 89 | objs.update(loss.data[0], n) 90 | top1.update(prec1.data[0], n) 91 | top5.update(prec5.data[0], n) 92 | 93 | if step % args.report_freq == 0: 94 | logging.info('test %03d %e %f %f', step, objs.avg, top1.avg, top5.avg) 95 | 96 | return top1.avg, objs.avg 97 | 98 | 99 | if __name__ == '__main__': 100 | main() 101 | 102 | -------------------------------------------------------------------------------- /publications/ss_vfnas/architects/architect.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import torch.nn as nn 4 | from torch.autograd import Variable 5 | 6 | 7 | def _concat(xs): 8 | return torch.cat([x.view(-1) for x in xs]) 9 | 10 | 11 | class Architect(object): 12 | 13 | def __init__(self, model, args): 14 | self.network_momentum = args.momentum 15 | self.network_weight_decay = args.weight_decay 16 | self.model = model 17 | self.optimizer = torch.optim.Adam(self.model.arch_parameters(), 18 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 19 | weight_decay=args.arch_weight_decay) 20 | 21 | def _compute_unrolled_model(self, input, target, eta, network_optimizer): 22 | loss = self.model._loss(input, target) 23 | theta = _concat(self.model.parameters()).data 24 | try: 25 | moment = _concat(network_optimizer.state[v]['momentum_buffer'] for v in self.model.parameters()).mul_( 26 | self.network_momentum) 27 | except: 28 | moment = torch.zeros_like(theta) 29 | dtheta = _concat(torch.autograd.grad(loss, self.model.parameters())).data + self.network_weight_decay * theta 30 | unrolled_model = self._construct_model_from_theta(theta.sub(eta, moment + dtheta)) 31 | return unrolled_model 32 | 33 | def step(self, input_train, target_train, input_valid, target_valid, eta, network_optimizer, unrolled): 34 | self.optimizer.zero_grad() 35 | if unrolled: 36 | self._backward_step_unrolled(input_train, target_train, input_valid, target_valid, eta, network_optimizer) 37 | else: 38 | self._backward_step(input_valid, target_valid) 39 | self.optimizer.step() 40 | 41 | def _backward_step(self, input_valid, target_valid): 42 | loss, _ = self.model._loss(input_valid, target_valid) 43 | loss.backward() 44 | 45 | def _backward_step_unrolled(self, input_train, target_train, input_valid, target_valid, eta, network_optimizer): 46 | unrolled_model = self._compute_unrolled_model(input_train, target_train, eta, network_optimizer) 47 | unrolled_loss = unrolled_model._loss(input_valid, target_valid) 48 | 49 | unrolled_loss.backward() 50 | dalpha = [v.grad for v in unrolled_model.arch_parameters()] 51 | vector = [v.grad.data for v in unrolled_model.parameters()] 52 | implicit_grads = self._hessian_vector_product(vector, input_train, target_train) 53 | 54 | for g, ig in zip(dalpha, implicit_grads): 55 | g.data.sub_(eta, ig.data) 56 | 57 | for v, g in zip(self.model.arch_parameters(), dalpha): 58 | if v.grad is None: 59 | v.grad = Variable(g.data) 60 | else: 61 | v.grad.data.copy_(g.data) 62 | 63 | def _construct_model_from_theta(self, theta): 64 | model_new = self.model.new() 65 | model_dict = self.model.state_dict() 66 | 67 | params, offset = {}, 0 68 | for k, v in self.model.named_parameters(): 69 | v_length = np.prod(v.size()) 70 | params[k] = theta[offset: offset + v_length].view(v.size()) 71 | offset += v_length 72 | 73 | assert offset == len(theta) 74 | model_dict.update(params) 75 | model_new.load_state_dict(model_dict) 76 | return model_new.cuda() 77 | 78 | def _hessian_vector_product(self, vector, input, target, r=1e-2): 79 | R = r / _concat(vector).norm() 80 | for p, v in zip(self.model.parameters(), vector): 81 | p.data.add_(R, v) 82 | loss = self.model._loss(input, target) 83 | grads_p = torch.autograd.grad(loss, self.model.arch_parameters()) 84 | 85 | for p, v in zip(self.model.parameters(), vector): 86 | p.data.sub_(2 * R, v) 87 | loss = self.model._loss(input, target) 88 | grads_n = torch.autograd.grad(loss, self.model.arch_parameters()) 89 | 90 | for p, v in zip(self.model.parameters(), vector): 91 | p.data.add_(R, v) 92 | 93 | return [(x - y).div_(2 * R) for x, y in zip(grads_p, grads_n)] 94 | -------------------------------------------------------------------------------- /publications/ss_vfnas/operations.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | 4 | OPS = { 5 | 'none' : lambda C, stride, affine: Zero(stride), 6 | 'avg_pool_3x3' : lambda C, stride, affine: nn.AvgPool2d(3, stride=stride, padding=1, count_include_pad=False), 7 | 'max_pool_3x3' : lambda C, stride, affine: nn.MaxPool2d(3, stride=stride, padding=1), 8 | 'skip_connect' : lambda C, stride, affine: Identity() if stride == 1 else FactorizedReduce(C, C, affine=affine), 9 | 'sep_conv_3x3' : lambda C, stride, affine: SepConv(C, C, 3, stride, 1, affine=affine), 10 | 'sep_conv_5x5' : lambda C, stride, affine: SepConv(C, C, 5, stride, 2, affine=affine), 11 | 'sep_conv_7x7' : lambda C, stride, affine: SepConv(C, C, 7, stride, 3, affine=affine), 12 | 'dil_conv_3x3' : lambda C, stride, affine: DilConv(C, C, 3, stride, 2, 2, affine=affine), 13 | 'dil_conv_5x5' : lambda C, stride, affine: DilConv(C, C, 5, stride, 4, 2, affine=affine), 14 | 'conv_7x1_1x7' : lambda C, stride, affine: nn.Sequential( 15 | nn.ReLU(inplace=False), 16 | nn.Conv2d(C, C, (1,7), stride=(1, stride), padding=(0, 3), bias=False), 17 | nn.Conv2d(C, C, (7,1), stride=(stride, 1), padding=(3, 0), bias=False), 18 | nn.BatchNorm2d(C, affine=affine) 19 | ), 20 | } 21 | 22 | class ReLUConvBN(nn.Module): 23 | 24 | def __init__(self, C_in, C_out, kernel_size, stride, padding, affine=True): 25 | super(ReLUConvBN, self).__init__() 26 | self.op = nn.Sequential( 27 | nn.ReLU(inplace=False), 28 | nn.Conv2d(C_in, C_out, kernel_size, stride=stride, padding=padding, bias=False), 29 | nn.BatchNorm2d(C_out, affine=affine) 30 | ) 31 | 32 | def forward(self, x): 33 | return self.op(x) 34 | 35 | class DilConv(nn.Module): 36 | 37 | def __init__(self, C_in, C_out, kernel_size, stride, padding, dilation, affine=True): 38 | super(DilConv, self).__init__() 39 | self.op = nn.Sequential( 40 | nn.ReLU(inplace=False), 41 | nn.Conv2d(C_in, C_in, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, groups=C_in, bias=False), 42 | nn.Conv2d(C_in, C_out, kernel_size=1, padding=0, bias=False), 43 | nn.BatchNorm2d(C_out, affine=affine), 44 | ) 45 | 46 | def forward(self, x): 47 | return self.op(x) 48 | 49 | 50 | class SepConv(nn.Module): 51 | 52 | def __init__(self, C_in, C_out, kernel_size, stride, padding, affine=True): 53 | super(SepConv, self).__init__() 54 | self.op = nn.Sequential( 55 | nn.ReLU(inplace=False), 56 | nn.Conv2d(C_in, C_in, kernel_size=kernel_size, stride=stride, padding=padding, groups=C_in, bias=False), 57 | nn.Conv2d(C_in, C_in, kernel_size=1, padding=0, bias=False), 58 | nn.BatchNorm2d(C_in, affine=affine), 59 | nn.ReLU(inplace=False), 60 | nn.Conv2d(C_in, C_in, kernel_size=kernel_size, stride=1, padding=padding, groups=C_in, bias=False), 61 | nn.Conv2d(C_in, C_out, kernel_size=1, padding=0, bias=False), 62 | nn.BatchNorm2d(C_out, affine=affine), 63 | ) 64 | 65 | def forward(self, x): 66 | return self.op(x) 67 | 68 | 69 | class Identity(nn.Module): 70 | 71 | def __init__(self): 72 | super(Identity, self).__init__() 73 | 74 | def forward(self, x): 75 | return x 76 | 77 | 78 | class Zero(nn.Module): 79 | 80 | def __init__(self, stride): 81 | super(Zero, self).__init__() 82 | self.stride = stride 83 | 84 | def forward(self, x): 85 | if self.stride == 1: 86 | return x.mul(0.) 87 | return x[:,:,::self.stride,::self.stride].mul(0.) 88 | 89 | 90 | class FactorizedReduce(nn.Module): 91 | 92 | def __init__(self, C_in, C_out, affine=True): 93 | super(FactorizedReduce, self).__init__() 94 | assert C_out % 2 == 0 95 | self.relu = nn.ReLU(inplace=False) 96 | self.conv_1 = nn.Conv2d(C_in, C_out // 2, 1, stride=2, padding=0, bias=False) 97 | self.conv_2 = nn.Conv2d(C_in, C_out // 2, 1, stride=2, padding=0, bias=False) 98 | self.bn = nn.BatchNorm2d(C_out, affine=affine) 99 | 100 | def forward(self, x): 101 | x = self.relu(x) 102 | out = torch.cat([self.conv_1(x), self.conv_2(x[:,:,1:,1:])], dim=1) 103 | out = self.bn(out) 104 | return out 105 | 106 | -------------------------------------------------------------------------------- /publications/ss_vfnas/architects/architect_k_party_milenas.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import torch.nn as nn 4 | from torch.autograd import Variable 5 | 6 | 7 | def _concat(xs): 8 | return torch.cat([x.view(-1) for x in xs]) 9 | 10 | 11 | class Architect_A(object): 12 | def __init__(self, model, args): 13 | self.network_momentum = args.momentum 14 | self.network_weight_decay = args.weight_decay 15 | self.k = args.k 16 | self.model = model 17 | self.val_lambda = 1.0 18 | self.optimizer = torch.optim.Adam(self.model.arch_parameters(), 19 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 20 | weight_decay=args.arch_weight_decay) 21 | 22 | def update(self, train_alpha_gradients, train_weights_gradients, val_alpha_gradients, w_optimizer, grad_clip): 23 | for alpha, val_gradient, trn_gradient in zip(self.model.arch_parameters(), val_alpha_gradients, 24 | train_alpha_gradients): 25 | alpha.grad = self.val_lambda * val_gradient.detach() + trn_gradient.detach() 26 | self.optimizer.step() 27 | w_optimizer.zero_grad() 28 | for w, trn_gradient in zip(self.model.parameters(), train_weights_gradients): 29 | if trn_gradient is not None: 30 | w.grad = trn_gradient.detach() 31 | nn.utils.clip_grad_norm_(self.model.parameters(), grad_clip) 32 | w_optimizer.step() 33 | 34 | def compute_grad(self, X, U_B_list, target, need_weight_grad): 35 | if U_B_list is not None: 36 | U_B_list = [torch.autograd.Variable(U_B_list[i], requires_grad=True).cuda() for i in 37 | range(0, len(U_B_list))] 38 | loss, logits = self.model._loss(X, U_B_list, target) 39 | U_B_gradients_list = None 40 | if U_B_list is not None: 41 | U_B_gradients_list = [torch.autograd.grad(loss, U_B, retain_graph=True) for U_B in 42 | U_B_list] 43 | alpha_gradients = torch.autograd.grad(loss, self.model.arch_parameters(), retain_graph=True) 44 | if need_weight_grad: 45 | weights_gradients = torch.autograd.grad(loss, self.model.parameters(), retain_graph=True, allow_unused=True) 46 | return U_B_gradients_list, alpha_gradients, weights_gradients, logits, loss 47 | else: 48 | return U_B_gradients_list, alpha_gradients 49 | 50 | 51 | class Architect_B(object): 52 | def __init__(self, model, args): 53 | self.network_momentum = args.momentum 54 | self.network_weight_decay = args.weight_decay 55 | self.model = model 56 | self.val_lambda = 1.0 57 | self.optimizer = torch.optim.Adam(self.model.arch_parameters(), 58 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 59 | weight_decay=args.arch_weight_decay) 60 | 61 | def update_alpha(self, U_B_train, U_B_train_gradients, U_B_val, U_B_valid_gradients): 62 | self.optimizer.zero_grad() 63 | alpha_train_gradients = torch.autograd.grad(U_B_train, self.model.arch_parameters(), 64 | grad_outputs=U_B_train_gradients, 65 | retain_graph=True) 66 | alpha_valid_gradients = torch.autograd.grad(U_B_val, self.model.arch_parameters(), 67 | grad_outputs=U_B_valid_gradients, 68 | retain_graph=True) 69 | for alpha, val_gradient, trn_gradient in zip(self.model.arch_parameters(), alpha_valid_gradients, 70 | alpha_train_gradients): 71 | alpha.grad = self.val_lambda * val_gradient.detach() + trn_gradient.detach() 72 | self.optimizer.step() 73 | 74 | def update_weights(self, U_B_train, U_B_gradients, weights_optim, grad_clip): 75 | model_B_weight_gradients = torch.autograd.grad(U_B_train, self.model.parameters(), grad_outputs=U_B_gradients, 76 | retain_graph=True) 77 | weights_optim.zero_grad() 78 | for w, g in zip(self.model.parameters(), model_B_weight_gradients): 79 | w.grad = g.detach() 80 | nn.utils.clip_grad_norm_(self.model.parameters(), grad_clip) 81 | weights_optim.step() 82 | -------------------------------------------------------------------------------- /publications/ss_vfnas/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | import torch 4 | import shutil 5 | import torchvision.transforms as transforms 6 | from torch.autograd import Variable 7 | from sklearn import metrics 8 | 9 | class AvgrageMeter(object): 10 | 11 | def __init__(self): 12 | self.reset() 13 | 14 | def reset(self): 15 | self.avg = 0 16 | self.sum = 0 17 | self.cnt = 0 18 | 19 | def update(self, val, n=1): 20 | self.sum += val * n 21 | self.cnt += n 22 | self.avg = self.sum / self.cnt 23 | 24 | 25 | def accuracy(output, target, topk=(1,)): 26 | maxk = max(topk) 27 | batch_size = target.size(0) 28 | 29 | _, pred = output.topk(maxk, 1, True, True) 30 | pred = pred.t() 31 | correct = pred.eq(target.view(1, -1).expand_as(pred)) 32 | 33 | res = [] 34 | for k in topk: 35 | correct_k = correct[:k].view(-1).float().sum(0) 36 | res.append(correct_k.mul_(100.0 / batch_size)) 37 | return res 38 | 39 | 40 | class Cutout(object): 41 | def __init__(self, length): 42 | self.length = length 43 | 44 | def __call__(self, img): 45 | h, w = img.size(1), img.size(2) 46 | mask = np.ones((h, w), np.float32) 47 | y = np.random.randint(h) 48 | x = np.random.randint(w) 49 | 50 | y1 = np.clip(y - self.length // 2, 0, h) 51 | y2 = np.clip(y + self.length // 2, 0, h) 52 | x1 = np.clip(x - self.length // 2, 0, w) 53 | x2 = np.clip(x + self.length // 2, 0, w) 54 | 55 | mask[y1: y2, x1: x2] = 0. 56 | mask = torch.from_numpy(mask) 57 | mask = mask.expand_as(img) 58 | img *= mask 59 | return img 60 | 61 | 62 | def _data_transforms_cifar10(args): 63 | CIFAR_MEAN = [0.49139968, 0.48215827, 0.44653124] 64 | CIFAR_STD = [0.24703233, 0.24348505, 0.26158768] 65 | 66 | train_transform = transforms.Compose([ 67 | # transforms.Resize((224, 224)), 68 | # transforms.RandomCrop(32, padding=4), 69 | # transforms.RandomHorizontalFlip(), 70 | transforms.ToTensor(), 71 | transforms.Normalize(CIFAR_MEAN, CIFAR_STD), 72 | ]) 73 | # if args.cutout: 74 | # train_transform.transforms.append(Cutout(args.cutout_length)) 75 | 76 | valid_transform = transforms.Compose([ 77 | # transforms.Resize((224, 224)), 78 | transforms.ToTensor(), 79 | transforms.Normalize(CIFAR_MEAN, CIFAR_STD), 80 | ]) 81 | return train_transform, valid_transform 82 | 83 | 84 | def count_parameters_in_MB(model): 85 | return np.sum(np.prod(v.size()) for name, v in model.named_parameters() if "auxiliary" not in name) / 1e6 86 | 87 | 88 | def save_checkpoint(state, is_best, save): 89 | filename = os.path.join(save, 'checkpoint.pth.tar') 90 | torch.save(state, filename) 91 | if is_best: 92 | best_filename = os.path.join(save, 'model_best.pth.tar') 93 | shutil.copyfile(filename, best_filename) 94 | 95 | 96 | def save(model, model_path): 97 | torch.save(model.state_dict(), model_path) 98 | 99 | 100 | def load(model, model_path): 101 | model.load_state_dict(torch.load(model_path)) 102 | 103 | 104 | def drop_path(x, drop_prob): 105 | if drop_prob > 0.: 106 | keep_prob = 1. - drop_prob 107 | mask = Variable(torch.cuda.FloatTensor(x.size(0), 1, 1, 1).bernoulli_(keep_prob)) 108 | x.div_(keep_prob) 109 | x.mul_(mask) 110 | return x 111 | 112 | 113 | def create_exp_dir(path, scripts_to_save=None): 114 | os.makedirs(path, exist_ok=True) 115 | print('Experiment dir : {}'.format(path)) 116 | 117 | if scripts_to_save is not None: 118 | os.makedirs(os.path.join(path, 'scripts'), exist_ok=True) 119 | for script in scripts_to_save: 120 | dst_file = os.path.join(path, 'scripts', os.path.basename(script)) 121 | shutil.copyfile(script, dst_file) 122 | 123 | 124 | def get_loss(output, target, index): 125 | target = target[:, index].view(-1) 126 | output = output[index].view(-1) 127 | if target.sum() == 0: 128 | loss = torch.tensor(0., requires_grad=True).cuda() 129 | else: 130 | weight = (target.size(0) - target.sum()) / target.sum() 131 | loss = torch.nn.functional.binary_cross_entropy_with_logits(output, target, weight=weight) 132 | label = torch.sigmoid(output).ge(0.5).float() 133 | acc = (target == label).float().sum() / len(label) 134 | return (loss, acc, label) -------------------------------------------------------------------------------- /publications/ss_vfnas/genotypes.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | 3 | Genotype = namedtuple('Genotype', 'normal normal_concat reduce reduce_concat') 4 | 5 | PRIMITIVES = [ 6 | 'none', 7 | 'max_pool_3x3', 8 | 'avg_pool_3x3', 9 | 'skip_connect', 10 | 'sep_conv_3x3', 11 | 'sep_conv_5x5', 12 | 'dil_conv_3x3', 13 | 'dil_conv_5x5' 14 | ] 15 | 16 | NASNet = Genotype( 17 | normal=[ 18 | ('sep_conv_5x5', 1), 19 | ('sep_conv_3x3', 0), 20 | ('sep_conv_5x5', 0), 21 | ('sep_conv_3x3', 0), 22 | ('avg_pool_3x3', 1), 23 | ('skip_connect', 0), 24 | ('avg_pool_3x3', 0), 25 | ('avg_pool_3x3', 0), 26 | ('sep_conv_3x3', 1), 27 | ('skip_connect', 1), 28 | ], 29 | normal_concat=[2, 3, 4, 5, 6], 30 | reduce=[ 31 | ('sep_conv_5x5', 1), 32 | ('sep_conv_7x7', 0), 33 | ('max_pool_3x3', 1), 34 | ('sep_conv_7x7', 0), 35 | ('avg_pool_3x3', 1), 36 | ('sep_conv_5x5', 0), 37 | ('skip_connect', 3), 38 | ('avg_pool_3x3', 2), 39 | ('sep_conv_3x3', 2), 40 | ('max_pool_3x3', 1), 41 | ], 42 | reduce_concat=[4, 5, 6], 43 | ) 44 | 45 | AmoebaNet = Genotype( 46 | normal=[ 47 | ('avg_pool_3x3', 0), 48 | ('max_pool_3x3', 1), 49 | ('sep_conv_3x3', 0), 50 | ('sep_conv_5x5', 2), 51 | ('sep_conv_3x3', 0), 52 | ('avg_pool_3x3', 3), 53 | ('sep_conv_3x3', 1), 54 | ('skip_connect', 1), 55 | ('skip_connect', 0), 56 | ('avg_pool_3x3', 1), 57 | ], 58 | normal_concat=[4, 5, 6], 59 | reduce=[ 60 | ('avg_pool_3x3', 0), 61 | ('sep_conv_3x3', 1), 62 | ('max_pool_3x3', 0), 63 | ('sep_conv_7x7', 2), 64 | ('sep_conv_7x7', 0), 65 | ('avg_pool_3x3', 1), 66 | ('max_pool_3x3', 0), 67 | ('max_pool_3x3', 1), 68 | ('conv_7x1_1x7', 0), 69 | ('sep_conv_3x3', 5), 70 | ], 71 | reduce_concat=[3, 4, 6] 72 | ) 73 | 74 | DARTS_V1 = Genotype( 75 | normal=[('sep_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 0), ('sep_conv_3x3', 1), ('skip_connect', 0), 76 | ('sep_conv_3x3', 1), ('sep_conv_3x3', 0), ('skip_connect', 2)], normal_concat=[2, 3, 4, 5], 77 | reduce=[('max_pool_3x3', 0), ('max_pool_3x3', 1), ('skip_connect', 2), ('max_pool_3x3', 0), ('max_pool_3x3', 0), 78 | ('skip_connect', 2), ('skip_connect', 2), ('avg_pool_3x3', 0)], reduce_concat=[2, 3, 4, 5]) 79 | DARTS_V2 = Genotype( 80 | normal=[('sep_conv_3x3', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 0), ('sep_conv_3x3', 1), ('sep_conv_3x3', 1), 81 | ('skip_connect', 0), ('skip_connect', 0), ('dil_conv_3x3', 2)], normal_concat=[2, 3, 4, 5], 82 | reduce=[('max_pool_3x3', 0), ('max_pool_3x3', 1), ('skip_connect', 2), ('max_pool_3x3', 1), ('max_pool_3x3', 0), 83 | ('skip_connect', 2), ('skip_connect', 2), ('max_pool_3x3', 1)], reduce_concat=[2, 3, 4, 5]) 84 | 85 | A = Genotype(normal=[('skip_connect', 0), ('sep_conv_5x5', 1), ('skip_connect', 0), ('sep_conv_5x5', 2), ('dil_conv_5x5', 2), ('dil_conv_3x3', 3), ('dil_conv_3x3', 0), ('sep_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('avg_pool_3x3', 0), ('skip_connect', 1), ('avg_pool_3x3', 0), ('dil_conv_5x5', 2), ('avg_pool_3x3', 0), ('skip_connect', 2), ('avg_pool_3x3', 1), ('avg_pool_3x3', 0)], reduce_concat=range(2, 6)) 86 | # A = Genotype(normal=[('skip_connect', 0), ('dil_conv_3x3', 1), ('skip_connect', 0), ('dil_conv_5x5', 2), ('dil_conv_3x3', 1), ('sep_conv_3x3', 2), ('dil_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('avg_pool_3x3', 1), ('max_pool_3x3', 0), ('avg_pool_3x3', 1), ('dil_conv_3x3', 2), ('avg_pool_3x3', 1), ('skip_connect', 2), ('avg_pool_3x3', 1), ('dil_conv_5x5', 4)], reduce_concat=range(2, 6)) 87 | B = Genotype(normal=[('sep_conv_3x3', 0), ('dil_conv_3x3', 1), ('dil_conv_5x5', 1), ('sep_conv_3x3', 0), ('dil_conv_5x5', 1), ('dil_conv_3x3', 0), ('dil_conv_3x3', 3), ('dil_conv_3x3', 4)], normal_concat=range(2, 6), reduce=[('max_pool_3x3', 0), ('max_pool_3x3', 1), ('avg_pool_3x3', 0), ('dil_conv_3x3', 2), ('avg_pool_3x3', 0), ('skip_connect', 2), ('avg_pool_3x3', 1), ('dil_conv_3x3', 2)], reduce_concat=range(2, 6)) 88 | DARTS = DARTS_V2 89 | 90 | 91 | def parse_str(genotype_file): 92 | lines = open(genotype_file).readlines()[-12:] 93 | genotype_list = [] 94 | for line in lines: 95 | if "Best Genotype" in line: 96 | genotype_str = line.strip().split(" = ")[-1] 97 | genotype_list.append(genotype_str) 98 | return genotype_list -------------------------------------------------------------------------------- /publications/PrADA/experiments/ppd_loan/train_ppd_no_fg_adapt_pretrain.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | import torch 4 | 5 | from experiments.ppd_loan.train_config import data_tag, \ 6 | pre_train_hyperparameters, data_hyperparameters, no_fg_feature_extractor_architecture 7 | from experiments.ppd_loan.meta_data import column_name_list, group_ind_list, group_info 8 | from experiments.ppd_loan.train_ppd_fg_adapt_pretrain import parse_domain_data, create_embedding_dict 9 | from experiments.ppd_loan.train_ppd_utils import pretrain_ppd 10 | from models.classifier import GlobalClassifier, CensusFeatureAggregator 11 | from models.dann_models import GlobalModel, RegionalModel 12 | from models.discriminator import LendingRegionDiscriminator 13 | from models.feature_extractor import CensusRegionFeatureExtractorDense 14 | 15 | 16 | def store_domain_data(domain_data_dict, domain_data, domain_col_list, is_cat): 17 | if is_cat: 18 | emb_dict = OrderedDict() 19 | for col_index, col_name in enumerate(domain_col_list): 20 | emb_dict[col_name] = domain_data[:, col_index] 21 | domain_data_dict["embeddings"] = emb_dict 22 | 23 | else: 24 | domain_data_dict["non_embedding"] = {"tabular_data": domain_data} 25 | 26 | 27 | def aggregate_domains(domain_list): 28 | agg_domain = dict({'embeddings': None, 'non_embedding': dict()}) 29 | agg_embed_dict = dict() 30 | non_embed_list = [] 31 | for domain in domain_list: 32 | embed_dict = domain['embeddings'] 33 | if embed_dict: 34 | agg_embed_dict.update(embed_dict) 35 | non_embed = domain['non_embedding'] 36 | if non_embed: 37 | non_embed_list.append(non_embed['tabular_data']) 38 | 39 | agg_domain['embeddings'] = agg_embed_dict 40 | agg_domain['non_embedding']['tabular_data'] = torch.cat(non_embed_list, dim=1) 41 | return agg_domain 42 | 43 | 44 | def partition_data(data): 45 | wide_feat_list, domain_list = parse_domain_data(data, 46 | column_name_list, 47 | group_ind_list, 48 | group_info) 49 | agg_domain = aggregate_domains(domain_list) 50 | return wide_feat_list, [agg_domain] 51 | 52 | 53 | def create_region_model(extractor_input_dims_list, aggregation_dim): 54 | extractor = CensusRegionFeatureExtractorDense(input_dims=extractor_input_dims_list) 55 | aggregator = CensusFeatureAggregator(input_dim=extractor_input_dims_list[-1], output_dim=aggregation_dim) 56 | discriminator = LendingRegionDiscriminator(input_dim=extractor_input_dims_list[-1]) 57 | return RegionalModel(extractor=extractor, 58 | aggregator=aggregator, 59 | discriminator=discriminator) 60 | 61 | 62 | def create_region_model_list(feature_extractor_arch_list, aggregation_dim): 63 | model_list = list() 64 | for feature_extractor_arch in feature_extractor_arch_list: 65 | model_list.append(create_region_model(feature_extractor_arch, aggregation_dim)) 66 | return model_list 67 | 68 | 69 | def create_no_fg_pdd_global_model(aggregation_dim=5, num_wide_feature=6, pos_class_weight=1.0): 70 | embedding_dict = create_embedding_dict() 71 | 72 | feature_extractor_architecture = no_fg_feature_extractor_architecture 73 | print(f"[INFO] feature_extractor_architecture list:{[feature_extractor_architecture]}") 74 | 75 | region_wrapper_list = create_region_model_list([feature_extractor_architecture], aggregation_dim) 76 | global_input_dim = aggregation_dim + num_wide_feature 77 | print(f"[INFO] global_input_dim: {global_input_dim}") 78 | source_classifier = GlobalClassifier(input_dim=global_input_dim) 79 | wrapper = GlobalModel(source_classifier=source_classifier, 80 | regional_model_list=region_wrapper_list, 81 | embedding_dict=embedding_dict, 82 | partition_data_fn=partition_data, 83 | pos_class_weight=pos_class_weight, 84 | loss_name="BCE") 85 | return wrapper 86 | 87 | 88 | if __name__ == "__main__": 89 | pretrained_model_dir = data_hyperparameters["ppd_no-fg_pretrained_model_dir"] 90 | pos_class_weight = pre_train_hyperparameters['pos_class_weight'] 91 | init_model = create_no_fg_pdd_global_model(pos_class_weight=pos_class_weight) 92 | task_id = pretrain_ppd(data_tag, 93 | pretrained_model_dir, 94 | pre_train_hyperparameters, 95 | data_hyperparameters, 96 | model=init_model, 97 | apply_feature_group=False) 98 | 99 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/income_census/draw_census_tsne_graph.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from sklearn import manifold 3 | 4 | from utils import draw_distribution 5 | from experiments.income_census.tsne_config import tsne_embedding_creation 6 | 7 | 8 | def draw_distribution_for_each_group(dim_reducer, 9 | feature_group_name_list, 10 | tag, 11 | num_samples, 12 | print_num_points, 13 | data_dir, 14 | to_dir, 15 | version="0"): 16 | 17 | for name in feature_group_name_list: 18 | src_file_name = 'prada_{}{}_src_emb_{}_v{}.csv'.format(tag, num_samples, name, version) 19 | tgt_file_name = 'prada_{}{}_tgt_emb_{}_v{}.csv'.format(tag, num_samples, name, version) 20 | print(f"[INFO] tag:{tag}; feature_group_name:{name}") 21 | 22 | df_src_data = pd.read_csv(data_dir + src_file_name, header=None, skipinitialspace=True) 23 | df_tgt_data = pd.read_csv(data_dir + tgt_file_name, header=None, skipinitialspace=True) 24 | print(f"[INFO] df_src_data shape :{df_src_data.shape}") 25 | print(f"[INFO] df_tgt_data shape :{df_tgt_data.shape}") 26 | 27 | draw_distribution(df_src_data, 28 | df_tgt_data, 29 | num_points=print_num_points, 30 | dim_reducer=dim_reducer, 31 | tag=tag, 32 | feature_group_name=name, 33 | to_dir=to_dir, 34 | version=version) 35 | 36 | 37 | def draw_distribution_for_concat_feature(dim_reducer, 38 | feature_group_name_list, 39 | tag, 40 | num_samples, 41 | print_num_points, 42 | data_dir, 43 | to_dir): 44 | df_src_data_list = list() 45 | df_tgt_data_list = list() 46 | for name in feature_group_name_list: 47 | src_file_name = 'prada_{}{}_src_emb_{}.csv'.format(tag, num_samples, name) 48 | tgt_file_name = 'prada_{}{}_tgt_emb_{}.csv'.format(tag, num_samples, name) 49 | 50 | print(f"[INFO] tag:{tag}; feature_group_name:{name}") 51 | 52 | df_src_data = pd.read_csv(data_dir + src_file_name, header=None, skipinitialspace=True) 53 | df_tgt_data = pd.read_csv(data_dir + tgt_file_name, header=None, skipinitialspace=True) 54 | 55 | df_src_data_list.append(df_src_data) 56 | df_tgt_data_list.append(df_tgt_data) 57 | print(f"[INFO] df_src_data shape :{df_src_data.shape}") 58 | print(f"[INFO] df_tgt_data shape :{df_tgt_data.shape}") 59 | 60 | df_src_all_data = pd.concat(df_src_data_list, axis=1) 61 | df_tgt_all_data = pd.concat(df_tgt_data_list, axis=1) 62 | 63 | print(f"[INFO] df_src_all_data shape :{df_src_all_data.shape}") 64 | print(f"[INFO] df_tgt_all_data shape :{df_tgt_all_data.shape}") 65 | 66 | draw_distribution(df_src_all_data, df_tgt_all_data, 67 | num_points=print_num_points, dim_reducer=dim_reducer, tag=tag, 68 | feature_group_name='all_combined', to_dir=to_dir) 69 | 70 | 71 | if __name__ == "__main__": 72 | 73 | apply_adaptation = tsne_embedding_creation["apply_adaptation"] 74 | using_interaction = tsne_embedding_creation["using_interaction"] 75 | 76 | tsne_embedding_dir = tsne_embedding_creation["tsne_embedding_data_dir"] 77 | tsne_output_dir = tsne_embedding_creation["tsne_graph_output_dir"] 78 | 79 | tag = "ad" if apply_adaptation else "no-ad" 80 | feature_group_name_list = ['employment', 'demographics', 'migration', 'household'] 81 | if using_interaction: 82 | feature_grp_intr_name_list = ['emp-demo', 'emp-mig', 'emp-house', 'demo-mig', 'demo-house', 'mig-house'] 83 | feature_group_name_list = feature_group_name_list + feature_grp_intr_name_list 84 | 85 | dim_reducer = manifold.TSNE(n_components=2, init='random', perplexity=10, learning_rate=600, n_iter=1000, 86 | verbose=2, early_exaggeration=12, random_state=10) 87 | num_samples = 4000 88 | print_num_points = 4000 89 | draw_distribution_for_each_group(dim_reducer, 90 | feature_group_name_list, 91 | tag, 92 | num_samples, 93 | print_num_points, 94 | tsne_embedding_dir, 95 | tsne_output_dir) 96 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/model/roi_module.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | from string import Template 3 | 4 | import cupy, torch 5 | import cupy as cp 6 | import torch as t 7 | from torch.autograd import Function 8 | 9 | from model.utils.roi_cupy import kernel_backward, kernel_forward 10 | 11 | Stream = namedtuple('Stream', ['ptr']) 12 | 13 | 14 | @cupy.util.memoize(for_each_device=True) 15 | def load_kernel(kernel_name, code, **kwargs): 16 | cp.cuda.runtime.free(0) 17 | code = Template(code).substitute(**kwargs) 18 | kernel_code = cupy.cuda.compile_with_cache(code) 19 | return kernel_code.get_function(kernel_name) 20 | 21 | 22 | CUDA_NUM_THREADS = 1024 23 | 24 | 25 | def GET_BLOCKS(N, K=CUDA_NUM_THREADS): 26 | return (N + K - 1) // K 27 | 28 | 29 | class RoI(Function): 30 | def __init__(self, outh, outw, spatial_scale): 31 | self.forward_fn = load_kernel('roi_forward', kernel_forward) 32 | self.backward_fn = load_kernel('roi_backward', kernel_backward) 33 | self.outh, self.outw, self.spatial_scale = outh, outw, spatial_scale 34 | 35 | def forward(self, x, rois): 36 | # NOTE: MAKE SURE input is contiguous too 37 | x = x.contiguous() 38 | rois = rois.contiguous() 39 | self.in_size = B, C, H, W = x.size() 40 | self.N = N = rois.size(0) 41 | output = t.zeros(N, C, self.outh, self.outw).cuda() 42 | self.argmax_data = t.zeros(N, C, self.outh, self.outw).int().cuda() 43 | self.rois = rois 44 | args = [x.data_ptr(), rois.data_ptr(), 45 | output.data_ptr(), 46 | self.argmax_data.data_ptr(), 47 | self.spatial_scale, C, H, W, 48 | self.outh, self.outw, 49 | output.numel()] 50 | stream = Stream(ptr=torch.cuda.current_stream().cuda_stream) 51 | self.forward_fn(args=args, 52 | block=(CUDA_NUM_THREADS, 1, 1), 53 | grid=(GET_BLOCKS(output.numel()), 1, 1), 54 | stream=stream) 55 | return output 56 | 57 | def backward(self, grad_output): 58 | ##NOTE: IMPORTANT CONTIGUOUS 59 | # TODO: input 60 | grad_output = grad_output.contiguous() 61 | B, C, H, W = self.in_size 62 | grad_input = t.zeros(self.in_size).cuda() 63 | stream = Stream(ptr=torch.cuda.current_stream().cuda_stream) 64 | args = [grad_output.data_ptr(), 65 | self.argmax_data.data_ptr(), 66 | self.rois.data_ptr(), 67 | grad_input.data_ptr(), 68 | self.N, self.spatial_scale, C, H, W, self.outh, self.outw, 69 | grad_input.numel()] 70 | self.backward_fn(args=args, 71 | block=(CUDA_NUM_THREADS, 1, 1), 72 | grid=(GET_BLOCKS(grad_input.numel()), 1, 1), 73 | stream=stream 74 | ) 75 | return grad_input, None 76 | 77 | 78 | class RoIPooling2D(t.nn.Module): 79 | 80 | def __init__(self, outh, outw, spatial_scale): 81 | super(RoIPooling2D, self).__init__() 82 | self.RoI = RoI(outh, outw, spatial_scale) 83 | 84 | def forward(self, x, rois): 85 | return self.RoI(x, rois) 86 | 87 | 88 | def test_roi_module(): 89 | ## fake data### 90 | B, N, C, H, W, PH, PW = 2, 8, 4, 32, 32, 7, 7 91 | 92 | bottom_data = t.randn(B, C, H, W).cuda() 93 | bottom_rois = t.randn(N, 5) 94 | bottom_rois[:int(N / 2), 0] = 0 95 | bottom_rois[int(N / 2):, 0] = 1 96 | bottom_rois[:, 1:] = (t.rand(N, 4) * 100).float() 97 | bottom_rois = bottom_rois.cuda() 98 | spatial_scale = 1. / 16 99 | outh, outw = PH, PW 100 | 101 | # pytorch version 102 | module = RoIPooling2D(outh, outw, spatial_scale) 103 | x = bottom_data.requires_grad_() 104 | rois = bottom_rois.detach() 105 | 106 | output = module(x, rois) 107 | output.sum().backward() 108 | 109 | def t2c(variable): 110 | npa = variable.data.cpu().numpy() 111 | return cp.array(npa) 112 | 113 | def test_eq(variable, array, info): 114 | cc = cp.asnumpy(array) 115 | neq = (cc != variable.data.cpu().numpy()) 116 | assert neq.sum() == 0, 'test failed: %s' % info 117 | 118 | # chainer version,if you're going to run this 119 | # pip install chainer 120 | import chainer.functions as F 121 | from chainer import Variable 122 | x_cn = Variable(t2c(x)) 123 | 124 | o_cn = F.roi_pooling_2d(x_cn, t2c(rois), outh, outw, spatial_scale) 125 | test_eq(output, o_cn.array, 'forward') 126 | F.sum(o_cn).backward() 127 | test_eq(x.grad, x_cn.grad, 'backward') 128 | print('test pass') 129 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/data/dataset.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | import torch as t 4 | from data.voc_dataset import VOCBboxDataset 5 | from skimage import transform as sktsf 6 | from torchvision import transforms as tvtsf 7 | from data import util 8 | import numpy as np 9 | from utils.config import opt 10 | 11 | 12 | def inverse_normalize(img): 13 | if opt.caffe_pretrain: 14 | img = img + (np.array([122.7717, 115.9465, 102.9801]).reshape(3, 1, 1)) 15 | return img[::-1, :, :] 16 | # approximate un-normalize for visualize 17 | return (img * 0.225 + 0.45).clip(min=0, max=1) * 255 18 | 19 | 20 | def pytorch_normalze(img): 21 | """ 22 | https://github.com/pytorch/vision/issues/223 23 | return appr -1~1 RGB 24 | """ 25 | normalize = tvtsf.Normalize(mean=[0.485, 0.456, 0.406], 26 | std=[0.229, 0.224, 0.225]) 27 | img = normalize(t.from_numpy(img)) 28 | return img.numpy() 29 | 30 | 31 | def caffe_normalize(img): 32 | """ 33 | return appr -125-125 BGR 34 | """ 35 | img = img[[2, 1, 0], :, :] # RGB-BGR 36 | img = img * 255 37 | mean = np.array([122.7717, 115.9465, 102.9801]).reshape(3, 1, 1) 38 | img = (img - mean).astype(np.float32, copy=True) 39 | return img 40 | 41 | 42 | def preprocess(img, min_size=600, max_size=1000): 43 | """Preprocess an image for feature extraction. 44 | 45 | The length of the shorter edge is scaled to :obj:`self.min_size`. 46 | After the scaling, if the length of the longer edge is longer than 47 | :param min_size: 48 | :obj:`self.max_size`, the image is scaled to fit the longer edge 49 | to :obj:`self.max_size`. 50 | 51 | After resizing the image, the image is subtracted by a mean image value 52 | :obj:`self.mean`. 53 | 54 | Args: 55 | img (~numpy.ndarray): An image. This is in CHW and RGB format. 56 | The range of its value is :math:`[0, 255]`. 57 | 58 | Returns: 59 | ~numpy.ndarray: A preprocessed image. 60 | 61 | """ 62 | C, H, W = img.shape 63 | scale1 = min_size / min(H, W) 64 | scale2 = max_size / max(H, W) 65 | scale = min(scale1, scale2) 66 | img = img / 255. 67 | img = sktsf.resize(img, (C, H * scale, W * scale), mode='reflect',anti_aliasing=False) 68 | # both the longer and shorter should be less than 69 | # max_size and min_size 70 | if opt.caffe_pretrain: 71 | normalize = caffe_normalize 72 | else: 73 | normalize = pytorch_normalze 74 | return normalize(img) 75 | 76 | 77 | class Transform(object): 78 | 79 | def __init__(self, min_size=600, max_size=1000): 80 | self.min_size = min_size 81 | self.max_size = max_size 82 | 83 | def __call__(self, in_data): 84 | img, bbox, label = in_data 85 | _, H, W = img.shape 86 | img = preprocess(img, self.min_size, self.max_size) 87 | _, o_H, o_W = img.shape 88 | scale = o_H / H 89 | bbox = util.resize_bbox(bbox, (H, W), (o_H, o_W)) 90 | 91 | # horizontally flip 92 | img, params = util.random_flip( 93 | img, x_random=True, return_param=True) 94 | bbox = util.flip_bbox( 95 | bbox, (o_H, o_W), x_flip=params['x_flip']) 96 | 97 | return img, bbox, label, scale 98 | 99 | 100 | class Dataset: 101 | def __init__(self, opt): 102 | self.opt = opt 103 | self.db = VOCBboxDataset(opt.voc_data_dir, opt.label_names) 104 | self.tsf = Transform(opt.min_size, opt.max_size) 105 | 106 | def __getitem__(self, idx): 107 | ori_img, bbox, label, difficult = self.db.get_example(idx) 108 | 109 | img, bbox, label, scale = self.tsf((ori_img, bbox, label)) 110 | # TODO: check whose stride is negative to fix this instead copy all 111 | # some of the strides of a given numpy array are negative. 112 | return img.copy(), ori_img.shape[1:], bbox.copy(), \ 113 | label.copy(), scale, difficult 114 | 115 | def __len__(self): 116 | return len(self.db) 117 | 118 | 119 | class TestDataset: 120 | def __init__(self, opt, split='test', use_difficult=True): 121 | self.opt = opt 122 | self.db = VOCBboxDataset(opt.voc_data_dir, opt.label_names, 123 | split=split, use_difficult=use_difficult) 124 | 125 | def __getitem__(self, idx): 126 | ori_img, bbox, label, difficult = self.db.get_example(idx) 127 | img = preprocess(ori_img) 128 | scale = ori_img.shape[1] / img.shape[1] 129 | return img, ori_img.shape[1:], bbox, label, scale, difficult 130 | 131 | def __len__(self): 132 | return len(self.db) 133 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/Dataset_description.md: -------------------------------------------------------------------------------- 1 | ## FedVision 2 | **FedVison dataset** is created jointly by WeBank and ExtremeVision to facilitate the advancement of academic research 3 | and industrial applications of federated learning. 4 | 5 | ### The FedVision project 6 | 7 | * Provides images data sets with standardized annotation for federated object detection. 8 | * Provides key statistics and systems metrics of the data sets. 9 | * Provides a set of implementations of baseline for further research. 10 | 11 | ### Datasets 12 | We introduce two realistic federated datasets. 13 | 14 | * **Federated Street**, a real-world object detection dataset that annotates images captured by a set of street cameras 15 | based on object present in them, including 7 classes. In this dataset, each or every few cameras serve as a device. 16 | 17 | | Dataset | Number of devices | Total samples | Number of class| 18 | |:---:|:---:|:---:|:---:| 19 | | Federated Street | 5, 20 | 956 | 7 | 20 | 21 | ### File descriptions 22 | 23 | * **Street_Dataset.tar** contains the image data and ground truth for the train and test set of the street data set. 24 | * **Images**: The directory which contains the train and test image data. 25 | * **train_label.json**: The annotations file is saved in json format. **train_label.json** is a `list`, which 26 | contains the annotation information of the Images set. The length of `list` is the same as the number of image and each value 27 | in the `list` represents one image_info. Each `image_info` is in format of `dictionary` with keys and values. The keys 28 | of `image_info` are `image_id`, `device1_id`, `device2_id` and `items`. We split the street data set in two ways. For the first, we 29 | split the data into 5 parts according to the geographic information. Besides, we turn 5 into 20. Therefore we have `device1_id` and 30 | `device2_id`. It means that we have 5 or 20 devices. `items` is a list, which may contain multiple objects. 31 | [ 32 |   { 33 |    `"image_id"`: the id of the train image, for example 009579. 34 |    `"device1_id"`: the id of device1 ,specifies which device the image is on. 35 |    `"device2_id"`: the id of device2. 36 |    `"items"`: [ 37 |     { 38 |      `"class"`: the class of one object, 39 |      `"bbox"`: ["xmin", "ymin", "xmax", "ymax"], the coordinates of a bounding box 40 |     }, 41 |     ... 42 |     ] 43 |   }, 44 |   ... 45 | ] 46 | * **test_label.json**: The annotations of test data are almost the same as of the **train_label.json**. The only difference between them is that 47 | the `image_info` of test data does not have the key `device_id`. 48 | 49 | ### Evaluation 50 | We use he standard [PASCAL VOC 2010](http://host.robots.ox.ac.uk/pascal/VOC/voc2010/devkit_doc_08-May-2010.pdf) mean Average Precision (mAP) for evaluation (mean is taken over per-class APs). 51 | To be considered a correct detection, the overlap ratio ![avatar](http://fedcs.fedai.org.cn/1.png) between the predicted bounding box ![avatar](http://fedcs.fedai.org.cn/2.png) and ground truth bounding ![avatar](http://fedcs.fedai.org.cn/3.png) by the formula 52 | 53 | when denotes the intersection of the predicted and ground truth bounding boxes and their union. 54 | Average Precision is calculated for each class respectively. 55 | 56 | where n is the number of total object in given class. 57 | For $k$ classes, mAP is the average of APs. 58 | 59 | -------------------------------------------------------------------------------- /publications/FedCG/main.py: -------------------------------------------------------------------------------- 1 | from dataset import * 2 | from utils import set_seed 3 | 4 | if args.algorithm == 'local': 5 | from clients.local import Client 6 | elif args.algorithm == 'fedavg': 7 | from clients.fedavg import Client 8 | from servers.fedavg import Server 9 | elif args.algorithm == 'fedsplit': 10 | from clients.fedsplit import Client 11 | from servers.fedsplit import Server 12 | elif args.algorithm == 'fedprox': 13 | from clients.fedprox import Client 14 | from servers.fedprox import Server 15 | elif args.algorithm == 'feddf': 16 | from clients.feddf import Client 17 | from servers.feddf import Server 18 | elif args.algorithm == 'fedgen': 19 | from clients.fedgen import Client 20 | from servers.fedgen import Server 21 | elif args.algorithm == 'fedcg': 22 | from clients.fedcg import Client 23 | from servers.fedcg import Server 24 | elif args.algorithm == 'fedcg_w': 25 | from clients.fedcg_w import Client 26 | from servers.fedcg import Server 27 | 28 | 29 | def main(): 30 | logger.info("#" * 100) 31 | logger.info(str(args)) 32 | set_seed(args.seed) 33 | 34 | # create dataset 35 | logger.info("Clients' Data Partition") 36 | if args.dataset == "fmnist": 37 | dataset = FMNIST() 38 | elif args.dataset == "cifar": 39 | dataset = Cifar() 40 | elif args.dataset == "digit": 41 | dataset = Digit() 42 | elif args.dataset == "office": 43 | dataset = Office() 44 | elif args.dataset == "domainnet": 45 | dataset = Domainnet() 46 | 47 | # create clients and server 48 | if args.algorithm == 'feddf': 49 | trainsets, valsets, testsets, server_dataset = dataset.data_partition() 50 | clients = [] 51 | for i in range(args.n_clients): 52 | client = Client(i, trainsets[i], valsets[i], testsets[i]) 53 | clients.append(client) 54 | server = Server(clients, server_dataset) 55 | 56 | elif args.algorithm == 'local': 57 | trainsets, valsets, testsets = dataset.data_partition() 58 | clients = [] 59 | for i in range(args.n_clients): 60 | client = Client(i, trainsets[i], valsets[i], testsets[i]) 61 | clients.append(client) 62 | 63 | else: 64 | trainsets, valsets, testsets = dataset.data_partition() 65 | clients = [] 66 | for i in range(args.n_clients): 67 | client = Client(i, trainsets[i], valsets[i], testsets[i]) 68 | clients.append(client) 69 | server = Server(clients) 70 | 71 | # record best val acc 72 | best_val_accs = [0.] * args.n_clients 73 | test_accs = [0.] * args.n_clients 74 | best_rounds = [-1] * args.n_clients 75 | 76 | # federated learning process 77 | current_round = 0 78 | while True: 79 | logger.info("** Communication Round:[%2d] Start! **" % current_round) 80 | 81 | # client train 82 | for i in range(args.n_clients): 83 | clients[i].local_train(current_round) 84 | 85 | # client test 86 | for i in range(args.n_clients): 87 | val_acc = clients[i].local_val() 88 | if val_acc > best_val_accs[i]: 89 | best_val_accs[i] = val_acc 90 | test_accs[i] = clients[i].local_test() 91 | best_rounds[i] = current_round 92 | 93 | # round result 94 | logger.info("communication round:%2d, after local train result:" % current_round) 95 | for i in range(args.n_clients): 96 | logger.info("client:%2d, test acc:%2.6f, best epoch:%2d" % (i, test_accs[i], best_rounds[i])) 97 | 98 | # early stop 99 | early_stop = True 100 | for i in range(args.n_clients): 101 | if current_round <= best_rounds[i] + args.early_stop_rounds: 102 | early_stop = False 103 | break 104 | if early_stop: 105 | break 106 | 107 | # communication 108 | if args.algorithm == "local": 109 | pass 110 | 111 | elif args.algorithm == "fedsplit": 112 | server.receive(["classifier"]) 113 | server.send(["classifier"]) 114 | 115 | elif args.algorithm == "fedavg" or args.algorithm == "fedprox": 116 | server.receive(["extractor", "classifier"]) 117 | server.send(["extractor", "classifier"]) 118 | 119 | elif args.algorithm == "fedgen": 120 | server.receive(["generator", "classifier"]) 121 | server.global_train() 122 | server.send(["generator", "classifier"]) 123 | 124 | elif args.algorithm == "feddf": 125 | server.receive(["extractor", "classifier"]) 126 | server.global_train() 127 | server.send(["extractor", "classifier"]) 128 | 129 | elif args.algorithm == "fedcg" or args.algorithm == "fedcg_w": 130 | server.receive(["generator", "classifier"]) 131 | server.global_train() 132 | server.send(["generator", "classifier"]) 133 | 134 | current_round += 1 135 | if current_round >= 200: 136 | break 137 | 138 | # final result 139 | logger.info("** Federated Learning Finish! **") 140 | for i in range(args.n_clients): 141 | logger.info("client:%2d, test acc:%2.6f, best epoch:%2d" % (i, test_accs[i], best_rounds[i])) 142 | 143 | 144 | if __name__ == "__main__": 145 | main() 146 | -------------------------------------------------------------------------------- /publications/FedCG/servers/fedgen.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import torch 3 | import torch.nn as nn 4 | import torch.optim as optim 5 | 6 | from config import args, logger, device 7 | from models import Classifier, Generator 8 | from utils import AvgMeter, set_seed 9 | 10 | 11 | class Server(): 12 | 13 | def __init__(self, clients): 14 | self.clients = clients 15 | 16 | self.weights = [] 17 | for client in clients: 18 | self.weights.append(client.train_size) 19 | self.weights = np.array(self.weights) / np.sum(self.weights) 20 | logger.info("client weights: %s" % str(self.weights.tolist())) 21 | 22 | self.init_net() 23 | 24 | def get_params(self, models): 25 | params = [] 26 | for model in models: 27 | params.append({"params": self.global_net[model].parameters()}) 28 | return params 29 | 30 | def frozen_net(self, models, frozen): 31 | for model in models: 32 | for param in self.global_net[model].parameters(): 33 | param.requires_grad = not frozen 34 | if frozen: 35 | self.global_net[model].eval() 36 | else: 37 | self.global_net[model].train() 38 | 39 | def init_net(self): 40 | ############################################################## 41 | # frozen all models' parameters, unfrozen when need to train # 42 | ############################################################## 43 | set_seed(args.seed) 44 | self.global_net = nn.ModuleDict() 45 | 46 | self.global_net["generator"] = Generator() 47 | self.global_net["classifier"] = Classifier() 48 | self.frozen_net(["generator", "classifier"], True) 49 | self.G_optimizer = optim.Adam(self.get_params(["generator"]), lr=args.lr, weight_decay=args.weight_decay) 50 | 51 | self.global_net.to(device) 52 | 53 | self.KL_criterion = nn.KLDivLoss(reduction="batchmean").to(device) 54 | self.CE_criterion = nn.CrossEntropyLoss().to(device) 55 | 56 | def load_client(self): 57 | for i in range(len(self.clients)): 58 | checkpoint = torch.load(args.checkpoint_dir + "/client" + str(i) + ".pkl") 59 | self.clients[i].net.load_state_dict(checkpoint["net"]) 60 | self.clients[i].EC_optimizer.load_state_dict(checkpoint["EC_optimizer"]) 61 | 62 | def save_client(self): 63 | for i in range(len(self.clients)): 64 | optim_dict = { 65 | "net": self.clients[i].net.state_dict(), 66 | "EC_optimizer": self.clients[i].EC_optimizer.state_dict(), 67 | } 68 | torch.save(optim_dict, args.checkpoint_dir + "/client" + str(i) + ".pkl") 69 | 70 | def receive(self, models): 71 | for model in models: 72 | avg_param = {} 73 | params = [] 74 | for client in self.clients: 75 | params.append(client.net[model].state_dict()) 76 | 77 | for key in params[0].keys(): 78 | avg_param[key] = params[0][key] * self.weights[0] 79 | for idx in range(1, len(self.clients)): 80 | avg_param[key] += params[idx][key] * self.weights[idx] 81 | self.global_net[model].load_state_dict(avg_param) 82 | 83 | def send(self, models): 84 | for model in models: 85 | global_param = self.global_net[model].state_dict() 86 | for client in self.clients: 87 | client.net[model].load_state_dict(global_param) 88 | 89 | def global_train(self): 90 | set_seed(args.seed) 91 | 92 | logger.info("Training Server's Network Start!") 93 | G_loss_meter = AvgMeter() 94 | G_div_meter = AvgMeter() 95 | 96 | self.frozen_net(["generator"], False) 97 | 98 | for epoch in range(args.global_epoch): 99 | G_loss_meter.reset() 100 | G_div_meter.reset() 101 | 102 | for batch in range(args.global_iter_per_epoch): 103 | y = torch.randint(0, args.num_classes, (args.batch_size,)).to(device) 104 | z = torch.randn(args.batch_size, args.noise_dim, 1, 1).to(device) 105 | 106 | self.G_optimizer.zero_grad() 107 | 108 | # gen loss 109 | pred = 0 110 | G = self.global_net["generator"](z, y) 111 | for i, client in enumerate(self.clients): 112 | GC = client.net["classifier"](G) 113 | pred += self.weights[i] * GC 114 | G_loss = self.CE_criterion(pred, y) 115 | 116 | # div loss 117 | split_size = int(args.batch_size / 2) 118 | z1, z2 = torch.split(z, split_size, dim=0) 119 | G1, G2 = torch.split(G, split_size, dim=0) 120 | lz = torch.mean(torch.abs(G1 - G2)) / torch.mean(torch.abs(z1 - z2)) 121 | eps = 1 * 1e-5 122 | G_div = 1 / (lz + eps) 123 | 124 | (G_loss + G_div).backward() 125 | self.G_optimizer.step() 126 | G_loss_meter.update(G_loss.item()) 127 | G_div_meter.update(G_div.item()) 128 | 129 | G_loss = G_loss_meter.get() 130 | G_div_meter.update(G_div.item()) 131 | logger.info("Server Epoch:[%2d], G_loss:%2.6f, G_div:%2.6f" % (epoch, G_loss, G_div)) 132 | 133 | self.frozen_net(["generator"], True) 134 | -------------------------------------------------------------------------------- /publications/ss_vfnas/architects/architect_two_party_preg.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | import torch.nn as nn 4 | from torch.autograd import Variable 5 | import copy 6 | 7 | 8 | def _concat(xs): 9 | return torch.cat([x.view(-1) for x in xs]) 10 | 11 | 12 | class Architect_A(object): 13 | def __init__(self, model, args): 14 | self.network_momentum = args.momentum 15 | self.network_weight_decay = args.weight_decay 16 | self.model = model 17 | self.alpha_optimizer = torch.optim.Adam(self.model.arch_parameters(), 18 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 19 | weight_decay=args.arch_weight_decay) 20 | self.n_local_update = args.n_local_update 21 | self.mu = 0.001 22 | 23 | def _mark_model(self): 24 | self.copy_model = copy.deepcopy(self.model) 25 | 26 | def compute_weights_proximal_regularization(self): 27 | 28 | weights_loss = 0 29 | for w, initial_w in zip(self.model.parameters(), self.copy_model.parameters()): 30 | weights_loss += torch.norm(w - initial_w.detach()) 31 | return weights_loss 32 | 33 | def compute_alpha_proximal_regularization(self): 34 | alpha_loss = 0 35 | for alpha, initial_alpha in zip(self.model.arch_parameters(), self.copy_model.arch_parameters()): 36 | alpha_loss += torch.norm(alpha - initial_alpha.detach()) 37 | return alpha_loss 38 | 39 | def update_alpha(self, input_valid, U_B_valid, target_valid): 40 | self._mark_model() 41 | U_B_valid = torch.autograd.Variable(U_B_valid, requires_grad=True).cuda() 42 | for _ in range(self.n_local_update): 43 | self.alpha_optimizer.zero_grad() 44 | model_loss, _ = self.model._loss(input_valid, U_B_valid, target_valid) 45 | preg_loss = self.compute_alpha_proximal_regularization() 46 | loss = model_loss + self.mu * preg_loss 47 | loss.backward(retain_graph=True) 48 | self.alpha_optimizer.step() 49 | U_B_gradients = torch.autograd.grad(model_loss, U_B_valid, retain_graph=True) 50 | return U_B_gradients 51 | 52 | def update_weights(self, input_train, U_B_train, target_train, weights_optim, grad_clip): 53 | self._mark_model() 54 | U_B_train = torch.autograd.Variable(U_B_train, requires_grad=True).cuda() 55 | for _ in range(self.n_local_update): 56 | weights_optim.zero_grad() 57 | model_loss, logits = self.model._loss(input_train, U_B_train, target_train) 58 | preg_loss = self.compute_weights_proximal_regularization() 59 | loss = model_loss + self.mu * preg_loss 60 | loss.backward(retain_graph=True) 61 | nn.utils.clip_grad_norm_(self.model.parameters(), grad_clip) 62 | weights_optim.step() 63 | U_B_gradients = torch.autograd.grad(model_loss, U_B_train, retain_graph=True) 64 | return U_B_gradients, logits, model_loss 65 | 66 | 67 | class Architect_B(object): 68 | def __init__(self, model, args): 69 | self.network_momentum = args.momentum 70 | self.network_weight_decay = args.weight_decay 71 | self.model = model 72 | self.alpha_optimizer = torch.optim.Adam(self.model.arch_parameters(), 73 | lr=args.arch_learning_rate, betas=(0.5, 0.999), 74 | weight_decay=args.arch_weight_decay) 75 | self.weight_optimizer = torch.optim.SGD(self.model.parameters(), args.learning_rate, 76 | momentum=args.momentum, weight_decay=args.weight_decay) 77 | self.n_local_update = args.n_local_update 78 | self.mu = 0.001 79 | 80 | def _mark_model(self): 81 | self.copy_model = copy.deepcopy(self.model) 82 | 83 | def compute_weights_proximal_regularization(self): 84 | 85 | weights_loss = 0 86 | for w, initial_w in zip(self.model.parameters(), self.copy_model.parameters()): 87 | weights_loss += torch.norm(w - initial_w.detach()) 88 | return weights_loss 89 | 90 | def compute_alpha_proximal_regularization(self): 91 | alpha_loss = 0 92 | for alpha, initial_alpha in zip(self.model.arch_parameters(), self.copy_model.arch_parameters()): 93 | alpha_loss += torch.norm(alpha - initial_alpha.detach()) 94 | return alpha_loss 95 | 96 | def update_alpha(self, U_B_val, U_B_gradients): 97 | self._mark_model() 98 | model_B_alpha_gradients = torch.autograd.grad(U_B_val, self.model.arch_parameters(), 99 | grad_outputs=U_B_gradients, retain_graph=True) 100 | self.alpha_optimizer.zero_grad() 101 | for w, g1 in zip(self.model.arch_parameters(), model_B_alpha_gradients): 102 | w.grad = g1 103 | self.alpha_optimizer.step() 104 | 105 | def update_weights(self, U_B_train, U_B_gradients, weights_optim, grad_clip): 106 | self._mark_model() 107 | model_B_weight_gradients = torch.autograd.grad(U_B_train, self.model.parameters(), 108 | grad_outputs=U_B_gradients, retain_graph=True) 109 | weights_optim.zero_grad() 110 | for w, g1 in zip(self.model.parameters(), model_B_weight_gradients): 111 | w.grad = g1.detach() 112 | nn.utils.clip_grad_norm_(self.model.parameters(), grad_clip) 113 | weights_optim.step() 114 | -------------------------------------------------------------------------------- /publications/FedCG/config.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import datetime 3 | import logging 4 | import os 5 | 6 | import torch 7 | 8 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 9 | 10 | parser = argparse.ArgumentParser() 11 | parser.add_argument('--algorithm', type=str, default="fedavg", 12 | choices=["local", "fedavg", "fedsplit", "fedprox", "fedgen", "feddf", "fedcg", "fedcg_w"]) 13 | parser.add_argument('--dataset', type=str, default="fmnist", 14 | choices=["fmnist", "digit", "office", "cifar", "domainnet"]) 15 | parser.add_argument('--model', type=str, default="lenet5", choices=["lenet5", "resnet18"]) 16 | parser.add_argument('--distance', type=str, default="mse", choices=["none", "mse", "cos"]) 17 | 18 | parser.add_argument('--seed', type=int, default=1, help='seed for initializing training (default: 1)') 19 | parser.add_argument('--batch_size', type=int, default=8, help='input batch size for training (default: 8)') 20 | parser.add_argument('--lr', type=float, default=3e-4, help="learning rate for optimizer (default: 3e-4)") 21 | parser.add_argument('--weight_decay', type=float, default=1e-4, help="weight decay for optimizer (default: 1e-4)") 22 | 23 | parser.add_argument('--noise_dim', type=int, default=100, help="the noise dim for the generator input (default: 100)") 24 | parser.add_argument('--mu', type=float, default=0.01, help="mu for fedprox (default: 0.01)") 25 | parser.add_argument('--n_clients', type=int, default=4, help="the number of clients") 26 | 27 | parser.add_argument('--num_classes', type=int, default=10, help='num for classes') 28 | parser.add_argument('--image_channel', type=int, default=3, help="channel for images") 29 | parser.add_argument('--image_size', type=int, default=32, help='size for images') 30 | 31 | parser.add_argument('--local_epoch', type=int, default=20, 32 | help="the epochs for clients' local task training (default: 20)") 33 | parser.add_argument('--gan_epoch', type=int, default=20, 34 | help="the epochs for clients' local gan training (default: 20)") 35 | parser.add_argument('--early_stop_rounds', type=int, default=20, 36 | help="the early stop rounds for federated learning communication (default: 20)") 37 | parser.add_argument('--global_epoch', type=int, default=20, help="the epochs for server's training (default: 20)") 38 | parser.add_argument('--global_iter_per_epoch', type=int, default=100, 39 | help="the number of iteration per epoch for server training (default: 100)") 40 | parser.add_argument('--add_noise', dest='add_noise', action='store_true', default=False, 41 | help="whether adding noise to image") 42 | parser.add_argument('--noise_std', type=float, default=1., help="std for gaussian noise added to image(default: 1.)") 43 | parser.add_argument('--gpu', type=int, default=0, help='gpu device id') 44 | parser.add_argument('--data_dir', type=str, default="./data/", help="Data directory path") 45 | 46 | # args = parser.parse_args() 47 | args = parser.parse_known_args()[0] 48 | current_time = datetime.datetime.now().strftime("%Y-%m-%d-%H:%M-%S") 49 | # args.name = args.name + '-%s' % current_time 50 | 51 | if args.dataset == "fmnist": 52 | args.image_channel = 1 53 | args.num_classes = 10 54 | elif args.dataset == "cifar": 55 | args.num_classes = 10 56 | elif args.dataset == "digit": 57 | args.n_clients = 4 58 | args.num_classes = 10 59 | elif args.dataset == "office": 60 | args.n_clients = 4 61 | args.num_classes = 10 62 | elif args.dataset == "domainnet": 63 | args.n_clients = 5 64 | args.num_classes = 10 65 | 66 | if args.model == "lenet5": 67 | # extractor input size [3*32*32] 68 | args.image_size = 32 69 | # extractor ouput size [16*5*5] 70 | args.feature_num = 16 71 | args.feature_size = 5 72 | elif args.model == "alexnet": 73 | # extractor input size [3*224*224] 74 | args.image_size = 224 75 | # extractor ouput size [192*13*13] 76 | args.feature_num = 192 77 | args.feature_size = 13 78 | elif args.model == "resnet18": 79 | # extractor input size [3*224*224] 80 | args.image_size = 224 81 | # extractor ouput size [128*28*28] 82 | args.feature_num = 128 83 | args.feature_size = 28 84 | 85 | if args.algorithm == "fedcg" or args.algorithm == "fedcg_w": 86 | args.name = args.algorithm + '_' + args.dataset + str( 87 | args.n_clients) + '_' + args.model + '_' + args.distance + '_' + str(args.seed) 88 | else: 89 | args.name = args.algorithm + '_' + args.dataset + str(args.n_clients) + '_' + args.model + '_' + str(args.seed) 90 | args.dir = 'experiments/' + 'bs' + str(args.batch_size) + 'lr' + str(args.lr) + 'wd' + str(args.weight_decay) 91 | args.checkpoint_dir = os.path.join(args.dir, args.name, 'checkpoint') 92 | os.makedirs(args.checkpoint_dir, exist_ok=True) 93 | 94 | for handler in logging.root.handlers[:]: 95 | logging.root.removeHandler(handler) 96 | logger = logging.getLogger() 97 | logger.setLevel(logging.DEBUG) 98 | fileHandler = logging.FileHandler(os.path.join(args.dir, args.name, 'log.txt'), mode='a') 99 | fileHandler.setLevel(logging.INFO) 100 | consoleHandler = logging.StreamHandler() 101 | consoleHandler.setLevel(logging.INFO) 102 | formatter = logging.Formatter('[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s', 103 | datefmt='%Y-%m-%d %H:%M:%S') 104 | consoleHandler.setFormatter(formatter) 105 | fileHandler.setFormatter(formatter) 106 | logger.addHandler(fileHandler) 107 | logger.addHandler(consoleHandler) 108 | if torch.cuda.is_available(): 109 | torch.cuda.set_device(args.gpu) 110 | -------------------------------------------------------------------------------- /publications/PrADA/statistics_utils.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | from scipy.stats import kde 3 | 4 | 5 | def ks_statistic(data1, data2): 6 | """Calculate the Kolmogorov-Smirnov statistic to compare two sets of data. 7 | The empirical cumulative distribution function for each set of 8 | set of 1-dimensional data points is calculated. The K-S statistic 9 | the maximum absolute distance between the two cumulative distribution 10 | functions. 11 | Parameters: 12 | data1, data2: 1-dimensional lists or arrays of data points to compare. 13 | """ 14 | x1 = numpy.sort(data1) 15 | x2 = numpy.sort(data2) 16 | x = numpy.sort(numpy.concatenate([x1, x2])) 17 | y1 = numpy.linspace(0, 1, len(x1) + 1)[ 18 | 1:] # empirical CDF for data1: curve going up by 1/len(data1) at each observed data-point 19 | y2 = numpy.linspace(0, 1, len(x2) + 1)[1:] # as above but for data2 20 | cdf1 = numpy.interp(x, x1, y1, left=0) # linearly interpolate both CDFs onto a common set of x-values. 21 | cdf2 = numpy.interp(x, x2, y2, left=0) 22 | return abs(cdf1 - cdf2).max() 23 | 24 | 25 | def ks_statistic_kde(data1, data2, num_points=None): 26 | """Calculate the Kolmogorov-Smirnov statistic to compare two sets of data. 27 | Kernel Density Estimation is used to estimate the distribution of each set 28 | set of 1-dimensional data points. From this, the K-S statistic is 29 | calculated: the maximum absolute distance between the two cumulative 30 | distribution functions. 31 | Parameters: 32 | data1, data2: 1-dimensional lists or arrays of data points to compare. 33 | num_points: number of points to evaluate the density along. 34 | """ 35 | xs, kd1, kd2 = _get_estimators_and_xs(data1, data2, num_points) 36 | with numpy.errstate(under='ignore'): 37 | cdf1 = numpy.array([kd1.integrate_box_1d(-numpy.inf, x) for x in xs]) 38 | cdf2 = numpy.array([kd2.integrate_box_1d(-numpy.inf, x) for x in xs]) 39 | return abs(cdf1 - cdf2).max() 40 | 41 | 42 | def js_metric(data1, data2, num_points=None): 43 | """Calculate the Jensen-Shannon metric to compare two sets of data. 44 | Kernel Density Estimation is used to estimate the distribution of each set 45 | set of 1-dimensional data points. From this, the J-S metric (square root of 46 | J-S divergence) is calculated. 47 | Note: KDE will often underestimate the probability at the far tails of the 48 | distribution (outside of where supported by the data), which can lead to 49 | overestimates of K-L divergence (and hence J-S divergence) for highly 50 | non-overlapping datasets. 51 | Parameters: 52 | data1, data2: 1-dimensional lists or arrays of data points to compare. 53 | num_points: number of points to evaluate the density along. 54 | """ 55 | xs, p1, p2 = _get_point_estimates(data1, data2, num_points) 56 | m = (p1 + p2) / 2 57 | return ((_kl_divergence(xs, p1, m) + _kl_divergence(xs, p2, m)) / 2) ** 0.5 58 | 59 | 60 | def kl_divergence(data1, data2, num_points=None): 61 | """Calculate the Kullback-Leibler divergence between two sets of data. 62 | Kernel Density Estimation is used to estimate the distribution of each set 63 | set of 1-dimensional data points. From this, the K-L divergence is 64 | calculated. 65 | Note: KDE will often underestimate the probability at the far tails of the 66 | distribution (outside of where supported by the data), which can lead to 67 | overestimates of K-L divergence for highly non-overlapping datasets. 68 | Parameters: 69 | data1, data2: 1-dimensional lists or arrays of data points to compare. 70 | num_points: number of points to evaluate the density along. 71 | """ 72 | xs, p1, p2 = _get_point_estimates(data1, data2, num_points) 73 | return _kl_divergence(xs, p1, p2) 74 | 75 | 76 | def _get_kd_estimator_and_xs(data, num_points): 77 | """Get KDE estimator for a given dataset, and generate a good set of 78 | points to sample the density at.""" 79 | data = numpy.asarray(data, dtype=numpy.float) 80 | kd_estimator = kde.gaussian_kde(data) 81 | data_samples = kd_estimator.resample(num_points // 2)[0] 82 | xs = numpy.sort(data_samples) 83 | return kd_estimator, xs 84 | 85 | 86 | def _get_estimators_and_xs(data1, data2, num_points): 87 | """Get KDE estimators for two different datasets and a set of points 88 | to evaluate both distributions on.""" 89 | if num_points is None: 90 | num_points = min(5000, (len(data1) + len(data2)) // 2) 91 | kd1, xs1 = _get_kd_estimator_and_xs(data1, num_points // 2) 92 | kd2, xs2 = _get_kd_estimator_and_xs(data2, num_points // 2) 93 | xs = numpy.sort(numpy.concatenate([xs1, xs2])) 94 | return xs, kd1, kd2 95 | 96 | 97 | def _get_point_estimates(data1, data2, num_points): 98 | """Get point estimates for KDE distributions for two different datasets. 99 | """ 100 | xs, kd1, kd2 = _get_estimators_and_xs(data1, data2, num_points) 101 | with numpy.errstate(under='ignore'): 102 | p1 = kd1(xs) 103 | p2 = kd2(xs) 104 | return xs, p1, p2 105 | 106 | 107 | def _kl_divergence(xs, p1, p2): 108 | """Calculate Kullback-Leibler divergence of p1 and p2, which are assumed to 109 | values of two different density functions at the given positions xs. 110 | Return divergence in nats.""" 111 | with numpy.errstate(divide='ignore', invalid='ignore'): 112 | kl = p1 * (numpy.log(p1) - numpy.log(p2)) 113 | kl[~numpy.isfinite(kl)] = 0 # small numbers in p1 or p2 can cause NaN/-inf, etc. 114 | return numpy.trapz(kl, x=xs) # integrate curve 115 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/data/custom/train.txt: -------------------------------------------------------------------------------- 1 | data/custom/images/000001.jpg 2 | data/custom/images/000002.jpg 3 | data/custom/images/000003.jpg 4 | data/custom/images/000004.jpg 5 | data/custom/images/000005.jpg 6 | data/custom/images/000006.jpg 7 | data/custom/images/000008.jpg 8 | data/custom/images/000010.jpg 9 | data/custom/images/000013.jpg 10 | data/custom/images/000014.jpg 11 | data/custom/images/000016.jpg 12 | data/custom/images/000017.jpg 13 | data/custom/images/000018.jpg 14 | data/custom/images/000019.jpg 15 | data/custom/images/000020.jpg 16 | data/custom/images/000021.jpg 17 | data/custom/images/000022.jpg 18 | data/custom/images/000023.jpg 19 | data/custom/images/000024.jpg 20 | data/custom/images/000026.jpg 21 | data/custom/images/000027.jpg 22 | data/custom/images/000028.jpg 23 | data/custom/images/000029.jpg 24 | data/custom/images/000030.jpg 25 | data/custom/images/000031.jpg 26 | data/custom/images/000032.jpg 27 | data/custom/images/000033.jpg 28 | data/custom/images/000034.jpg 29 | data/custom/images/000035.jpg 30 | data/custom/images/000036.jpg 31 | data/custom/images/000037.jpg 32 | data/custom/images/000040.jpg 33 | data/custom/images/000041.jpg 34 | data/custom/images/000042.jpg 35 | data/custom/images/000043.jpg 36 | data/custom/images/000044.jpg 37 | data/custom/images/000045.jpg 38 | data/custom/images/000046.jpg 39 | data/custom/images/000047.jpg 40 | data/custom/images/000049.jpg 41 | data/custom/images/000050.jpg 42 | data/custom/images/000051.jpg 43 | data/custom/images/000053.jpg 44 | data/custom/images/000054.jpg 45 | data/custom/images/000055.jpg 46 | data/custom/images/000056.jpg 47 | data/custom/images/000057.jpg 48 | data/custom/images/000058.jpg 49 | data/custom/images/000060.jpg 50 | data/custom/images/000061.jpg 51 | data/custom/images/000062.jpg 52 | data/custom/images/000064.jpg 53 | data/custom/images/000065.jpg 54 | data/custom/images/000066.jpg 55 | data/custom/images/000067.jpg 56 | data/custom/images/000068.jpg 57 | data/custom/images/000069.jpg 58 | data/custom/images/000070.jpg 59 | data/custom/images/000071.jpg 60 | data/custom/images/000072.jpg 61 | data/custom/images/000074.jpg 62 | data/custom/images/000075.jpg 63 | data/custom/images/000076.jpg 64 | data/custom/images/000077.jpg 65 | data/custom/images/000078.jpg 66 | data/custom/images/000079.jpg 67 | data/custom/images/000080.jpg 68 | data/custom/images/000082.jpg 69 | data/custom/images/000083.jpg 70 | data/custom/images/000084.jpg 71 | data/custom/images/000085.jpg 72 | data/custom/images/000086.jpg 73 | data/custom/images/000087.jpg 74 | data/custom/images/000088.jpg 75 | data/custom/images/000089.jpg 76 | data/custom/images/000090.jpg 77 | data/custom/images/000092.jpg 78 | data/custom/images/000093.jpg 79 | data/custom/images/000094.jpg 80 | data/custom/images/000095.jpg 81 | data/custom/images/000096.jpg 82 | data/custom/images/000097.jpg 83 | data/custom/images/000098.jpg 84 | data/custom/images/000099.jpg 85 | data/custom/images/000100.jpg 86 | data/custom/images/000101.jpg 87 | data/custom/images/000102.jpg 88 | data/custom/images/000103.jpg 89 | data/custom/images/000105.jpg 90 | data/custom/images/000106.jpg 91 | data/custom/images/000108.jpg 92 | data/custom/images/000109.jpg 93 | data/custom/images/000110.jpg 94 | data/custom/images/000113.jpg 95 | data/custom/images/000114.jpg 96 | data/custom/images/000116.jpg 97 | data/custom/images/000117.jpg 98 | data/custom/images/000118.jpg 99 | data/custom/images/000119.jpg 100 | data/custom/images/000121.jpg 101 | data/custom/images/000122.jpg 102 | data/custom/images/000123.jpg 103 | data/custom/images/000124.jpg 104 | data/custom/images/000127.jpg 105 | data/custom/images/000129.jpg 106 | data/custom/images/000130.jpg 107 | data/custom/images/000131.jpg 108 | data/custom/images/000132.jpg 109 | data/custom/images/000133.jpg 110 | data/custom/images/000134.jpg 111 | data/custom/images/000135.jpg 112 | data/custom/images/000137.jpg 113 | data/custom/images/000139.jpg 114 | data/custom/images/000140.jpg 115 | data/custom/images/000141.jpg 116 | data/custom/images/000142.jpg 117 | data/custom/images/000144.jpg 118 | data/custom/images/000145.jpg 119 | data/custom/images/000146.jpg 120 | data/custom/images/000148.jpg 121 | data/custom/images/000149.jpg 122 | data/custom/images/000150.jpg 123 | data/custom/images/000151.jpg 124 | data/custom/images/000152.jpg 125 | data/custom/images/000153.jpg 126 | data/custom/images/000154.jpg 127 | data/custom/images/000155.jpg 128 | data/custom/images/000157.jpg 129 | data/custom/images/000158.jpg 130 | data/custom/images/000160.jpg 131 | data/custom/images/000162.jpg 132 | data/custom/images/000163.jpg 133 | data/custom/images/000164.jpg 134 | data/custom/images/000165.jpg 135 | data/custom/images/000166.jpg 136 | data/custom/images/000167.jpg 137 | data/custom/images/000168.jpg 138 | data/custom/images/000169.jpg 139 | data/custom/images/000170.jpg 140 | data/custom/images/000171.jpg 141 | data/custom/images/000172.jpg 142 | data/custom/images/000173.jpg 143 | data/custom/images/000174.jpg 144 | data/custom/images/000175.jpg 145 | data/custom/images/000177.jpg 146 | data/custom/images/000178.jpg 147 | data/custom/images/000179.jpg 148 | data/custom/images/000181.jpg 149 | data/custom/images/000182.jpg 150 | data/custom/images/000183.jpg 151 | data/custom/images/000184.jpg 152 | data/custom/images/000185.jpg 153 | data/custom/images/000186.jpg 154 | data/custom/images/000187.jpg 155 | data/custom/images/000188.jpg 156 | data/custom/images/000189.jpg 157 | data/custom/images/000191.jpg 158 | data/custom/images/000192.jpg 159 | data/custom/images/000195.jpg 160 | data/custom/images/000196.jpg 161 | data/custom/images/000198.jpg 162 | data/custom/images/000199.jpg 163 | data/custom/images/000200.jpg 164 | -------------------------------------------------------------------------------- /publications/FedCG/README.md: -------------------------------------------------------------------------------- 1 | # FedCG: Leverage Conditional GAN for Protecting Privacy and Maintaining Competitive Performance in Federated Learning 2 | 3 | ## FedCG介绍 4 | 5 | 联邦学习(FL)旨在通过让客户端在不分享其私人数据、保护数据隐私的前提下协作建立机器学习模型。最近的一些研究证明了在联邦学习过程中交换的信息会受到基于梯度的隐私攻击,因此,各种隐私保护方法已被采用来阻止此类攻击,保护数据隐私。然而,这些防御性方法要么引入数量级更多的计算和通信开销(例如,同态加密),要么在预测准确性方面导致模型性能大幅下降(例如,使用差分隐私)。**FedCG**将条件生成对抗网络与分割学习相结合,实现对数据的有效隐私保护,同时保持有竞争力的模型性能。 6 | 7 | 更具体地说,FedCG将每个客户端的本地网络分解为私有特征提取器(extractor)和公共分类器(classifier),并将特征提取器保留在本地以保护隐私。每个客户端用一个生成器(generator)来拟合特征提取器的输出表征。FedCG的新颖之处在于它与服务器共享客户端的生成器而不是提取器,以聚合客户端的共享知识,提高模型性能 (如图1)。 8 | 9 |

10 | 11 |

图1:FedCG 架构概览
12 |

13 | 14 | 15 | 16 | 这种策略有两个直接的优势:首先,与服务器可以得到完整的客户端模型的联邦学习方法(例如,FedAvg 和 FedProx)相比,FedCG没有暴露直接与原始数据接触的模型 (也即,extractor),因此客户端数据泄露的可能性显著降低。其次,服务器可以使用知识蒸馏(Hinton, Vinyals, and Dean 2015)聚合客户端的生成器和分类器,而无需访问任何公共数据。 17 | 18 | 19 | 20 | ### FedCG训练步骤 21 | 22 | FedCG的训练步骤分为两阶段客户端更新(如图2)和服务器端聚合(如图3)。在两阶段客户端更新中,我们首先利用从服务器下发的全局生成器来优化分类网络(包括特征提取器和分类器),然后再训练一个本地生成器来拟合特征提取器的输出表征 $G(z,y) \approx F(x|y)$ 我们用这个本地生成器来代替特征提取器, 在服务器端聚合所有客户端的知识同时保护数据隐私。 23 | 24 |

25 | 26 |

图2:FedCG 客户端训练示意图。
27 |

28 | 29 | 30 | 31 | 在服务器端聚合中,我们通过知识蒸馏的方式聚合一个公共分类器 $C_g$ 和一个公共生成器 $G_g$ 。然后,服务器下发公共分类器和公共生成器给每个客户端。 32 | 33 |

34 | 35 |

图3:FedCG服务器端训练示意图。
36 |

37 | 38 | 39 | 40 | ### FedCG实验结果 41 | 42 | 如表1所示,总体来说,FedCG 在4个数据集 (共6个数据集) 上取得最高准确率. 在IID 场景 : 在 FMNIST 上达到最高准确率。在Non-IID 场景: 在 3 个数据集上都达到最优,特别是在 Office 数据集上,FedCG比第二高准确率的 FedProx 高出 4.35% 。 43 | 44 |

45 | 46 |

表1:FedCG与基线在Top-1精度上的比较。粗体字表示最好的性能。*表示没有测量结果。括号内的数字表示客户端数量。
47 |

48 | 49 | 50 | 51 | IID 场景: 所有的FL方法在所有的客户端上都以较大的优势超过了本地模型。在FMNIST数据集上,FedCG在所有客户端的表现都是最好的(见图4(a))。FedCG的表现与那些共享所有本地模型的FL方法相差不大(见图4(b))。Non-IID 场景: 在所有3个Non-IID数据集中,没有一种FL方法能在每个客户上都击败本地模型(见图4(c),图4(d)和图4(e))。 FedCG在最多的客户端上取得了最好的效果。同时也是击败local最多的算法。 52 |

53 | 54 |

图4:在5个数据集上的实验中,在每个客户端上FEDAVG、FEDPROX、FEDDF、FEDSPLIT和FEDCG(红色)与LOCAL相比,都取得了精度提高。纵轴是准确性方面的性能差异(%)。正的(负的)收益意味着FL方法比LOCAL方法取得了 比LOCAL模型更好(更差)。
55 |

56 | 57 | 58 | 如表2所示,隐私分析的实验结果表明,使用FedAvg,随着 DP 噪声添加得越多,能更好的保护隐私,但会导致较大的准确率损失;使用FedSplit,能保护隐私, 但有较大的准确率损失;使用FedCG,能在保护隐私的条件下,取得一个较高的准确率。 59 | 60 |

61 | 62 |

表2: FedAVG,FedSPLIT和FedCG的模型性能与隐私保护效果对比
63 |

64 | 65 | ### 总结和后续工作 66 | 67 | 我们提出了FedCG,目的是保护数据隐私,同时保持有竞争力的模型性能。FedCG将每个客户的本地网络分解为一个私有特征提取器和一个公共分类器,并将特征提取器保持在本地以保护隐私。它与服务器共享客户端的生成器,以聚合共享知识,从而提高客户端本地分类网络的性能。实验表明 FedCG具有高水平的隐私保护能力,并且可以实现有竞争力的模型性能。 68 | 69 | 本篇论文的不足之处在于FedCG的隐私保护理论分析仍待研究。此外,本篇论文使用 LeNet 作为本地网络,模型较小。作者将研究更深层次的神经网络,以进一步检验 FedCG 方法的有效性。 70 | 71 | 72 | 73 | 74 | ## Usage 75 | - Train `FedAVG` `Lenet` on `FashionMNIST` dataset: 76 | ```bash 77 | python main.py --algorithm="fedavg" --dataset="fmnist" --model="lenet5" --seed=1 --gpu=1 78 | ``` 79 | - Train `FedCG` `Lenet` on `Cifar` dataset: 80 | ```bash 81 | python main.py --algorithm="fedcg" --dataset="cifar" --model="lenet5" --seed=1 --gpu=1 82 | ``` 83 | 84 | 85 | | Parameter | Description | 86 | | ----------------------------- | ---------------------------------------- | 87 | | `algorithm` | The training algorithm. Options: `local`, `fedavg`, `fedsplit`, `fedprox`, `fedcg`. Default = `fedavg`. | 88 | | `dataset` | Dataset to use. Options: `fmnist`, `digit`, `office`, `cifar`. Default = `digit`. | 89 | | `model` | The model architecture. Options: `lenet5`, `resnet18`. Default = `lenet5`. | 90 | | `distance` | The distance between extractor and generator. This parameter takes effect only when the algorithm is fedcg. Options: `none`, `mse`, `cos`. Default = `none`. | 91 | | `lr` | learning rate for clients' extractor and classifier optimzer and server's generator and classifier optimizer, default = 2e-4. | 92 | | `weight_decay` | weight decay for clients' extractor and classifier optimzer and server's generator and classifier optimizer, default = 1e-5. | 93 | | `add_noise` | Whether adding noise to train data, default = False. | 94 | | `batch_size` | Batch size, default = `8`. | 95 | | `local_epoch` | Number of local training epochs, default = `20`. | 96 | | `gan_epoch` | Number of local gan training epochs, default = `20`. | 97 | | `global_epoch` | Number of server training epochs, default = `20`. | 98 | | `global_iter_per_epoch` | Number of iteration per epoch for server training, default = `100`. | 99 | | `mu` | The proximal term parameter for FedProx, default = `0.01`. | 100 | 101 | 102 | 103 | ## Citation 104 | 105 | Please kindly cite our paper if you find this code useful for your research. 106 | 107 | ``` 108 | @inproceedings{ijcai2022-324, 109 | title = {FedCG: Leverage Conditional GAN for Protecting Privacy and Maintaining Competitive Performance in Federated Learning}, 110 | author = {Wu, Yuezhou and Kang, Yan and Luo, Jiahuan and He, Yuanqin and Fan, Lixin and Pan, Rong and Yang, Qiang}, 111 | booktitle = {Proceedings of the Thirty-First International Joint Conference on 112 | Artificial Intelligence, {IJCAI-22}}, 113 | publisher = {International Joint Conferences on Artificial Intelligence Organization}, 114 | editor = {Lud De Raedt}, 115 | pages = {2334--2340}, 116 | year = {2022}, 117 | month = {7}, 118 | note = {Main Track} 119 | doi = {10.24963/ijcai.2022/324}, 120 | url = {https://doi.org/10.24963/ijcai.2022/324}, 121 | } 122 | ``` 123 | -------------------------------------------------------------------------------- /datasets/federated_object_detection_benchmark/utils/datasets.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import random 3 | import os 4 | import sys 5 | import numpy as np 6 | from PIL import Image 7 | import torch 8 | import torch.nn.functional as F 9 | 10 | from utils.augmentations import horisontal_flip 11 | from torch.utils.data import Dataset 12 | import torchvision.transforms as transforms 13 | 14 | 15 | def pad_to_square(img, pad_value): 16 | c, h, w = img.shape 17 | dim_diff = np.abs(h - w) 18 | # (upper / left) padding and (lower / right) padding 19 | pad1, pad2 = dim_diff // 2, dim_diff - dim_diff // 2 20 | # Determine padding 21 | pad = (0, 0, pad1, pad2) if h <= w else (pad1, pad2, 0, 0) 22 | # Add padding 23 | img = F.pad(img, pad, "constant", value=pad_value) 24 | 25 | return img, pad 26 | 27 | 28 | def resize(image, size): 29 | image = F.interpolate(image.unsqueeze(0), size=size, mode="nearest").squeeze(0) 30 | return image 31 | 32 | 33 | def random_resize(images, min_size=288, max_size=448): 34 | new_size = random.sample(list(range(min_size, max_size + 1, 32)), 1)[0] 35 | images = F.interpolate(images, size=new_size, mode="nearest") 36 | return images 37 | 38 | 39 | class ImageFolder(Dataset): 40 | def __init__(self, folder_path, img_size=416): 41 | self.files = sorted(glob.glob("%s/*.*" % folder_path)) 42 | self.img_size = img_size 43 | 44 | def __getitem__(self, index): 45 | img_path = self.files[index % len(self.files)] 46 | # Extract image as PyTorch tensor 47 | img = transforms.ToTensor()(Image.open(img_path)) 48 | # Pad to square resolution 49 | img, _ = pad_to_square(img, 0) 50 | # Resize 51 | img = resize(img, self.img_size) 52 | 53 | return img_path, img 54 | 55 | def __len__(self): 56 | return len(self.files) 57 | 58 | 59 | class ListDataset(Dataset): 60 | def __init__(self, list_path, img_size=416, augment=True, multiscale=True, normalized_labels=True): 61 | with open(list_path, "r") as file: 62 | self.img_files = file.readlines() 63 | 64 | self.label_files = [ 65 | path.replace("images", "labels").replace("JPEGImages", "labels").replace(".png", ".txt").replace(".jpg", ".txt") 66 | for path in self.img_files 67 | ] 68 | self.img_size = img_size 69 | self.max_objects = 100 70 | self.augment = augment 71 | self.multiscale = multiscale 72 | self.normalized_labels = normalized_labels 73 | self.min_size = self.img_size - 3 * 32 74 | self.max_size = self.img_size + 3 * 32 75 | self.batch_count = 0 76 | 77 | def __getitem__(self, index): 78 | 79 | # --------- 80 | # Image 81 | # --------- 82 | 83 | img_path = self.img_files[index % len(self.img_files)].rstrip() 84 | 85 | # Extract image as PyTorch tensor 86 | img = transforms.ToTensor()(Image.open(img_path).convert('RGB')) 87 | 88 | # Handle images with less than three channels 89 | if len(img.shape) != 3: 90 | img = img.unsqueeze(0) 91 | img = img.expand((3, img.shape[1:])) 92 | 93 | _, h, w = img.shape 94 | h_factor, w_factor = (h, w) if self.normalized_labels else (1, 1) 95 | # Pad to square resolution 96 | img, pad = pad_to_square(img, 0) 97 | _, padded_h, padded_w = img.shape 98 | 99 | # --------- 100 | # Label 101 | # --------- 102 | 103 | label_path = self.label_files[index % len(self.img_files)].rstrip() 104 | 105 | targets = None 106 | if os.path.exists(label_path): 107 | boxes = torch.from_numpy(np.loadtxt(label_path).reshape(-1, 5)) 108 | # Extract coordinates for unpadded + unscaled image 109 | x1 = w_factor * (boxes[:, 1] - boxes[:, 3] / 2) 110 | y1 = h_factor * (boxes[:, 2] - boxes[:, 4] / 2) 111 | x2 = w_factor * (boxes[:, 1] + boxes[:, 3] / 2) 112 | y2 = h_factor * (boxes[:, 2] + boxes[:, 4] / 2) 113 | # Adjust for added padding 114 | x1 += pad[0] 115 | y1 += pad[2] 116 | x2 += pad[1] 117 | y2 += pad[3] 118 | # Returns (x, y, w, h) 119 | boxes[:, 1] = ((x1 + x2) / 2) / padded_w 120 | boxes[:, 2] = ((y1 + y2) / 2) / padded_h 121 | boxes[:, 3] *= w_factor / padded_w 122 | boxes[:, 4] *= h_factor / padded_h 123 | 124 | targets = torch.zeros((len(boxes), 6)) 125 | targets[:, 1:] = boxes 126 | 127 | # Apply augmentations 128 | if self.augment: 129 | if np.random.random() < 0.5: 130 | img, targets = horisontal_flip(img, targets) 131 | 132 | return img_path, img, targets 133 | 134 | def collate_fn(self, batch): 135 | paths, imgs, targets = list(zip(*batch)) 136 | # Remove empty placeholder targets 137 | targets = [boxes for boxes in targets if boxes is not None] 138 | # Add sample index to targets 139 | for i, boxes in enumerate(targets): 140 | boxes[:, 0] = i 141 | targets = torch.cat(targets, 0) 142 | # Selects new image size every tenth batch 143 | if self.multiscale and self.batch_count % 10 == 0: 144 | self.img_size = random.choice(range(self.min_size, self.max_size + 1, 32)) 145 | # Resize images to input shape 146 | imgs = torch.stack([resize(img, self.img_size) for img in imgs]) 147 | self.batch_count += 1 148 | return paths, imgs, targets 149 | 150 | def __len__(self): 151 | return len(self.img_files) 152 | -------------------------------------------------------------------------------- /publications/PrADA/experiments/ppd_loan/train_ppd_fg_adapt_pretrain.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | from experiments.ppd_loan.train_config import feature_extractor_architecture_list, data_tag, \ 4 | pre_train_hyperparameters, data_hyperparameters 5 | from experiments.ppd_loan.meta_data import column_name_list, group_ind_list, group_info, embedding_shape_map 6 | from experiments.ppd_loan.train_ppd_utils import pretrain_ppd 7 | from models.classifier import CensusFeatureAggregator 8 | from models.dann_models import create_embeddings 9 | from models.discriminator import CensusRegionDiscriminator 10 | from models.feature_extractor import CensusRegionFeatureExtractorDense 11 | from models.model_config import wire_fg_dann_global_model 12 | 13 | 14 | def record_domain_data(domain_data_dict, domain_data, domain_col_list, is_categorical): 15 | if is_categorical: 16 | emb_dict = OrderedDict() 17 | for col_index, col_name in enumerate(domain_col_list): 18 | emb_dict[col_name] = domain_data[:, col_index] 19 | domain_data_dict["embeddings"] = emb_dict 20 | 21 | else: 22 | domain_data_dict["non_embedding"] = {"tabular_data": domain_data} 23 | 24 | 25 | def parse_domain_data(data, column_name_list, df_group_ind_list, df_group_info_list): 26 | wide_feat_list = [] 27 | domain_list = [] 28 | for group_ind, group_info in zip(df_group_ind_list, df_group_info_list): 29 | start_index = group_info[0] 30 | # 2 stands for wide features (i.e., features for active parties) 31 | if group_ind == 2: 32 | length, _ = group_info[1] 33 | wide_feat_list.append(data[:, start_index:start_index + length]) 34 | # 1 stands for feature group (i.e., feature for passive party) 35 | elif group_ind == 1: 36 | new_domain = dict() 37 | new_domain["embeddings"] = None 38 | new_domain["non_embedding"] = None 39 | tuple_num = len(group_info) 40 | for i in range(1, tuple_num): 41 | length, is_cat = group_info[i] 42 | domain_data = data[:, start_index:start_index + length] 43 | domain_col_list = column_name_list[start_index:start_index + length] 44 | record_domain_data(new_domain, domain_data, domain_col_list, is_cat) 45 | start_index = start_index + length 46 | domain_list.append(new_domain) 47 | return wide_feat_list, domain_list 48 | 49 | 50 | def partition_data(data): 51 | """ 52 | partition data into party C and party A(B). Data in party C is partitioned into group 53 | """ 54 | 55 | wide_feat_list, domain_list = parse_domain_data(data, 56 | column_name_list, 57 | group_ind_list, 58 | group_info) 59 | return wide_feat_list, domain_list 60 | 61 | 62 | def create_model_group(extractor_input_dim): 63 | """ 64 | create a group of models, namely feature extractor, aggregator and discriminator, for each feature group 65 | """ 66 | 67 | extractor = CensusRegionFeatureExtractorDense(input_dims=extractor_input_dim) 68 | classifier = CensusFeatureAggregator(input_dim=extractor_input_dim[-1]) 69 | discriminator = CensusRegionDiscriminator(input_dim=extractor_input_dim[-1]) 70 | return extractor, classifier, discriminator 71 | 72 | 73 | def create_embedding_dict(): 74 | """ 75 | create embedding dictionary for categorical features/columns 76 | """ 77 | 78 | embedding_meta_dict = dict() 79 | for feat_name, emb_shape in embedding_shape_map.items(): 80 | embedding_meta_dict[feat_name] = emb_shape 81 | print(f"embedding_meta_dict: \n {embedding_meta_dict}") 82 | return create_embeddings(embedding_meta_dict) 83 | 84 | 85 | def create_fg_pdd_global_model(pos_class_weight=1.0, num_wide_feature=6, using_interaction=False): 86 | embedding_dict = create_embedding_dict() 87 | 88 | num_wide_feature = num_wide_feature 89 | using_feature_group = True 90 | global_model = wire_fg_dann_global_model(embedding_dict=embedding_dict, 91 | feat_extr_archit_list=feature_extractor_architecture_list, 92 | intr_feat_extr_archit_list=None, 93 | num_wide_feature=num_wide_feature, 94 | using_feature_group=using_feature_group, 95 | using_interaction=using_interaction, 96 | partition_data_fn=partition_data, 97 | create_model_group_fn=create_model_group, 98 | pos_class_weight=pos_class_weight) 99 | 100 | return global_model 101 | 102 | 103 | if __name__ == "__main__": 104 | ppd_dann_root_dir = data_hyperparameters['ppd_fg_pretrained_model_dir'] 105 | using_interaction = pre_train_hyperparameters['using_interaction'] 106 | pos_class_weight = pre_train_hyperparameters['pos_class_weight'] 107 | init_model = create_fg_pdd_global_model(using_interaction=using_interaction, 108 | pos_class_weight=pos_class_weight) 109 | 110 | task_id = pretrain_ppd(data_tag, 111 | ppd_dann_root_dir, 112 | pre_train_hyperparameters, 113 | data_hyperparameters, 114 | model=init_model, 115 | apply_feature_group=True) 116 | print(f"[INFO] adaptation task id:{task_id}") 117 | --------------------------------------------------------------------------------