Fenics is a comprehensive simulator designed for decentralized federated learning environments. It allows researchers and practitioners to experiment with various network topologies, participant selection strategies, and attack scenarios to evaluate the robustness and efficiency of federated learning algorithms.
- Features
- Prerequisites
- Installation
- Project Structure
- Configuration
- Usage
- Extending Fenics
- Examples
- Contributing
- License
- Customizable Network Topologies: Define and utilize custom network structures via edge list files or built-in topologies
- Flexible Participant Selection: Implement various client selection strategies based on data size or other metrics
- Support for Attacks: Simulate adversarial attacks to assess the resilience of federated learning models
- Modular Architecture: Extensible components for models, topologies, attack types, and more
- Comprehensive Logging and Visualization: Generate detailed logs and visual plots to analyze simulation results
- Scalable Simulations: Handle simulations with varying numbers of nodes and complex network structures
- Real-Time Progress Monitoring: Visualize simulation progress with an integrated loading bar
Before installing and using Fenics, ensure that your system meets the following requirements:
- Operating System: Windows, macOS, or Linux
- Python Version: Python 3.7 or higher
- Virtual Environment (Recommended): It's advisable to use a virtual environment to manage dependencies
-
Clone the Repository:
git clone https://github.com/yourusername/fenics.git cd fenics
-
Create and Activate a Virtual Environment (Optional but Recommended):
-
Windows:
python -m venv venv venv\Scripts\activate
-
Unix/Linux:
python3 -m venv venv source venv/bin/activate
-
-
Install Required Dependencies:
Ensure you have
pip
updated to the latest version:pip install --upgrade pip
-
Install the Package in Editable Mode:
This allows you to modify the code without reinstalling the package each time.
pip install -e .
Note: The
setup.py
is configured to install all necessary dependencies, includingtorch
,numpy
,psutil
,colorama
,pyfiglet
, andpydantic
. -
Verify Installation:
After installation, the
fenics
command-line tool should be available.fenics --help
Expected Output:
Usage: phoenix [OPTIONS] COMMAND [ARGS]... Distributed Federated Learning Simulator Options: --help Show this message and exit. Commands: setup Initialize the simulation environment with desired... run Execute the simulation with the provided options. list_simulations List all available simulation configurations. parameters Display all available simulation parameters and...
If you need to uninstall Fenics, follow these steps:
-
Deactivate the Virtual Environment (If Active):
deactivate
-
Uninstall the Package:
pip uninstall fenics
-
Remove the Virtual Environment (Optional):
If you created a virtual environment specifically for Fenics, you can delete it:
-
Windows:
rmdir /s /q venv
-
Unix/Linux:
rm -rf venv
-
Fenics follows a modular architecture with the following components:
fenics/
├── fenics/
│ ├── __init__.py
│ ├── aggregation/ # Aggregation strategies (FedAvg, etc.)
│ ├── attack/ # Attack implementations (poison, delay)
│ ├── cli/ # CLI interface components
│ ├── client_selection/ # Client selection strategies
│ ├── communication/ # Communication protocols
│ ├── data/ # Data handling and loading
│ ├── models/ # ML model implementations
│ ├── plotting/ # Visualization utilities
│ ├── topology/ # Network topology implementations
│ ├── training/ # Training and evaluation
│ ├── config.py # Configuration handling
│ ├── simulator.py # Main simulation logic
│ └── utils.py # Utility functions
├── config.yaml # Configuration file
├── fenics.py # Main entry point
├── setup.py # Package setup
├── LICENSE
└── README.md
Each module is designed to be extensible, allowing you to add custom implementations without modifying the core code.
Fenics uses a config.yaml
file to manage simulation parameters. Proper configuration ensures that simulations run as intended with the desired settings.
Below is an explanation of the primary parameters you can configure:
simulations:
simulation1:
rounds: 3 # Number of training rounds
epochs: 1 # Number of epochs per round
num_nodes: 5 # Total number of nodes in the simulation
num_attackers: 0 # Number of attacker nodes
attacker_nodes: [] # Specific nodes designated as attackers
attacks: [] # Types of attacks to simulate
use_attackers: false # Flag to enable or disable attacker simulation
participation_rate: 0.6 # Fraction of nodes participating each round
topology: fully_connected # Network topology type
topology_file: null # Path to a custom topology edge list file
max_attacks: null # Maximum number of attacks an attacker can perform
gossip_steps: 3 # Number of gossiping steps during aggregation
protocol: gossip # Aggregation protocol ('gossip' or 'neighboring')
alpha: 0.5 # Dirichlet distribution parameter for data partitioning
model_type: cnn # Model type to use ('cnn', 'mlp', or custom)
Parameter Descriptions:
rounds
: Total number of training rounds to execute.epochs
: Number of training epochs each node performs per round.num_nodes
: Total number of participating nodes in the simulation.num_attackers
: Number of nodes designated as attackers.attacker_nodes
: List of specific node IDs to act as attackers. Overridesnum_attackers
if provided.attacks
: Types of attacks to simulate (e.g., 'delay', 'poison'). Define the attack strategies you want to test.use_attackers
: Boolean flag to enable (true
) or disable (false
) attacker simulations.participation_rate
: Fraction of nodes selected to participate in each round. For example,0.6
means 60% of nodes are selected each round.topology
: Defines the network topology. Common options include:fully_connected
: Every node is connected to every other node.ring
: Nodes are connected in a ring structure.random
: Random graph with probabilistic connections.custom
: Use a custom topology defined in an edge list file.
topology_file
: Path to a custom topology edge list file. Required iftopology
is set tocustom
.max_attacks
: Maximum number of attacks an attacker node can perform throughout the simulation.gossip_steps
: Number of gossiping steps to perform during the aggregation phase.protocol
: Communication protocol to use. Options:gossip
: Nodes exchange updates in a gossip manner.neighboring
: Nodes exchange updates with their immediate neighbors.
alpha
: Parameter for the Dirichlet distribution used in data partitioning among nodes.model_type
: Type of model to use. Options:cnn
: Convolutional Neural Network (default).mlp
: Multi-Layer Perceptron.- Custom models can be registered and used.
When using a custom network topology, you need to define the connections between nodes in an edge list file. Here's how to set it up:
-
Create the Edge List File:
- Filename:
topology.edgelist
(or any name of your choice) - Format: Each line represents an undirected edge between two nodes, specified by their node IDs separated by a space.
Example
topology.edgelist
:0 1 1 2 1 4 2 3 3 5 3 6 4 5 5 6 5 7 7 8 8 9
Explanation:
- Node
0
is connected to Node1
. - Node
1
is connected to Nodes0
,2
, and4
. - And so on...
- Filename:
-
Place the Edge List File:
Save the
topology.edgelist
file in a directory accessible to your project. For example, you can place it in the root directory of your project. -
Configure
config.yaml
to Use the Custom Topology:Update the
config.yaml
to reference your custom edge list file.simulations: simulation1: # Other parameters... topology: custom topology_file: path/to/your/topology.edgelist
-
Understanding the
topology.edgelist
:- Node IDs: Ensure that node IDs in the edge list start from
0
and are consecutive integers up tonum_nodes - 1
. - Undirected Edges: Each connection is bidirectional. If you want Node
0
connected to Node1
, you only need to specify0 1
. There's no need to add1 0
.
- Node IDs: Ensure that node IDs in the edge list start from
Fenics provides a command-line interface called Fenics Shell to interact with the simulator. Below are instructions on how to set up and run simulations.
-
Launch the Fenics Shell:
fenics
Sample Output:
______ _ | ____| (_) | |__ ___ _ __ ___ _ ___ ___ | __/ _ \ '_ \/ __| |/ __/ __| | | | __/ | | \__ \ | (__\__ \ |_| \___|_| |_|___/_|\___|___/ Welcome to Fenics Shell! Type 'help' to see available commands. Fenics>
-
Setup the Simulation Environment:
Use the
setup
command to initialize simulation parameters.-
Using Direct Parameters:
setup --rounds 3 --epochs 1 --topology fully_connected --participation_rate 0.6 --protocol gossip --num_nodes 5 --alpha 0.5
-
Using a Configuration File:
setup --config config.yaml --simulation_name simulation1
Explanation:
--config
: Specifies the path to theconfig.yaml
file.--simulation_name
: Identifies which simulation parameters to load from the configuration file.
-
-
Run the Simulation:
After setup, execute the simulation using the
run
command.run
Sample Output:
Final Simulation Arguments: Rounds: 3 Epochs: 1 Topology: fully_connected Participation rate: 0.6 Protocol: gossip Num nodes: 5 Alpha: 0.5 Starting simulation... Simulation Progress: 100%|██████████████████████████████████████████████████████████| 3/3 [00:01<00:00, 2.50round/s, CPU Usage: 55%] Simulation completed successfully. Check the 'results' directory for outputs.
Explanation:
- Progress Bar: A real-time progress bar displays the simulation's progress, showing the percentage completed and the latest CPU usage.
- Logs and Plots: Detailed logs and visual plots are saved in the
results
directory.
-
Exit the Fenics Shell:
Use the
exit
orquit
command to exit.exit
Alternatively, you can run simulations directly without entering the Fenics Shell by passing commands as arguments.
fenics setup --config config.yaml --simulation_name simulation1 && fenics run
Note: This approach sequentially executes the setup
and run
commands.
Fenics is designed to be modular and extensible. You can easily add custom implementations for various components without modifying the core code.
- Create a new Python file in the
fenics/topology/
directory:
# fenics/topology/my_topology.py
from fenics.topology import TopologyBase, TopologyFactory
import networkx as nx
class MyTopology(TopologyBase):
def __init__(self, num_nodes, **kwargs):
super().__init__(num_nodes)
# Additional initialization if needed
def build(self):
# Implement your topology building logic
G = nx.Graph()
# Add nodes and edges
return G
# Register the topology
TopologyFactory.register_topology('my_topology', MyTopology)
- Import your file and use it:
import fenics.topology.my_topology
# Use in configuration
# topology: my_topology
- Create a new Python file in the
fenics/models/
directory:
# fenics/models/my_model.py
import torch.nn as nn
import torch.nn.functional as F
from fenics.models import ModelBase, ModelFactory
class MyModel(ModelBase):
def __init__(self):
super().__init__()
# Define your model architecture
def forward(self, x):
# Implement forward pass
return x
# Register the model
ModelFactory.register_model('my_model', MyModel)
- Import your file and use it:
import fenics.models.my_model
# Use in configuration
# model_type: my_model
- Create a new Python file in the
fenics/client_selection/strategies/
directory:
# fenics/client_selection/strategies/my_strategy.py
import random
from typing import List, Optional
import logging
def select_clients_my_strategy(nodes: List[int],
num_participants: int,
logger: Optional[logging.Logger] = None) -> List[int]:
"""Custom selection strategy."""
logger = logger or logging.getLogger()
# Implement your selection logic
return selected_nodes
- Register and use it:
from fenics.client_selection.factory import SelectionFactory
from fenics.client_selection.strategies.my_strategy import select_clients_my_strategy
# Register the strategy
SelectionFactory.register_strategy('my_strategy', select_clients_my_strategy)
- Create a new Python file in the
fenics/attack/attack_types/
directory:
# fenics/attack/attack_types/my_attack.py
from fenics.attack.attack_types.base import Attack
from fenics.attack.attack_factory import AttackFactory
class MyAttack(Attack):
def __init__(self, node_id, logger=None):
super().__init__(node_id, logger)
def execute(self, model):
# Implement your attack logic
return model.state_dict()
# Register the attack
AttackFactory.register_attack('my_attack', MyAttack)
- Import and use your attack:
import fenics.attack.attack_types.my_attack
# Use in configuration
# attacks: [my_attack]
- Create a new Python file in the
fenics/aggregation/
directory:
# fenics/aggregation/my_strategy.py
import torch
from fenics.aggregation.base import AggregationStrategy
from fenics.aggregation.factory import AggregationFactory
class MyAggregationStrategy(AggregationStrategy):
def aggregate(self, models_state_dicts, data_sizes):
# Implement your aggregation logic
return aggregated_state_dict
# Register the strategy
AggregationFactory.register_strategy('my_aggregation', MyAggregationStrategy)
- Import and use your strategy:
import fenics.aggregation.my_strategy
# Use in your code
agg_strategy = AggregationFactory.get_strategy('my_aggregation')
- Create a new Python file in the
fenics/communication/
directory:
# fenics/communication/my_protocol.py
from fenics.communication.base import CommunicationProtocol
from fenics.communication.factory import ProtocolFactory
class MyProtocol(CommunicationProtocol):
def exchange(self, nodes, G, local_models, executor):
# Implement your exchange logic
pass
# Register the protocol
ProtocolFactory.register_protocol('my_protocol', MyProtocol)
- Import and use your protocol:
import fenics.communication.my_protocol
# Use in configuration
# protocol: my_protocol
Here's a step-by-step example to demonstrate how to set up and run a simulation using a custom network topology.
Create a file named topology.edgelist
with the following content:
0 1
1 2
1 4
2 3
3 5
3 6
4 5
5 6
5 7
7 8
8 9
Create or update your config.yaml
to include the custom topology.
simulations:
simulation1:
rounds: 5
epochs: 2
num_nodes: 10
num_attackers: 2
attacker_nodes: [3, 7]
attacks: ['poison', 'delay']
use_attackers: true
participation_rate: 0.6
topology: custom
topology_file: topology.edgelist
max_attacks: 3
gossip_steps: 4
protocol: gossip
alpha: 0.5
model_type: cnn
-
Launch the Fenics Shell:
fenics
-
Setup the Simulation Using
config.yaml
:setup --config config.yaml --simulation_name simulation1
-
Execute the Simulation:
run
-
Monitor Outputs:
- Logs: Check the
results/simulation_log.txt
file for detailed logs. - Plots: Generated plots will be saved as PDF files in the
results
directory. - Simulation Results: Ensure that attacker nodes (3 and 7) perform their designated attacks, and observe how the network handles these adversarial behaviors.
- Logs: Check the
Contributions are welcome! If you'd like to enhance Fenics, please follow these steps:
-
Fork the Repository:
Click the "Fork" button on the repository's GitHub page to create your own copy.
-
Clone Your Fork:
git clone https://github.com/yourusername/fenics.git cd fenics
-
Create a New Branch:
git checkout -b feature/your-feature-name
-
Make Your Changes:
Implement your desired features or fixes.
-
Commit Your Changes:
git add . git commit -m "Add feature XYZ"
-
Push to Your Fork:
git push origin feature/your-feature-name
-
Create a Pull Request:
Navigate to the original repository and create a pull request from your forked repository.
This project is licensed under the MIT License.
- This project was part of a course project (DAT-300: Data-diven support for cyberphysical systems) at Chalmers University of Technology under the supervision of Romaric Duvignau and Carla Fabiana Chiasserini.
For any questions or feedback, please contact Shubham Saha or Sifat Nawrin Nova.