jwsouza2025 commited on
Commit
8136541
·
verified ·
1 Parent(s): 3e6e2fa

Upload 13 files

Browse files
Files changed (13) hide show
  1. README +306 -0
  2. SETUP_GUIDE.md +0 -0
  3. analysis_tool.py +388 -0
  4. client.py +197 -0
  5. client_1_fedadagrad.log +172 -0
  6. client_2_fedadagrad.log +172 -0
  7. client_3_fedadagrad.log +172 -0
  8. requeriments.txt +33 -0
  9. run.sh +227 -0
  10. run_all_strategies.sh +213 -0
  11. server.py +449 -0
  12. server_fedadagrad.log +213 -0
  13. utils.py +139 -0
README ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Federated Learning para Previsão de Consumo de Combustível
2
+
3
+ Sistema de Aprendizado Federado (FL) para prever consumo de combustível usando dados de sensores OBD de diferentes veículos, mantendo a privacidade dos dados em cada cliente.
4
+
5
+ ## 📋 Visão Geral
6
+
7
+ Este projeto implementa um sistema de Aprendizado Federado usando o framework Flower, onde:
8
+ - **3 clientes** (Ubuntu) representam diferentes veículos com seus dados locais
9
+ - **1 servidor** (Windows) coordena o treinamento sem acessar os dados brutos
10
+ - Modelo LSTM para previsão de séries temporais de consumo (P_kW)
11
+ - Múltiplas estratégias de agregação: FedAvg, FedAdam, FedYogi, FedAdagrad
12
+
13
+ ## 🏗️ Arquitetura do Sistema
14
+
15
+ ```
16
+ ┌─────────────────┐
17
+ │ Servidor (Win) │
18
+ │ 16GB RAM │
19
+ │ Porta: 8080 │
20
+ └────────┬────────┘
21
+
22
+ ┌────┴────┬──────────┐
23
+ │ │ │
24
+ ┌───▼───┐ ┌──▼───┐ ┌────▼───┐
25
+ │Cliente│ │Cliente│ │Cliente │
26
+ │ 1 │ │ 2 │ │ 3 │
27
+ │Ubuntu │ │Ubuntu│ │Ubuntu │
28
+ │ 8GB │ │ 8GB │ │ 8GB │
29
+ └───────┘ └──────┘ └────────┘
30
+ ```
31
+
32
+ ## 📁 Estrutura do Projeto
33
+
34
+ ```
35
+ fl_project/
36
+ ├── data/ # Dados dos veículos (não versionado)
37
+ │ ├── client_1/ # Percursos do veículo 1
38
+ │ │ ├── percurso_1.csv
39
+ │ │ ├── percurso_2.csv
40
+ │ │ └── ...
41
+ │ ├── client_2/ # Percursos do veículo 2
42
+ │ └── client_3/ # Percursos do veículo 3
43
+ ├── server.py # Código do servidor FL
44
+ ├── client.py # Código dos clientes FL
45
+ ├── utils.py # Modelo LSTM e funções auxiliares
46
+ ├── analysis_tool.py # Ferramenta de análise pós-treinamento
47
+ ├── run.sh # Script para execução local
48
+ ├── run_all_strategies.sh # Script para testar todas as estratégias
49
+ ├── requirements.txt # Dependências Python
50
+ └── README.md # Este arquivo
51
+ ```
52
+
53
+ ## 🔧 Requisitos do Sistema
54
+
55
+ ### Hardware Mínimo
56
+ - **Servidor**: 8GB RAM (recomendado 16GB)
57
+ - **Clientes**: 4GB RAM cada (recomendado 8GB)
58
+ - **Rede**: Conexão estável entre servidor e clientes
59
+
60
+ ### Software
61
+ - **Python**: 3.10 - 3.11
62
+ - **Sistema Operacional**:
63
+ - Servidor: Windows 10/11 ou Linux
64
+ - Clientes: Ubuntu 20.04/22.04
65
+
66
+ ## 📦 Instalação
67
+
68
+ ### 1. Clone o Repositório
69
+
70
+ ```bash
71
+ git clone https://github.com/seu-usuario/fl_project.git
72
+ cd fl_project
73
+ ```
74
+
75
+ ### 2. Crie um Ambiente Virtual
76
+
77
+ **No Ubuntu (Clientes):**
78
+ ```bash
79
+ python3 -m venv venv
80
+ source venv/bin/activate
81
+ ```
82
+
83
+ **No Windows (Servidor):**
84
+ ```powershell
85
+ python -m venv venv
86
+ .\venv\Scripts\activate
87
+ ```
88
+
89
+ ### 3. Instale as Dependências
90
+
91
+ ```bash
92
+ pip install -r requirements.txt
93
+ ```
94
+
95
+ ### 4. Prepare os Dados
96
+
97
+ Organize os dados de cada veículo na estrutura:
98
+ ```
99
+ data/
100
+ ├── client_1/ # Dados do veículo 1
101
+ ├── client_2/ # Dados do veículo 2
102
+ └── client_3/ # Dados do veículo 3
103
+ ```
104
+
105
+ **Formato esperado dos CSVs:**
106
+ - Colunas principais: `vehicle_speed`, `engine_rpm`, `accel_x`, `accel_y`, `P_kW`, `dt`
107
+ - Cada arquivo representa um percurso diferente
108
+ - Mínimo de 2 percursos por cliente recomendado
109
+
110
+ ## 🚀 Execução em Ambiente Distribuído
111
+
112
+ ### Configuração de Rede
113
+
114
+ 1. **Identifique o IP do servidor Windows:**
115
+ ```powershell
116
+ ipconfig
117
+ ```
118
+ Procure pelo IPv4 Address (ex: 192.168.1.100)
119
+
120
+ 2. **Teste a conectividade dos clientes Ubuntu:**
121
+ ```bash
122
+ ping 192.168.1.100
123
+ ```
124
+
125
+ ### Passo 1: Iniciar o Servidor (Windows)
126
+
127
+ ```powershell
128
+ # Ative o ambiente virtual
129
+ .\venv\Scripts\activate
130
+
131
+ # Execute o servidor
132
+ python server.py --strategy fedavg --rounds 15
133
+
134
+ # Ou com parâmetros customizados
135
+ python server.py --strategy fedadam --rounds 20 --min-clients 3
136
+ ```
137
+
138
+ O servidor iniciará na porta 8080 e aguardará a conexão dos clientes.
139
+
140
+ ### Passo 2: Iniciar os Clientes (Ubuntu)
141
+
142
+ **Em cada máquina Ubuntu, execute em terminais separados:**
143
+
144
+ **Cliente 1:**
145
+ ```bash
146
+ # Ative o ambiente virtual
147
+ source venv/bin/activate
148
+
149
+ # Execute o cliente 1
150
+ python client.py --client-id 1 --server-address 192.168.1.100:8080 --prediction-length 10
151
+ ```
152
+
153
+ **Cliente 2:**
154
+ ```bash
155
+ source venv/bin/activate
156
+ python client.py --client-id 2 --server-address 192.168.1.100:8080 --prediction-length 10
157
+ ```
158
+
159
+ **Cliente 3:**
160
+ ```bash
161
+ source venv/bin/activate
162
+ python client.py --client-id 3 --server-address 192.168.1.100:8080 --prediction-length 10
163
+ ```
164
+
165
+ ### Monitoramento
166
+
167
+ O progresso será exibido em tempo real:
168
+ - **Servidor**: Mostra rodadas completas e métricas globais
169
+ - **Clientes**: Exibem perdas locais de treino/validação
170
+
171
+ ## 📊 Análise dos Resultados
172
+
173
+ ### Após o Treinamento
174
+
175
+ 1. **Executar análise automática:**
176
+ ```bash
177
+ python analysis_tool.py --results-dir results
178
+ ```
179
+
180
+ 2. **Visualizações geradas (PDFs):**
181
+ - `performance_analysis_*.pdf`: Análise de desempenho completa
182
+ - `convergence_analysis_*.pdf`: Métricas de convergência
183
+ - `heatmap_performance_*.pdf`: Mapa de calor temporal
184
+ - `comparative_analysis.pdf`: Comparação entre estratégias
185
+ - `client_evolution_analysis.pdf`: Evolução individual
186
+
187
+ 3. **Métricas salvas:**
188
+ - `results/detailed_metrics_*.csv`: Dados completos
189
+ - `results/summary_report.json`: Relatório consolidado
190
+ - `metrics/client_*/metrics_history.json`: Histórico por cliente
191
+
192
+ ## 🔬 Estratégias de Agregação
193
+
194
+ | Estratégia | Descrição | Quando Usar |
195
+ |------------|-----------|-------------|
196
+ | **FedAvg** | Média ponderada simples | Dados homogêneos |
197
+ | **FedAdam** | Otimização adaptativa | Convergência mais rápida |
198
+ | **FedYogi** | Adam com controle de variância | Dados heterogêneos |
199
+ | **FedAdagrad** | Taxa de aprendizado adaptativa | Dados esparsos |
200
+
201
+ ### Comparar Todas as Estratégias
202
+
203
+ ```bash
204
+ # Linux/Ubuntu
205
+ chmod +x run_all_strategies.sh
206
+ ./run_all_strategies.sh 15 10
207
+
208
+ # Windows (usando Git Bash ou WSL)
209
+ bash run_all_strategies.sh 15 10
210
+ ```
211
+
212
+ ## 🛠️ Troubleshooting
213
+
214
+ ### Erro de Conexão
215
+
216
+ **Problema**: Clientes não conseguem conectar ao servidor
217
+
218
+ **Soluções**:
219
+ 1. Verifique o firewall do Windows:
220
+ ```powershell
221
+ # Permitir porta 8080
222
+ netsh advfirewall firewall add rule name="FL Server" dir=in action=allow protocol=TCP localport=8080
223
+ ```
224
+
225
+ 2. Confirme que o servidor está rodando:
226
+ ```powershell
227
+ netstat -an | findstr :8080
228
+ ```
229
+
230
+ ### Erro de Memória
231
+
232
+ **Problema**: Out of Memory durante treinamento
233
+
234
+ **Soluções**:
235
+ 1. Reduza o batch_size em `utils.py`
236
+ 2. Diminua sequence_length ou prediction_length
237
+ 3. Use menos épocas por rodada
238
+
239
+ ### Dados Insuficientes
240
+
241
+ **Problema**: "conjunto de treino ou teste vazio"
242
+
243
+ **Soluções**:
244
+ 1. Verifique se há dados suficientes em `data/client_X/`
245
+ 2. Ajuste sequence_length e prediction_length
246
+ 3. Confirme que os CSVs têm as colunas esperadas
247
+
248
+ ## 📈 Parâmetros Importantes
249
+
250
+ ### Server.py
251
+ - `--strategy`: Estratégia de agregação (fedavg, fedadam, etc.)
252
+ - `--rounds`: Número de rodadas de FL (default: 10)
253
+ - `--min-clients`: Clientes mínimos para iniciar (default: 3)
254
+
255
+ ### Client.py
256
+ - `--client-id`: ID do cliente (1, 2 ou 3)
257
+ - `--server-address`: Endereço IP:porta do servidor
258
+ - `--prediction-length`: Passos futuros a prever (default: 10)
259
+
260
+ ### Utils.py (configurações internas)
261
+ - `sequence_length`: Janela de entrada (default: 60)
262
+ - `batch_size`: Tamanho do batch (default: 32)
263
+ - `learning_rate`: Taxa de aprendizado (default: 1e-5)
264
+
265
+ ## 📝 Notas de Desenvolvimento
266
+
267
+ ### Modelo LSTM
268
+ - Entrada: 6 features (velocidade, RPM, acelerações, consumo, tempo)
269
+ - Hidden size: 50 neurônios
270
+ - Saída: Previsão de N passos futuros de consumo (P_kW)
271
+
272
+ ### Divisão dos Dados
273
+ - 80% para treinamento
274
+ - 20% para validação
275
+ - Normalização MinMaxScaler por cliente
276
+
277
+ ### Métricas
278
+ - Loss: MSE (Mean Squared Error)
279
+ - Avaliação: Por cliente e global
280
+ - Convergência: Variância entre clientes
281
+
282
+ ## 🤝 Contribuindo
283
+
284
+ 1. Fork o projeto
285
+ 2. Crie sua feature branch (`git checkout -b feature/AmazingFeature`)
286
+ 3. Commit suas mudanças (`git commit -m 'Add some AmazingFeature'`)
287
+ 4. Push para a branch (`git push origin feature/AmazingFeature`)
288
+ 5. Abra um Pull Request
289
+
290
+ ## 📄 Licença
291
+
292
+ Distribuído sob a licença MIT. Veja `LICENSE` para mais informações.
293
+
294
+ ## 👥 Autores
295
+
296
+ - José Wilson C. Souza
297
+ - Erick Andrade Borba
298
+ - João Alfredo Cal Braz
299
+
300
+ ## 🙏 Agradecimentos
301
+
302
+ - [Flower Framework](https://flower.dev/) - Framework de Aprendizado Federado
303
+ - [PyTorch](https://pytorch.org/) - Framework de Deep Learning
304
+ - Dados coletados via OBD Link
305
+
306
+ ---
SETUP_GUIDE.md ADDED
File without changes
analysis_tool.py ADDED
@@ -0,0 +1,388 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Ferramenta de análise pós-treinamento para comparar resultados de diferentes estratégias
4
+ e gerar relatórios consolidados.
5
+ """
6
+
7
+ import json
8
+ import pandas as pd
9
+ import numpy as np
10
+ import matplotlib.pyplot as plt
11
+ import seaborn as sns
12
+ from pathlib import Path
13
+ import argparse
14
+ from typing import Dict, List
15
+
16
+ plt.style.use('seaborn-v0_8-darkgrid')
17
+ sns.set_palette("husl")
18
+
19
+ class FLAnalyzer:
20
+ """Analisador de resultados de Aprendizado Federado."""
21
+
22
+ def __init__(self, results_dir: str = "results"):
23
+ self.results_dir = Path(results_dir)
24
+ self.metrics_dir = Path("metrics")
25
+ self.strategies_data = {}
26
+ self.client_data = {}
27
+
28
+ def load_server_metrics(self):
29
+ """Carrega métricas do servidor para todas as estratégias."""
30
+ print("Carregando métricas do servidor...")
31
+
32
+ for csv_file in self.results_dir.glob("detailed_metrics_*.csv"):
33
+ strategy = csv_file.stem.replace("detailed_metrics_", "")
34
+ df = pd.read_csv(csv_file)
35
+ self.strategies_data[strategy] = df
36
+ print(f" - Carregado: {strategy}")
37
+
38
+ def load_client_metrics(self):
39
+ """Carrega métricas individuais dos clientes."""
40
+ print("Carregando métricas dos clientes...")
41
+
42
+ for client_dir in self.metrics_dir.glob("client_*"):
43
+ client_id = int(client_dir.name.split("_")[1])
44
+ metrics_file = client_dir / "metrics_history.json"
45
+
46
+ if metrics_file.exists():
47
+ with open(metrics_file, 'r') as f:
48
+ self.client_data[client_id] = json.load(f)
49
+ print(f" - Cliente {client_id} carregado")
50
+
51
+ def generate_comparative_analysis(self):
52
+ """Gera análise comparativa entre estratégias."""
53
+ if not self.strategies_data:
54
+ print("Nenhum dado de estratégia encontrado!")
55
+ return
56
+
57
+ fig, axes = plt.subplots(2, 2, figsize=(16, 12))
58
+
59
+ # 1. Comparação de convergência entre estratégias
60
+ ax1 = axes[0, 0]
61
+ for strategy, df in self.strategies_data.items():
62
+ eval_df = df[df['phase'] == 'eval']
63
+ if not eval_df.empty and 'global_eval_loss' in eval_df.columns:
64
+ ax1.plot(eval_df['rounds'], eval_df['global_eval_loss'],
65
+ marker='o', label=strategy.upper(), linewidth=2)
66
+
67
+ ax1.set_title('Comparação de Convergência entre Estratégias', fontsize=14, fontweight='bold')
68
+ ax1.set_xlabel('Rodada')
69
+ ax1.set_ylabel('Perda de Validação Global')
70
+ ax1.legend()
71
+ ax1.grid(True, alpha=0.3)
72
+
73
+ # 2. Taxa de convergência
74
+ ax2 = axes[0, 1]
75
+ convergence_rates = {}
76
+
77
+ for strategy, df in self.strategies_data.items():
78
+ eval_df = df[df['phase'] == 'eval']
79
+ if not eval_df.empty and 'global_eval_loss' in eval_df.columns:
80
+ losses = eval_df['global_eval_loss'].values
81
+ if len(losses) > 1:
82
+ # Taxa de melhoria por rodada
83
+ improvements = -np.diff(losses)
84
+ convergence_rates[strategy] = improvements
85
+ ax2.plot(eval_df['rounds'].values[1:], improvements,
86
+ marker='s', label=strategy.upper(), linewidth=1.5, alpha=0.7)
87
+
88
+ ax2.axhline(y=0, color='k', linestyle='--', alpha=0.5)
89
+ ax2.set_title('Taxa de Melhoria por Rodada', fontsize=14, fontweight='bold')
90
+ ax2.set_xlabel('Rodada')
91
+ ax2.set_ylabel('Redução na Perda')
92
+ ax2.legend()
93
+ ax2.grid(True, alpha=0.3)
94
+
95
+ # 3. Boxplot de desempenho final dos clientes
96
+ ax3 = axes[1, 0]
97
+ final_performances = []
98
+ labels = []
99
+
100
+ for strategy, df in self.strategies_data.items():
101
+ eval_df = df[df['phase'] == 'eval']
102
+ if not eval_df.empty:
103
+ last_round = eval_df['rounds'].max()
104
+ last_round_data = eval_df[eval_df['rounds'] == last_round]
105
+
106
+ client_losses = []
107
+ for i in range(1, 4):
108
+ col = f'client_{i}_eval_loss'
109
+ if col in last_round_data.columns:
110
+ value = last_round_data[col].values
111
+ if len(value) > 0 and not pd.isna(value[0]):
112
+ client_losses.append(value[0])
113
+
114
+ if client_losses:
115
+ final_performances.append(client_losses)
116
+ labels.append(strategy.upper())
117
+
118
+ if final_performances:
119
+ bp = ax3.boxplot(final_performances, labels=labels, patch_artist=True)
120
+ for patch, color in zip(bp['boxes'], sns.color_palette("husl", len(labels))):
121
+ patch.set_facecolor(color)
122
+ patch.set_alpha(0.7)
123
+
124
+ ax3.set_title('Distribuição Final de Desempenho dos Clientes', fontsize=14, fontweight='bold')
125
+ ax3.set_xlabel('Estratégia')
126
+ ax3.set_ylabel('Perda Final de Validação')
127
+ ax3.grid(True, alpha=0.3, axis='y')
128
+
129
+ # 4. Métricas de eficiência
130
+ ax4 = axes[1, 1]
131
+ strategies = []
132
+ metrics_data = {
133
+ 'Convergência': [],
134
+ 'Estabilidade': [],
135
+ 'Heterogeneidade': []
136
+ }
137
+
138
+ for strategy, df in self.strategies_data.items():
139
+ eval_df = df[df['phase'] == 'eval']
140
+ if not eval_df.empty and 'global_eval_loss' in eval_df.columns:
141
+ strategies.append(strategy.upper())
142
+
143
+ # Convergência: melhoria total
144
+ losses = eval_df['global_eval_loss'].values
145
+ if len(losses) > 1:
146
+ convergence = (losses[0] - losses[-1]) / losses[0]
147
+ metrics_data['Convergência'].append(convergence)
148
+ else:
149
+ metrics_data['Convergência'].append(0)
150
+
151
+ # Estabilidade: desvio padrão das mudanças
152
+ if len(losses) > 1:
153
+ changes = np.diff(losses)
154
+ stability = 1 / (1 + np.std(changes)) # Invertido para que maior = mais estável
155
+ metrics_data['Estabilidade'].append(stability)
156
+ else:
157
+ metrics_data['Estabilidade'].append(0)
158
+
159
+ # Heterogeneidade: variação média entre clientes
160
+ client_cols = [f'client_{i}_eval_loss' for i in range(1, 4)]
161
+ last_round = eval_df['rounds'].max()
162
+ last_round_data = eval_df[eval_df['rounds'] == last_round]
163
+
164
+ client_values = []
165
+ for col in client_cols:
166
+ if col in last_round_data.columns:
167
+ val = last_round_data[col].values
168
+ if len(val) > 0 and not pd.isna(val[0]):
169
+ client_values.append(val[0])
170
+
171
+ if len(client_values) > 1:
172
+ heterogeneity = 1 / (1 + np.std(client_values)) # Invertido
173
+ metrics_data['Heterogeneidade'].append(heterogeneity)
174
+ else:
175
+ metrics_data['Heterogeneidade'].append(0)
176
+
177
+ if strategies:
178
+ x = np.arange(len(strategies))
179
+ width = 0.25
180
+
181
+ for i, (metric, values) in enumerate(metrics_data.items()):
182
+ ax4.bar(x + i * width, values, width, label=metric, alpha=0.8)
183
+
184
+ ax4.set_xlabel('Estratégia')
185
+ ax4.set_ylabel('Score Normalizado')
186
+ ax4.set_title('Métricas de Eficiência Comparativas', fontsize=14, fontweight='bold')
187
+ ax4.set_xticks(x + width)
188
+ ax4.set_xticklabels(strategies)
189
+ ax4.legend()
190
+ ax4.grid(True, alpha=0.3, axis='y')
191
+
192
+ plt.suptitle('Análise Comparativa de Estratégias de Aprendizado Federado',
193
+ fontsize=16, fontweight='bold')
194
+ plt.tight_layout()
195
+ plt.savefig(self.results_dir / 'comparative_analysis.pdf', dpi=300, bbox_inches='tight')
196
+ plt.close()
197
+
198
+ print(f"Análise comparativa salva em: {self.results_dir / 'comparative_analysis.pdf'}")
199
+
200
+ def generate_client_evolution_analysis(self):
201
+ """Analisa a evolução individual dos clientes."""
202
+ if not self.client_data:
203
+ print("Nenhum dado de cliente encontrado!")
204
+ return
205
+
206
+ fig, axes = plt.subplots(2, 2, figsize=(15, 10))
207
+
208
+ # 1. Evolução do treinamento por cliente
209
+ ax1 = axes[0, 0]
210
+ for client_id, data in self.client_data.items():
211
+ if 'rounds' in data and 'train_losses' in data:
212
+ ax1.plot(data['rounds'], data['train_losses'],
213
+ marker='o', label=f'Cliente {client_id}', linewidth=2)
214
+
215
+ ax1.set_title('Evolução do Treinamento por Cliente', fontsize=14, fontweight='bold')
216
+ ax1.set_xlabel('Rodada')
217
+ ax1.set_ylabel('Perda de Treinamento')
218
+ ax1.legend()
219
+ ax1.grid(True, alpha=0.3)
220
+
221
+ # 2. Evolução da validação por cliente
222
+ ax2 = axes[0, 1]
223
+ for client_id, data in self.client_data.items():
224
+ if 'eval_losses' in data and data['eval_losses']:
225
+ rounds = list(range(1, len(data['eval_losses']) + 1))
226
+ ax2.plot(rounds, data['eval_losses'],
227
+ marker='s', label=f'Cliente {client_id}', linewidth=2)
228
+
229
+ ax2.set_title('Evolução da Validação por Cliente', fontsize=14, fontweight='bold')
230
+ ax2.set_xlabel('Rodada')
231
+ ax2.set_ylabel('Perda de Validação')
232
+ ax2.legend()
233
+ ax2.grid(True, alpha=0.3)
234
+
235
+ # 3. Mudanças nos parâmetros do modelo
236
+ ax3 = axes[1, 0]
237
+ for client_id, data in self.client_data.items():
238
+ if 'model_updates' in data and data['model_updates']:
239
+ rounds = list(range(1, len(data['model_updates']) + 1))
240
+ ax3.plot(rounds, data['model_updates'],
241
+ marker='^', label=f'Cliente {client_id}', linewidth=1.5, alpha=0.7)
242
+
243
+ ax3.set_title('Magnitude das Atualizações do Modelo', fontsize=14, fontweight='bold')
244
+ ax3.set_xlabel('Rodada')
245
+ ax3.set_ylabel('Mudança Média nos Parâmetros')
246
+ ax3.legend()
247
+ ax3.grid(True, alpha=0.3)
248
+
249
+ # 4. Tempo de convergência relativo
250
+ ax4 = axes[1, 1]
251
+ convergence_times = []
252
+ client_ids = []
253
+
254
+ for client_id, data in self.client_data.items():
255
+ if 'train_losses' in data and len(data['train_losses']) > 1:
256
+ losses = np.array(data['train_losses'])
257
+ # Encontrar quando a perda estabiliza (mudança < 1%)
258
+ for i in range(1, len(losses)):
259
+ if abs(losses[i] - losses[i-1]) / losses[i-1] < 0.01:
260
+ convergence_times.append(data['rounds'][i])
261
+ client_ids.append(f'Cliente {client_id}')
262
+ break
263
+ else:
264
+ convergence_times.append(data['rounds'][-1])
265
+ client_ids.append(f'Cliente {client_id}')
266
+
267
+ if convergence_times:
268
+ colors = sns.color_palette("husl", len(client_ids))
269
+ bars = ax4.bar(client_ids, convergence_times, color=colors, alpha=0.7)
270
+ ax4.set_title('Tempo de Convergência por Cliente', fontsize=14, fontweight='bold')
271
+ ax4.set_xlabel('Cliente')
272
+ ax4.set_ylabel('Rodada de Convergência')
273
+ ax4.grid(True, alpha=0.3, axis='y')
274
+
275
+ # Adicionar valores nas barras
276
+ for bar, value in zip(bars, convergence_times):
277
+ height = bar.get_height()
278
+ ax4.text(bar.get_x() + bar.get_width()/2., height,
279
+ f'{value}', ha='center', va='bottom')
280
+
281
+ plt.suptitle('Análise de Evolução Individual dos Clientes',
282
+ fontsize=16, fontweight='bold')
283
+ plt.tight_layout()
284
+ plt.savefig(self.results_dir / 'client_evolution_analysis.pdf', dpi=300, bbox_inches='tight')
285
+ plt.close()
286
+
287
+ print(f"Análise de evolução dos clientes salva em: {self.results_dir / 'client_evolution_analysis.pdf'}")
288
+
289
+ def generate_summary_report(self):
290
+ """Gera relatório resumido em formato texto e JSON."""
291
+ report = {
292
+ "timestamp": pd.Timestamp.now().isoformat(),
293
+ "strategies_analyzed": list(self.strategies_data.keys()),
294
+ "clients_analyzed": list(self.client_data.keys()),
295
+ "summary": {}
296
+ }
297
+
298
+ # Análise por estratégia
299
+ for strategy, df in self.strategies_data.items():
300
+ eval_df = df[df['phase'] == 'eval']
301
+ train_df = df[df['phase'] == 'train']
302
+
303
+ strategy_summary = {
304
+ "total_rounds": int(eval_df['rounds'].max()) if not eval_df.empty else 0,
305
+ "final_global_eval_loss": float(eval_df['global_eval_loss'].iloc[-1]) if not eval_df.empty else None,
306
+ "final_global_train_loss": float(train_df['global_train_loss'].iloc[-1]) if not train_df.empty else None,
307
+ }
308
+
309
+ # Calcular métricas de melhoria
310
+ if not eval_df.empty and len(eval_df) > 1:
311
+ initial = eval_df['global_eval_loss'].iloc[0]
312
+ final = eval_df['global_eval_loss'].iloc[-1]
313
+ strategy_summary["improvement_percentage"] = float((initial - final) / initial * 100)
314
+ strategy_summary["convergence_rate"] = float(np.mean(np.diff(eval_df['global_eval_loss'].values)))
315
+
316
+ # Métricas por cliente
317
+ client_metrics = {}
318
+ for i in range(1, 4):
319
+ col = f'client_{i}_eval_loss'
320
+ if col in eval_df.columns:
321
+ client_losses = eval_df[col].dropna()
322
+ if not client_losses.empty:
323
+ client_metrics[f'client_{i}'] = {
324
+ "final_loss": float(client_losses.iloc[-1]),
325
+ "best_loss": float(client_losses.min()),
326
+ "worst_loss": float(client_losses.max()),
327
+ "std_loss": float(client_losses.std())
328
+ }
329
+
330
+ strategy_summary["client_metrics"] = client_metrics
331
+ report["summary"][strategy] = strategy_summary
332
+
333
+ # Salvar relatório
334
+ report_file = self.results_dir / "summary_report.json"
335
+ with open(report_file, 'w') as f:
336
+ json.dump(report, f, indent=2)
337
+
338
+ print(f"\nRelatório resumido salvo em: {report_file}")
339
+
340
+ # Imprimir resumo no console
341
+ print("\n" + "="*60)
342
+ print("RESUMO DA ANÁLISE")
343
+ print("="*60)
344
+
345
+ for strategy, summary in report["summary"].items():
346
+ print(f"\nEstratégia: {strategy.upper()}")
347
+ print(f" - Rodadas totais: {summary['total_rounds']}")
348
+ print(f" - Perda final (validação): {summary['final_global_eval_loss']:.6f}" if summary['final_global_eval_loss'] else " - Perda final: N/A")
349
+ print(f" - Melhoria: {summary.get('improvement_percentage', 0):.2f}%")
350
+
351
+ if summary['client_metrics']:
352
+ print(" - Desempenho por cliente:")
353
+ for client, metrics in summary['client_metrics'].items():
354
+ print(f" {client}: Final={metrics['final_loss']:.6f}, Melhor={metrics['best_loss']:.6f}")
355
+
356
+ def run_full_analysis(self):
357
+ """Executa análise completa."""
358
+ print("\n" + "="*60)
359
+ print("INICIANDO ANÁLISE COMPLETA DOS RESULTADOS")
360
+ print("="*60 + "\n")
361
+
362
+ self.load_server_metrics()
363
+ self.load_client_metrics()
364
+
365
+ if self.strategies_data:
366
+ self.generate_comparative_analysis()
367
+
368
+ if self.client_data:
369
+ self.generate_client_evolution_analysis()
370
+
371
+ if self.strategies_data or self.client_data:
372
+ self.generate_summary_report()
373
+
374
+ print("\n" + "="*60)
375
+ print("ANÁLISE COMPLETA FINALIZADA")
376
+ print("="*60)
377
+
378
+ def main():
379
+ parser = argparse.ArgumentParser(description="Análise de Resultados FL")
380
+ parser.add_argument("--results-dir", type=str, default="results",
381
+ help="Diretório com os resultados")
382
+ args = parser.parse_args()
383
+
384
+ analyzer = FLAnalyzer(args.results_dir)
385
+ analyzer.run_full_analysis()
386
+
387
+ if __name__ == "__main__":
388
+ main()
client.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import flwr as fl
3
+ import torch
4
+ import json
5
+ import numpy as np
6
+ from collections import OrderedDict
7
+ from pathlib import Path
8
+ from datetime import datetime
9
+
10
+ from utils import Net, load_data, train, test
11
+
12
+ # Argumentos da linha de comando para identificar o cliente
13
+ parser = argparse.ArgumentParser(description="Flower Client")
14
+ parser.add_argument("--client-id", type=int, required=True, help="ID do Cliente (1, 2, ou 3)")
15
+ parser.add_argument("--server-address", type=str, default="127.0.0.1:8080", help="Endereço do servidor")
16
+ parser.add_argument(
17
+ "--prediction-length",
18
+ type=int,
19
+ default=10,
20
+ help="Define quantos passos no futuro o modelo deve prever."
21
+ )
22
+
23
+ # Checa se a GPU está disponível
24
+ DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
25
+
26
+ class MetricsTracker:
27
+ """Classe para rastrear e salvar métricas locais do cliente."""
28
+
29
+ def __init__(self, client_id):
30
+ self.client_id = client_id
31
+ self.metrics = {
32
+ "client_id": client_id,
33
+ "rounds": [],
34
+ "train_losses": [],
35
+ "eval_losses": [],
36
+ "timestamps": [],
37
+ "model_updates": []
38
+ }
39
+ self.output_dir = Path(f"metrics/client_{client_id}")
40
+ self.output_dir.mkdir(parents=True, exist_ok=True)
41
+
42
+ def add_train_metrics(self, round_num, loss):
43
+ """Adiciona métricas de treinamento."""
44
+ self.metrics["rounds"].append(round_num)
45
+ self.metrics["train_losses"].append(float(loss))
46
+ self.metrics["timestamps"].append(datetime.now().isoformat())
47
+
48
+ def add_eval_metrics(self, loss):
49
+ """Adiciona métricas de avaliação."""
50
+ self.metrics["eval_losses"].append(float(loss))
51
+
52
+ def add_model_update(self, params_diff):
53
+ """Rastreia mudanças nos parâmetros do modelo."""
54
+ self.metrics["model_updates"].append(float(params_diff))
55
+
56
+ def save_metrics(self):
57
+ """Salva as métricas em arquivo JSON."""
58
+ output_file = self.output_dir / f"metrics_history.json"
59
+ with open(output_file, 'w') as f:
60
+ json.dump(self.metrics, f, indent=2)
61
+ print(f"[Cliente {self.client_id}] Métricas salvas em {output_file}")
62
+
63
+ def save_checkpoint(self, model, round_num):
64
+ """Salva checkpoint do modelo."""
65
+ checkpoint_file = self.output_dir / f"model_round_{round_num}.pt"
66
+ torch.save(model.state_dict(), checkpoint_file)
67
+ print(f"[Cliente {self.client_id}] Checkpoint salvo: {checkpoint_file}")
68
+
69
+ def calculate_params_diff(old_params, new_params):
70
+ """Calcula a diferença entre parâmetros antigos e novos."""
71
+ if old_params is None:
72
+ return 0.0
73
+
74
+ total_diff = 0.0
75
+ for old, new in zip(old_params, new_params):
76
+ diff = np.mean(np.abs(old - new))
77
+ total_diff += diff
78
+
79
+ return total_diff / len(old_params)
80
+
81
+ def main():
82
+ args = parser.parse_args()
83
+
84
+ # Carrega dados específicos deste cliente
85
+ print(f"Carregando dados para o cliente {args.client_id}...")
86
+ print(f"Dispositivo: {DEVICE}")
87
+
88
+ trainloader, testloader, num_features = load_data(
89
+ client_id=args.client_id,
90
+ prediction_length=args.prediction_length
91
+ )
92
+
93
+ print(f"Dados carregados: {len(trainloader)} batches de treino, {len(testloader)} batches de teste")
94
+
95
+ # Instancia o modelo
96
+ print(f"Criando modelo LSTM para prever {args.prediction_length} passos.")
97
+ net = Net(
98
+ input_size=num_features,
99
+ hidden_size=50,
100
+ output_size=args.prediction_length
101
+ ).to(DEVICE)
102
+
103
+ # Inicializa o rastreador de métricas
104
+ metrics_tracker = MetricsTracker(args.client_id)
105
+
106
+ # Implementação do cliente Flower
107
+ class FlClient(fl.client.NumPyClient):
108
+ def __init__(self):
109
+ self.round_num = 0
110
+ self.previous_params = None
111
+
112
+ def get_parameters(self, config):
113
+ """Retorna os pesos do modelo local."""
114
+ return [val.cpu().numpy() for _, val in net.state_dict().items()]
115
+
116
+ def set_parameters(self, parameters):
117
+ """Atualiza os pesos do modelo local com os do servidor."""
118
+ params_dict = zip(net.state_dict().keys(), parameters)
119
+ state_dict = OrderedDict({k: torch.tensor(v) for k, v in params_dict})
120
+ net.load_state_dict(state_dict, strict=True)
121
+
122
+ # Calcula a diferença entre parâmetros
123
+ if self.previous_params is not None:
124
+ params_diff = calculate_params_diff(self.previous_params, parameters)
125
+ metrics_tracker.add_model_update(params_diff)
126
+
127
+ self.previous_params = [p.copy() for p in parameters]
128
+
129
+ def fit(self, parameters, config):
130
+ """Treina o modelo localmente e retorna a perda de treinamento."""
131
+ self.round_num += 1
132
+ print(f"\n[Cliente {args.client_id}] === Rodada {self.round_num} ===")
133
+
134
+ # Define os parâmetros recebidos do servidor
135
+ self.set_parameters(parameters)
136
+
137
+ # Treina o modelo
138
+ print(f"[Cliente {args.client_id}] Iniciando treinamento...")
139
+ avg_train_loss = train(net, trainloader, epochs=1, device=DEVICE)
140
+
141
+ # Registra métricas
142
+ metrics_tracker.add_train_metrics(self.round_num, avg_train_loss)
143
+ print(f"[Cliente {args.client_id}] Perda de treinamento local: {avg_train_loss:.6f}")
144
+
145
+ # Salva checkpoint a cada 5 rodadas
146
+ if self.round_num % 5 == 0:
147
+ metrics_tracker.save_checkpoint(net, self.round_num)
148
+
149
+ # Salva métricas
150
+ metrics_tracker.save_metrics()
151
+
152
+ return self.get_parameters(config={}), len(trainloader.dataset), {
153
+ "train_loss": avg_train_loss,
154
+ "client_id": args.client_id,
155
+ "round": self.round_num
156
+ }
157
+
158
+ def evaluate(self, parameters, config):
159
+ """Avalia o modelo localmente."""
160
+ self.set_parameters(parameters)
161
+ print(f"[Cliente {args.client_id}] Avaliando modelo...")
162
+
163
+ loss, num_examples = test(net, testloader, device=DEVICE)
164
+
165
+ # Registra métricas de avaliação
166
+ metrics_tracker.add_eval_metrics(loss)
167
+ metrics_tracker.save_metrics()
168
+
169
+ print(f"[Cliente {args.client_id}] Perda de validação: {loss:.6f}")
170
+
171
+ return loss, num_examples, {
172
+ "loss": loss,
173
+ "client_id": args.client_id,
174
+ "round": self.round_num
175
+ }
176
+
177
+ # Inicia o cliente
178
+ print(f"\n{'='*50}")
179
+ print(f"Iniciando cliente {args.client_id}")
180
+ print(f"Conectando ao servidor em {args.server_address}")
181
+ print(f"Modelo: LSTM com {sum(p.numel() for p in net.parameters())} parâmetros")
182
+ print(f"{'='*50}\n")
183
+
184
+ try:
185
+ fl.client.start_client(
186
+ server_address=args.server_address,
187
+ client=FlClient().to_client(),
188
+ )
189
+
190
+ except Exception as e:
191
+ print(f"[Cliente {args.client_id}] Erro: {e}")
192
+ metrics_tracker.save_metrics()
193
+ finally:
194
+ print(f"\n[Cliente {args.client_id}] Finalizado. Métricas salvas em {metrics_tracker.output_dir}")
195
+
196
+ if __name__ == "__main__":
197
+ main()
client_1_fedadagrad.log ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ WARNING : DEPRECATED FEATURE: flwr.client.start_client() is deprecated.
2
+ Instead, use the `flower-supernode` CLI command to start a SuperNode as shown below:
3
+
4
+ $ flower-supernode --insecure --superlink='<IP>:<PORT>'
5
+
6
+ To view all available options, run:
7
+
8
+ $ flower-supernode --help
9
+
10
+ Using `start_client()` is deprecated.
11
+
12
+ This is a deprecated feature. It will be removed
13
+ entirely in future versions of Flower.
14
+
15
+ INFO :
16
+ INFO : Received: train message 291d80fe-1d64-4e2a-9cc3-c07e0b31623a
17
+ INFO : Sent reply
18
+ INFO :
19
+ INFO : Received: evaluate message c9e6f2aa-e700-4c85-a0e9-4e5367b01b52
20
+ INFO : Sent reply
21
+ INFO :
22
+ INFO : Received: train message 8d273cce-32d4-483d-9588-a016cc012493
23
+ INFO : Sent reply
24
+ INFO :
25
+ INFO : Received: evaluate message aba72052-b296-4f4c-99a0-21ab26af46e3
26
+ INFO : Sent reply
27
+ INFO :
28
+ INFO : Received: train message 65d5ecd1-e554-402a-9c56-935e9c962829
29
+ INFO : Sent reply
30
+ INFO :
31
+ INFO : Received: evaluate message 65a7d7f4-be1b-4f76-ae2e-d49e50a58219
32
+ INFO : Sent reply
33
+ INFO :
34
+ INFO : Received: train message 28acbc3d-ed5c-496a-b85e-aa1150fd9de2
35
+ INFO : Sent reply
36
+ INFO :
37
+ INFO : Received: evaluate message 75b4e73b-f09d-4033-a3fa-43f6f5ed702a
38
+ INFO : Sent reply
39
+ INFO :
40
+ INFO : Received: train message f5b93afe-d985-4193-acfb-ab4536c928a4
41
+ INFO : Sent reply
42
+ INFO :
43
+ INFO : Received: evaluate message 44d83f54-1cdf-4a6e-a9f0-b55b29a55d3b
44
+ INFO : Sent reply
45
+ INFO :
46
+ INFO : Received: train message 8b6164bb-4371-46fd-8bd6-205790be539a
47
+ INFO : Sent reply
48
+ INFO :
49
+ INFO : Received: evaluate message d547915d-42a7-4ce5-a6ca-54d59e933b69
50
+ INFO : Sent reply
51
+ INFO :
52
+ INFO : Received: train message 0a210acf-de6a-4813-b415-db9d71378c74
53
+ INFO : Sent reply
54
+ INFO :
55
+ INFO : Received: evaluate message f321a6c0-ae43-4f82-92b6-00b0955ce4a8
56
+ INFO : Sent reply
57
+ INFO :
58
+ INFO : Received: train message a31760dc-1a27-4af3-8f4b-9e849a01d5f7
59
+ INFO : Sent reply
60
+ INFO :
61
+ INFO : Received: evaluate message 8dea38f0-76a7-4a33-acfb-4a1286102bc1
62
+ INFO : Sent reply
63
+ INFO :
64
+ INFO : Received: train message 48cfe5e0-b781-4130-8162-c418261ae5a6
65
+ INFO : Sent reply
66
+ INFO :
67
+ INFO : Received: evaluate message 34a6bbdf-6692-43b6-860f-ac2e416755ea
68
+ INFO : Sent reply
69
+ INFO :
70
+ INFO : Received: train message 80e5e17b-175c-42e0-be18-bd18436eef6c
71
+ INFO : Sent reply
72
+ INFO :
73
+ INFO : Received: evaluate message c2151701-7139-4dd7-b2b1-802805c4da83
74
+ INFO : Sent reply
75
+ INFO :
76
+ INFO : Received: reconnect message f4c73386-bf01-439d-8dca-e7522f1cf998
77
+ INFO : Disconnect and shut down
78
+ Carregando dados para o cliente 1...
79
+ Dispositivo: cpu
80
+ Dados carregados: 623 batches de treino, 153 batches de teste
81
+ Criando modelo LSTM para prever 90 passos.
82
+
83
+ ==================================================
84
+ Iniciando cliente 1
85
+ Conectando ao servidor em 127.0.0.1:8080
86
+ Modelo: LSTM com 16190 par�metros
87
+ ==================================================
88
+
89
+
90
+ [Cliente 1] === Rodada 1 ===
91
+ [Cliente 1] Iniciando treinamento...
92
+ [Cliente 1] Perda de treinamento local: 0.011821
93
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
94
+ [Cliente 1] Avaliando modelo...
95
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
96
+ [Cliente 1] Perda de valida��o: 9.976543
97
+
98
+ [Cliente 1] === Rodada 2 ===
99
+ [Cliente 1] Iniciando treinamento...
100
+ [Cliente 1] Perda de treinamento local: 9.190875
101
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
102
+ [Cliente 1] Avaliando modelo...
103
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
104
+ [Cliente 1] Perda de valida��o: 1.286495
105
+
106
+ [Cliente 1] === Rodada 3 ===
107
+ [Cliente 1] Iniciando treinamento...
108
+ [Cliente 1] Perda de treinamento local: 0.605915
109
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
110
+ [Cliente 1] Avaliando modelo...
111
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
112
+ [Cliente 1] Perda de valida��o: 0.279315
113
+
114
+ [Cliente 1] === Rodada 4 ===
115
+ [Cliente 1] Iniciando treinamento...
116
+ [Cliente 1] Perda de treinamento local: 0.197050
117
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
118
+ [Cliente 1] Avaliando modelo...
119
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
120
+ [Cliente 1] Perda de valida��o: 0.596508
121
+
122
+ [Cliente 1] === Rodada 5 ===
123
+ [Cliente 1] Iniciando treinamento...
124
+ [Cliente 1] Perda de treinamento local: 0.139895
125
+ [Cliente 1] Checkpoint salvo: metrics\client_1\model_round_5.pt
126
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
127
+ [Cliente 1] Avaliando modelo...
128
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
129
+ [Cliente 1] Perda de valida��o: 0.038253
130
+
131
+ [Cliente 1] === Rodada 6 ===
132
+ [Cliente 1] Iniciando treinamento...
133
+ [Cliente 1] Perda de treinamento local: 0.020903
134
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
135
+ [Cliente 1] Avaliando modelo...
136
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
137
+ [Cliente 1] Perda de valida��o: 0.267797
138
+
139
+ [Cliente 1] === Rodada 7 ===
140
+ [Cliente 1] Iniciando treinamento...
141
+ [Cliente 1] Perda de treinamento local: 0.147180
142
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
143
+ [Cliente 1] Avaliando modelo...
144
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
145
+ [Cliente 1] Perda de valida��o: 0.058362
146
+
147
+ [Cliente 1] === Rodada 8 ===
148
+ [Cliente 1] Iniciando treinamento...
149
+ [Cliente 1] Perda de treinamento local: 0.036225
150
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
151
+ [Cliente 1] Avaliando modelo...
152
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
153
+ [Cliente 1] Perda de valida��o: 0.081573
154
+
155
+ [Cliente 1] === Rodada 9 ===
156
+ [Cliente 1] Iniciando treinamento...
157
+ [Cliente 1] Perda de treinamento local: 0.021779
158
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
159
+ [Cliente 1] Avaliando modelo...
160
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
161
+ [Cliente 1] Perda de valida��o: 0.029207
162
+
163
+ [Cliente 1] === Rodada 10 ===
164
+ [Cliente 1] Iniciando treinamento...
165
+ [Cliente 1] Perda de treinamento local: 0.014076
166
+ [Cliente 1] Checkpoint salvo: metrics\client_1\model_round_10.pt
167
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
168
+ [Cliente 1] Avaliando modelo...
169
+ [Cliente 1] M�tricas salvas em metrics\client_1\metrics_history.json
170
+ [Cliente 1] Perda de valida��o: 0.024229
171
+
172
+ [Cliente 1] Finalizado. M�tricas salvas em metrics\client_1
client_2_fedadagrad.log ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ WARNING : DEPRECATED FEATURE: flwr.client.start_client() is deprecated.
2
+ Instead, use the `flower-supernode` CLI command to start a SuperNode as shown below:
3
+
4
+ $ flower-supernode --insecure --superlink='<IP>:<PORT>'
5
+
6
+ To view all available options, run:
7
+
8
+ $ flower-supernode --help
9
+
10
+ Using `start_client()` is deprecated.
11
+
12
+ This is a deprecated feature. It will be removed
13
+ entirely in future versions of Flower.
14
+
15
+ INFO :
16
+ INFO : Received: train message f63b3be7-35a8-40b1-a0a9-20bce59fac6e
17
+ INFO : Sent reply
18
+ INFO :
19
+ INFO : Received: evaluate message 9f3010c9-fa04-4d9e-8803-979b37827a84
20
+ INFO : Sent reply
21
+ INFO :
22
+ INFO : Received: train message 0c6e2356-9efe-4475-b69a-c6588ef3b826
23
+ INFO : Sent reply
24
+ INFO :
25
+ INFO : Received: evaluate message 32f6c96c-e75e-484f-9e91-a86cf19961da
26
+ INFO : Sent reply
27
+ INFO :
28
+ INFO : Received: train message 6d672c95-660d-4d9a-9d46-5b68d91c375a
29
+ INFO : Sent reply
30
+ INFO :
31
+ INFO : Received: evaluate message 395215b3-06dc-411a-a836-fd88fe798d47
32
+ INFO : Sent reply
33
+ INFO :
34
+ INFO : Received: train message 9d3c92a9-6163-40d9-914c-555d23d5e4d0
35
+ INFO : Sent reply
36
+ INFO :
37
+ INFO : Received: evaluate message 235e95a8-6a3b-4d55-a3ff-952b9db35949
38
+ INFO : Sent reply
39
+ INFO :
40
+ INFO : Received: train message 5accefb0-48ed-40aa-a7bb-16c5c02ef94f
41
+ INFO : Sent reply
42
+ INFO :
43
+ INFO : Received: evaluate message 3c57952d-2100-4363-a3ec-eab5f84023bf
44
+ INFO : Sent reply
45
+ INFO :
46
+ INFO : Received: train message 20d1f6d1-07fb-4130-8567-1fbaa05e5740
47
+ INFO : Sent reply
48
+ INFO :
49
+ INFO : Received: evaluate message 8438ac71-a3ca-4651-ace0-eedd0d24ff66
50
+ INFO : Sent reply
51
+ INFO :
52
+ INFO : Received: train message 8756ce44-0d73-4d3c-9929-54b9c30f0497
53
+ INFO : Sent reply
54
+ INFO :
55
+ INFO : Received: evaluate message d9094dbc-7205-43e9-bb8d-b90a3acf2ed5
56
+ INFO : Sent reply
57
+ INFO :
58
+ INFO : Received: train message 306a0600-bd21-42c9-9ce3-e907fb67ad37
59
+ INFO : Sent reply
60
+ INFO :
61
+ INFO : Received: evaluate message d80fe3a9-259a-4bb5-bd25-3c7b42f93669
62
+ INFO : Sent reply
63
+ INFO :
64
+ INFO : Received: train message 8b553028-68ab-44a9-836e-74e9325db492
65
+ INFO : Sent reply
66
+ INFO :
67
+ INFO : Received: evaluate message d9cc9852-c707-47f0-ac29-443948f7081d
68
+ INFO : Sent reply
69
+ INFO :
70
+ INFO : Received: train message f3758c26-02ea-4f19-9f0f-765b2e0e805e
71
+ INFO : Sent reply
72
+ INFO :
73
+ INFO : Received: evaluate message c0d18b3e-93f7-4262-88e9-a2390bf4c14f
74
+ INFO : Sent reply
75
+ INFO :
76
+ INFO : Received: reconnect message f2598685-f192-43a1-a234-4382f8ed8e70
77
+ INFO : Disconnect and shut down
78
+ Carregando dados para o cliente 2...
79
+ Dispositivo: cpu
80
+ Dados carregados: 790 batches de treino, 194 batches de teste
81
+ Criando modelo LSTM para prever 90 passos.
82
+
83
+ ==================================================
84
+ Iniciando cliente 2
85
+ Conectando ao servidor em 127.0.0.1:8080
86
+ Modelo: LSTM com 16190 par�metros
87
+ ==================================================
88
+
89
+
90
+ [Cliente 2] === Rodada 1 ===
91
+ [Cliente 2] Iniciando treinamento...
92
+ [Cliente 2] Perda de treinamento local: 0.005995
93
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
94
+ [Cliente 2] Avaliando modelo...
95
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
96
+ [Cliente 2] Perda de valida��o: 10.002637
97
+
98
+ [Cliente 2] === Rodada 2 ===
99
+ [Cliente 2] Iniciando treinamento...
100
+ [Cliente 2] Perda de treinamento local: 9.031767
101
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
102
+ [Cliente 2] Avaliando modelo...
103
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
104
+ [Cliente 2] Perda de valida��o: 1.361941
105
+
106
+ [Cliente 2] === Rodada 3 ===
107
+ [Cliente 2] Iniciando treinamento...
108
+ [Cliente 2] Perda de treinamento local: 0.753927
109
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
110
+ [Cliente 2] Avaliando modelo...
111
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
112
+ [Cliente 2] Perda de valida��o: 0.240407
113
+
114
+ [Cliente 2] === Rodada 4 ===
115
+ [Cliente 2] Iniciando treinamento...
116
+ [Cliente 2] Perda de treinamento local: 0.163903
117
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
118
+ [Cliente 2] Avaliando modelo...
119
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
120
+ [Cliente 2] Perda de valida��o: 0.388674
121
+
122
+ [Cliente 2] === Rodada 5 ===
123
+ [Cliente 2] Iniciando treinamento...
124
+ [Cliente 2] Perda de treinamento local: 0.204387
125
+ [Cliente 2] Checkpoint salvo: metrics\client_2\model_round_5.pt
126
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
127
+ [Cliente 2] Avaliando modelo...
128
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
129
+ [Cliente 2] Perda de valida��o: 0.032693
130
+
131
+ [Cliente 2] === Rodada 6 ===
132
+ [Cliente 2] Iniciando treinamento...
133
+ [Cliente 2] Perda de treinamento local: 0.016730
134
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
135
+ [Cliente 2] Avaliando modelo...
136
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
137
+ [Cliente 2] Perda de valida��o: 0.273893
138
+
139
+ [Cliente 2] === Rodada 7 ===
140
+ [Cliente 2] Iniciando treinamento...
141
+ [Cliente 2] Perda de treinamento local: 0.125370
142
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
143
+ [Cliente 2] Avaliando modelo...
144
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
145
+ [Cliente 2] Perda de valida��o: 0.060165
146
+
147
+ [Cliente 2] === Rodada 8 ===
148
+ [Cliente 2] Iniciando treinamento...
149
+ [Cliente 2] Perda de treinamento local: 0.032033
150
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
151
+ [Cliente 2] Avaliando modelo...
152
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
153
+ [Cliente 2] Perda de valida��o: 0.072853
154
+
155
+ [Cliente 2] === Rodada 9 ===
156
+ [Cliente 2] Iniciando treinamento...
157
+ [Cliente 2] Perda de treinamento local: 0.017977
158
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
159
+ [Cliente 2] Avaliando modelo...
160
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
161
+ [Cliente 2] Perda de valida��o: 0.029051
162
+
163
+ [Cliente 2] === Rodada 10 ===
164
+ [Cliente 2] Iniciando treinamento...
165
+ [Cliente 2] Perda de treinamento local: 0.014848
166
+ [Cliente 2] Checkpoint salvo: metrics\client_2\model_round_10.pt
167
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
168
+ [Cliente 2] Avaliando modelo...
169
+ [Cliente 2] M�tricas salvas em metrics\client_2\metrics_history.json
170
+ [Cliente 2] Perda de valida��o: 0.017167
171
+
172
+ [Cliente 2] Finalizado. M�tricas salvas em metrics\client_2
client_3_fedadagrad.log ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ WARNING : DEPRECATED FEATURE: flwr.client.start_client() is deprecated.
2
+ Instead, use the `flower-supernode` CLI command to start a SuperNode as shown below:
3
+
4
+ $ flower-supernode --insecure --superlink='<IP>:<PORT>'
5
+
6
+ To view all available options, run:
7
+
8
+ $ flower-supernode --help
9
+
10
+ Using `start_client()` is deprecated.
11
+
12
+ This is a deprecated feature. It will be removed
13
+ entirely in future versions of Flower.
14
+
15
+ INFO :
16
+ INFO : Received: train message 5bf40068-c93c-4602-bf14-895c53f8261d
17
+ INFO : Sent reply
18
+ INFO :
19
+ INFO : Received: evaluate message e60b7d20-e6fb-4b54-bba5-54996ce4715b
20
+ INFO : Sent reply
21
+ INFO :
22
+ INFO : Received: train message 7f1c0945-8a25-4062-9b42-482284436d2f
23
+ INFO : Sent reply
24
+ INFO :
25
+ INFO : Received: evaluate message 2ae803e1-04a1-4dde-b2a9-74af9730b699
26
+ INFO : Sent reply
27
+ INFO :
28
+ INFO : Received: train message 6001a64d-9f07-4e76-a36e-ef21f12f0603
29
+ INFO : Sent reply
30
+ INFO :
31
+ INFO : Received: evaluate message 2f886dc7-3aaa-457f-bbcd-a31e13a35538
32
+ INFO : Sent reply
33
+ INFO :
34
+ INFO : Received: train message 109d8ec5-7e2a-4451-acb4-1b455598091d
35
+ INFO : Sent reply
36
+ INFO :
37
+ INFO : Received: evaluate message 146896ae-66fb-4dcf-ae0e-b671f39730c7
38
+ INFO : Sent reply
39
+ INFO :
40
+ INFO : Received: train message d93e8bde-83f5-4213-aa66-31a52f8670dc
41
+ INFO : Sent reply
42
+ INFO :
43
+ INFO : Received: evaluate message c96107d0-5866-46de-b168-dd8d6370e53c
44
+ INFO : Sent reply
45
+ INFO :
46
+ INFO : Received: train message e1bb6d68-e284-4a31-991f-4fdeb7727b6a
47
+ INFO : Sent reply
48
+ INFO :
49
+ INFO : Received: evaluate message 084dbcf4-ee02-460c-a8e4-a0117faef750
50
+ INFO : Sent reply
51
+ INFO :
52
+ INFO : Received: train message 98c62b99-2c4e-4b91-8d65-d62b483eeafb
53
+ INFO : Sent reply
54
+ INFO :
55
+ INFO : Received: evaluate message a5c80502-28c4-46ce-bcf2-615d0940bd83
56
+ INFO : Sent reply
57
+ INFO :
58
+ INFO : Received: train message 4eade5d9-3553-4fcc-bc8f-87abe591fa5b
59
+ INFO : Sent reply
60
+ INFO :
61
+ INFO : Received: evaluate message 40d2c213-cb1d-42fe-b73a-8ca2de4763b6
62
+ INFO : Sent reply
63
+ INFO :
64
+ INFO : Received: train message 729add19-adf9-40d2-961a-574782e0637b
65
+ INFO : Sent reply
66
+ INFO :
67
+ INFO : Received: evaluate message 153d4189-00f1-4f9e-86c1-f4fb126fe539
68
+ INFO : Sent reply
69
+ INFO :
70
+ INFO : Received: train message 72102c53-639a-4983-b85a-57b20d5a52b3
71
+ INFO : Sent reply
72
+ INFO :
73
+ INFO : Received: evaluate message 24104043-0419-439f-9bba-3da769cb80ef
74
+ INFO : Sent reply
75
+ INFO :
76
+ INFO : Received: reconnect message 8f83b63e-303b-4178-b218-4eb319429999
77
+ INFO : Disconnect and shut down
78
+ Carregando dados para o cliente 3...
79
+ Dispositivo: cpu
80
+ Dados carregados: 992 batches de treino, 245 batches de teste
81
+ Criando modelo LSTM para prever 90 passos.
82
+
83
+ ==================================================
84
+ Iniciando cliente 3
85
+ Conectando ao servidor em 127.0.0.1:8080
86
+ Modelo: LSTM com 16190 par�metros
87
+ ==================================================
88
+
89
+
90
+ [Cliente 3] === Rodada 1 ===
91
+ [Cliente 3] Iniciando treinamento...
92
+ [Cliente 3] Perda de treinamento local: 0.047731
93
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
94
+ [Cliente 3] Avaliando modelo...
95
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
96
+ [Cliente 3] Perda de valida��o: 9.831532
97
+
98
+ [Cliente 3] === Rodada 2 ===
99
+ [Cliente 3] Iniciando treinamento...
100
+ [Cliente 3] Perda de treinamento local: 8.576512
101
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
102
+ [Cliente 3] Avaliando modelo...
103
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
104
+ [Cliente 3] Perda de valida��o: 1.461328
105
+
106
+ [Cliente 3] === Rodada 3 ===
107
+ [Cliente 3] Iniciando treinamento...
108
+ [Cliente 3] Perda de treinamento local: 0.702148
109
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
110
+ [Cliente 3] Avaliando modelo...
111
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
112
+ [Cliente 3] Perda de valida��o: 0.341640
113
+
114
+ [Cliente 3] === Rodada 4 ===
115
+ [Cliente 3] Iniciando treinamento...
116
+ [Cliente 3] Perda de treinamento local: 0.209710
117
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
118
+ [Cliente 3] Avaliando modelo...
119
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
120
+ [Cliente 3] Perda de valida��o: 0.511448
121
+
122
+ [Cliente 3] === Rodada 5 ===
123
+ [Cliente 3] Iniciando treinamento...
124
+ [Cliente 3] Perda de treinamento local: 0.252078
125
+ [Cliente 3] Checkpoint salvo: metrics\client_3\model_round_5.pt
126
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
127
+ [Cliente 3] Avaliando modelo...
128
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
129
+ [Cliente 3] Perda de valida��o: 0.058146
130
+
131
+ [Cliente 3] === Rodada 6 ===
132
+ [Cliente 3] Iniciando treinamento...
133
+ [Cliente 3] Perda de treinamento local: 0.039224
134
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
135
+ [Cliente 3] Avaliando modelo...
136
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
137
+ [Cliente 3] Perda de valida��o: 0.304315
138
+
139
+ [Cliente 3] === Rodada 7 ===
140
+ [Cliente 3] Iniciando treinamento...
141
+ [Cliente 3] Perda de treinamento local: 0.190494
142
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
143
+ [Cliente 3] Avaliando modelo...
144
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
145
+ [Cliente 3] Perda de valida��o: 0.058137
146
+
147
+ [Cliente 3] === Rodada 8 ===
148
+ [Cliente 3] Iniciando treinamento...
149
+ [Cliente 3] Perda de treinamento local: 0.039078
150
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
151
+ [Cliente 3] Avaliando modelo...
152
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
153
+ [Cliente 3] Perda de valida��o: 0.083307
154
+
155
+ [Cliente 3] === Rodada 9 ===
156
+ [Cliente 3] Iniciando treinamento...
157
+ [Cliente 3] Perda de treinamento local: 0.034105
158
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
159
+ [Cliente 3] Avaliando modelo...
160
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
161
+ [Cliente 3] Perda de valida��o: 0.049672
162
+
163
+ [Cliente 3] === Rodada 10 ===
164
+ [Cliente 3] Iniciando treinamento...
165
+ [Cliente 3] Perda de treinamento local: 0.031320
166
+ [Cliente 3] Checkpoint salvo: metrics\client_3\model_round_10.pt
167
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
168
+ [Cliente 3] Avaliando modelo...
169
+ [Cliente 3] M�tricas salvas em metrics\client_3\metrics_history.json
170
+ [Cliente 3] Perda de valida��o: 0.029677
171
+
172
+ [Cliente 3] Finalizado. M�tricas salvas em metrics\client_3
requeriments.txt ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core FL Framework
2
+ flwr==1.10.0
3
+ flwr-datasets==0.3.0
4
+
5
+ # Deep Learning
6
+ torch==2.0.1
7
+ torchvision==0.15.2
8
+ torchaudio==2.0.2
9
+
10
+ # Data Processing & Analysis
11
+ numpy==1.24.3
12
+ pandas==2.0.3
13
+ scikit-learn==1.3.0
14
+ scipy==1.11.1
15
+
16
+ # Visualization
17
+ matplotlib==3.7.2
18
+ seaborn==0.12.2
19
+
20
+ # Network & System
21
+ psutil==5.9.5
22
+ requests==2.31.0
23
+
24
+ # Development Tools (optional but recommended)
25
+ jupyter==1.0.0
26
+ ipython==8.14.0
27
+ tqdm==4.65.0
28
+
29
+ # For Windows compatibility
30
+ pywin32==306; sys_platform == 'win32'
31
+
32
+ # For Linux compatibility
33
+ python-dotenv==1.0.0
run.sh ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Cores para output
4
+ RED='\033[0;31m'
5
+ GREEN='\033[0;32m'
6
+ YELLOW='\033[1;33m'
7
+ BLUE='\033[0;34m'
8
+ NC='\033[0m' # No Color
9
+
10
+ # Configurações
11
+ STRATEGY=${1:-fedavg} # Estratégia padrão: fedavg
12
+ ROUNDS=${2:-15} # Número de rodadas padrão: 15
13
+ PREDICTION_LENGTH=${3:-10} # Tamanho da previsão padrão: 10
14
+
15
+ echo -e "${BLUE}================================================${NC}"
16
+ echo -e "${BLUE} SIMULAÇÃO DE APRENDIZADO FEDERADO${NC}"
17
+ echo -e "${BLUE}================================================${NC}"
18
+ echo -e "${GREEN}Estratégia: ${YELLOW}$STRATEGY${NC}"
19
+ echo -e "${GREEN}Rodadas: ${YELLOW}$ROUNDS${NC}"
20
+ echo -e "${GREEN}Tamanho da Previsão: ${YELLOW}$PREDICTION_LENGTH passos${NC}"
21
+ echo -e "${BLUE}================================================${NC}\n"
22
+
23
+ # Limpar logs anteriores
24
+ echo -e "${YELLOW}Limpando logs anteriores...${NC}"
25
+ rm -f *.log
26
+ rm -rf metrics/
27
+ mkdir -p metrics
28
+ mkdir -p results
29
+
30
+ # Verificar se os dados existem
31
+ if [ ! -d "data" ]; then
32
+ echo -e "${RED}Erro: Diretório 'data' não encontrado!${NC}"
33
+ echo -e "${YELLOW}Certifique-se de que os dados estão organizados em:${NC}"
34
+ echo " data/client_1/*.csv"
35
+ echo " data/client_2/*.csv"
36
+ echo " data/client_3/*.csv"
37
+ exit 1
38
+ fi
39
+
40
+ # Função para verificar se o servidor está pronto
41
+ wait_for_server() {
42
+ echo -e "${YELLOW}Aguardando servidor iniciar...${NC}"
43
+ for i in {1..30}; do
44
+ if netstat -an | grep ":8080" | grep -q "LISTENING"; then
45
+ echo -e "${GREEN}Servidor pronto!${NC}"
46
+ return 0
47
+ fi
48
+ sleep 1
49
+ echo -n "."
50
+ done
51
+ echo -e "\n${RED}Timeout esperando servidor!${NC}"
52
+ return 1
53
+ }
54
+
55
+ # Iniciar servidor
56
+ echo -e "${BLUE}Iniciando servidor FL...${NC}"
57
+ #python server.py --strategy $STRATEGY --rounds $ROUNDS > server_$STRATEGY.log 2>&1 &
58
+ python server.py --strategy $STRATEGY --rounds $ROUNDS --prediction-length $PREDICTION_LENGTH > server_$STRATEGY.log 2>&1 &
59
+ SERVER_PID=$!
60
+
61
+ # Aguardar servidor
62
+ if ! wait_for_server; then
63
+ echo -e "${RED}Falha ao iniciar servidor. Verifique server_$STRATEGY.log${NC}"
64
+ exit 1
65
+ fi
66
+
67
+ # Iniciar clientes
68
+ echo -e "\n${BLUE}Iniciando 3 clientes FL...${NC}"
69
+ CLIENT_PIDS=()
70
+
71
+ for i in {1..3}; do
72
+ echo -e "${GREEN} → Iniciando cliente $i${NC}"
73
+ python client.py \
74
+ --client-id $i \
75
+ --prediction-length $PREDICTION_LENGTH \
76
+ > client_${i}_$STRATEGY.log 2>&1 &
77
+ CLIENT_PIDS+=($!)
78
+ sleep 2 # Pequeno delay entre clientes
79
+ done
80
+
81
+ # Monitorar progresso
82
+ echo -e "\n${BLUE}================================================${NC}"
83
+ echo -e "${BLUE} TREINAMENTO EM PROGRESSO${NC}"
84
+ echo -e "${BLUE}================================================${NC}"
85
+ echo -e "${YELLOW}Monitorando treinamento...${NC}"
86
+ echo -e "${YELLOW}Logs disponíveis em:${NC}"
87
+ echo -e " • Servidor: server_$STRATEGY.log"
88
+ echo -e " • Clientes: client_*_$STRATEGY.log"
89
+ echo -e " • Métricas: metrics/client_*/metrics_history.json"
90
+
91
+ # Função para mostrar progresso
92
+ show_progress() {
93
+ while kill -0 $SERVER_PID 2>/dev/null; do
94
+ if [ -f "server_$STRATEGY.log" ]; then
95
+ CURRENT_ROUND=$(grep -o "round [0-9]*:" server_$STRATEGY.log | tail -1 | grep -o "[0-9]*" || echo "0")
96
+ if [ ! -z "$CURRENT_ROUND" ] && [ "$CURRENT_ROUND" != "0" ]; then
97
+ echo -ne "\r${GREEN}Progresso: Rodada $CURRENT_ROUND de $ROUNDS${NC} "
98
+ fi
99
+ fi
100
+ sleep 2
101
+ done
102
+ }
103
+
104
+ # Mostrar progresso
105
+ show_progress
106
+
107
+ # Aguardar conclusão
108
+ echo -e "\n\n${YELLOW}Aguardando conclusão do treinamento...${NC}"
109
+ wait $SERVER_PID
110
+ SERVER_EXIT_CODE=$?
111
+
112
+ # Verificar se o servidor terminou com sucesso
113
+ if [ $SERVER_EXIT_CODE -eq 0 ]; then
114
+ echo -e "${GREEN}✓ Servidor concluído com sucesso!${NC}"
115
+ else
116
+ echo -e "${RED}✗ Servidor terminou com erro (código: $SERVER_EXIT_CODE)${NC}"
117
+ fi
118
+
119
+ # Aguardar clientes (com timeout)
120
+ echo -e "${YELLOW}Aguardando clientes finalizarem...${NC}"
121
+ TIMEOUT=30
122
+ for pid in ${CLIENT_PIDS[@]}; do
123
+ COUNT=0
124
+ while kill -0 $pid 2>/dev/null && [ $COUNT -lt $TIMEOUT ]; do
125
+ sleep 1
126
+ COUNT=$((COUNT + 1))
127
+ done
128
+ if [ $COUNT -ge $TIMEOUT ]; then
129
+ echo -e "${YELLOW} Cliente PID $pid demorou muito. Finalizando...${NC}"
130
+ kill $pid 2>/dev/null
131
+ fi
132
+ done
133
+
134
+ # Limpar processos órfãos
135
+ echo -e "${YELLOW}Limpando processos...${NC}"
136
+ pkill -f "python client.py" 2>/dev/null
137
+ pkill -f "python server.py" 2>/dev/null
138
+
139
+ # Executar análise
140
+ echo -e "\n${BLUE}================================================${NC}"
141
+ echo -e "${BLUE} EXECUTANDO ANÁLISE DOS RESULTADOS${NC}"
142
+ echo -e "${BLUE}================================================${NC}"
143
+
144
+ if [ -f "analysis_tool.py" ]; then
145
+ echo -e "${GREEN}Gerando visualizações e relatórios...${NC}"
146
+ python analysis_tool.py --results-dir results
147
+
148
+ if [ $? -eq 0 ]; then
149
+ echo -e "${GREEN}✓ Análise concluída com sucesso!${NC}"
150
+ else
151
+ echo -e "${RED}✗ Erro na análise dos resultados${NC}"
152
+ fi
153
+ else
154
+ echo -e "${YELLOW}Arquivo analysis_tool.py não encontrado. Pulando análise.${NC}"
155
+ fi
156
+
157
+ # Resumo final
158
+ echo -e "\n${BLUE}================================================${NC}"
159
+ echo -e "${BLUE} SIMULAÇÃO CONCLUÍDA${NC}"
160
+ echo -e "${BLUE}================================================${NC}"
161
+
162
+ # Verificar arquivos gerados
163
+ echo -e "${GREEN}Arquivos gerados:${NC}"
164
+
165
+ # Resultados
166
+ if [ -d "results" ]; then
167
+ echo -e "\n${YELLOW}Resultados em 'results/':${NC}"
168
+ ls -la results/*.pdf 2>/dev/null | awk '{print " • " $9}'
169
+ ls -la results/*.csv 2>/dev/null | awk '{print " • " $9}'
170
+ ls -la results/*.json 2>/dev/null | awk '{print " • " $9}'
171
+ fi
172
+
173
+ # Métricas dos clientes
174
+ if [ -d "metrics" ]; then
175
+ echo -e "\n${YELLOW}Métricas dos clientes em 'metrics/':${NC}"
176
+ for i in {1..3}; do
177
+ if [ -f "metrics/client_$i/metrics_history.json" ]; then
178
+ echo -e " • Cliente $i: metrics/client_$i/metrics_history.json"
179
+ fi
180
+ done
181
+ fi
182
+
183
+ # Logs
184
+ echo -e "\n${YELLOW}Logs de execução:${NC}"
185
+ ls -la *.log | awk '{print " • " $9 " (" $5 " bytes)"}'
186
+
187
+ # Estatísticas finais dos logs
188
+ echo -e "\n${BLUE}Estatísticas Finais:${NC}"
189
+
190
+ # Extrair perda final do servidor
191
+ if [ -f "server_$STRATEGY.log" ]; then
192
+ FINAL_LOSS=$(grep "Perda final de treino:" server_$STRATEGY.log | tail -1 | grep -o "[0-9.]*" | head -1)
193
+ if [ ! -z "$FINAL_LOSS" ]; then
194
+ echo -e " ${GREEN}• Perda final de treino (global): $FINAL_LOSS${NC}"
195
+ fi
196
+
197
+ FINAL_EVAL=$(grep "Perda final de validação:" server_$STRATEGY.log | tail -1 | grep -o "[0-9.]*" | head -1)
198
+ if [ ! -z "$FINAL_EVAL" ]; then
199
+ echo -e " ${GREEN}• Perda final de validação (global): $FINAL_EVAL${NC}"
200
+ fi
201
+ fi
202
+
203
+ # Extrair perdas finais dos clientes
204
+ for i in {1..3}; do
205
+ if [ -f "client_${i}_$STRATEGY.log" ]; then
206
+ CLIENT_LOSS=$(grep "Perda de validação:" client_${i}_$STRATEGY.log | tail -1 | grep -o "[0-9.]*" | head -1)
207
+ if [ ! -z "$CLIENT_LOSS" ]; then
208
+ echo -e " ${GREEN}• Cliente $i - Perda final: $CLIENT_LOSS${NC}"
209
+ fi
210
+ fi
211
+ done
212
+
213
+ echo -e "\n${BLUE}================================================${NC}"
214
+ echo -e "${GREEN}✓ Simulação completa!${NC}"
215
+ echo -e "${BLUE}================================================${NC}"
216
+
217
+ # Sugestões
218
+ echo -e "\n${YELLOW}Próximos passos sugeridos:${NC}"
219
+ echo -e " 1. Visualizar os gráficos em ${GREEN}results/*.pdf${NC}"
220
+ echo -e " 2. Analisar métricas detalhadas em ${GREEN}results/detailed_metrics_$STRATEGY.csv${NC}"
221
+ echo -e " 3. Revisar o relatório resumido em ${GREEN}results/summary_report.json${NC}"
222
+ echo -e " 4. Comparar com outras estratégias executando:"
223
+ echo -e " ${BLUE}./run_enhanced.sh fedadam $ROUNDS${NC}"
224
+ echo -e " ${BLUE}./run_enhanced.sh fedyogi $ROUNDS${NC}"
225
+ echo -e " ${BLUE}./run_enhanced.sh fedadagrad $ROUNDS${NC}"
226
+
227
+ exit $SERVER_EXIT_CODE
run_all_strategies.sh ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Script para executar todas as estratégias e gerar comparação final
4
+
5
+ # Cores para output
6
+ RED='\033[0;31m'
7
+ GREEN='\033[0;32m'
8
+ YELLOW='\033[1;33m'
9
+ BLUE='\033[0;34m'
10
+ PURPLE='\033[0;35m'
11
+ NC='\033[0m' # No Color
12
+
13
+ # Configurações
14
+ ROUNDS=${1:-15}
15
+ PREDICTION_LENGTH=${2:-10}
16
+ STRATEGIES=("fedavg" "fedadam" "fedyogi" "fedadagrad")
17
+
18
+ echo -e "${PURPLE}╔══════════════════════════════════════════════════════╗${NC}"
19
+ echo -e "${PURPLE}║ EXECUÇÃO COMPLETA - TODAS AS ESTRATÉGIAS FL ║${NC}"
20
+ echo -e "${PURPLE}╚══════════════════════════════════════════════════════╝${NC}"
21
+ echo -e "${GREEN}Rodadas: ${YELLOW}$ROUNDS${NC}"
22
+ echo -e "${GREEN}Tamanho da Previsão: ${YELLOW}$PREDICTION_LENGTH passos${NC}"
23
+ echo -e "${GREEN}Estratégias: ${YELLOW}${STRATEGIES[@]}${NC}"
24
+ echo -e "${PURPLE}════════════════════════════════════════════════════════${NC}\n"
25
+
26
+ # Criar diretório para resultados consolidados
27
+ TIMESTAMP=$(date +%Y%m%d_%H%M%S)
28
+ RESULTS_DIR="results_comparison_$TIMESTAMP"
29
+ mkdir -p $RESULTS_DIR
30
+
31
+ # Log geral
32
+ MAIN_LOG="$RESULTS_DIR/execution_log.txt"
33
+ echo "Execução iniciada em: $(date)" > $MAIN_LOG
34
+
35
+ # Executar cada estratégia
36
+ for STRATEGY in "${STRATEGIES[@]}"; do
37
+ echo -e "\n${BLUE}════════════════════════════════════════════════════════${NC}"
38
+ echo -e "${BLUE} Executando estratégia: ${YELLOW}$STRATEGY${NC}"
39
+ echo -e "${BLUE}════════════════════════════════════════════════════════${NC}"
40
+
41
+ # Registrar no log
42
+ echo -e "\n\n=== ESTRATÉGIA: $STRATEGY ===" >> $MAIN_LOG
43
+ echo "Início: $(date)" >> $MAIN_LOG
44
+
45
+ # Executar estratégia
46
+ ./run.sh $STRATEGY $ROUNDS $PREDICTION_LENGTH
47
+
48
+ # Verificar sucesso
49
+ if [ $? -eq 0 ]; then
50
+ echo -e "${GREEN}✓ $STRATEGY concluída com sucesso!${NC}"
51
+ echo "Status: SUCESSO" >> $MAIN_LOG
52
+ else
53
+ echo -e "${RED}✗ Erro ao executar $STRATEGY${NC}"
54
+ echo "Status: ERRO" >> $MAIN_LOG
55
+ fi
56
+
57
+ echo "Fim: $(date)" >> $MAIN_LOG
58
+
59
+ # Copiar resultados para diretório consolidado
60
+ echo -e "${YELLOW}Copiando resultados...${NC}"
61
+
62
+ # Criar subdiretório para a estratégia
63
+ STRATEGY_DIR="$RESULTS_DIR/$STRATEGY"
64
+ mkdir -p $STRATEGY_DIR
65
+
66
+ # Copiar arquivos de resultados
67
+ if [ -d "results" ]; then
68
+ cp -r results/* $STRATEGY_DIR/ 2>/dev/null
69
+ fi
70
+
71
+ # Copiar métricas dos clientes
72
+ if [ -d "metrics" ]; then
73
+ cp -r metrics $STRATEGY_DIR/ 2>/dev/null
74
+ fi
75
+
76
+ # Copiar logs
77
+ cp *_$STRATEGY.log $STRATEGY_DIR/ 2>/dev/null
78
+
79
+ # Renomear arquivos para incluir estratégia
80
+ if [ -f "results/detailed_metrics_$STRATEGY.csv" ]; then
81
+ cp "results/detailed_metrics_$STRATEGY.csv" "$RESULTS_DIR/metrics_$STRATEGY.csv"
82
+ fi
83
+
84
+ # Aguardar antes da próxima estratégia
85
+ echo -e "${YELLOW}Aguardando 5 segundos antes da próxima estratégia...${NC}"
86
+ sleep 5
87
+ done
88
+
89
+ echo -e "\n${PURPLE}════════════════════════════════════════════════════════${NC}"
90
+ echo -e "${PURPLE} GERANDO ANÁLISE COMPARATIVA FINAL${NC}"
91
+ echo -e "${PURPLE}════════════════════════════════════════════════════════${NC}"
92
+
93
+ # Mover todos os CSVs de métricas para results/
94
+ echo -e "${YELLOW}Consolidando métricas...${NC}"
95
+ cp $RESULTS_DIR/metrics_*.csv results/ 2>/dev/null
96
+
97
+ # Executar análise comparativa final
98
+ echo -e "${GREEN}Executando análise comparativa...${NC}"
99
+ python analysis_tool.py --results-dir results
100
+
101
+ # Copiar análise comparativa para diretório consolidado
102
+ if [ -f "results/comparative_analysis.pdf" ]; then
103
+ cp results/comparative_analysis.pdf $RESULTS_DIR/
104
+ echo -e "${GREEN}✓ Análise comparativa gerada!${NC}"
105
+ fi
106
+
107
+ if [ -f "results/summary_report.json" ]; then
108
+ cp results/summary_report.json $RESULTS_DIR/
109
+ fi
110
+
111
+ # Criar relatório resumido em texto
112
+ SUMMARY_FILE="$RESULTS_DIR/summary.txt"
113
+ echo "════════════════════════════════════════════════════════" > $SUMMARY_FILE
114
+ echo " RESUMO DA COMPARAÇÃO DE ESTRATÉGIAS FL" >> $SUMMARY_FILE
115
+ echo "════════════════════════════════════════════════════════" >> $SUMMARY_FILE
116
+ echo "" >> $SUMMARY_FILE
117
+ echo "Data: $(date)" >> $SUMMARY_FILE
118
+ echo "Rodadas: $ROUNDS" >> $SUMMARY_FILE
119
+ echo "Tamanho da Previsão: $PREDICTION_LENGTH passos" >> $SUMMARY_FILE
120
+ echo "" >> $SUMMARY_FILE
121
+ echo "RESULTADOS POR ESTRATÉGIA:" >> $SUMMARY_FILE
122
+ echo "----------------------------" >> $SUMMARY_FILE
123
+
124
+ # Extrair métricas finais de cada estratégia
125
+ for STRATEGY in "${STRATEGIES[@]}"; do
126
+ echo "" >> $SUMMARY_FILE
127
+ echo "[$STRATEGY]" >> $SUMMARY_FILE
128
+
129
+ LOG_FILE="$STRATEGY_DIR/$STRATEGY/server_$STRATEGY.log"
130
+ if [ -f "$LOG_FILE" ]; then
131
+ FINAL_TRAIN=$(grep "Perda final de treino:" "$LOG_FILE" | tail -1 | grep -oE "[0-9]+\.[0-9]+" | head -1)
132
+ FINAL_VAL=$(grep "Perda final de validação:" "$LOG_FILE" | tail -1 | grep -oE "[0-9]+\.[0-9]+" | head -1)
133
+ IMPROVEMENT=$(grep "Melhoria no treino:" "$LOG_FILE" | tail -1 | grep -oE "[0-9]+\.[0-9]+%" | head -1)
134
+
135
+ echo " Perda Final (Treino): ${FINAL_TRAIN:-N/A}" >> $SUMMARY_FILE
136
+ echo " Perda Final (Validação): ${FINAL_VAL:-N/A}" >> $SUMMARY_FILE
137
+ echo " Melhoria: ${IMPROVEMENT:-N/A}" >> $SUMMARY_FILE
138
+ else
139
+ echo " Status: Dados não disponíveis" >> $SUMMARY_FILE
140
+ fi
141
+ done
142
+
143
+ echo "" >> $SUMMARY_FILE
144
+ echo "════════════════════════════════════════════════════════" >> $SUMMARY_FILE
145
+
146
+ # Exibir resumo no terminal
147
+ cat $SUMMARY_FILE
148
+
149
+ # Estatísticas finais
150
+ echo -e "\n${PURPLE}════════════════════════════════════════════════════════${NC}"
151
+ echo -e "${PURPLE} EXECUÇÃO COMPLETA${NC}"
152
+ echo -e "${PURPLE}════════════════════════════════════════════════════════${NC}"
153
+
154
+ echo -e "\n${GREEN}Resultados salvos em: ${YELLOW}$RESULTS_DIR/${NC}"
155
+ echo -e "${GREEN}Estrutura de arquivos:${NC}"
156
+ echo -e " ${YELLOW}$RESULTS_DIR/${NC}"
157
+ echo -e " ├── ${BLUE}summary.txt${NC} - Resumo geral"
158
+ echo -e " ├── ${BLUE}execution_log.txt${NC} - Log de execução"
159
+ echo -e " ├── ${BLUE}comparative_analysis.pdf${NC} - Análise comparativa"
160
+ echo -e " ├── ${BLUE}summary_report.json${NC} - Relatório detalhado"
161
+
162
+ for STRATEGY in "${STRATEGIES[@]}"; do
163
+ echo -e " ├── ${GREEN}$STRATEGY/${NC}"
164
+ echo -e " │ ├── Resultados específicos"
165
+ echo -e " │ ├── Métricas dos clientes"
166
+ echo -e " │ └── Logs de execução"
167
+ done
168
+
169
+ echo -e "\n${YELLOW}Visualizações disponíveis:${NC}"
170
+ echo -e " • ${GREEN}comparative_analysis.pdf${NC} - Comparação entre estratégias"
171
+ echo -e " • ${GREEN}client_evolution_analysis.pdf${NC} - Evolução dos clientes"
172
+ echo -e " • ${GREEN}performance_analysis_*.pdf${NC} - Análise por estratégia"
173
+ echo -e " • ${GREEN}convergence_analysis_*.pdf${NC} - Análise de convergência"
174
+ echo -e " • ${GREEN}heatmap_performance_*.pdf${NC} - Mapas de calor"
175
+
176
+ # Determinar melhor estratégia
177
+ echo -e "\n${PURPLE}════════════════════════════════════════════════════════${NC}"
178
+ echo -e "${PURPLE} MELHOR ESTRATÉGIA${NC}"
179
+ echo -e "${PURPLE}════════════════════════════════════════════════════════${NC}"
180
+
181
+ BEST_STRATEGY=""
182
+ BEST_LOSS=999999
183
+
184
+ for STRATEGY in "${STRATEGIES[@]}"; do
185
+ CSV_FILE="results/detailed_metrics_$STRATEGY.csv"
186
+ if [ -f "$CSV_FILE" ]; then
187
+ # Pegar última linha com fase 'eval' e coluna 'global_eval_loss'
188
+ FINAL_LOSS=$(tail -n 20 "$CSV_FILE" | grep "eval" | tail -1 | cut -d',' -f3)
189
+
190
+ if [ ! -z "$FINAL_LOSS" ]; then
191
+ # Comparar usando bc para números decimais
192
+ if (( $(echo "$FINAL_LOSS < $BEST_LOSS" | bc -l) )); then
193
+ BEST_LOSS=$FINAL_LOSS
194
+ BEST_STRATEGY=$STRATEGY
195
+ fi
196
+ fi
197
+ fi
198
+ done
199
+
200
+ if [ ! -z "$BEST_STRATEGY" ]; then
201
+ echo -e "${GREEN}Melhor estratégia: ${YELLOW}$BEST_STRATEGY${NC}"
202
+ echo -e "${GREEN}Perda final de validação: ${YELLOW}$BEST_LOSS${NC}"
203
+ else
204
+ echo -e "${YELLOW}Não foi possível determinar a melhor estratégia${NC}"
205
+ fi
206
+
207
+ echo -e "\n${BLUE}════════════════════════════════════════════════════════${NC}"
208
+ echo -e "${GREEN}✓ Comparação completa de todas as estratégias!${NC}"
209
+ echo -e "${BLUE}════════════════════════════════════════════════════════${NC}"
210
+
211
+ # Fim
212
+ echo "Execução finalizada em: $(date)" >> $MAIN_LOG
213
+ exit 0
server.py ADDED
@@ -0,0 +1,449 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import flwr as fl
3
+ import torch
4
+ import pandas as pd
5
+ import numpy as np
6
+ import matplotlib.pyplot as plt
7
+ import seaborn as sns
8
+ from typing import List, Tuple, Dict, Optional
9
+ from flwr.common import Metrics, ndarrays_to_parameters
10
+ from pathlib import Path
11
+ import json
12
+ from datetime import datetime
13
+
14
+ from utils import Net
15
+
16
+ # Configurações de visualização
17
+ plt.style.use('seaborn-v0_8-darkgrid')
18
+ sns.set_palette("husl")
19
+
20
+ # Dicionário de estratégias disponíveis
21
+ STRATEGIES = {
22
+ "fedavg": fl.server.strategy.FedAvg,
23
+ "fedadam": fl.server.strategy.FedAdam,
24
+ "fedyogi": fl.server.strategy.FedYogi,
25
+ "fedadagrad": fl.server.strategy.FedAdagrad,
26
+ }
27
+
28
+ class MetricsCollector:
29
+ """Coleta e organiza métricas de treinamento e validação."""
30
+
31
+ def __init__(self, strategy_name):
32
+ self.strategy_name = strategy_name
33
+ self.train_metrics = {
34
+ "rounds": [],
35
+ "global_train_loss": [],
36
+ "client_1_train_loss": [],
37
+ "client_2_train_loss": [],
38
+ "client_3_train_loss": []
39
+ }
40
+ self.eval_metrics = {
41
+ "rounds": [],
42
+ "global_eval_loss": [],
43
+ "client_1_eval_loss": [],
44
+ "client_2_eval_loss": [],
45
+ "client_3_eval_loss": []
46
+ }
47
+ self.convergence_metrics = {
48
+ "rounds": [],
49
+ "loss_variance": [],
50
+ "loss_std": [],
51
+ "max_min_diff": []
52
+ }
53
+
54
+ def add_train_round(self, round_num, metrics):
55
+ """Adiciona métricas de uma rodada de treinamento."""
56
+ self.train_metrics["rounds"].append(round_num)
57
+ for key, value in metrics.items():
58
+ if key in self.train_metrics:
59
+ self.train_metrics[key].append(value)
60
+
61
+ def add_eval_round(self, round_num, metrics):
62
+ """Adiciona métricas de uma rodada de avaliação."""
63
+ self.eval_metrics["rounds"].append(round_num)
64
+ for key, value in metrics.items():
65
+ if key in self.eval_metrics:
66
+ self.eval_metrics[key].append(value)
67
+
68
+ def calculate_convergence_metrics(self, client_losses):
69
+ """Calcula métricas de convergência entre clientes."""
70
+ if len(client_losses) > 0:
71
+ variance = np.var(client_losses)
72
+ std_dev = np.std(client_losses)
73
+ max_min_diff = max(client_losses) - min(client_losses)
74
+ return variance, std_dev, max_min_diff
75
+ return 0, 0, 0
76
+
77
+ def weighted_average(metrics: List[Tuple[int, Metrics]]) -> Dict[str, any]:
78
+ """Função de agregação para métricas de avaliação."""
79
+ individual_losses = {}
80
+
81
+ for num_examples, m in metrics:
82
+ client_id = m.get("client_id", 0)
83
+ if client_id > 0:
84
+ individual_losses[f"client_{client_id}_eval_loss"] = m["loss"]
85
+
86
+ # Calcula média ponderada
87
+ losses = [num_examples * m["loss"] for num_examples, m in metrics]
88
+ examples = [num_examples for num_examples, _ in metrics]
89
+ avg_loss = sum(losses) / sum(examples) if sum(examples) > 0 else 0
90
+
91
+ aggregated_metrics = {"global_eval_loss": avg_loss}
92
+ aggregated_metrics.update(individual_losses)
93
+
94
+ return aggregated_metrics
95
+
96
+ def fit_metrics_aggregator(metrics: List[Tuple[int, Metrics]]) -> Dict[str, float]:
97
+ """Agrega métricas de treinamento."""
98
+ individual_losses = {}
99
+
100
+ for num_examples, m in metrics:
101
+ client_id = m.get("client_id", 0)
102
+ if client_id > 0:
103
+ individual_losses[f"client_{client_id}_train_loss"] = m["train_loss"]
104
+
105
+ losses = [num_examples * m["train_loss"] for num_examples, m in metrics]
106
+ examples = [num_examples for num_examples, _ in metrics]
107
+
108
+ avg_loss = sum(losses) / sum(examples) if sum(examples) > 0 else 0
109
+
110
+ aggregated_metrics = {"global_train_loss": avg_loss}
111
+ aggregated_metrics.update(individual_losses)
112
+
113
+ return aggregated_metrics
114
+
115
+ def create_visualizations(collector: MetricsCollector, output_dir: Path):
116
+ """Cria todas as visualizações de desempenho."""
117
+
118
+ # 1. Gráfico de Comparação Geral (Treino vs Validação - Global e Clientes)
119
+ fig, axes = plt.subplots(2, 2, figsize=(15, 12))
120
+
121
+ # Subplot 1: Desempenho Global
122
+ ax1 = axes[0, 0]
123
+ rounds = collector.train_metrics["rounds"]
124
+ ax1.plot(rounds, collector.train_metrics["global_train_loss"],
125
+ 'b-', marker='s', label='Treino Global', linewidth=2)
126
+ ax1.plot(collector.eval_metrics["rounds"], collector.eval_metrics["global_eval_loss"],
127
+ 'r-', marker='o', label='Validação Global', linewidth=2)
128
+ ax1.set_title('Desempenho do Modelo Global', fontsize=14, fontweight='bold')
129
+ ax1.set_xlabel('Rodada')
130
+ ax1.set_ylabel('Perda (MSE)')
131
+ ax1.legend()
132
+ ax1.grid(True, alpha=0.3)
133
+
134
+ # Subplot 2: Comparação entre Clientes (Treino)
135
+ ax2 = axes[0, 1]
136
+ colors = ['#2E7D32', '#1565C0', '#E65100']
137
+ for i in range(1, 4):
138
+ key = f"client_{i}_train_loss"
139
+ if key in collector.train_metrics and collector.train_metrics[key]:
140
+ ax2.plot(rounds, collector.train_metrics[key],
141
+ marker='o', label=f'Cliente {i}', color=colors[i-1], linewidth=1.5)
142
+ ax2.plot(rounds, collector.train_metrics["global_train_loss"],
143
+ 'k--', label='Média Global', linewidth=2, alpha=0.7)
144
+ ax2.set_title('Perda de Treinamento por Cliente', fontsize=14, fontweight='bold')
145
+ ax2.set_xlabel('Rodada')
146
+ ax2.set_ylabel('Perda de Treino (MSE)')
147
+ ax2.legend()
148
+ ax2.grid(True, alpha=0.3)
149
+
150
+ # Subplot 3: Comparação entre Clientes (Validação)
151
+ ax3 = axes[1, 0]
152
+ for i in range(1, 4):
153
+ key = f"client_{i}_eval_loss"
154
+ if key in collector.eval_metrics and collector.eval_metrics[key]:
155
+ ax3.plot(collector.eval_metrics["rounds"], collector.eval_metrics[key],
156
+ marker='s', label=f'Cliente {i}', color=colors[i-1], linewidth=1.5)
157
+ ax3.plot(collector.eval_metrics["rounds"], collector.eval_metrics["global_eval_loss"],
158
+ 'k--', label='Média Global', linewidth=2, alpha=0.7)
159
+ ax3.set_title('Perda de Validação por Cliente', fontsize=14, fontweight='bold')
160
+ ax3.set_xlabel('Rodada')
161
+ ax3.set_ylabel('Perda de Validação (MSE)')
162
+ ax3.legend()
163
+ ax3.grid(True, alpha=0.3)
164
+
165
+ # Subplot 4: Taxa de Melhoria
166
+ ax4 = axes[1, 1]
167
+ if len(rounds) > 1:
168
+ train_improvement = np.diff(collector.train_metrics["global_train_loss"])
169
+ eval_improvement = np.diff(collector.eval_metrics["global_eval_loss"])
170
+ ax4.plot(rounds[1:], train_improvement, 'g-', marker='v', label='Δ Treino', linewidth=1.5)
171
+ ax4.plot(collector.eval_metrics["rounds"][1:], eval_improvement,
172
+ 'm-', marker='^', label='Δ Validação', linewidth=1.5)
173
+ ax4.axhline(y=0, color='k', linestyle='--', alpha=0.5)
174
+ ax4.set_title('Taxa de Melhoria (Δ Perda)', fontsize=14, fontweight='bold')
175
+ ax4.set_xlabel('Rodada')
176
+ ax4.set_ylabel('Mudança na Perda')
177
+ ax4.legend()
178
+ ax4.grid(True, alpha=0.3)
179
+
180
+ plt.suptitle(f'Análise de Desempenho - Estratégia: {collector.strategy_name.upper()}',
181
+ fontsize=16, fontweight='bold')
182
+ plt.tight_layout()
183
+ plt.savefig(output_dir / f'performance_analysis_{collector.strategy_name}.pdf', dpi=300, bbox_inches='tight')
184
+ plt.close()
185
+
186
+ # 2. Gráfico de Convergência e Heterogeneidade
187
+ fig, axes = plt.subplots(1, 3, figsize=(18, 6))
188
+
189
+ # Calcular métricas de convergência
190
+ for round_idx, round_num in enumerate(rounds):
191
+ client_losses = []
192
+ for i in range(1, 4):
193
+ key = f"client_{i}_eval_loss"
194
+ if key in collector.eval_metrics and round_idx < len(collector.eval_metrics[key]):
195
+ client_losses.append(collector.eval_metrics[key][round_idx])
196
+
197
+ if client_losses:
198
+ var, std, diff = collector.calculate_convergence_metrics(client_losses)
199
+ collector.convergence_metrics["rounds"].append(round_num)
200
+ collector.convergence_metrics["loss_variance"].append(var)
201
+ collector.convergence_metrics["loss_std"].append(std)
202
+ collector.convergence_metrics["max_min_diff"].append(diff)
203
+
204
+ # Subplot 1: Variância entre clientes
205
+ ax1 = axes[0]
206
+ ax1.plot(collector.convergence_metrics["rounds"],
207
+ collector.convergence_metrics["loss_variance"],
208
+ 'b-', marker='o', linewidth=2)
209
+ ax1.fill_between(collector.convergence_metrics["rounds"],
210
+ collector.convergence_metrics["loss_variance"],
211
+ alpha=0.3)
212
+ ax1.set_title('Variância da Perda entre Clientes', fontsize=14, fontweight='bold')
213
+ ax1.set_xlabel('Rodada')
214
+ ax1.set_ylabel('Variância')
215
+ ax1.grid(True, alpha=0.3)
216
+
217
+ # Subplot 2: Desvio padrão
218
+ ax2 = axes[1]
219
+ ax2.plot(collector.convergence_metrics["rounds"],
220
+ collector.convergence_metrics["loss_std"],
221
+ 'g-', marker='s', linewidth=2)
222
+ ax2.fill_between(collector.convergence_metrics["rounds"],
223
+ collector.convergence_metrics["loss_std"],
224
+ alpha=0.3, color='green')
225
+ ax2.set_title('Desvio Padrão da Perda entre Clientes', fontsize=14, fontweight='bold')
226
+ ax2.set_xlabel('Rodada')
227
+ ax2.set_ylabel('Desvio Padrão')
228
+ ax2.grid(True, alpha=0.3)
229
+
230
+ # Subplot 3: Diferença máx-mín
231
+ ax3 = axes[2]
232
+ ax3.plot(collector.convergence_metrics["rounds"],
233
+ collector.convergence_metrics["max_min_diff"],
234
+ 'r-', marker='^', linewidth=2)
235
+ ax3.fill_between(collector.convergence_metrics["rounds"],
236
+ collector.convergence_metrics["max_min_diff"],
237
+ alpha=0.3, color='red')
238
+ ax3.set_title('Diferença Máx-Mín entre Clientes', fontsize=14, fontweight='bold')
239
+ ax3.set_xlabel('Rodada')
240
+ ax3.set_ylabel('Diferença')
241
+ ax3.grid(True, alpha=0.3)
242
+
243
+ plt.suptitle(f'Análise de Convergência e Heterogeneidade - {collector.strategy_name.upper()}',
244
+ fontsize=16, fontweight='bold')
245
+ plt.tight_layout()
246
+ plt.savefig(output_dir / f'convergence_analysis_{collector.strategy_name}.pdf', dpi=300, bbox_inches='tight')
247
+ plt.close()
248
+
249
+ # 3. Heatmap de desempenho por cliente ao longo do tempo
250
+ fig, ax = plt.subplots(figsize=(12, 6))
251
+
252
+ # Preparar dados para heatmap
253
+ heatmap_data = []
254
+ for i in range(1, 4):
255
+ key = f"client_{i}_eval_loss"
256
+ if key in collector.eval_metrics:
257
+ heatmap_data.append(collector.eval_metrics[key])
258
+
259
+ if heatmap_data:
260
+ heatmap_array = np.array(heatmap_data)
261
+ im = ax.imshow(heatmap_array, aspect='auto', cmap='RdYlGn_r')
262
+
263
+ ax.set_xticks(range(len(collector.eval_metrics["rounds"])))
264
+ ax.set_xticklabels(collector.eval_metrics["rounds"])
265
+ ax.set_yticks(range(3))
266
+ ax.set_yticklabels([f'Cliente {i}' for i in range(1, 4)])
267
+
268
+ ax.set_xlabel('Rodada', fontsize=12)
269
+ ax.set_title(f'Mapa de Calor - Perda de Validação por Cliente - {collector.strategy_name.upper()}',
270
+ fontsize=14, fontweight='bold')
271
+
272
+ # Adicionar valores nas células
273
+ for i in range(3):
274
+ for j in range(len(collector.eval_metrics["rounds"])):
275
+ if j < len(heatmap_data[i]):
276
+ text = ax.text(j, i, f'{heatmap_data[i][j]:.4f}',
277
+ ha="center", va="center", color="black", fontsize=8)
278
+
279
+ plt.colorbar(im, ax=ax, label='Perda (MSE)')
280
+
281
+ plt.tight_layout()
282
+ plt.savefig(output_dir / f'heatmap_performance_{collector.strategy_name}.pdf', dpi=300, bbox_inches='tight')
283
+ plt.close()
284
+
285
+ print(f"Visualizações salvas em {output_dir}")
286
+
287
+ def save_detailed_metrics(collector: MetricsCollector, output_dir: Path):
288
+ """Salva métricas detalhadas em diferentes formatos."""
289
+
290
+ # 1. CSV com todas as métricas
291
+ all_metrics = pd.DataFrame()
292
+
293
+ # Adicionar métricas de treino
294
+ if collector.train_metrics["rounds"]:
295
+ train_df = pd.DataFrame(collector.train_metrics)
296
+ train_df['phase'] = 'train'
297
+ all_metrics = pd.concat([all_metrics, train_df], ignore_index=True)
298
+
299
+ # Adicionar métricas de validação
300
+ if collector.eval_metrics["rounds"]:
301
+ eval_df = pd.DataFrame(collector.eval_metrics)
302
+ eval_df['phase'] = 'eval'
303
+ all_metrics = pd.concat([all_metrics, eval_df], ignore_index=True)
304
+
305
+ # Salvar CSV detalhado
306
+ csv_file = output_dir / f'detailed_metrics_{collector.strategy_name}.csv'
307
+ all_metrics.to_csv(csv_file, index=False)
308
+ print(f"Métricas detalhadas salvas em {csv_file}")
309
+
310
+ # 2. JSON com análise estatística
311
+ stats = {
312
+ "strategy": collector.strategy_name,
313
+ "total_rounds": len(collector.train_metrics["rounds"]),
314
+ "final_global_train_loss": collector.train_metrics["global_train_loss"][-1] if collector.train_metrics["global_train_loss"] else None,
315
+ "final_global_eval_loss": collector.eval_metrics["global_eval_loss"][-1] if collector.eval_metrics["global_eval_loss"] else None,
316
+ "train_improvement": (collector.train_metrics["global_train_loss"][0] - collector.train_metrics["global_train_loss"][-1]) if len(collector.train_metrics["global_train_loss"]) > 1 else 0,
317
+ "eval_improvement": (collector.eval_metrics["global_eval_loss"][0] - collector.eval_metrics["global_eval_loss"][-1]) if len(collector.eval_metrics["global_eval_loss"]) > 1 else 0,
318
+ "convergence_metrics": collector.convergence_metrics,
319
+ "timestamp": datetime.now().isoformat()
320
+ }
321
+
322
+ json_file = output_dir / f'analysis_{collector.strategy_name}.json'
323
+ with open(json_file, 'w') as f:
324
+ json.dump(stats, f, indent=2)
325
+ print(f"Análise estatística salva em {json_file}")
326
+
327
+ def main():
328
+ parser = argparse.ArgumentParser(description="Flower Server Enhanced")
329
+ parser.add_argument(
330
+ "--strategy", type=str, choices=list(STRATEGIES.keys()), default="fedavg",
331
+ help="Estratégia de agregação a ser usada."
332
+ )
333
+ parser.add_argument(
334
+ "--rounds", type=int, default=10, help="Número de rodadas de FL."
335
+ )
336
+ parser.add_argument(
337
+ "--min-clients", type=int, default=3, help="Número mínimo de clientes."
338
+ )
339
+ parser.add_argument(
340
+ "--prediction-length", type=int, default=10, help="Tamanho da previsão."
341
+ )
342
+ args = parser.parse_args()
343
+
344
+ print(f"Tamanho da Previsão: {args.prediction_length}")
345
+ # Cria uma instância do modelo no servidor para obter os parâmetros iniciais
346
+ # Os valores de input/hidden devem ser os mesmos do cliente
347
+ net = Net(input_size=6, hidden_size=50, output_size=args.prediction_length)
348
+ initial_parameters = [val.cpu().numpy() for _, val in net.state_dict().items()]
349
+
350
+
351
+ print(f"\n{'='*60}")
352
+ print(f"SERVIDOR DE APRENDIZADO FEDERADO")
353
+ print(f"{'='*60}")
354
+ print(f"Estratégia: {args.strategy.upper()}")
355
+ print(f"Rodadas: {args.rounds}")
356
+ print(f"Clientes mínimos: {args.min_clients}")
357
+ print(f"{'='*60}\n")
358
+
359
+ # Cria diretórios de saída
360
+ output_dir = Path("results")
361
+ output_dir.mkdir(exist_ok=True)
362
+
363
+ # Inicializa coletor de métricas
364
+ collector = MetricsCollector(args.strategy)
365
+
366
+ # Função customizada de agregação que também coleta métricas
367
+ def enhanced_weighted_average(metrics: List[Tuple[int, Metrics]]) -> Dict[str, any]:
368
+ result = weighted_average(metrics)
369
+ # Coletar métricas para visualização
370
+ round_num = max([m.get("round", 0) for _, m in metrics])
371
+ if round_num > 0:
372
+ collector.add_eval_round(round_num, result)
373
+ return result
374
+
375
+ def enhanced_fit_aggregator(metrics: List[Tuple[int, Metrics]]) -> Dict[str, float]:
376
+ result = fit_metrics_aggregator(metrics)
377
+ # Coletar métricas para visualização
378
+ round_num = max([m.get("round", 0) for _, m in metrics])
379
+ if round_num > 0:
380
+ collector.add_train_round(round_num, result)
381
+ return result
382
+
383
+ # Cria a estratégia com as funções de agregação aprimoradas
384
+ strategy_params = {
385
+ "min_fit_clients": args.min_clients,
386
+ "min_available_clients": args.min_clients,
387
+ "evaluate_metrics_aggregation_fn": enhanced_weighted_average,
388
+ "fit_metrics_aggregation_fn": enhanced_fit_aggregator,
389
+ }
390
+
391
+ if args.strategy != "fedavg":
392
+ strategy_params["initial_parameters"] = ndarrays_to_parameters(initial_parameters)
393
+
394
+ strategy = STRATEGIES[args.strategy](**strategy_params)
395
+
396
+
397
+ # Inicia o servidor
398
+ print("Iniciando servidor FL...")
399
+ history = fl.server.start_server(
400
+ server_address="0.0.0.0:8080",
401
+ config=fl.server.ServerConfig(num_rounds=args.rounds),
402
+ strategy=strategy,
403
+ )
404
+
405
+ print("\n" + "="*60)
406
+ print("TREINAMENTO CONCLUÍDO - GERANDO ANÁLISES")
407
+ print("="*60)
408
+
409
+ # Criar visualizações
410
+ create_visualizations(collector, output_dir)
411
+
412
+ # Salvar métricas detalhadas
413
+ save_detailed_metrics(collector, output_dir)
414
+
415
+ # Análise final
416
+ print("\n" + "="*60)
417
+ print("RESUMO DO TREINAMENTO")
418
+ print("="*60)
419
+
420
+ if collector.train_metrics["global_train_loss"]:
421
+ initial_loss = collector.train_metrics["global_train_loss"][0]
422
+ final_loss = collector.train_metrics["global_train_loss"][-1]
423
+ improvement = ((initial_loss - final_loss) / initial_loss) * 100
424
+
425
+ print(f"Perda inicial de treino: {initial_loss:.6f}")
426
+ print(f"Perda final de treino: {final_loss:.6f}")
427
+ print(f"Melhoria no treino: {improvement:.2f}%")
428
+
429
+ if collector.eval_metrics["global_eval_loss"]:
430
+ initial_eval = collector.eval_metrics["global_eval_loss"][0]
431
+ final_eval = collector.eval_metrics["global_eval_loss"][-1]
432
+ eval_improvement = ((initial_eval - final_eval) / initial_eval) * 100
433
+
434
+ print(f"\nPerda inicial de validação: {initial_eval:.6f}")
435
+ print(f"Perda final de validação: {final_eval:.6f}")
436
+ print(f"Melhoria na validação: {eval_improvement:.2f}%")
437
+
438
+ # Análise de convergência
439
+ if collector.convergence_metrics["loss_std"]:
440
+ final_std = collector.convergence_metrics["loss_std"][-1]
441
+ print(f"\nDesvio padrão final entre clientes: {final_std:.6f}")
442
+ print(f"Convergência: {'Boa' if final_std < 0.01 else 'Moderada' if final_std < 0.05 else 'Baixa'}")
443
+
444
+ print("\n" + "="*60)
445
+ print(f"Resultados salvos em: {output_dir}")
446
+ print("="*60)
447
+
448
+ if __name__ == "__main__":
449
+ main()
server_fedadagrad.log ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ WARNING : DEPRECATED FEATURE: flwr.server.start_server() is deprecated.
2
+ Instead, use the `flower-superlink` CLI command to start a SuperLink as shown below:
3
+
4
+ $ flower-superlink --insecure
5
+
6
+ To view usage and all available options, run:
7
+
8
+ $ flower-superlink --help
9
+
10
+ Using `start_server()` is deprecated.
11
+
12
+ This is a deprecated feature. It will be removed
13
+ entirely in future versions of Flower.
14
+
15
+ INFO : Starting Flower server, config: num_rounds=10, no round_timeout
16
+ INFO : Flower ECE: gRPC server running (10 rounds), SSL is disabled
17
+ INFO : [INIT]
18
+ INFO : Using initial global parameters provided by strategy
19
+ INFO : Starting evaluation of initial global parameters
20
+ INFO : Evaluation returned no results (`None`)
21
+ INFO :
22
+ INFO : [ROUND 1]
23
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
24
+ INFO : aggregate_fit: received 3 results and 0 failures
25
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
26
+ INFO : aggregate_evaluate: received 3 results and 0 failures
27
+ INFO :
28
+ INFO : [ROUND 2]
29
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
30
+ INFO : aggregate_fit: received 3 results and 0 failures
31
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
32
+ INFO : aggregate_evaluate: received 3 results and 0 failures
33
+ INFO :
34
+ INFO : [ROUND 3]
35
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
36
+ INFO : aggregate_fit: received 3 results and 0 failures
37
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
38
+ INFO : aggregate_evaluate: received 3 results and 0 failures
39
+ INFO :
40
+ INFO : [ROUND 4]
41
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
42
+ INFO : aggregate_fit: received 3 results and 0 failures
43
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
44
+ INFO : aggregate_evaluate: received 3 results and 0 failures
45
+ INFO :
46
+ INFO : [ROUND 5]
47
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
48
+ INFO : aggregate_fit: received 3 results and 0 failures
49
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
50
+ INFO : aggregate_evaluate: received 3 results and 0 failures
51
+ INFO :
52
+ INFO : [ROUND 6]
53
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
54
+ INFO : aggregate_fit: received 3 results and 0 failures
55
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
56
+ INFO : aggregate_evaluate: received 3 results and 0 failures
57
+ INFO :
58
+ INFO : [ROUND 7]
59
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
60
+ INFO : aggregate_fit: received 3 results and 0 failures
61
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
62
+ INFO : aggregate_evaluate: received 3 results and 0 failures
63
+ INFO :
64
+ INFO : [ROUND 8]
65
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
66
+ INFO : aggregate_fit: received 3 results and 0 failures
67
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
68
+ INFO : aggregate_evaluate: received 3 results and 0 failures
69
+ INFO :
70
+ INFO : [ROUND 9]
71
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
72
+ INFO : aggregate_fit: received 3 results and 0 failures
73
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
74
+ INFO : aggregate_evaluate: received 3 results and 0 failures
75
+ INFO :
76
+ INFO : [ROUND 10]
77
+ INFO : configure_fit: strategy sampled 3 clients (out of 3)
78
+ INFO : aggregate_fit: received 3 results and 0 failures
79
+ INFO : configure_evaluate: strategy sampled 3 clients (out of 3)
80
+ INFO : aggregate_evaluate: received 3 results and 0 failures
81
+ INFO :
82
+ INFO : [SUMMARY]
83
+ INFO : Run finished 10 round(s) in 146.09s
84
+ INFO : History (loss, distributed):
85
+ INFO : round 1: 9.925077960899166
86
+ INFO : round 2: 1.3836319349268043
87
+ INFO : round 3: 0.29234505289901225
88
+ INFO : round 4: 0.49308163151779894
89
+ INFO : round 5: 0.0446630789378426
90
+ INFO : round 6: 0.284914885456677
91
+ INFO : round 7: 0.058860671314457845
92
+ INFO : round 8: 0.07942846971222137
93
+ INFO : round 9: 0.037627383500482725
94
+ INFO : round 10: 0.024166644675821698
95
+ INFO : History (metrics, distributed, fit):
96
+ INFO : {'client_1_train_loss': [(1, 0.011821450406897624),
97
+ INFO : (2, 9.19087529878669),
98
+ INFO : (3, 0.6059146807741652),
99
+ INFO : (4, 0.19704961071376878),
100
+ INFO : (5, 0.13989461602253406),
101
+ INFO : (6, 0.020903305802541017),
102
+ INFO : (7, 0.1471804918425052),
103
+ INFO : (8, 0.03622452800638312),
104
+ INFO : (9, 0.021778890335108998),
105
+ INFO : (10, 0.014076102254991698)],
106
+ INFO : 'client_2_train_loss': [(1, 0.005994700957002613),
107
+ INFO : (2, 9.031767151078034),
108
+ INFO : (3, 0.7539265559325762),
109
+ INFO : (4, 0.16390307652051578),
110
+ INFO : (5, 0.20438744467001307),
111
+ INFO : (6, 0.016729887813302254),
112
+ INFO : (7, 0.12536963731445314),
113
+ INFO : (8, 0.03203308185613172),
114
+ INFO : (9, 0.01797729913919752),
115
+ INFO : (10, 0.014847784393701121)],
116
+ INFO : 'client_3_train_loss': [(1, 0.0477309877821325),
117
+ INFO : (2, 8.576512244819956),
118
+ INFO : (3, 0.7021478945708147),
119
+ INFO : (4, 0.20970996846132312),
120
+ INFO : (5, 0.2520780406049325),
121
+ INFO : (6, 0.039224337560547065),
122
+ INFO : (7, 0.19049448489231752),
123
+ INFO : (8, 0.03907830891323567),
124
+ INFO : (9, 0.03410547275085612),
125
+ INFO : (10, 0.03132038051823111)],
126
+ INFO : 'global_train_loss': [(1, 0.024723581809669777),
127
+ INFO : (2, 8.885175558524038),
128
+ INFO : (3, 0.6942090508692439),
129
+ INFO : (4, 0.19139092719798328),
130
+ INFO : (5, 0.20735043383995075),
131
+ INFO : (6, 0.027091810488224646),
132
+ INFO : (7, 0.15788991120164078),
133
+ INFO : (8, 0.03602586002639032),
134
+ INFO : (9, 0.025616361683664917),
135
+ INFO : (10, 0.021443837521512663)]}
136
+ INFO : History (metrics, distributed, evaluate):
137
+ INFO : {'client_1_eval_loss': [(1, 9.976542702888077),
138
+ INFO : (2, 1.2864945372182275),
139
+ INFO : (3, 0.2793154488706755),
140
+ INFO : (4, 0.5965077027088073),
141
+ INFO : (5, 0.03825337379663002),
142
+ INFO : (6, 0.2677974948383068),
143
+ INFO : (7, 0.058361862074286265),
144
+ INFO : (8, 0.08157266843303032),
145
+ INFO : (9, 0.029206974828750388),
146
+ INFO : (10, 0.02422947784015051)],
147
+ INFO : 'client_2_eval_loss': [(1, 10.00263674723258),
148
+ INFO : (2, 1.3619409297631837),
149
+ INFO : (3, 0.24040741897930812),
150
+ INFO : (4, 0.38867445768531034),
151
+ INFO : (5, 0.032692949841941314),
152
+ INFO : (6, 0.2738929928920669),
153
+ INFO : (7, 0.060165285674857814),
154
+ INFO : (8, 0.07285282868754381),
155
+ INFO : (9, 0.029050754143804952),
156
+ INFO : (10, 0.01716736676326117)],
157
+ INFO : 'client_3_eval_loss': [(1, 9.831531776215563),
158
+ INFO : (2, 1.461328144772189),
159
+ INFO : (3, 0.3416395899531878),
160
+ INFO : (4, 0.5114476139352474),
161
+ INFO : (5, 0.05814581121184792),
162
+ INFO : (6, 0.3043146318768071),
163
+ INFO : (7, 0.058136951014934914),
164
+ INFO : (8, 0.08330663724478181),
165
+ INFO : (9, 0.049671815384144585),
166
+ INFO : (10, 0.029676996694472633)],
167
+ INFO : 'global_eval_loss': [(1, 9.925078071091885),
168
+ INFO : (2, 1.3836319280429141),
169
+ INFO : (3, 0.29234505846417363),
170
+ INFO : (4, 0.4930816239130249),
171
+ INFO : (5, 0.0446630791944702),
172
+ INFO : (6, 0.2849148775837404),
173
+ INFO : (7, 0.058860671175644294),
174
+ INFO : (8, 0.07942846919600849),
175
+ INFO : (9, 0.03762738416111641),
176
+ INFO : (10, 0.024166644736454038)]}
177
+ INFO :
178
+ Tamanho da Previs�o: 90
179
+
180
+ ============================================================
181
+ SERVIDOR DE APRENDIZADO FEDERADO
182
+ ============================================================
183
+ Estrat�gia: FEDADAGRAD
184
+ Rodadas: 10
185
+ Clientes m�nimos: 3
186
+ ============================================================
187
+
188
+ Iniciando servidor FL...
189
+
190
+ ============================================================
191
+ TREINAMENTO CONCLU�DO - GERANDO AN�LISES
192
+ ============================================================
193
+ Visualiza��es salvas em results
194
+ M�tricas detalhadas salvas em results\detailed_metrics_fedadagrad.csv
195
+ An�lise estat�stica salva em results\analysis_fedadagrad.json
196
+
197
+ ============================================================
198
+ RESUMO DO TREINAMENTO
199
+ ============================================================
200
+ Perda inicial de treino: 0.024724
201
+ Perda final de treino: 0.021444
202
+ Melhoria no treino: 13.27%
203
+
204
+ Perda inicial de valida��o: 9.925078
205
+ Perda final de valida��o: 0.024167
206
+ Melhoria na valida��o: 99.76%
207
+
208
+ Desvio padr�o final entre clientes: 0.005121
209
+ Converg�ncia: Boa
210
+
211
+ ============================================================
212
+ Resultados salvos em: results
213
+ ============================================================
utils.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import torch
4
+ from torch.utils.data import TensorDataset, DataLoader
5
+ from sklearn.preprocessing import MinMaxScaler
6
+ from pathlib import Path
7
+ import os
8
+
9
+ # Definição do Modelo LSTM com PyTorch
10
+ class Net(torch.nn.Module):
11
+ def __init__(self, input_size, hidden_size, output_size, num_layers=1):
12
+ super(Net, self).__init__()
13
+ self.lstm = torch.nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
14
+ self.linear = torch.nn.Linear(hidden_size, output_size)
15
+
16
+ def forward(self, x):
17
+ lstm_out, _ = self.lstm(x)
18
+ # Usamos apenas a saída do último passo de tempo para a previsão
19
+ last_time_step_out = lstm_out[:, -1, :]
20
+ out = self.linear(last_time_step_out)
21
+ return out
22
+
23
+ def create_sliding_windows(data, sequence_length, prediction_length):
24
+ """Cria janelas deslizantes para problemas de séries temporais."""
25
+ xs, ys = [], []
26
+ for i in range(len(data) - sequence_length - prediction_length + 1):
27
+ x = data[i:(i + sequence_length)]
28
+ y = data[(i + sequence_length):(i + sequence_length + prediction_length), -1] # A última coluna é 'P_kW'
29
+ xs.append(x)
30
+ ys.append(y)
31
+ return np.array(xs), np.array(ys)
32
+
33
+ def load_data(client_id: int, sequence_length=60, prediction_length=30, batch_size=32):
34
+ """
35
+ Carrega os dados para um cliente específico, processa e retorna DataLoaders.
36
+ NOVA VERSÃO: Concatena todos os percursos e divide em 80% para treino e 20% para teste.
37
+ """
38
+ data_dir = Path(f"data/client_{client_id}")
39
+
40
+ # 1. Carrega todos os percursos em uma lista de DataFrames
41
+ all_routes_df = [pd.read_csv(f) for f in data_dir.glob("*.csv")]
42
+
43
+ if not all_routes_df:
44
+ raise FileNotFoundError(f"Nenhum arquivo CSV encontrado para o cliente {client_id} no diretório {data_dir}")
45
+
46
+ # 2. Concatena TODOS os percursos em um único DataFrame
47
+ combined_df = pd.concat(all_routes_df, ignore_index=True)
48
+
49
+ feature_columns = ['vehicle_speed', 'engine_rpm', 'accel_x', 'accel_y', 'P_kW', 'dt']
50
+ processed_df = combined_df[feature_columns].dropna()
51
+
52
+ # 3. Divide o DataFrame combinado em 80% para treino e 20% para teste
53
+ split_index = int(len(processed_df) * 0.8)
54
+ train_df = processed_df.iloc[:split_index]
55
+ test_df = processed_df.iloc[split_index:]
56
+
57
+ # 4. AJUSTA O SCALER APENAS NOS DADOS DE TREINO (ESSENCIAL!)
58
+ scaler = MinMaxScaler()
59
+ scaler.fit(train_df)
60
+
61
+ # 5. TRANSFORMA AMBOS OS CONJUNTOS COM O SCALER AJUSTADO
62
+ train_scaled = scaler.transform(train_df)
63
+ test_scaled = scaler.transform(test_df)
64
+
65
+ # 6. CRIA JANELAS SEPARADAMENTE PARA TREINO E TESTE
66
+ X_train, y_train = create_sliding_windows(train_scaled, sequence_length, prediction_length)
67
+ X_test, y_test = create_sliding_windows(test_scaled, sequence_length, prediction_length)
68
+
69
+ # Garante que os conjuntos não sejam vazios
70
+ if len(X_train) == 0 or len(X_test) == 0:
71
+ raise ValueError(f"A divisão de dados para o cliente {client_id} resultou em um conjunto de treino ou teste vazio. Verifique a quantidade de dados.")
72
+
73
+ # Conversão para tensores PyTorch
74
+ X_train_tensor = torch.from_numpy(X_train).float()
75
+ y_train_tensor = torch.from_numpy(y_train).float()
76
+ X_test_tensor = torch.from_numpy(X_test).float()
77
+ y_test_tensor = torch.from_numpy(y_test).float()
78
+
79
+ # Criação de DataLoaders
80
+ train_dataset = TensorDataset(X_train_tensor, y_train_tensor)
81
+ test_dataset = TensorDataset(X_test_tensor, y_test_tensor)
82
+
83
+ trainloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
84
+ testloader = DataLoader(test_dataset, batch_size=batch_size)
85
+
86
+ num_features = X_train_tensor.shape[2]
87
+
88
+ return trainloader, testloader, num_features
89
+
90
+
91
+ def train(net, trainloader, epochs, device):
92
+ """Treina e retorna a perda média por amostra (float)."""
93
+ criterion = torch.nn.MSELoss(reduction="mean") # perda média por saída
94
+ optimizer = torch.optim.Adam(net.parameters(), lr=1e-5)
95
+ net.to(device)
96
+ net.train()
97
+
98
+ total_loss_sum = 0.0
99
+ total_samples = 0
100
+
101
+ for _ in range(epochs):
102
+ for sequences, labels in trainloader:
103
+ sequences, labels = sequences.to(device), labels.to(device)
104
+ optimizer.zero_grad()
105
+ outputs = net(sequences)
106
+ loss = criterion(outputs, labels) # média por amostra no batch
107
+ loss.backward()
108
+ torch.nn.utils.clip_grad_norm_(net.parameters(), max_norm=1.0)
109
+ optimizer.step()
110
+
111
+ batch_size = sequences.size(0)
112
+ total_loss_sum += loss.item() * batch_size # soma por amostra
113
+ total_samples += batch_size
114
+
115
+ if total_samples == 0:
116
+ return 0.0
117
+ return total_loss_sum / total_samples # média por amostra
118
+
119
+ # --- substitua a função test ---
120
+ def test(net, testloader, device):
121
+ """Avalia e retorna (avg_loss_per_sample, num_examples)."""
122
+ criterion = torch.nn.MSELoss(reduction="mean")
123
+ net.to(device)
124
+ net.eval()
125
+ total_loss_sum = 0.0
126
+ total_samples = 0
127
+ with torch.no_grad():
128
+ for sequences, labels in testloader:
129
+ sequences, labels = sequences.to(device), labels.to(device)
130
+ outputs = net(sequences)
131
+ loss = criterion(outputs, labels)
132
+ batch_size = sequences.size(0)
133
+ total_loss_sum += loss.item() * batch_size
134
+ total_samples += batch_size
135
+
136
+ if total_samples == 0:
137
+ return 0.0, 0
138
+ avg_loss = total_loss_sum / total_samples
139
+ return avg_loss, total_samples