Source code for byzfl.fed_framework.byzantine_client

from byzfl.attacks import attacks

[docs] class ByzantineClient: """ Initialization Parameters ------------------------- params : dict A dictionary containing the configuration for the Byzantine attack. Must include: - `"f"`: int The number of faulty (Byzantine) vectors to generate. - `"name"`: str The name of the attack to be executed (e.g., `"InnerProductManipulation"`). - `"parameters"`: dict A dictionary of parameters for the specified attack, where keys are parameter names and values are their corresponding values. Methods ------- apply_attack(honest_vectors) Applies the specified Byzantine attack to the input vectors and returns a list of faulty vectors. Calling the Instance -------------------- Input Parameters ---------------- honest_vectors : numpy.ndarray, torch.Tensor, list of numpy.ndarray, or list of torch.Tensor A collection of input vectors, matrices, or tensors representing gradients submitted by honest participants. Returns ------- list A list containing `f` faulty vectors generated by the Byzantine attack, each with the same data type as the input. Examples -------- Initialize the `ByzantineClient` with a specific attack and apply it to input vectors: >>> from byzfl import ByzantineClient >>> attack = { >>> "name": "InnerProductManipulation", >>> "f": 3, >>> "parameters": {"tau": 3.0}, >>> } >>> byz_worker = ByzantineClient(attack) Using numpy arrays: >>> import numpy as np >>> honest_vectors = np.array([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]]) >>> byz_worker.apply_attack(honest_vectors) [array([-12., -15., -18.]), array([-12., -15., -18.]), array([-12., -15., -18.])] Using torch tensors: >>> import torch >>> honest_vectors = torch.tensor([[1., 2., 3.], [4., 5., 6.], [7., 8., 9.]]) >>> byz_worker.apply_attack(honest_vectors) [tensor([-12., -15., -18.]), tensor([-12., -15., -18.]), tensor([-12., -15., -18.])] Using a list of numpy arrays: >>> import numpy as np >>> honest_vectors = [np.array([1., 2., 3.]), np.array([4., 5., 6.]), np.array([7., 8., 9.])] >>> byz_worker.apply_attack(honest_vectors) [array([-12., -15., -18.]), array([-12., -15., -18.]), array([-12., -15., -18.])] Using a list of torch tensors: >>> import torch >>> honest_vectors = [torch.tensor([1., 2., 3.]), torch.tensor([4., 5., 6.]), torch.tensor([7., 8., 9.])] >>> byz_worker.apply_attack(honest_vectors) [tensor([-12., -15., -18.]), tensor([-12., -15., -18.]), tensor([-12., -15., -18.])] """ def __init__(self, params): """ Initializes the ByzantineClient with the specified attack configuration. Parameters ---------- params : dict A dictionary with the attack configuration. Must include: - `"f"`: int Number of faulty vectors. - `"name"`: str Name of the attack to execute. - `"parameters"`: dict Parameters for the specified attack. """ # Check for correct types and values in params if not isinstance(params, dict): raise TypeError("params must be a dictionary") if "f" not in params or not isinstance(params["f"], int) or params["f"] < 0: raise ValueError("f must be a non-negative integer") if "name" not in params or not isinstance(params["name"], str): raise TypeError("name must be a string") if "parameters" not in params or not isinstance(params["parameters"], dict): raise TypeError("parameters must be a dictionary") # Initialize the ByzantineClient instance self.f = params["f"] self.attack = getattr( attacks, params["name"] )(**params["parameters"])
[docs] def apply_attack(self, honest_vectors): """ Applies the specified Byzantine attack to the input vectors. Parameters ---------- honest_vectors : numpy.ndarray, torch.Tensor, list of numpy.ndarray, or list of torch.Tensor A collection of input vectors, matrices, or tensors representing gradients submitted by honest participants. Returns ------- list A list containing `f` faulty (Byzantine) vectors generated by the attack, each with the same data type as the input. If `f = 0`, an empty list is returned. """ if not self.f < len(honest_vectors): raise ValueError(f"f must be smaller than the number of honest_vectors, but got f={self.f} and len(honest_vectors)={len(honest_vectors)}") if self.f == 0: return [] # Generate the Byzantine vector by applying the attack byz_vector = self.attack(honest_vectors) # Return a list of the same Byzantine vector repeated `f` times return [byz_vector] * self.f