jwsouza2025 commited on
Commit
0b7ece2
·
verified ·
1 Parent(s): ac1172d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1042 -116
app.py CHANGED
@@ -1,116 +1,1042 @@
1
- import streamlit as st
2
- import matplotlib.pyplot as plt
3
- import networkx as nx
4
-
5
-
6
- st.set_page_config(page_title="APRENDIZADO FEDERADO PARA PREVISÃO DE DEMANDA ENERGÉTICA", page_icon=":bar_chart:", layout="wide", initial_sidebar_state="auto")
7
-
8
- st.markdown("<h2 style='text-align: center;'>FL com Flower </h2>", unsafe_allow_html=True)
9
- st.sidebar.image("images/logo_inmetro.jpg", width=200)
10
- st.sidebar.title("FL Inmetro")
11
-
12
- secao = st.sidebar.radio("Ir para:", ["🏠 Início", "📚 Artigos", "ℹ️ Sobre"])
13
-
14
- if secao == "🏠 Início":
15
-
16
- intro, agregamentos, clients_server,FL,sainda, integracao_rpi = st.tabs(['Introducão', 'Métodos de Agregação',
17
- 'Criando o Cliente e Servidor', 'Modelo', 'Saida', 'Integração com RPI'])
18
-
19
- with intro:
20
-
21
- st.title("Aprendizado Federado")
22
-
23
- col1, col2 = st.columns(2)
24
-
25
- with col1:
26
- # Introdução
27
-
28
- st.markdown("""
29
- Este projeto explora o aprendizado federado utilizando o **Flower**.
30
- Os principais passos incluem:
31
- - Criar código básico de FL com Flower
32
- - Configurar clientes e servidor
33
- - Testar na base CIFAR-10
34
- """)
35
-
36
- with col2:
37
- # Criando um fluxograma do processo
38
- st.markdown("""
39
- 1. **Aprender FL com Flower**: Estudo e configuração inicial.
40
- 2. **Criar Clientes e Servidor**: Implementação prática do FL.
41
- 3. **Testar na base CIFAR-10**: Avaliação do modelo treinado.
42
- 4. **Analisar Resultados**: Verificação do desempenho do modelo.
43
- """)
44
- with agregamentos:
45
- col1, col2 = st.columns(2)
46
- with col1:
47
- st.subheader(
48
- """
49
- Federated Averaging (FedAvg)
50
- """
51
- )
52
- st.image("./images/fedavg.png")
53
- st.markdown("[McMaham et al. 2023. Communication-Efficient Learning of Deep Networks from Decentralized Data](https://arxiv.org/pdf/1602.05629)")
54
-
55
- st.markdown("""
56
- - Normalmente, a taxa de convergência do FEDAVG piora com a heterogeneidade do cliente.
57
- -
58
- """)
59
- with col2:
60
- st.subheader("FedAdagrad, FedYogi, FedAdam")
61
- st.image('./images/FedAdaGrad-Yogi-Adam.png')
62
- st.markdown("[Reddi et al. DAPTIVE FEDERATED OPTIMIZATION](https://arxiv.org/pdf/2003.00295)")
63
-
64
-
65
-
66
- with clients_server:
67
- st.subheader("1. Criar Código de FL com Flower")
68
- st.code("""
69
- import flwr as fl
70
- import tensorflow as tf
71
-
72
- # Definição do modelo e cliente FLwr
73
- class Client(fl.client.NumPyClient):
74
- def get_parameters(self, config):
75
- return model.get_weights()
76
- def fit(self, parameters, config):
77
- model.set_weights(parameters)
78
- model.fit(X_train, y_train, epochs=1)
79
- return model.get_weights(), len(X_train), {}
80
-
81
- fl.client.start_numpy_client(server_address="127.0.0.1:8080", client=Client())
82
- """, language='python')
83
-
84
- st.subheader("2. Criar e Gerenciar Clientes e Servidor")
85
- st.code("""
86
- # Servidor FLwr
87
- import flwr as fl
88
- fl.server.start_server(config=fl.server.ServerConfig(num_rounds=3))
89
- """, language='python')
90
-
91
- st.subheader("3. Testar na Base CIFAR-10")
92
- st.markdown("Carregando e treinando modelo na base CIFAR-10...")
93
-
94
- if secao == "ℹ️ Sobre":
95
- st.markdown(
96
- """
97
- Este é um projeto para previsão de demanda de combustível utilizando aprendizado federado.
98
- Integrantes:
99
- - João
100
- - Erick
101
- - José Wilson
102
- """
103
- )
104
- if secao == "📚 Artigos":
105
- st.markdown(
106
- """
107
- ### Referências
108
- - FedAVG
109
-
110
- [McMaham et al. 2023. Communication-Efficient Learning of Deep Networks from Decentralized Data](https://arxiv.org/pdf/1602.05629)
111
-
112
- - ADAGRAD, ADAM, YOGI
113
-
114
- [Reddi et al. DAPTIVE FEDERATED OPTIMIZATION](https://arxiv.org/pdf/2003.00295)
115
- """
116
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import matplotlib.pyplot as plt
3
+ import networkx as nx
4
+ import numpy as np
5
+ from matplotlib.animation import FuncAnimation
6
+ import pandas as pd
7
+ import time
8
+ import plotly.graph_objects as go
9
+ import plotly.express as px
10
+ from io import BytesIO
11
+
12
+ st.set_page_config(page_title="APRENDIZADO FEDERADO PARA PREVISÃO DE DEMANDA ENERGÉTICA", page_icon=":bar_chart:", layout="wide", initial_sidebar_state="auto")
13
+
14
+ st.markdown("<h2 style='text-align: center;'>Aprendizado Federado com Flower</h2>", unsafe_allow_html=True)
15
+ st.sidebar.image("images/logo_inmetro.jpg", width=200)
16
+ st.sidebar.title("FL Inmetro")
17
+
18
+ secao = st.sidebar.radio("Ir para:", ["🏠 Início", "🖥️ Implementação", "📊 Visualização", "🍓 Integração Raspberry Pi", "📈 Modelos para EVs", "📚 Artigos", "ℹ️ Sobre"])
19
+
20
+ if secao == "🏠 Início":
21
+
22
+ tab1, tab2, tab3 = st.tabs(["📘 Aprendizado Centralizado", "📗 Aprendizado Federado", "O Projeto"])
23
+
24
+ with tab1:
25
+ st.markdown("## 📘 Aprendizado Centralizado: Fundamentos Teóricos")
26
+
27
+ # Definição formal do problema
28
+ st.markdown("### 🔍 Definição Formal do Problema")
29
+ st.latex(r"""
30
+ \begin{aligned}
31
+ &\text{Dado:} \\
32
+ &\quad \text{Conjunto de dados } \mathcal{D} = \{(\mathbf{x}_i, y_i)\}_{i=1}^N \\
33
+ &\quad \text{Modelo paramétrico } f_\theta: \mathcal{X} \to \mathcal{Y} \\
34
+ &\quad \text{Função perda } \ell: \mathcal{Y} \times \mathcal{Y} \to \mathbb{R}^+ \\
35
+ \\
36
+ &\text{Objetivo:} \\
37
+ &\quad \min_{\theta \in \mathbb{R}^d} \mathcal{L}(\theta) = \mathbb{E}_{(\mathbf{x},y) \sim \mathcal{P}} [\ell(f_\theta(\mathbf{x}), y)] \\
38
+ &\quad \text{com aproximação empírica:} \\
39
+ &\quad \hat{\mathcal{L}}(\theta) = \frac{1}{N} \sum_{i=1}^N \ell(f_\theta(\mathbf{x}_i), y_i)
40
+ \end{aligned}
41
+ """)
42
+
43
+ st.markdown("""
44
+ Onde:
45
+ - $\mathcal{P}$ é a distribuição de dados subjacente
46
+ - $\mathbf{x}_i \in \mathbb{R}^m$ são features de entrada
47
+ - $y_i \in \mathcal{Y}$ são targets (contínuos ou discretos)
48
+ - $\theta$ são parâmetros do modelo (e.g., pesos de rede neural)
49
+ """)
50
+
51
+ # Fundamentos de otimização
52
+ st.markdown("#### Algoritmo: Gradiente Descendente (GD)")
53
+ st.latex(r"""
54
+ \begin{aligned}
55
+ &\textbf{Input: } \theta_0 \text{ (inicialização)}, \eta > 0 \text{ (taxa aprendizado)}, T \\
56
+ &\textbf{For } t = 0 \text{ to } T-1: \\
57
+ &\quad g_t = \nabla_\theta \hat{\mathcal{L}}(\theta_t) = \frac{1}{N} \sum_{i=1}^N \nabla_\theta \ell(f_{\theta_t}(\mathbf{x}_i), y_i) \\
58
+ &\quad \theta_{t+1} = \theta_t - \eta g_t
59
+ \end{aligned}
60
+ """)
61
+
62
+ st.markdown("#### Formulação Estocástica (SGD)")
63
+ st.latex(r"""
64
+ \begin{aligned}
65
+ &\textbf{Input: } \theta_0, \eta > 0, T, \text{ tamanho lote } B \\
66
+ &\textbf{For } t = 0 \text{ to } T-1: \\
67
+ &\quad \text{Selecione } \mathcal{B}_t \subset \{1,\dots,N\} \text{ com } |\mathcal{B}_t| = B \\
68
+ &\quad \tilde{g}_t = \frac{1}{B} \sum_{i \in \mathcal{B}_t} \nabla_\theta \ell(f_{\theta_t}(\mathbf{x}_i), y_i) \\
69
+ &\quad \theta_{t+1} = \theta_t - \eta \tilde{g}_t
70
+ \end{aligned}
71
+ """)
72
+
73
+ # Análise de convergência
74
+ st.markdown("### Convergência")
75
+ st.latex(r"""
76
+ \text{Sob as condições:} \\
77
+ \begin{array}{ll}
78
+ (1) & \mathcal{L} \text{ é } \mu\text{-fortemente convexa} \\
79
+ (2) & \mathbb{E}[\|\nabla_\theta \ell(\cdot)\|^2_2] \leq G^2 \\
80
+ (3) & \eta_t = \frac{c}{t} \text{ (decay de taxa de aprendizado)}
81
+ \end{array}
82
+ """)
83
+ st.latex(r"""
84
+ \text{GD atinge:} \\
85
+ \mathcal{L}(\theta_T) - \mathcal{L}(\theta^*) \leq \mathcal{O}\left(\frac{1}{T}\right)
86
+ """)
87
+ st.latex(r"""
88
+ \text{SGD atinge:} \\
89
+ \mathbb{E}[\mathcal{L}(\theta_T)] - \mathcal{L}(\theta^*) \leq \mathcal{O}\left(\frac{1}{\sqrt{T}}\right)
90
+ """)
91
+
92
+ # Exemplo numérico
93
+ st.markdown("### 🔢 Exemplo Numérico")
94
+ st.markdown("Considere regressão linear com perda MSE:")
95
+ st.latex(r"""
96
+ \ell(f_\theta(\mathbf{x}), y) = \frac{1}{2} (\theta^\top \mathbf{x} - y)^2
97
+ """)
98
+ st.markdown("Gradiente para um único ponto:")
99
+ st.latex(r"""
100
+ \nabla_\theta \ell = (\theta^\top \mathbf{x} - y) \mathbf{x}
101
+ """)
102
+
103
+ st.markdown("Atualização de GD em tempo real:")
104
+ theta = st.slider("Parâmetro θ", -2.0, 2.0, 0.5, 0.1)
105
+ eta = st.slider("Taxa aprendizado η", 0.01, 1.0, 0.1, 0.01)
106
+
107
+ # Cálculo de exemplo
108
+ x, y = 2.0, 3.0 # Dado fixo para demonstração
109
+ loss = 0.5 * (theta*x - y)**2
110
+ gradient = (theta*x - y)*x
111
+ new_theta = theta - eta*gradient
112
+
113
+ st.latex(fr"""
114
+ \begin{{aligned}}
115
+ \theta^{{(t)}} &= {theta:.2f} \\
116
+ \nabla_\theta \mathcal{{L}} &= ({theta:.2f} \times {x} - {y}) \times {x} = {gradient:.2f} \\
117
+ \theta^{{(t+1)}} &= {theta:.2f} - {eta} \times {gradient:.2f} = {new_theta:.2f}
118
+ \end{{aligned}}
119
+ """)
120
+
121
+ with tab2:
122
+ st.markdown("## Aprendizado Federado: Fundamentos Teóricos")
123
+
124
+ # Definição formal do problema
125
+ st.markdown("### Formulação Matemática do Problema")
126
+ st.latex(r"""
127
+ \begin{aligned}
128
+ &\text{Dado:} \\
129
+ &\quad \text{Clientes } k = 1, \dots, K \text{ com conjuntos de dados locais } \mathcal{D}_k = \{(\mathbf{x}_i^k, y_i^k)\}_{i=1}^{n_k} \\
130
+ &\quad \text{Modelo paramétrico } f_\theta: \mathcal{X} \to \mathcal{Y} \\
131
+ &\quad \text{Função perda } \ell: \mathcal{Y} \times \mathcal{Y} \to \mathbb{R}^+ \\
132
+ \\
133
+ &\text{Objetivo Federado:} \\
134
+ &\quad \min_{\theta \in \mathbb{R}^d} \mathcal{L}(\theta) = \sum_{k=1}^K \frac{n_k}{n} \mathcal{L}_k(\theta) \\
135
+ &\quad \text{onde } \mathcal{L}_k(\theta) = \frac{1}{n_k} \sum_{i=1}^{n_k} \ell(f_\theta(\mathbf{x}_i^k), y_i^k) \\
136
+ &\quad n = \sum_{k=1}^K n_k \quad \text{(tamanho total do dataset)}
137
+ \end{aligned}
138
+ """)
139
+
140
+ st.markdown("""
141
+ Onde:
142
+ - $\mathcal{D}_k$ permanece localizado no dispositivo do cliente $k$
143
+ - $n_k$ é o número de amostras do cliente $k$
144
+ - O objetivo global é uma média ponderada dos objetivos locais
145
+ """)
146
+
147
+ # Algoritmo FedAvg detalhado
148
+ st.markdown("### Algoritmo Federado: FedAvg (Federated Averaging)")
149
+ st.latex(r"""
150
+ \begin{aligned}
151
+ 1. & \textbf{Inicialização:} \\
152
+ & \quad \theta^{(0)} \leftarrow \text{parâmetros iniciais} \\
153
+ 2. & \textbf{for } t = 0 \text{ to } T-1 \textbf{ do:} \\
154
+ 3. & \quad \text{Servidor seleciona subconjunto } S_t \subseteq \{1,\dots,K\} \\
155
+ 4. & \quad \text{Servidor transmite } \theta^{(t)} \text{ para todos os clientes } k \in S_t \\
156
+ 5. & \quad \textbf{for cada cliente } k \in S_t \textbf{ paralelamente do:} \\
157
+ 6. & \quad\quad \theta_k^{(t,0)} \leftarrow \theta^{(t)} \\
158
+ 7. & \quad\quad \textbf{for } \tau = 0 \text{ to } E-1 \textbf{ do:} \\
159
+ 8. & \quad\quad\quad \text{Selecione lote } \mathcal{B}_{\tau}^k \subseteq \mathcal{D}_k \\
160
+ 9. & \quad\quad\quad g_k^{(\tau)} = \frac{1}{|\mathcal{B}_{\tau}^k|} \sum_{(\mathbf{x},y)\in\mathcal{B}_{\tau}^k} \nabla_\theta \ell(f_{\theta_k^{(t,\tau)}}(\mathbf{x}), y) \\
161
+ 10. & \quad\quad\quad \theta_k^{(t,\tau+1)} = \theta_k^{(t,\tau)} - \eta_k g_k^{(\tau)} \\
162
+ 11. & \quad\quad \text{Cliente } k \text{ envia } \Delta_k^{(t)} = \theta_k^{(t,E)} - \theta^{(t)} \text{ para servidor} \\
163
+ 12. & \quad \text{Servidor atualiza: } \\
164
+ & \quad\quad \theta^{(t+1)} = \theta^{(t)} + \sum_{k \in S_t} \frac{n_k}{\sum_{j \in S_t} n_j} \Delta_k^{(t)}
165
+ \end{aligned}
166
+ """)
167
+
168
+ st.markdown("""
169
+ Parâmetros-chave:
170
+ - $E$: Número de épocas locais
171
+ - $\eta_k$: Taxa de aprendizado do cliente $k$
172
+ - $S_t$: Subconjunto de clientes na rodada $t$
173
+ - $\Delta_k^{(t)}$: Atualização do cliente $k$
174
+ """)
175
+
176
+ # Diagrama de arquitetura
177
+ st.markdown("### Arquitetura do Sistema Federado")
178
+ st.image("./images/fedlr_diagram.png", width=700)
179
+ st.markdown("""
180
+ Fluxo de operação:
181
+ 1. Servidor inicializa modelo global $\theta^{(0)}$
182
+ 2. A cada rodada $t$:
183
+ a. Servidor seleciona subconjunto de clientes $S_t$
184
+ b. Envia modelo global atual para clientes selecionados
185
+ c. Cada cliente atualiza modelo localmente com seus dados
186
+ d. Clientes enviam atualizações de parâmetros para servidor
187
+ e. Servidor agrega atualizações e calcula novo modelo global
188
+ """)
189
+
190
+ # Teoria de convergência
191
+ st.markdown("### Análise de Convergência")
192
+ st.markdown("#### Hipóteses Fundamentais")
193
+ st.latex(r"""
194
+ \begin{array}{ll}
195
+ \text{(A1)} & \mathcal{L} \text{ é } L\text{-suave: } \|\nabla\mathcal{L}(\theta) - \nabla\mathcal{L}(\theta')\| \leq L\|\theta - \theta'\| \\
196
+ \text{(A2)} & \text{Variância limitada: } \mathbb{E}_{k} \|\nabla\mathcal{L}_k(\theta) - \nabla\mathcal{L}(\theta)\|^2 \leq \sigma^2 \\
197
+ \text{(A3)} & \text{Conjunto de dados não-IID: } \exists \delta \geq 0 \text{ tal que } \frac{1}{K}\sum_{k=1}^K \|\nabla\mathcal{L}_k(\theta) - \nabla\mathcal{L}(\theta)\|^2 \leq \delta^2 \\
198
+ \text{(A4)} & \text{Gradiente limitado: } \mathbb{E} \|g_k^{(\tau)}\|^2 \leq G^2
199
+ \end{array}
200
+ """)
201
+
202
+ st.markdown("#### Teorema de Convergência (FedAvg)")
203
+ st.latex(r"""
204
+ \text{Sob as hipóteses (A1)-(A4), com } \eta_k = \eta \text{ e seleção uniforme de clientes:}
205
+ """)
206
+ st.latex(r"""
207
+ \min_{t \in \{0,\dots,T-1\}} \mathbb{E} \|\nabla \mathcal{L}(\theta^{(t)})\|^2 \leq \mathcal{O}\left( \frac{\mathcal{L}(\theta^{(0)}) - \mathcal{L}^*}{\eta E T} \right) + \mathcal{O}\left( \frac{\sigma^2}{M} \right) + \mathcal{O}\left( \eta^2 E^2 G^2 L^2 \right) + \mathcal{O}(\delta^2)
208
+ """)
209
+ st.markdown("""
210
+ Onde:
211
+ - $M = |S_t|$ (tamanho do subconjunto de clientes)
212
+ - $\mathcal{L}^*$ é o valor ótimo da função de perda
213
+ - $\delta$ mede o grau de heterogeneidade dos dados
214
+ """)
215
+
216
+ # Desafios técnicos detalhados
217
+ st.markdown("### Desafios Técnicos e Soluções")
218
+
219
+ st.markdown("#### 1. Heterogeneidade de Dados (não-IID)")
220
+ st.latex(r"""
221
+ \text{Definição: } \exists k \neq j: \mathbb{P}_k(\mathbf{x}, y) \neq \mathbb{P}_j(\mathbf{x}, y)
222
+ """)
223
+ st.latex(r"""
224
+ \text{Problemas: }\\
225
+ \text{Viés na agregação: } \mathbb{E}[\theta^{(t+1)}] \neq \theta_{\text{ótimo}}\\
226
+ \text{Divergência do modelo: } \|\theta^{(t)} - \theta^*\| \text{ cresce com t}\\
227
+
228
+ \text{Soluções teóricas: }\\
229
+ \text{1. Regularização proximal: } \min_\theta \mathcal{L}_k(\theta) + \frac{\mu}{2} \|\theta - \theta^{(t)}\|^2\\
230
+ \text{2. Controle de variância: } \Delta_k^{(t)} \leftarrow \Delta_k^{(t)} - \beta (\Delta_k^{(t)} - \Delta^{(t-1)})
231
+ """)
232
+
233
+ st.markdown("#### 3. Segurança e Privacidade")
234
+ st.latex(r"""
235
+ \begin{array}{c}
236
+ \text{Ataque: } \Delta_k^{(t)} = \Delta_{\text{malicioso}} \\
237
+ \text{Defesa: } \theta^{(t+1)} = \text{AGG}_{\gamma} \left( \{ \Delta_k^{(t)} \}_{k \in S_t} \right)
238
+ \end{array}
239
+ """)
240
+
241
+ st.latex(r"""
242
+ \text{Mecanismos de defesa: }\\
243
+ \text{2. DP-SGD: } g_k^{(\tau)} \leftarrow \text{Clip}(g_k^{(\tau)}, C) + \mathcal{N}(0, \sigma^2 I)\\
244
+ """)
245
+ st.markdown("""
246
+ O **DP-SGD** adapta o SGD clássico para fornecer garantias de **privacidade diferencial**,
247
+ limitando o impacto de cada amostra e adicionando ruído calibrado.
248
+ """)
249
+
250
+ # 1. Cálculo de gradientes por amostra
251
+ st.markdown("**1. Cálculo de gradientes por amostra**")
252
+ st.latex(r"""
253
+ g_i \;=\; \nabla_\theta \,\ell\bigl(f_\theta(x_i),\,y_i\bigr)
254
+ """)
255
+
256
+ # 2. Clipping de gradientes
257
+ st.markdown("**2. Clipping de gradientes**: limita a norma de cada gradiente a um máximo \(C\).")
258
+ st.latex(r"""
259
+ \bar g_i \;=\; \frac{g_i}{\max\!\bigl(1,\;\|g_i\|/C\bigr)}
260
+ """)
261
+
262
+ # 3. Soma e adição de ruído
263
+ st.markdown("**3. Soma e adição de ruído**: soma os gradientes recortados e adiciona ruído Gaussiano.")
264
+ st.latex(r"""
265
+ \tilde g \;=\; \frac{1}{B}\sum_{i=1}^B \bar g_i \;+\; \mathcal{N}\!\bigl(0,\;\sigma^2 C^2 I\bigr)
266
+ """)
267
+
268
+ # 4. Atualização de parâmetros
269
+ st.markdown("**4. Atualização de parâmetros** realiza o passo de descida de gradiente com o gradiente privatizado.")
270
+ st.latex(r"""
271
+ \theta \;\leftarrow\; \theta \;-\;\eta\,\tilde g
272
+ """)
273
+
274
+ st.markdown("---")
275
+ st.markdown("""
276
+ - **$C$** (clipping norm): controla o máximo de contribuição de uma única amostra.
277
+ - **$\sigma$** (noise multiplier): regula a intensidade do ruído; maior $\sigma$ → mais privacidade (menor $\epsilon$) mas potencialmente pior desempenho.
278
+ - **Moments Accountant**: método eficiente para juntar os gastos de privacidade de cada minibatch.
279
+ """)
280
+
281
+ # Comparação com aprendizado centralizado
282
+ st.markdown("### Comparação Teórica: Federado vs Centralizado")
283
+ st.latex(r"""
284
+ \begin{array}{c|c|c}
285
+ \text{Propriedade} & \text{Centralizado} & \text{Federado} \\
286
+ \hline
287
+ \text{Acesso aos dados} & \text{Completo} & \text{Nenhum} \\
288
+ \text{Comunicação} & \mathcal{O}(N \times d) & \mathcal{O}(T \times |S_t| \times d) \\
289
+ \text{Convergência} & \mathcal{O}(1/T) & \mathcal{O}(1/\sqrt{T}) \\
290
+ \text{Privacidade} & \text{Baixa} & \text{Alta (com DP)} \\
291
+ \text{Robustez} & \text{Alta} & \text{Controlável} \\
292
+ \text{Escalabilidade} & \text{Limitada} & \text{Alta}
293
+ \end{array}
294
+ """)
295
+ st.markdown("""
296
+ Onde:
297
+ - $d$: Dimensão dos parâmetros do modelo
298
+ - $N$: Número total de amostras de dados
299
+ - $T$: Número de rodadas de comunicação
300
+ """)
301
+
302
+ st.markdown("""
303
+ **Benefícios do aprendizado federado:**
304
+ - Preserva privacidade dos padrões de consumo
305
+ - Reduz tráfego de rede (dados permanecem locais)
306
+ - Permite personalização local do modelo
307
+ """)
308
+
309
+ with tab3:
310
+ st.title("Aprendizado Federado para Previsão de Demanda Energética")
311
+
312
+ col1, col2 = st.columns(2)
313
+
314
+ with col1:
315
+ st.image("images/federated_learning.png", caption="Conceito de Aprendizado Federado")
316
+
317
+ with col2:
318
+ st.markdown("""
319
+ O Aprendizado Federado (FL) é um paradigma de aprendizado de máquina onde o modelo é treinado em múltiplos dispositivos descentralizados sem compartilhar os dados locais. Isso oferece:
320
+
321
+ - **Privacidade de dados**: Os dados nunca saem dos dispositivos locais
322
+ - **Eficiência de comunicação**: Apenas parâmetros do modelo são compartilhados
323
+ - **Treinamento colaborativo**: Múltiplos dispositivos contribuem para um modelo global
324
+ - **Conformidade regulatória**: Ajuda no cumprimento de leis como LGPD e GDPR
325
+ """)
326
+
327
+ st.markdown("""
328
+ O aprendizado federado é especialmente adequado para prever a demanda energética porque:
329
+
330
+ - Permite análise de dados sensíveis de consumo sem expô-los
331
+ - Possibilita a colaboração entre múltiplos consumidores/medidores
332
+ - Reduz o tráfego de rede ao evitar a transferência de dados brutos
333
+ - Permite treinamento em dispositivos de borda (edge computing)
334
+ - Pode aperceiçoar modelos atuais que utilizam análise centralizada de dados
335
+
336
+ ## Objetivos do Projeto
337
+
338
+ 1. Implementar um sistema de aprendizado federado usando Flower
339
+ 2. Aplicar técnicas avançadas de agregação para otimizar o aprendizado
340
+ 3. Integrar com dispositivos Raspberry Pi para coleta de dados em tempo real
341
+ 4. Desenvolver modelos de regressão para previsão de demanda energética
342
+ """)
343
+
344
+ elif secao == "🖥️ Implementação":
345
+ st.title("Implementação de Aprendizado Federado com Flower")
346
+
347
+ steps = st.tabs(["1. Instalação", "2. Estrutura do Projeto", "3. Servidor", "4. Cliente","5. Modelo/Task", "6. Estratégias de Agregação", "7. Execução", '8. pyproject.toml'])
348
+
349
+ with steps[0]:
350
+ st.subheader("Instalação do Flower")
351
+ st.code("""
352
+ # Instalação via pip
353
+ pip install flwr
354
+ flwr new
355
+ flwr run -e . # instala as dependências que vem no arquivo pyproject.toml
356
+ flwr run .
357
+
358
+ """, language="bash")
359
+
360
+ st.info("No caso de ambientes virtuais para isolar as dependências:")
361
+ st.code("""
362
+ # Criar e ativar ambiente virtual
363
+ python -m venv fl_env
364
+ source fl_env/bin/activate # Linux/Mac
365
+ fl_env\\Scripts\\activate # Windows
366
+ """, language="bash")
367
+
368
+ with steps[1]:
369
+ st.subheader("Estrutura Básica do Projeto")
370
+ st.code("""
371
+ fl_project/
372
+ ├── server.py # Servidor Flower
373
+ ├── client.py # Implementação do cliente
374
+ ├── model.py # Definição do modelo ML
375
+ ├── data_loader.py # Carregamento e pré-processamento de dados
376
+ ├── utils/
377
+ │ ├── __init__.py
378
+ │ ├── metrics.py # Funções de avaliação de desempenho
379
+ │ └── visualization.py # Visualização de resultados
380
+ ├── config.py # Configurações do sistema
381
+ ├── requirements.txt # Dependências do projeto
382
+ └── run.sh # Script para iniciar servidor e clientes
383
+ |── pyproject.toml # Configurações do projeto e dependências
384
+ """, language="text")
385
+
386
+ with steps[2]:
387
+ st.subheader("Implementação do Servidor")
388
+ st.markdown("""
389
+ O servidor Flower é responsável por coordenar o treinamento, distribuir o modelo global e agregar as atualizações dos clientes.
390
+ """)
391
+
392
+ st.code('''
393
+ from flwr.common import Context, ndarrays_to_parameters
394
+ from flwr.server import ServerApp, ServerAppComponents, ServerConfig
395
+ from flwr.server.strategy import FedAvg
396
+ from fl_inmetro.task import Net, get_weights
397
+
398
+ def server_fn(context: Context):
399
+ # Read from config
400
+ num_rounds = context.run_config["num-server-rounds"]
401
+ fraction_fit = context.run_config["fraction-fit"]
402
+
403
+ # Initialize model parameters
404
+ ndarrays = get_weights(Net())
405
+ parameters = ndarrays_to_parameters(ndarrays)
406
+
407
+ # Define strategy
408
+ strategy = FedAvg(
409
+ fraction_fit=fraction_fit,
410
+ fraction_evaluate=1.0,
411
+ min_available_clients=2,
412
+ initial_parameters=parameters,
413
+ )
414
+ config = ServerConfig(num_rounds=num_rounds)
415
+
416
+ return ServerAppComponents(strategy=strategy, config=config)
417
+
418
+ # Create ServerApp
419
+ app = ServerApp(server_fn=server_fn)
420
+ ''', language="python")
421
+
422
+ with steps[3]:
423
+ st.subheader("Implementação do Cliente")
424
+ st.markdown("""
425
+ O cliente Flower é implementado nos dispositivos onde os dados estão armazenados.
426
+ Ele treina o modelo localmente e envia atualizações para o servidor.
427
+ """)
428
+
429
+ st.code('''
430
+ import torch
431
+ from flwr.client import ClientApp, NumPyClient
432
+ from flwr.common import Context
433
+ from fl_inmetro.task import Net, get_weights, load_data, set_weights, test, train
434
+
435
+ # Define Flower Client and client_fn
436
+ class FlowerClient(NumPyClient):
437
+ def __init__(self, net, trainloader, valloader, local_epochs):
438
+ self.net = net
439
+ self.trainloader = trainloader
440
+ self.valloader = valloader
441
+ self.local_epochs = local_epochs
442
+ self.device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
443
+ self.net.to(self.device)
444
+
445
+ def fit(self, parameters, config):
446
+ set_weights(self.net, parameters)
447
+ train_loss = train(
448
+ self.net,
449
+ self.trainloader,
450
+ self.local_epochs,
451
+ self.device,
452
+ )
453
+ return (
454
+ get_weights(self.net),
455
+ len(self.trainloader.dataset),
456
+ {"train_loss": train_loss},
457
+ )
458
+
459
+ def evaluate(self, parameters, config):
460
+ set_weights(self.net, parameters)
461
+ loss, accuracy = test(self.net, self.valloader, self.device)
462
+ return loss, len(self.valloader.dataset), {"accuracy": accuracy}
463
+
464
+ def client_fn(context: Context):
465
+ # Load model and data
466
+ net = Net()
467
+ partition_id = context.node_config["partition-id"]
468
+ num_partitions = context.node_config["num-partitions"]
469
+ trainloader, valloader = load_data(partition_id, num_partitions)
470
+ local_epochs = context.run_config["local-epochs"]
471
+
472
+ # Return Client instance
473
+ return FlowerClient(net, trainloader, valloader, local_epochs).to_client()
474
+
475
+ # Flower ClientApp
476
+ app = ClientApp(
477
+ client_fn,
478
+ )
479
+ ''', language="python")
480
+
481
+ with steps[4]:
482
+ st.subheader('Modelo/Tarefas')
483
+ st.code(
484
+ """
485
+ from collections import OrderedDict
486
+ import torch
487
+ import torch.nn as nn
488
+ import torch.nn.functional as F
489
+ from flwr_datasets import FederatedDataset
490
+ from flwr_datasets.partitioner import IidPartitioner
491
+ from torch.utils.data import DataLoader
492
+ from torchvision.transforms import Compose, Normalize, ToTensor
493
+
494
+ class Net(nn.Module):
495
+ '''Model (simple CNN adapted from 'PyTorch: A 60 Minute Blitz')'''
496
+
497
+ def __init__(self):
498
+ super(Net, self).__init__()
499
+ self.conv1 = nn.Conv2d(3, 6, 5)
500
+ self.pool = nn.MaxPool2d(2, 2)
501
+ self.conv2 = nn.Conv2d(6, 16, 5)
502
+ self.fc1 = nn.Linear(16 * 5 * 5, 120)
503
+ self.fc2 = nn.Linear(120, 84)
504
+ self.fc3 = nn.Linear(84, 10)
505
+
506
+ def forward(self, x):
507
+ x = self.pool(F.relu(self.conv1(x)))
508
+ x = self.pool(F.relu(self.conv2(x)))
509
+ x = x.view(-1, 16 * 5 * 5)
510
+ x = F.relu(self.fc1(x))
511
+ x = F.relu(self.fc2(x))
512
+ return self.fc3(x)
513
+
514
+ fds = None # Cache FederatedDataset
515
+
516
+ def load_data(partition_id: int, num_partitions: int):
517
+ '''Load partition CIFAR10 data.'''
518
+ # Only initialize `FederatedDataset` once
519
+ global fds
520
+ if fds is None:
521
+ partitioner = IidPartitioner(num_partitions=num_partitions)
522
+ fds = FederatedDataset(
523
+ dataset='uoft-cs/cifar10',
524
+ partitioners={'train': partitioner},
525
+ )
526
+ partition = fds.load_partition(partition_id)
527
+ # Divide data on each node: 80% train, 20% test
528
+ partition_train_test = partition.train_test_split(test_size=0.2, seed=42)
529
+ pytorch_transforms = Compose(
530
+ [ToTensor(), Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]
531
+ )
532
+
533
+ def apply_transforms(batch):
534
+ '''Apply transforms to the partition from FederatedDataset.'''
535
+ batch['img'] = [pytorch_transforms(img) for img in batch['img']]
536
+ return batch
537
+
538
+ partition_train_test = partition_train_test.with_transform(apply_transforms)
539
+ trainloader = DataLoader(partition_train_test['train'], batch_size=32, shuffle=True)
540
+ testloader = DataLoader(partition_train_test['test'], batch_size=32)
541
+ return trainloader, testloader
542
+
543
+ def train(net, trainloader, epochs, device):
544
+ '''Train the model on the training set.'''
545
+ net.to(device) # move model to GPU if available
546
+ criterion = torch.nn.CrossEntropyLoss().to(device)
547
+ optimizer = torch.optim.Adam(net.parameters(), lr=0.01)
548
+ net.train()
549
+ running_loss = 0.0
550
+ for _ in range(epochs):
551
+ for batch in trainloader:
552
+ images = batch['img']
553
+ labels = batch['label']
554
+ optimizer.zero_grad()
555
+ loss = criterion(net(images.to(device)), labels.to(device))
556
+ loss.backward()
557
+ optimizer.step()
558
+ running_loss += loss.item()
559
+
560
+ avg_trainloss = running_loss / len(trainloader)
561
+ return avg_trainloss
562
+
563
+ def test(net, testloader, device):
564
+ '''Validate the model on the test set.'''
565
+ net.to(device)
566
+ criterion = torch.nn.CrossEntropyLoss()
567
+ correct, loss = 0, 0.0
568
+ with torch.no_grad():
569
+ for batch in testloader:
570
+ images = batch['img'].to(device)
571
+ labels = batch['label'].to(device)
572
+ outputs = net(images)
573
+ loss += criterion(outputs, labels).item()
574
+ correct += (torch.max(outputs.data, 1)[1] == labels).sum().item()
575
+ accuracy = correct / len(testloader.dataset)
576
+ loss = loss / len(testloader)
577
+ return loss, accuracy
578
+
579
+ def get_weights(net):
580
+ return [val.cpu().numpy() for _, val in net.state_dict().items()]
581
+
582
+ def set_weights(net, parameters):
583
+ params_dict = zip(net.state_dict().keys(), parameters)
584
+ state_dict = OrderedDict({k: torch.tensor(v) for k, v in params_dict})
585
+ net.load_state_dict(state_dict, strict=True)
586
+ """, language="python"
587
+ )
588
+
589
+ with steps[5]:
590
+ st.subheader("Estratégias de Agregação")
591
+
592
+ st.markdown("""
593
+ O Flower oferece várias estratégias de agregação para combinar as atualizações dos clientes:
594
+ """)
595
+
596
+ strategy_tabs = st.tabs(["FedAvg", "FedAdagrad", "FedAdam", "FedYogi", "Personalizada",'Link para mais estratégias'])
597
+
598
+ with strategy_tabs[0]:
599
+ st.markdown("""
600
+ ### Federated Averaging (FedAvg)
601
+
602
+ O FedAvg é a estratégia mais comum, que realiza uma média ponderada dos parâmetros do modelo com base no número de amostras em cada cliente.
603
+ """)
604
+
605
+ st.image("./images/fedavg.png")
606
+ st.markdown("[McMaham et al. 2023. Communication-Efficient Learning of Deep Networks from Decentralized Data](https://arxiv.org/pdf/1602.05629)")
607
+
608
+ st.code("""
609
+ # Implementação do FedAvg no servidor
610
+ strategy = fl.server.strategy.FedAvg(
611
+ fraction_fit=1.0, # Fração de clientes usados em cada round
612
+ min_fit_clients=min_clients, # Mínimo de clientes para iniciar o treino
613
+ min_available_clients=min_clients, # Mínimo de clientes necessários
614
+ )
615
+ """, language="python")
616
+
617
+ with strategy_tabs[1]:
618
+ st.markdown("""
619
+ ### FedAdagrad
620
+
621
+ O FedAdagrad adapta o algoritmo Adagrad para o cenário federado, ajustando as taxas de aprendizado com base em gradientes anteriores.
622
+ """)
623
+
624
+ st.image('./images/FedAdaGrad-Yogi-Adam.png')
625
+ st.markdown("[Reddi et al. DAPTIVE FEDERATED OPTIMIZATION](https://arxiv.org/pdf/2003.00295)")
626
+
627
+ st.code("""
628
+ # Implementação do FedAdagrad no servidor
629
+ strategy = fl.server.strategy.FedAdagrad(
630
+ fraction_fit=1.0,
631
+ min_fit_clients=min_clients,
632
+ min_available_clients=min_clients,
633
+ eta=0.1, # Taxa de aprendizado do servidor
634
+ eta_l=0.01, # Taxa de aprendizado do cliente
635
+ )
636
+ """, language="python")
637
+
638
+ with strategy_tabs[2]:
639
+ st.markdown("""
640
+ ### FedAdam
641
+
642
+ O FedAdam adapta o otimizador Adam para o cenário federado, incorporando momentos para melhorar a convergência.
643
+ """)
644
+
645
+ st.image('./images/FedAdaGrad-Yogi-Adam.png')
646
+ st.markdown("[Reddi et al. DAPTIVE FEDERATED OPTIMIZATION](https://arxiv.org/pdf/2003.00295)")
647
+
648
+ st.code("""
649
+ # Implementação do FedAdam no servidor
650
+ strategy = fl.server.strategy.FedAdam(
651
+ fraction_fit=1.0,
652
+ min_fit_clients=min_clients,
653
+ min_available_clients=min_clients,
654
+ eta=0.1, # Taxa de aprendizado do servidor
655
+ eta_l=0.01, # Taxa de aprendizado do cliente
656
+ beta_1=0.9, # Decaimento exponencial para momentos de primeira ordem
657
+ beta_2=0.99, # Decaimento exponencial para momentos de segunda ordem
658
+ )
659
+ """, language="python")
660
+
661
+ with strategy_tabs[3]:
662
+ st.markdown("""
663
+ ### FedYogi
664
+
665
+ O FedYogi é uma variante do FedAdam que utiliza uma atualização diferente para os momentos de segunda ordem para melhor lidar com dados não IID.
666
+ """)
667
+
668
+ st.image('./images/FedAdaGrad-Yogi-Adam.png')
669
+ st.markdown("[Reddi et al. DAPTIVE FEDERATED OPTIMIZATION](https://arxiv.org/pdf/2003.00295)")
670
+
671
+ st.code("""
672
+ # Implementação do FedYogi no servidor
673
+ strategy = fl.server.strategy.FedYogi(
674
+ fraction_fit=1.0,
675
+ min_fit_clients=min_clients,
676
+ min_available_clients=min_clients,
677
+ eta=0.1, # Taxa de aprendizado do servidor
678
+ eta_l=0.01, # Taxa de aprendizado do cliente
679
+ beta_1=0.9, # Decaimento exponencial para momentos de primeira ordem
680
+ beta_2=0.99, # Decaimento exponencial para momentos de segunda ordem
681
+ tau=0.001, # Parâmetro de controle para atualização
682
+ )
683
+ """, language="python")
684
+
685
+ with strategy_tabs[4]:
686
+ st.markdown("""
687
+ ### Estratégia Personalizada
688
+ """)
689
+
690
+ st.code('''
691
+ # Estratégia personalizada para agregação
692
+ class MyStrategy(fl.server.strategy.FedAvg):
693
+ ''', language="python")
694
+
695
+ with strategy_tabs[5]:
696
+ st.markdown("""
697
+ ### Link para mais estratégias
698
+
699
+ Mais estratégias de agregação disponíveis na [documentação oficial](https://flower.dev/docs/strategies.html).
700
+
701
+ Link das opções de partição de dados: [Flower Partitioner](https://flower.ai/docs/datasets/ref-api/flwr_datasets.partitioner.html)
702
+ """)
703
+
704
+ with steps[6]:
705
+ st.subheader("Executando o Sistema")
706
+
707
+ st.markdown("""
708
+ Para executar o sistema de aprendizado federado, precisa iniciar o servidor e os clientes:
709
+ """)
710
+
711
+ st.code("""
712
+ # Iniciar o servidor
713
+ python server.py --rounds 10 --min_clients 3 --port 8080
714
+
715
+ # Em terminais diferentes, iniciar os clientes
716
+ python client.py --partition 0 --num_partitions 3 --server 127.0.0.1:8080
717
+ python client.py --partition 1 --num_partitions 3 --server 127.0.0.1:8080
718
+ python client.py --partition 2 --num_partitions 3 --server 127.0.0.1:8080
719
+ """, language="bash")
720
+
721
+ st.markdown("""
722
+ Alternativamente, dá para criar um script para automatizar este processo:
723
+ """)
724
+
725
+ st.code("""
726
+ #!/bin/bash
727
+ # run.sh
728
+
729
+ # Inicia o servidor em background
730
+ python server.py --rounds 10 --min_clients 3 --port 8080 &
731
+ SERVER_PID=$!
732
+
733
+ # Espera o servidor iniciar
734
+ sleep 2
735
+
736
+ # Inicia os clientes
737
+ for i in $(seq 0 2); do
738
+ python client.py --partition $i --num_partitions 3 --server 127.0.0.1:8080 &
739
+ CLIENT_PIDS[$i]=$!
740
+ done
741
+
742
+ # Espera pelo término do servidor
743
+ wait $SERVER_PID
744
+
745
+ # Mata os processos dos clientes se ainda estiverem rodando
746
+ for pid in "${CLIENT_PIDS[@]}"; do
747
+ kill -0 $pid 2>/dev/null && kill $pid
748
+ done
749
+ """, language="bash")
750
+ with steps[7]:
751
+ st.subheader("Arquivo pyproject.toml")
752
+
753
+ st.markdown("""
754
+ O arquivo `pyproject.toml` é usado para gerenciar as dependências do projeto e configurações do ambiente.
755
+ """)
756
+
757
+ st.code("""
758
+ [build-system]
759
+ requires = ["hatchling"]
760
+ build-backend = "hatchling.build"
761
+
762
+ [project]
763
+ name = "fl-inmetro"
764
+ version = "1.0.0"
765
+ description = ""
766
+ license = "Apache-2.0"
767
+ dependencies = [
768
+ "flwr[simulation]>=1.18.0",
769
+ "flwr-datasets[vision]>=0.5.0",
770
+ "torch==2.5.1",
771
+ "torchvision==0.20.1",
772
+ ]
773
+
774
+ [tool.hatch.build.targets.wheel]
775
+ packages = ["."]
776
+
777
+ [tool.flwr.app]
778
+ publisher = "jwsouza"
779
+
780
+ [tool.flwr.app.components]
781
+ serverapp = "fl_inmetro.server_app:app"
782
+ clientapp = "fl_inmetro.client_app:app"
783
+
784
+ [tool.flwr.app.config]
785
+ num-server-rounds = 3
786
+ fraction-fit = 0.5
787
+ local-epochs = 1
788
+
789
+ [tool.flwr.federations]
790
+ default = "local-simulation"
791
+
792
+ [tool.flwr.federations.local-simulation]
793
+ options.num-supernodes = 10
794
+
795
+ """, language="toml")
796
+
797
+ elif secao == "📊 Visualização":
798
+ st.title("Processo de Aprendizado Federado")
799
+
800
+ # visualization_tabs = st.tabs(["Animação do Processo FL", "Convergência do Modelo", "Desempenho por Cliente", "Comparação de Estratégias"])
801
+
802
+ # with visualization_tabs[0]:
803
+
804
+ # Criando um gráfico interativo com Plotly
805
+ fig = go.Figure()
806
+
807
+ # Nós
808
+ server_pos = [5, 10]
809
+ client_positions = [[2, 5], [5, 5], [8, 5]]
810
+ data_positions = [[2, 0], [5, 0], [8, 0]]
811
+
812
+ # Adicionando nós
813
+ fig.add_trace(go.Scatter(
814
+ x=[server_pos[0]],
815
+ y=[server_pos[1]],
816
+ mode='markers+text',
817
+ marker=dict(symbol='square', size=40, color='red'),
818
+ text=['Servidor'],
819
+ textposition='top center',
820
+ name='Servidor'
821
+ ))
822
+
823
+ fig.add_trace(go.Scatter(
824
+ x=[pos[0] for pos in client_positions],
825
+ y=[pos[1] for pos in client_positions],
826
+ mode='markers+text',
827
+ marker=dict(symbol='circle', size=30, color='green'),
828
+ text=['Cliente 1', 'Cliente 2', 'Cliente 3'],
829
+ textposition='middle right',
830
+ name='Clientes'
831
+ ))
832
+
833
+ fig.add_trace(go.Scatter(
834
+ x=[pos[0] for pos in data_positions],
835
+ y=[pos[1] for pos in data_positions],
836
+ mode='markers+text',
837
+ marker=dict(symbol='diamond', size=20, color='blue'),
838
+ text=['Dados 1', 'Dados 2', 'Dados 3'],
839
+ textposition='bottom center',
840
+ name='Dados'
841
+ ))
842
+
843
+ # Adicionando linhas de conexão
844
+ for i, client_pos in enumerate(client_positions):
845
+ # Linha do servidor para o cliente (modelo global)
846
+ fig.add_trace(go.Scatter(
847
+ x=[server_pos[0], client_pos[0]],
848
+ y=[server_pos[1], client_pos[1]],
849
+ mode='lines+text',
850
+ line=dict(width=2, color='red', dash='dash'),
851
+ text=['Modelo Global'],
852
+ textposition='top right',
853
+ showlegend=False
854
+ ))
855
+
856
+ # Linha do cliente para o servidor (atualizações)
857
+ fig.add_trace(go.Scatter(
858
+ x=[client_pos[0], server_pos[0]],
859
+ y=[client_pos[1], server_pos[1]],
860
+ mode='lines+text',
861
+ line=dict(width=2, color='green', dash='dot'),
862
+ text=['Atualizações'],
863
+ textposition='bottom left',
864
+ showlegend=False
865
+ ))
866
+
867
+ # Linha dos dados para o cliente (treino local)
868
+ fig.add_trace(go.Scatter(
869
+ x=[data_positions[i][0], client_pos[0]],
870
+ y=[data_positions[i][1], client_pos[1]],
871
+ mode='lines+text',
872
+ line=dict(width=2, color='blue'),
873
+ text=['Treino Local'],
874
+ textposition='middle left',
875
+ showlegend=False
876
+ ))
877
+
878
+ # Layout
879
+ fig.update_layout(
880
+ title='Fluxo de Aprendizado Federado Interativo',
881
+ xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
882
+ yaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
883
+ width=800,
884
+ height=500,
885
+ legend=dict(x=0, y=1),
886
+ hovermode='closest'
887
+ )
888
+
889
+ st.plotly_chart(fig)
890
+
891
+ if secao == "📈 Modelos para EVs":
892
+
893
+ st.caption("Zhang et al. (2024). Modelos de Consumo de Energia para Veículos Elétricos em Transporte Urbano. Renewable Energy")
894
+
895
+ st.markdown("""
896
+ **Objetivo**: Prever consumo energético (CE) de VEs em cenários urbanos:
897
+ """)
898
+ st.latex(r"""
899
+ \min_{\theta} \mathcal{L}(\theta) = \mathbb{E}_{(\mathbf{x},y) \sim \mathcal{P}} [\ell(f_\theta(\mathbf{x}), y)]
900
+ """)
901
+
902
+ st.markdown("""
903
+ Onde:
904
+ - $y$: consumo energético observado
905
+ - $f_\theta$: modelo de previsão
906
+ """)
907
+
908
+ st.header("Abordagens Tradicionais")
909
+ st.subheader("Modelos de Dinâmica Veicular")
910
+ st.latex(r"""
911
+ F_t = \underbrace{\delta Ma}_{\text{Inércia}} + \underbrace{Mg\sin\alpha}_{\text{Inclinação}} + \underbrace{Mg f \cos\alpha}_{\text{Rolamento}} + \underbrace{\frac{1}{2}\rho C_d A v^2}_{\text{Aerodinâmica}}
912
+ """)
913
+ st.latex(r"""
914
+ P_{\text{total}} = (F_t \cdot v)/\eta_{\text{motor}} + P_{\text{aux}}
915
+ """)
916
+ st.markdown("""
917
+ **Limitações**:
918
+ - Requer 12+ parâmetros específicos (Tabela 1)
919
+ - Não captura efeitos não-lineares em condições urbanas complexas
920
+ """)
921
+
922
+ st.subheader("Modelos Estatísticos")
923
+ st.latex(r"""
924
+ \text{CE} = \beta_0 + \sum_{i=1}^k \beta_i X_i + \epsilon \quad \text{(Regressão Linear)}
925
+ """)
926
+ st.latex(r"""
927
+ \text{UEC}(BDR) = a_0 + a_1 \cdot BDR + a_2 \cdot BDR^2 \quad \text{(Degradação de Bateria)}
928
+ """)
929
+ st.markdown("""
930
+ **Problemas**: Pressupõe relações lineares e não considera interações complexas entre variáveis
931
+ """)
932
+
933
+ st.subheader("Modelos Principais")
934
+ st.markdown("""
935
+ - **XGBoost/LightGBM**:
936
+ """)
937
+ st.latex(r"""
938
+ \mathcal{L}^{(t)} = \sum_{i=1}^n \ell(y_i, \hat{y}_i^{(t-1)} + f_t(\mathbf{x}_i)) + \Omega(f_t)
939
+ """)
940
+ st.markdown("""
941
+ - **Random Forest**: Média de $B$ árvores de decisão
942
+ """)
943
+
944
+ st.header("Redes Neurais para Alta Precisão")
945
+ st.markdown("""
946
+ **LSTM**:
947
+ """)
948
+ st.latex(r"""
949
+ \begin{aligned}
950
+ i_t &= \sigma(W_{ix} x_t + W_{ih} h_{t-1} + b_i) \\
951
+ c_t &= f_t \odot c_{t-1} + i_t \odot \tanh(W_{cx} x_t + W_{ch} h_{t-1} + b_c) \\
952
+ h_t &= o_t \odot \tanh(c_t)
953
+ \end{aligned}
954
+ """)
955
+ st.markdown("""
956
+ **Transformer**:
957
+ """)
958
+ st.latex(r"""
959
+ \text{Attention}(Q,K,V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
960
+ """)
961
+
962
+ st.subheader("4.2 Desempenho Comparativo")
963
+ st.markdown("""
964
+ | Modelo | RMSE (kWh) | MAPE (%) | Limitações |
965
+ |-----------------|------------|----------|--------------------------|
966
+ | Dinâmica Veicular | 6.06 | 14.10 | Parâmetros fixos |
967
+ | XGBoost | 3.94 | 9.31 | Menor capacidade não-linear |
968
+ | LSTM | 3.61 | 8.69 | Custo computacional alto |
969
+ | Transformer | 2.98 | 7.21 | Dados de treino massivos |
970
+ """)
971
+
972
+ if secao == "🍓 Integração Raspberry Pi":
973
+ st.markdown("""
974
+
975
+ 1. **Configurar acesso SSH**
976
+ - Habilite o SSH no Pi (`raspi-config` → *Interfacing Options* → *SSH*).
977
+ - Anote o endereço IP do Pi na sua rede.
978
+
979
+ 2. **Obter o código-fonte**
980
+ - **Via Git**:
981
+ ```bash
982
+ git clone https://github.com/SEU_USUARIO/SEU_PROJETO.git
983
+ cd SEU_PROJETO
984
+ ```
985
+ - **Via SCP/RSYNC** (se não usar Git):
986
+ ```bash
987
+ scp -r caminho/local/SEU_PROJETO pi@IP_DO_PI:~/SEU_PROJETO
988
+ ```
989
+
990
+ 3. **Instalar dependências no Pi**
991
+ ```bash
992
+ python3 -m venv venv
993
+ source venv/bin/activate
994
+ pip install -r requirements.txt
995
+ ```
996
+
997
+ 4. **Copiar arquivos estáticos**
998
+ - Certifique-se de que a pasta `images/` foi clonada/copied e que os paths relativos estejam corretos.
999
+
1000
+ 5. **Configurar serviço de inicialização**
1001
+ - Crie um serviço systemd em `/etc/systemd/system/fl-client.service` apontando para o comando de execução no seu virtualenv.
1002
+ - Habilite e inicie:
1003
+ ```bash
1004
+ sudo systemctl enable fl-client
1005
+ sudo systemctl start fl-client
1006
+ ```
1007
+
1008
+ 6. **Testar localmente**
1009
+ ```bash
1010
+ source venv/bin/activate
1011
+ python client_pi.py
1012
+ ```
1013
+
1014
+ 7. **Automatizar atualizações**
1015
+ - No CI/CD, adicione um passo para:
1016
+ ```bash
1017
+ ssh pi@IP_DO_PI \
1018
+ 'cd ~/SEU_PROJETO && git pull && source venv/bin/activate && pip install -r requirements.txt && systemctl restart fl-client'
1019
+ ```
1020
+ """, unsafe_allow_html=False)
1021
+
1022
+ if secao == "📚 Artigos":
1023
+
1024
+ st.markdown(
1025
+ """
1026
+ ### Referências
1027
+ - FedAVG
1028
+
1029
+ [McMaham et al. 2023. Communication-Efficient Learning of Deep Networks from Decentralized Data](https://arxiv.org/pdf/1602.05629)
1030
+
1031
+ - ADAGRAD, ADAM, YOGI
1032
+
1033
+ [Reddi et al. DAPTIVE FEDERATED OPTIMIZATION](https://arxiv.org/pdf/2003.00295)
1034
+
1035
+ - Privacdiade e Segurança
1036
+
1037
+ [Bonawitz et al. Practical Secure Aggregation for Privacy-Preserving Machine Learning](https://arxiv.org/pdf/1611.04482)
1038
+
1039
+
1040
+ [Abadi et al. Deep Learning with Differential Privacy](https://arxiv.org/pdf/1607.00133)
1041
+ """
1042
+ )