# FusionNet: AMD Hardware Integration This document outlines how FusionNet leverages AMD hardware and the compatibility decisions made to support heterogeneous device deployments. --- ## ROCm and PyTorch FusionNet uses PyTorch with ROCm support for high-performance AFLoRA fine-tuning on AMD hardware. ROCm surfaces AMD GPUs through the same `torch.cuda` API, so all device detection code (`torch.cuda.is_available()`, `torch.cuda.get_device_properties()`) works identically on ROCm and CUDA backends. The backend is distinguished at runtime in `hardware_utils.py`: ```python def _is_rocm() -> bool: return getattr(torch.version, "hip", None) is not None backend = "rocm" if _is_rocm() else "cuda" ``` On Windows, `hardware_utils.py` adds `C:\Windows\System32` to the DLL search path before accessing `torch.cuda`, which is required for PyTorch cu128 DLL resolution. --- ## bitsandbytes for 4-bit Quantization FusionNet uses `transformers` integrated with `bitsandbytes` to load models in `nf4` 4-bit precision with double quantization. This is the primary path for GPU nodes: ```python quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_compute_dtype=torch.float16, bnb_4bit_quant_type="nf4", bnb_4bit_use_double_quant=True, ) ``` `bitsandbytes` now natively supports ROCm 6.0, making 4-bit inference available on AMD GPUs without additional patches. **CPU-only fallback:** On nodes with no GPU, `bitsandbytes` 4-bit quantization is skipped. The model is loaded in FP32 (or FP16 if supported) using standard `from_pretrained()` without a `quantization_config`. This is why the federation model must be a small enough architecture (e.g. TinyLlama-1.1B) to fit in CPU RAM — Llama-3-8B in FP32 requires ≈32 GB. --- ## Opacus & Custom Fallback for DP-SGD FusionNet's privacy engine uses a dual-engine approach documented in `federation/privacy.py`: 1. **Opacus `PrivacyEngine` (primary):** Production-grade per-sample gradient clipping and calibrated Gaussian noise addition, providing mathematically sound (ε, δ)-DP guarantees. 2. **`CustomPrivacyEngine` (fallback):** Activated when Opacus hooks fail to attach to dynamically quantized modules (e.g. `bitsandbytes.nn.Linear4bit`), which is common on ROCm backends. Implements identical DP noise addition with the same formula and interface. ```python # In federation/privacy.py try: # Opacus path model, optimizer, dataloader, engine = privacy_engine.make_private(...) except Exception: # Fallback path — same (ε, δ) guarantee, manual noise injection engine = CustomPrivacyEngine(model, optimizer, ...) ``` Both engines guarantee `ε ≤ 1.0, δ ≤ 1e-5` per training round. --- ## RCCL for Secure Aggregation (Planned) RCCL (ROCm Collective Communications Library) is the AMD equivalent of NCCL and is used for multi-GPU tensor communication. PyTorch's distributed backend maps `nccl` → `rccl` automatically on ROCm, so the standard `dist.init_process_group(backend="nccl")` call works on both platforms. Current status: `comms/rccl_backend.py` is a placeholder. The planned use is `dist.all_reduce()` for AllReduce-based gradient aggregation across nodes as part of the MPC secure aggregation layer. --- ## Custom HIP Kernel for DP Noise (Optional Optimisation) `kernels/dp_noise.hip` contains a custom HIP kernel for constant-time Gaussian noise generation, intended as a performance optimisation over the CPU-side noise injection in `CustomPrivacyEngine`. This is only relevant on AMD ROCm hardware and is not required for correctness — the Python fallback produces identical noise distributions. --- ## Dirichlet Partitioning and AMD Compute Tiers The data partitioning system (`fl_datasets/partitioner.py`) is hardware-aware by design. The AMD hardware tier detected at startup directly determines both the shard size and the Dirichlet concentration parameter for the Non-IID split. This means AMD hardware capability is not just a training parameter — it shapes the data the node is allowed to see, creating a coherent heterogeneity story across compute and data layers simultaneously. See `docs/architecture.md` for the full tier-to-partition mapping. --- ## Hugging Face Hub as Serverless Parameter Server FusionNet uses a private HF Dataset repository (`yash-goswami/fusionnet-coordinator`) to exchange AFLoRA `A` matrices between clients and the coordinator without any custom server infrastructure. `federation/hf_hub.py` wraps `HfApi` and `hf_hub_download` into two methods: - `upload_local_A_matrices(round_num, client_id, updates)` — serialises a list of tensors to a `.pt` file and pushes to `round_N/client_K.pt` - `download_global_A_matrices(round_num)` — fetches `global/Global_A_round_N.pt`, returns `None` if not yet available Authentication is handled by `auth.get_token()`, which reads `HF_TOKEN` from `.env`. The token is passed directly to `HfApi(token=...)` so no global CLI login state is required. The coordinator (`scripts/hf_coordinator.py`) polls `list_repo_files()` until all expected client files appear, then downloads, FedAvgs, and re-uploads the global result. This makes the coordinator fully stateless — it can be restarted at any point in a round without data loss.