| import torch
|
| from torch.utils.data import DataLoader, TensorDataset
|
| import sys
|
| import os
|
|
|
|
|
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
|
| from fusionnet.models.llama_loader import load_llama_4bit
|
| from fusionnet.core.fl_coordinator import FLCoordinator
|
| from fusionnet.core.aggregator import fed_avg
|
|
|
| def create_mock_dataloader(batch_size=2, num_samples=16, seq_len=32):
|
| """Creates a mock dataloader with random tokens for testing."""
|
|
|
| input_ids = torch.randint(0, 32000, (num_samples, seq_len))
|
| labels = input_ids.clone()
|
|
|
| dataset = TensorDataset(input_ids, labels)
|
|
|
|
|
| def collate_fn(batch):
|
| b_input_ids = torch.stack([item[0] for item in batch])
|
| b_labels = torch.stack([item[1] for item in batch])
|
| return {
|
| "input_ids": b_input_ids,
|
| "labels": b_labels
|
| }
|
|
|
| return DataLoader(dataset, batch_size=batch_size, shuffle=True, collate_fn=collate_fn)
|
|
|
| def main():
|
| print("=== Testing FusionNet Local Training Pipeline ===")
|
|
|
|
|
| from fusionnet.models.model_selector import select_model_for_hardware
|
| selection = select_model_for_hardware()
|
| model_id = selection["model_id"]
|
| print(f"Using model: {model_id} ({selection['reason']})")
|
|
|
| try:
|
| model, tokenizer = load_llama_4bit(model_id, lora_rank=4)
|
| except Exception as e:
|
| print(f"Failed to load 4-bit model (this is expected if bitsandbytes/ROCm is not fully configured). Error: {e}")
|
| print("Falling back to a dummy Linear layer test to verify DP and orchestration logic...")
|
|
|
|
|
| class DummyModel(torch.nn.Module):
|
| def __init__(self):
|
| super().__init__()
|
| self.fc = torch.nn.Linear(32, 32)
|
| def forward(self, input_ids, attention_mask=None, labels=None):
|
|
|
| out = self.fc(input_ids.float())
|
| loss = torch.nn.functional.mse_loss(out, labels.float()) if labels is not None else None
|
| from collections import namedtuple
|
| Output = namedtuple('Output', ['loss'])
|
| return Output(loss=loss)
|
|
|
| model = DummyModel()
|
|
|
| for param in model.parameters():
|
| param.requires_grad = True
|
|
|
|
|
| coordinator = FLCoordinator(model)
|
|
|
|
|
| dataloader = create_mock_dataloader()
|
|
|
|
|
| print("\n--- Simulating Round 1 ---")
|
|
|
| updated_weights_round1, metrics_round1 = coordinator.start_round(
|
| global_weights=None,
|
| local_dataloader=dataloader,
|
| epochs=1,
|
| dp_epsilon=1.5,
|
| dp_delta=1e-5
|
| )
|
|
|
| print("\nMetrics Round 1:", metrics_round1)
|
|
|
|
|
| print("\n--- Testing FedAvg Aggregation ---")
|
|
|
| client2_weights = {}
|
| for k, v in updated_weights_round1.items():
|
| client2_weights[k] = v + (torch.randn_like(v) * 0.01)
|
|
|
| client_weights = [updated_weights_round1, client2_weights]
|
| client_sizes = [16, 32]
|
|
|
| aggregated_weights = fed_avg(client_weights, client_sizes)
|
|
|
| print("Aggregation successful!")
|
| print("Sample averaged weight tensor shape:", next(iter(aggregated_weights.values())).shape)
|
|
|
| if __name__ == "__main__":
|
| main()
|
|
|