FedModelKit 0.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- FedModelKit/README.md +25 -0
- FedModelKit/__init__.py +17 -0
- FedModelKit/aggregator.py +41 -0
- FedModelKit/cli.py +97 -0
- FedModelKit/default_create_functions.py +114 -0
- FedModelKit/interface.py +130 -0
- FedModelKit/local_learner.py +61 -0
- FedModelKit/py.typed +0 -0
- FedModelKit/src/utils.py +65 -0
- FedModelKit/templates/__init__template.py +0 -0
- FedModelKit/templates/client_app_template.py +118 -0
- FedModelKit/templates/ds_template.ipynb +332 -0
- FedModelKit/templates/extern_pyproject_template.toml +17 -0
- FedModelKit/templates/images/doSendModels.png +0 -0
- FedModelKit/templates/images/doWaitsForJobs.png +0 -0
- FedModelKit/templates/images/dsAggregateModels.png +0 -0
- FedModelKit/templates/images/dsDoneSubmittingJobs.png +0 -0
- FedModelKit/templates/images/dsSendsJobs.png +0 -0
- FedModelKit/templates/images/overview.png +0 -0
- FedModelKit/templates/main_template.py +27 -0
- FedModelKit/templates/pyproject_template.toml +53 -0
- FedModelKit/templates/readme_template.md +48 -0
- FedModelKit/templates/server_app_template.py +204 -0
- FedModelKit/templates/task_template.py +140 -0
- FedModelKit/templates/uv_template.lock +2812 -0
- FedModelKit/templates.py +76 -0
- fedmodelkit-0.5.0.dist-info/METADATA +283 -0
- fedmodelkit-0.5.0.dist-info/RECORD +31 -0
- fedmodelkit-0.5.0.dist-info/WHEEL +4 -0
- fedmodelkit-0.5.0.dist-info/entry_points.txt +2 -0
- fedmodelkit-0.5.0.dist-info/licenses/LICENSE +23 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model upload example script.
|
|
3
|
+
|
|
4
|
+
To run this code you need to install pytorch library, you can find it at this link: https://pytorch.org/get-started/locally/
|
|
5
|
+
"""
|
|
6
|
+
from FedModelKit import FederatedModel, submit_fl_model
|
|
7
|
+
|
|
8
|
+
# Create your custom function defining a PyTorch-based model and returning its instance
|
|
9
|
+
def create_local_learner():
|
|
10
|
+
import pandas as pd
|
|
11
|
+
from torch import nn, optim
|
|
12
|
+
from torch.utils.data import DataLoader, Dataset
|
|
13
|
+
import torch
|
|
14
|
+
import flwr
|
|
15
|
+
|
|
16
|
+
from src.utils import Utils # Dependency script stored inside the src directory
|
|
17
|
+
|
|
18
|
+
class CustomLocalLearner(nn.Module):
|
|
19
|
+
def __init__(self, input_size: int) -> None:
|
|
20
|
+
super(CustomLocalLearner, self).__init__()
|
|
21
|
+
self.linear = nn.Linear(input_size, 3)
|
|
22
|
+
self.softmax = nn.Softmax(dim=1)
|
|
23
|
+
self.loss_fn = nn.CrossEntropyLoss()
|
|
24
|
+
self.optimizer = optim.Adam(self.parameters(), lr=0.001)
|
|
25
|
+
|
|
26
|
+
def _forward(self, x):
|
|
27
|
+
x = self.linear(x)
|
|
28
|
+
return self.softmax(x)
|
|
29
|
+
|
|
30
|
+
def get_parameters(self) -> flwr.common.ParametersRecord:
|
|
31
|
+
return Utils.pytorch_to_parameter_record(self.state_dict())
|
|
32
|
+
|
|
33
|
+
def set_parameters(self, parameters: flwr.common.ParametersRecord) -> None:
|
|
34
|
+
self.load_state_dict(Utils.parameters_to_pytorch_state_dict(parameters))
|
|
35
|
+
|
|
36
|
+
def prepare_data(self, data: pd.DataFrame) -> None:
|
|
37
|
+
class IrisDataset(Dataset):
|
|
38
|
+
def __init__(self, dataframe: pd.DataFrame) -> None:
|
|
39
|
+
self.dataframe = dataframe
|
|
40
|
+
self.dataframe.loc[:, "class"] = dataframe.loc[:, "class"].replace(
|
|
41
|
+
{"Iris-setosa": 0, "Iris-versicolor": 1, "Iris-virginica": 2}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def __getitem__(self, idx: int):
|
|
45
|
+
x = self.dataframe.iloc[idx, :-1].to_numpy("float32")
|
|
46
|
+
y = torch.tensor(self.dataframe.iloc[idx, -1], dtype=torch.long)
|
|
47
|
+
return x, y
|
|
48
|
+
|
|
49
|
+
def __len__(self) -> int:
|
|
50
|
+
return len(self.dataframe)
|
|
51
|
+
|
|
52
|
+
dataset = IrisDataset(data)
|
|
53
|
+
dataloader = DataLoader(dataset, batch_size=32)
|
|
54
|
+
self.dataloader = dataloader
|
|
55
|
+
|
|
56
|
+
def train_round(self) -> flwr.common.MetricsRecord:
|
|
57
|
+
loss = torch.tensor(0.0)
|
|
58
|
+
for batch in self.dataloader:
|
|
59
|
+
x, y = batch
|
|
60
|
+
self.optimizer.zero_grad()
|
|
61
|
+
y_hat = self._forward(x)
|
|
62
|
+
loss = self.loss_fn(y_hat, y)
|
|
63
|
+
loss.backward()
|
|
64
|
+
self.optimizer.step()
|
|
65
|
+
|
|
66
|
+
return flwr.common.MetricsRecord({"loss": loss.item()})
|
|
67
|
+
|
|
68
|
+
def evaluate(self) -> flwr.common.MetricsRecord:
|
|
69
|
+
correct = 0
|
|
70
|
+
total = 0
|
|
71
|
+
with torch.no_grad():
|
|
72
|
+
for batch in self.dataloader:
|
|
73
|
+
x, y = batch
|
|
74
|
+
y_hat = self._forward(x)
|
|
75
|
+
_, predicted = torch.max(y_hat, 1)
|
|
76
|
+
total += y.size(0)
|
|
77
|
+
correct += (predicted == y).sum().item()
|
|
78
|
+
return flwr.common.MetricsRecord({"accuracy": correct / total})
|
|
79
|
+
|
|
80
|
+
return CustomLocalLearner(4)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Create your custom function defining an aggregation strategy and returning its instance
|
|
84
|
+
def create_aggregator():
|
|
85
|
+
from collections import OrderedDict
|
|
86
|
+
import numpy as np
|
|
87
|
+
import flwr
|
|
88
|
+
from typing import Optional
|
|
89
|
+
|
|
90
|
+
from src.utils import Utils # Dependency script stored inside the src directory #type: ignore[import]
|
|
91
|
+
|
|
92
|
+
class CustomAggregator:
|
|
93
|
+
|
|
94
|
+
def aggregate_parameters(self, results: list[flwr.common.ParametersRecord], config: Optional[flwr.common.ConfigsRecord]=None
|
|
95
|
+
) -> flwr.common.ParametersRecord:
|
|
96
|
+
parameters = [Utils.parameters_to_dict(param) for param in results]
|
|
97
|
+
keys = parameters[0].keys()
|
|
98
|
+
result = OrderedDict()
|
|
99
|
+
for key in keys:
|
|
100
|
+
# Init array
|
|
101
|
+
this_array: np.ndarray = np.zeros_like(parameters[0][key])
|
|
102
|
+
for p in parameters:
|
|
103
|
+
this_array += p[key]
|
|
104
|
+
result[key] = this_array / len(results)
|
|
105
|
+
return Utils.dict_to_parameter_record(result)
|
|
106
|
+
|
|
107
|
+
def aggregate_metrics(self, results: list[flwr.common.MetricsRecord], config: Optional[flwr.common.ConfigsRecord]=None) -> flwr.common.MetricsRecord:
|
|
108
|
+
keys = results[0].keys()
|
|
109
|
+
result = OrderedDict()
|
|
110
|
+
for key in keys:
|
|
111
|
+
# Init array
|
|
112
|
+
cumsum = 0.0
|
|
113
|
+
for m in results:
|
|
114
|
+
if not isinstance(m[key], (int, float)):
|
|
115
|
+
raise ValueError(
|
|
116
|
+
f"flwr.common.MetricsRecord value type not supported: {type(m[key])}"
|
|
117
|
+
)
|
|
118
|
+
cumsum += m[key] # type: ignore
|
|
119
|
+
result[key] = cumsum / len(results)
|
|
120
|
+
return flwr.common.MetricsRecord(result)
|
|
121
|
+
|
|
122
|
+
return CustomAggregator()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
# Create FederatedModel with custom aggregator and local learner
|
|
127
|
+
federated_model = FederatedModel(create_local_learner=create_local_learner,
|
|
128
|
+
model_name="your_model_name",
|
|
129
|
+
create_aggregator=create_aggregator,
|
|
130
|
+
aggregator_name="custom_aggregator")
|
|
131
|
+
|
|
132
|
+
# Submit the FederatedModel to the Federated Platform Model Catalogue with credentials and experiment name
|
|
133
|
+
submit_fl_model(federated_model,
|
|
134
|
+
platform_url="your_platform_url",
|
|
135
|
+
username="your_username",
|
|
136
|
+
password="your_password",
|
|
137
|
+
experiment_name="your_experiment_name",
|
|
138
|
+
disease="AML",
|
|
139
|
+
trained=False
|
|
140
|
+
)
|