diff --git a/examples/federated-learning-surface-defect-detection-aggregation.Dockerfile b/examples/federated-learning-surface-defect-detection-aggregation.Dockerfile index 0f75cd7af..b233d2877 100644 --- a/examples/federated-learning-surface-defect-detection-aggregation.Dockerfile +++ b/examples/federated-learning-surface-defect-detection-aggregation.Dockerfile @@ -20,6 +20,6 @@ RUN rm -rf /home/plato/.git RUN pip install -r /home/plato/requirements.txt WORKDIR /home/work -COPY examples/federated_learning/surface_defect_detection_v2 /home/work/ +COPY examples/federated_learning/surface_defect_detection_pytorch /home/work/ CMD ["/bin/sh", "-c", "ulimit -n 50000; python aggregate.py"] diff --git a/examples/federated-learning-surface-defect-detection-train.Dockerfile b/examples/federated-learning-surface-defect-detection-train.Dockerfile index 773fa4cc4..38b400c37 100644 --- a/examples/federated-learning-surface-defect-detection-train.Dockerfile +++ b/examples/federated-learning-surface-defect-detection-train.Dockerfile @@ -23,6 +23,6 @@ RUN rm -rf /home/plato/.git RUN pip install -r /home/plato/requirements.txt WORKDIR /home/work -COPY examples/federated_learning/surface_defect_detection_v2 /home/work/ +COPY examples/federated_learning/surface_defect_detection_pytorch /home/work/ ENTRYPOINT ["python", "train.py"] diff --git a/examples/federated_learning/surface_defect_detection_v2/README.md b/examples/federated_learning/surface_defect_detection_mindspore/README.md similarity index 100% rename from examples/federated_learning/surface_defect_detection_v2/README.md rename to examples/federated_learning/surface_defect_detection_mindspore/README.md diff --git a/examples/federated_learning/surface_defect_detection_v2/aggregate.py b/examples/federated_learning/surface_defect_detection_mindspore/aggregate.py similarity index 100% rename from examples/federated_learning/surface_defect_detection_v2/aggregate.py rename to examples/federated_learning/surface_defect_detection_mindspore/aggregate.py diff --git a/examples/federated_learning/surface_defect_detection_mindspore/interface.py b/examples/federated_learning/surface_defect_detection_mindspore/interface.py new file mode 100644 index 000000000..ed84a61d0 --- /dev/null +++ b/examples/federated_learning/surface_defect_detection_mindspore/interface.py @@ -0,0 +1,130 @@ +# Copyright 2021 The KubeEdge Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import numpy as np + +import mindspore as ms +import mindspore.nn as nn +from mindspore.dataset import GeneratorDataset +import mindspore.dataset.vision.c_transforms as c_vision +import mindspore.dataset.vision.py_transforms as py_vision + +from sedna.algorithms.aggregation import FedAvgV2 +from sedna.algorithms.client_choose import SimpleClientChoose +from sedna.common.config import Context +from sedna.core.federated_learning import FederatedLearningV2 + +# os.environ['BACKEND_TYPE'] = 'KERAS' + +simple_chooser = SimpleClientChoose(per_round=2) + +# It has been determined that mistnet is required here. +fedavg = FedAvgV2() + +# The function `get_transmitter_from_config()` returns an object instance. +s3_transmitter = FederatedLearningV2.get_transmitter_from_config() + +class SddDataset(): + def __init__(self, x, y) -> None: + self.labels = y + self.images = x + self.index = 0 + + def __len__(self): + return len(self.images) + + def __iter__(self): + return self + + def __next__(self): + self.index = self.index % len(self.images) + x, y = self.images[self.index], self.labels[self.index] + self.index = self.index + 1 + return x, y + + +class myDataset: + def __init__(self, trainset=None, testset=None) -> None: + self.customized = True + transform = [ + c_vision.Resize((128, 128)), + py_vision.ToTensor(), + py_vision.Normalize((0.5, ), (0.5, )) + ] + self.trainset = GeneratorDataset(SddDataset(trainset[0], trainset[1]), + column_names=["image", "label"]) + self.testset = GeneratorDataset(SddDataset(trainset[0], trainset[1]), + column_names=["image", "label"]) + + self.trainset = self.trainset.map(operations=transform, + input_columns="image").batch( + batch_size=int(Context.get_parameters("batch_size", 32))) + + self.testset = self.testset.map(operations=transform, + input_columns="image").batch( + batch_size=int(Context.get_parameters("batch_size", 32))) + +class SddModel(nn.Cell): + def __init__(self): + super().__init__() + self.conv1 = nn.Conv2d(in_channels=1, out_channels=64, kernel_size=(3, 3), stride=2) + self.relu1 = nn.ReLU() + self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) + + self.conv2 = nn.Conv2d(in_channels=64, out_channels=32, kernel_size=(3, 3)) + self.relu2 = nn.ReLU() + self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) + + self.flatten = nn.Flatten() + + self.dropout = nn.Dropout(0.25) + + self.fc1 = nn.Dense(8192, 64) + self.relu3 = nn.ReLU() + + self.fc2 = nn.Dense(64, 32) + self.relu4 = nn.ReLU() + + self.fc3 = nn.Dense(32, 2) + + def construct(self, x): + x = self.pool1(self.relu1(self.conv1(x))) + x = self.pool2(self.relu2(self.conv2(x))) + x = self.dropout(self.flatten(x)) + x = self.relu3(self.fc1(x)) + x = self.relu4(self.fc2(x)) + x = self.fc3(x) + return x + +class Estimator: + def __init__(self) -> None: + self.model = SddModel() + self.pretrained = None + self.saved = None + self.hyperparameters = { + "use_mindspore": True, + "type": "basic", + "rounds": int(Context.get_parameters("exit_round", 5)), + "target_accuracy": 0.97, + "epochs": int(Context.get_parameters("epochs", 5)), + "batch_size": int(Context.get_parameters("batch_size", 32)), + "optimizer": "SGD", + "learning_rate": float(Context.get_parameters("learning_rate", 0.01)), + # The machine learning model + "model_name": "sdd_model", + "momentum": 0.9, + "weight_decay": 0.0, + "history": 0.1 + } + + diff --git a/examples/federated_learning/surface_defect_detection_mindspore/train.py b/examples/federated_learning/surface_defect_detection_mindspore/train.py new file mode 100644 index 000000000..4cbf8bb54 --- /dev/null +++ b/examples/federated_learning/surface_defect_detection_mindspore/train.py @@ -0,0 +1,63 @@ +# Copyright 2021 The KubeEdge Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +from PIL import Image + +from interface import fedavg, s3_transmitter +from interface import myDataset, Estimator +from sedna.core.federated_learning import FederatedLearningV2 +from sedna.datasources import TxtDataParse +from sedna.common.config import BaseConfig + +def image_process(line): + file_path, label = line.split(',') + root_path = os.getcwd() + file_path = os.path.join(root_path, file_path) + x = Image.open(file_path) + y = int(label) + return [x, y] + +def readFromTxt(path): + data_x = [] + data_y = [] + with open(path) as f: + lines = f.readlines() + for line in lines: + x, y = image_process(line) + data_x.append(x) + data_y.append(y) + return data_x, data_y + +def main(): + train_dataset_url = BaseConfig.train_dataset_url + # we have same data in the trainset and testset + test_dataset_url = BaseConfig.train_dataset_url + + # train_data = TxtDataParse(data_type="train", func=image_process) + # train_data.parse(train_dataset_url) + train_data = readFromTxt(train_dataset_url) + data = myDataset(trainset=train_data, testset=train_data) + + estimator = Estimator() + + fl_model = FederatedLearningV2( + data=data, + estimator=estimator, + aggregation=fedavg, + transmitter=s3_transmitter) + + fl_model.train() + +if __name__ == '__main__': + main() diff --git a/examples/federated_learning/surface_defect_detection_pytorch/README.md b/examples/federated_learning/surface_defect_detection_pytorch/README.md new file mode 100644 index 000000000..7fe40a44e --- /dev/null +++ b/examples/federated_learning/surface_defect_detection_pytorch/README.md @@ -0,0 +1,177 @@ +# Using Federated Learning Job in Surface Defect Detection Scenario +This case introduces how to use federated learning job in surface defect detection scenario. +In the safety surface defect detection, data is scattered in different places (such as server node, camera or others) and cannot be aggregated due to data privacy and bandwidth. As a result, we cannot use all the data for training. +Using Federated Learning, we can solve the problem. Each place uses its own data for model training ,uploads the weight to the cloud for aggregation, and obtains the aggregation result for model update. + + +## Surface Defect Detection Experiment +> Assume that there are two edge nodes and a cloud node. Data on the edge nodes cannot be migrated to the cloud due to privacy issues. +> Base on this scenario, we will demonstrate the surface inspection. + +### Prepare Nodes +``` +CLOUD_NODE="cloud-node-name" +EDGE1_NODE="edge1-node-name" +EDGE2_NODE="edge2-node-name" +``` + +### Install Sedna + +Follow the [Sedna installation document](/docs/setup/install.md) to install Sedna. + +### Prepare Dataset + +Download [dataset](https://github.com/abin24/Magnetic-tile-defect-datasets.) and the [label file](/examples/federated_learning/surface_defect_detection/data/1.txt) to `/data` of ```EDGE1_NODE```. +``` +mkdir -p /data +cd /data +git clone https://github.com/abin24/Magnetic-tile-defect-datasets..git Magnetic-tile-defect-datasets +curl -o 1.txt https://raw.githubusercontent.com/kubeedge/sedna/main/examples/federated_learning/surface_defect_detection/data/1.txt +``` + +Download [dataset](https://github.com/abin24/Magnetic-tile-defect-datasets.) and the [label file](/examples/federated_learning/surface_defect_detection/data/2.txt) to `/data` of ```EDGE2_NODE```. +``` +mkdir -p /data +cd /data +git clone https://github.com/abin24/Magnetic-tile-defect-datasets..git Magnetic-tile-defect-datasets +curl -o 2.txt https://raw.githubusercontent.com/kubeedge/sedna/main/examples/federated_learning/surface_defect_detection/data/2.txt +``` + +### Prepare Images +This example uses these images: +1. aggregation worker: ```kubeedge/sedna-example-federated-learning-surface-defect-detection-aggregation:v0.3.0``` +2. train worker: ```kubeedge/sedna-example-federated-learning-surface-defect-detection-train:v0.3.0``` + +These images are generated by the script [build_images.sh](/examples/build_image.sh). + +### Create Federated Learning Job + +#### Create Dataset + +create dataset for `$EDGE1_NODE` +``` +kubectl create -f - < None: + self.images = x + self.labels = y + + def __len__(self): + return len(self.images) + + def __getitem__(self, index): + return self.images[index], self.labels[index] + +class myDataset: + def __init__(self, trainset=None, testset=None) -> None: + self.customized = True + self.trainset = SddDataset(trainset[0], trainset[1]) + self.testset = SddDataset(testset[0], testset[1]) + +class Estimator: + def __init__(self) -> None: + self.model = self.build() + self.pretrained = None + self.saved = None + self.hyperparameters = { + "type": "basic", + "rounds": int(Context.get_parameters("exit_round", 5)), + "target_accuracy": 0.97, + "epochs": int(Context.get_parameters("epochs", 5)), + "batch_size": int(Context.get_parameters("batch_size", 32)), + "optimizer": "SGD", + "learning_rate": float(Context.get_parameters("learning_rate", 0.01)), + # The machine learning model + "model_name": "sdd_model", + "momentum": 0.9, + "weight_decay": 0.0, + "history": 0.1 + } + + @staticmethod + def build(): + model = nn.Sequential( + nn.Conv2d(in_channels=1, out_channels=64, kernel_size=(3, 3), stride=(2, 2)), + nn.ReLU(), + nn.MaxPool2d(2, 2), + nn.Conv2d(in_channels=64, out_channels=32, kernel_size=(3, 3)), + nn.ReLU(), + nn.MaxPool2d(2, 2), + nn.Flatten(), + nn.Dropout(p=0.25), + nn.Linear(6272, 64), + nn.ReLU(), + nn.Linear(64, 32), + nn.ReLU(), + nn.Linear(32, 2)) + return model + + diff --git a/examples/federated_learning/surface_defect_detection_pytorch/train.py b/examples/federated_learning/surface_defect_detection_pytorch/train.py new file mode 100644 index 000000000..fa4958cfe --- /dev/null +++ b/examples/federated_learning/surface_defect_detection_pytorch/train.py @@ -0,0 +1,68 @@ +# Copyright 2021 The KubeEdge Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +from torchvision import transforms +from PIL import Image + +from interface import fedavg, s3_transmitter +from interface import myDataset, Estimator +from sedna.core.federated_learning import FederatedLearningV2 +from sedna.datasources import TxtDataParse +from sedna.common.config import BaseConfig + +def image_process(line): + file_path, label = line.split(',') + root_path = os.getcwd() + file_path = os.path.join(root_path, file_path) + transform = transforms.Compose([transforms.Resize((128, 128)), + transforms.PILToTensor()]) + x = Image.open(file_path) + x = transform(x)/255. + y = int(label) + + return [x, y] + +def readFromTxt(path): + data_x = [] + data_y = [] + with open(path) as f: + lines = f.readlines() + for line in lines: + x, y = image_process(line) + data_x.append(x) + data_y.append(y) + return data_x, data_y + +def main(): + train_dataset_url = BaseConfig.train_dataset_url + # we have same data in the trainset and testset + test_dataset_url = BaseConfig.train_dataset_url + + # train_data = TxtDataParse(data_type="train", func=image_process) + # train_data.parse(train_dataset_url) + train_data = readFromTxt(train_dataset_url) + data = myDataset(trainset=train_data, testset=train_data) + + estimator = Estimator() + + fl_model = FederatedLearningV2( + data=data, + estimator=estimator, + aggregation=fedavg, + transmitter=s3_transmitter) + + fl_model.train() + +if __name__ == '__main__': + main() diff --git a/examples/federated_learning/surface_defect_detection_tensorflow/README.md b/examples/federated_learning/surface_defect_detection_tensorflow/README.md new file mode 100644 index 000000000..7fe40a44e --- /dev/null +++ b/examples/federated_learning/surface_defect_detection_tensorflow/README.md @@ -0,0 +1,177 @@ +# Using Federated Learning Job in Surface Defect Detection Scenario +This case introduces how to use federated learning job in surface defect detection scenario. +In the safety surface defect detection, data is scattered in different places (such as server node, camera or others) and cannot be aggregated due to data privacy and bandwidth. As a result, we cannot use all the data for training. +Using Federated Learning, we can solve the problem. Each place uses its own data for model training ,uploads the weight to the cloud for aggregation, and obtains the aggregation result for model update. + + +## Surface Defect Detection Experiment +> Assume that there are two edge nodes and a cloud node. Data on the edge nodes cannot be migrated to the cloud due to privacy issues. +> Base on this scenario, we will demonstrate the surface inspection. + +### Prepare Nodes +``` +CLOUD_NODE="cloud-node-name" +EDGE1_NODE="edge1-node-name" +EDGE2_NODE="edge2-node-name" +``` + +### Install Sedna + +Follow the [Sedna installation document](/docs/setup/install.md) to install Sedna. + +### Prepare Dataset + +Download [dataset](https://github.com/abin24/Magnetic-tile-defect-datasets.) and the [label file](/examples/federated_learning/surface_defect_detection/data/1.txt) to `/data` of ```EDGE1_NODE```. +``` +mkdir -p /data +cd /data +git clone https://github.com/abin24/Magnetic-tile-defect-datasets..git Magnetic-tile-defect-datasets +curl -o 1.txt https://raw.githubusercontent.com/kubeedge/sedna/main/examples/federated_learning/surface_defect_detection/data/1.txt +``` + +Download [dataset](https://github.com/abin24/Magnetic-tile-defect-datasets.) and the [label file](/examples/federated_learning/surface_defect_detection/data/2.txt) to `/data` of ```EDGE2_NODE```. +``` +mkdir -p /data +cd /data +git clone https://github.com/abin24/Magnetic-tile-defect-datasets..git Magnetic-tile-defect-datasets +curl -o 2.txt https://raw.githubusercontent.com/kubeedge/sedna/main/examples/federated_learning/surface_defect_detection/data/2.txt +``` + +### Prepare Images +This example uses these images: +1. aggregation worker: ```kubeedge/sedna-example-federated-learning-surface-defect-detection-aggregation:v0.3.0``` +2. train worker: ```kubeedge/sedna-example-federated-learning-surface-defect-detection-train:v0.3.0``` + +These images are generated by the script [build_images.sh](/examples/build_image.sh). + +### Create Federated Learning Job + +#### Create Dataset + +create dataset for `$EDGE1_NODE` +``` +kubectl create -f - < None: # The machine learning model "model_name": "sdd_model", "momentum": 0.9, - "weight_decay": 0.0 + "weight_decay": 0.0, + "history": 0.1 } @staticmethod diff --git a/examples/federated_learning/surface_defect_detection_v2/train.py b/examples/federated_learning/surface_defect_detection_tensorflow/train.py similarity index 100% rename from examples/federated_learning/surface_defect_detection_v2/train.py rename to examples/federated_learning/surface_defect_detection_tensorflow/train.py diff --git a/examples/federated_learning/yolov5_coco128_mistnet/hyp.scratch.yaml b/examples/federated_learning/yolov5_coco128_mistnet/hyp.scratch.yaml index 44f26b665..31f6d142e 100644 --- a/examples/federated_learning/yolov5_coco128_mistnet/hyp.scratch.yaml +++ b/examples/federated_learning/yolov5_coco128_mistnet/hyp.scratch.yaml @@ -1,10 +1,10 @@ +# YOLOv5 🚀 by Ultralytics, GPL-3.0 license # Hyperparameters for COCO training from scratch # python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300 # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials - lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) -lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) +lrf: 0.1 # final OneCycleLR learning rate (lr0 * lrf) momentum: 0.937 # SGD momentum/Adam beta1 weight_decay: 0.0005 # optimizer weight decay 5e-4 warmup_epochs: 3.0 # warmup epochs (fractions ok) @@ -31,3 +31,4 @@ flipud: 0.0 # image flip up-down (probability) fliplr: 0.5 # image flip left-right (probability) mosaic: 1.0 # image mosaic (probability) mixup: 0.0 # image mixup (probability) +copy_paste: 0.0 # segment copy-paste (probability) diff --git a/examples/federated_learning/yolov5_coco128_mistnet/yolov5s.yaml b/examples/federated_learning/yolov5_coco128_mistnet/yolov5s.yaml index e4e9e4dde..f35beabb1 100644 --- a/examples/federated_learning/yolov5_coco128_mistnet/yolov5s.yaml +++ b/examples/federated_learning/yolov5_coco128_mistnet/yolov5s.yaml @@ -1,48 +1,48 @@ -# parameters +# YOLOv5 🚀 by Ultralytics, GPL-3.0 license + +# Parameters nc: 80 # number of classes depth_multiple: 0.33 # model depth multiple width_multiple: 0.50 # layer channel multiple - -# anchors anchors: - - [ 10,13, 16,30, 33,23 ] # P3/8 - - [ 30,61, 62,45, 59,119 ] # P4/16 - - [ 116,90, 156,198, 373,326 ] # P5/32 + - [10,13, 16,30, 33,23] # P3/8 + - [30,61, 62,45, 59,119] # P4/16 + - [116,90, 156,198, 373,326] # P5/32 -# YOLOv5 backbone +# YOLOv5 v6.0 backbone backbone: # [from, number, module, args] - [ [ -1, 1, Focus, [ 64, 3 ] ], # 0-P1/2 - [ -1, 1, Conv, [ 128, 3, 2 ] ], # 1-P2/4 - [ -1, 3, C3, [ 128 ] ], - [ -1, 1, Conv, [ 256, 3, 2 ] ], # 3-P3/8 - [ -1, 9, C3, [ 256 ] ], - [ -1, 1, Conv, [ 512, 3, 2 ] ], # 5-P4/16 - [ -1, 9, C3, [ 512 ] ], - [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 7-P5/32 - [ -1, 1, SPP, [ 1024, [ 5, 9, 13 ] ] ], - [ -1, 3, C3, [ 1024, False ] ], # 9 + [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 + [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 + [-1, 3, C3, [128]], + [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 + [-1, 6, C3, [256]], + [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 + [-1, 9, C3, [512]], + [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 + [-1, 3, C3, [1024]], + [-1, 1, SPPF, [1024, 5]], # 9 ] -# YOLOv5 head +# YOLOv5 v6.0 head head: - [ [ -1, 1, Conv, [ 512, 1, 1 ] ], - [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], - [ [ -1, 6 ], 1, Concat, [ 1 ] ], # cat backbone P4 - [ -1, 3, C3, [ 512, False ] ], # 13 + [[-1, 1, Conv, [512, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 6], 1, Concat, [1]], # cat backbone P4 + [-1, 3, C3, [512, False]], # 13 - [ -1, 1, Conv, [ 256, 1, 1 ] ], - [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ], - [ [ -1, 4 ], 1, Concat, [ 1 ] ], # cat backbone P3 - [ -1, 3, C3, [ 256, False ] ], # 17 (P3/8-small) + [-1, 1, Conv, [256, 1, 1]], + [-1, 1, nn.Upsample, [None, 2, 'nearest']], + [[-1, 4], 1, Concat, [1]], # cat backbone P3 + [-1, 3, C3, [256, False]], # 17 (P3/8-small) - [ -1, 1, Conv, [ 256, 3, 2 ] ], - [ [ -1, 14 ], 1, Concat, [ 1 ] ], # cat head P4 - [ -1, 3, C3, [ 512, False ] ], # 20 (P4/16-medium) + [-1, 1, Conv, [256, 3, 2]], + [[-1, 14], 1, Concat, [1]], # cat head P4 + [-1, 3, C3, [512, False]], # 20 (P4/16-medium) - [ -1, 1, Conv, [ 512, 3, 2 ] ], - [ [ -1, 10 ], 1, Concat, [ 1 ] ], # cat head P5 - [ -1, 3, C3, [ 1024, False ] ], # 23 (P5/32-large) + [-1, 1, Conv, [512, 3, 2]], + [[-1, 10], 1, Concat, [1]], # cat head P5 + [-1, 3, C3, [1024, False]], # 23 (P5/32-large) - [ [ 17, 20, 23 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5) + [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ] diff --git a/lib/sedna/algorithms/aggregation/aggregation.py b/lib/sedna/algorithms/aggregation/aggregation.py index 30a11faf0..a3efbdfea 100644 --- a/lib/sedna/algorithms/aggregation/aggregation.py +++ b/lib/sedna/algorithms/aggregation/aggregation.py @@ -121,7 +121,7 @@ def __init__(self, cut_layer, epsilon=100): if isinstance(self.parameters["epsilon"], str): if self.parameters["epsilon"].isdigit(): - self.parameters["epsilon"] = int(cut_layer) + self.parameters["epsilon"] = int(epsilon) def aggregate(self, clients: List[AggClient]): pass