ajvelasque commited on
Commit
7e4a4be
·
verified ·
1 Parent(s): d198870
README.md ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - qsar
5
+ - cheminformatics
6
+ - drug-discovery
7
+ - machine-learning
8
+ ---
9
+
10
+ # 🧬 About this Model
11
+
12
+ This model was generated and shared through **QSAR IA**, an open-source platform designed to support QSAR studies, machine learning workflows, and scientific collaboration in cheminformatics and pharmaceutical research.
13
+
14
+ ## 👤 Researcher Information
15
+
16
+ - **Researcher:** Ana Julia Velasque
17
+ - **ORCID:** 0009-0006-4627-958X
18
+
19
+ ## 📖 Description
20
+
21
+ This repository contains a predictive model developed using the QSAR IA platform.
22
+
23
+ The model has been published to facilitate scientific reproducibility, collaboration, and reuse by the research community.
24
+
25
+ ## 📚 Citation
26
+
27
+ If you use this model in your research, please cite the associated researcher and/or any related scientific publication.
28
+
29
+ ## 🔬 Scientific Reproducibility
30
+
31
+ This repository is part of the QSAR IA ecosystem, which aims to promote transparent and reproducible computational research in drug discovery and cheminformatics.
32
+
33
+ ## 🚀 About QSAR IA
34
+
35
+ QSAR IA is an open-source platform developed to support the complete lifecycle of QSAR and machine learning projects.
36
+
37
+ Project repository:
38
+
39
+ https://github.com/altobellibm/qsar_ia_project
model/mpl_pequeno_torch/dataset.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Dataset concreto do pipeline ``atualizado`` — dados tabulares + PyTorch.
3
+
4
+ A maior parte da lógica está em :class:`base_dataset.BaseDataset`
5
+ (``docker/base_dataset.py``). Aqui só fica o que é específico:
6
+
7
+ - :py:meth:`build_features` — seleciona colunas numéricas do DataFrame,
8
+ descartando colunas de identificação (``id``, ``image_path``, ...).
9
+ - :py:meth:`get_data_loader` — devolve ``DataLoader`` do PyTorch
10
+ montado em cima dos arrays preparados pela base.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import os
16
+ import sys
17
+ from typing import Optional, Tuple
18
+
19
+ import numpy as np
20
+ import pandas as pd
21
+
22
+ try:
23
+ import torch
24
+ from torch.utils.data import DataLoader, TensorDataset
25
+ _TORCH_AVAILABLE = True
26
+ except ImportError: # pragma: no cover
27
+ _TORCH_AVAILABLE = False
28
+
29
+ # Importa BaseDataset de ../base_dataset.py
30
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
31
+ from base_dataset import BaseDataset # noqa: E402
32
+
33
+
34
+ class TrainingDataset(BaseDataset):
35
+ """Dataset tabular para o pipeline em ``docker/atualizado``."""
36
+
37
+ # ------------------------------------------------------------------
38
+ # Hooks da base
39
+ # ------------------------------------------------------------------
40
+ def build_features(self) -> None:
41
+ if self.df is None:
42
+ raise RuntimeError("self.df está vazio; load_raw_data() não rodou.")
43
+
44
+ # Prioridade: lista explícita no metadata.json
45
+ explicit = self.metadata.get("features")
46
+ if explicit:
47
+ missing = [c for c in explicit if c not in self.df.columns]
48
+ if missing:
49
+ raise ValueError(
50
+ f"Colunas declaradas em metadata['features'] não encontradas no DataFrame: {missing}"
51
+ )
52
+ self.feature_columns = list(explicit)
53
+ self.X = self.df[self.feature_columns].to_numpy(dtype=np.float32)
54
+ return
55
+
56
+ # Fallback: inferência automática de colunas numéricas
57
+ feats = []
58
+ for col in self.df.columns:
59
+ if col == self.target_column:
60
+ continue
61
+ if col.lower() in self.NON_FEATURE_COLS:
62
+ continue
63
+ if not pd.api.types.is_numeric_dtype(self.df[col]):
64
+ continue
65
+ feats.append(col)
66
+
67
+ if not feats:
68
+ raise ValueError(
69
+ "Nenhuma coluna numérica encontrada para usar como feature."
70
+ )
71
+
72
+ self.feature_columns = feats
73
+ self.X = self.df[feats].to_numpy(dtype=np.float32)
74
+
75
+ def get_data_loader(
76
+ self,
77
+ batch_size: int = 32,
78
+ train_ratio: Optional[float] = None,
79
+ seed: Optional[int] = None,
80
+ ) -> Tuple["DataLoader", "DataLoader"]:
81
+ if not _TORCH_AVAILABLE:
82
+ raise RuntimeError(
83
+ "PyTorch não está instalado; instale-o ou use get_arrays()."
84
+ )
85
+
86
+ train_ratio, seed = self._resolve_split_params(train_ratio, seed)
87
+ idx_train, idx_val = self._split_indices(train_ratio, seed)
88
+
89
+ assert self.X is not None and self.y is not None # pra mypy
90
+
91
+ X_train = torch.from_numpy(self.X[idx_train])
92
+ y_train = torch.from_numpy(self.y[idx_train]).long()
93
+ X_val = torch.from_numpy(self.X[idx_val])
94
+ y_val = torch.from_numpy(self.y[idx_val]).long()
95
+
96
+ bs = self._resolve_batch_size(batch_size)
97
+ train_loader = DataLoader(
98
+ TensorDataset(X_train, y_train), batch_size=bs, shuffle=True
99
+ )
100
+ val_loader = DataLoader(
101
+ TensorDataset(X_val, y_val), batch_size=bs, shuffle=False
102
+ )
103
+
104
+ print(
105
+ f" - Train samples: {len(X_train)} | Val samples: {len(X_val)}"
106
+ f" | Batch size: {bs}"
107
+ )
108
+ return train_loader, val_loader
model/mpl_pequeno_torch/help.md ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # RNNs / LSTMs for Sequences
2
+
3
+ ## Resume
4
+ Recurrent Neural Networks (RNNs) and Long Short-Term Memory (LSTM) networks are sequential neural architectures designed to map time-series data or sequential text structures. LSTMs introduce explicit gating mechanisms to regulate internal information persistence, successfully resolving the vanishing gradient flaws of traditional RNN blocks.
5
+
6
+ ### Common Use Cases:
7
+ * **SMILES Generation:** Autoregressively printing valid chemical strings token by token.
8
+ * **Biosignal Analysis:** Evaluating chronological streaming signals from patient telemetry or ECG readouts.
9
+ * **Clinical Notes Sequence Modeling:** Tracking medical event timelines over long EHR spans.
10
+
11
+ ## Content
12
+
13
+ ### 1. Core Architecture & Gated Memory
14
+ Standard RNNs maintain a recurring hidden state vector $h_t$ that gets updated with every timestamp token input. However, backpropagating through long sequences causes gradients to rapidly disappear or explode.
15
+
16
+ LSTMs solve this by introducing an internal **Cell State** ($c_t$) alongside three specialized gating mechanisms:
17
+ * **Forget Gate ($f_t$):** Controls how much historical context from the cell state should be discarded.
18
+ * **Input Gate ($i_t$):** Regulates what new contextual state information should be infused into the current cell vector.
19
+ * **Output Gate ($o_t$):** Determines what subset of internal hidden cell states should be exposed as the final output block.
20
+
21
+ ### 2. Operational Execution Sequence
22
+ As a sequence executes, the architecture reads the token input at step $t$, merges it with the prior step's hidden vector $h_{t-1}$, adjusts cell memories through the gating parameters, and pushes forward the updated state vectors. This linear memory highway allows the architecture to carry context across extended sequence matrices.
23
+
24
+ ### 3. Advantages and Disadvantages
25
+ * **Advantages:**
26
+ * Natural alignment with arbitrary, variable-length chronological or textual stream structures.
27
+ * O(L) computational complexity scaling linearly with sequence length.
28
+ * **Disadvantages:**
29
+ * Strict step-by-step dependency makes parallel sequence acceleration impossible during training.
30
+ * Susceptible to information decay over extremely long sequences compared to attention structures.
31
+
32
+ ### References
33
+ * Hochreiter, S., & Schmidhuber, J. (1997). *Long short-term memory*. Neural Computation.
34
+ * Segler, M. H., et al. (2018). *Generating focused molecule libraries for drug discovery with recurrent neural networks*. ACS Central Science.
model/mpl_pequeno_torch/hyperparameters.json ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "setting": {
3
+ "name": {
4
+ "text": "Nome do modelo",
5
+ "value": "mpl_pequeno_torch",
6
+ "Help": "Identificação do modelo PyTorch tabular. Pode ser usado para salvar checkpoints ou registros.",
7
+ "default": "mpl_pequeno_torch",
8
+ "type": "string",
9
+ "required": true
10
+ },
11
+ "architecture": {
12
+ "text": "Arquitetura do modelo",
13
+ "value": "MLP tabular",
14
+ "Help": "Arquitetura da rede neural para dados tabulares usando PyTorch.",
15
+ "default": "MLP tabular",
16
+ "type": "string",
17
+ "required": true
18
+ },
19
+ "tipo": {
20
+ "text": "Tipo do modelo",
21
+ "value": "classification",
22
+ "Help": "Define o tipo de tarefa do modelo.",
23
+ "default": "classification",
24
+ "type": "string",
25
+ "required": true
26
+ },
27
+ "learning_type": {
28
+ "text": "Tipo de aprendizado",
29
+ "value": "deep_learning",
30
+ "Help": "Indica se o modelo é de machine learning clássico ou deep learning.",
31
+ "default": "deep_learning",
32
+ "type": "string",
33
+ "required": true
34
+ }
35
+ },
36
+ "train": {
37
+ "batch_size": {
38
+ "text": "Tamanho do batch",
39
+ "Help": "Tamanho do batch usado durante o treinamento.",
40
+ "default": 32,
41
+ "range": {
42
+ "min": 1,
43
+ "max": null
44
+ },
45
+ "type": "integer",
46
+ "required": true
47
+ },
48
+ "epochs": {
49
+ "text": "Número de épocas",
50
+ "Help": "Quantidade de épocas de treinamento.",
51
+ "default": 10,
52
+ "range": {
53
+ "min": 1,
54
+ "max": 1000
55
+ },
56
+ "type": "integer",
57
+ "required": true
58
+ },
59
+ "learning_rate": {
60
+ "text": "Taxa de aprendizado",
61
+ "Help": "Taxa usada pelo otimizador.",
62
+ "default": 0.001,
63
+ "range": {
64
+ "min": 0.000001,
65
+ "max": 1.0
66
+ },
67
+ "type": "float",
68
+ "required": true
69
+ },
70
+ "weight_decay": {
71
+ "text": "Decaimento de peso",
72
+ "Help": "Regularização L2 usada pelo otimizador.",
73
+ "default": 0.0001,
74
+ "range": {
75
+ "min": 0.0,
76
+ "max": 0.1
77
+ },
78
+ "type": "float",
79
+ "required": false
80
+ },
81
+ "optimizer": {
82
+ "text": "Otimizador",
83
+ "Help": "Otimizador usado no treinamento.",
84
+ "default": "adam",
85
+ "type": "string",
86
+ "required": true
87
+ },
88
+ "hidden_dims": {
89
+ "text": "Dimensões ocultas",
90
+ "Help": "Lista de camadas ocultas do MLP.",
91
+ "default": [32, 16],
92
+ "type": "list",
93
+ "required": false
94
+ },
95
+ "dropout": {
96
+ "text": "Dropout",
97
+ "Help": "Taxa de dropout aplicada entre camadas.",
98
+ "default": 0.0,
99
+ "range": {
100
+ "min": 0.0,
101
+ "max": 1.0
102
+ },
103
+ "type": "float",
104
+ "required": false
105
+ }
106
+ },
107
+ "test": {
108
+ "batch_size": {
109
+ "text": "Tamanho do batch",
110
+ "Help": "Tamanho do batch usado na avaliação.",
111
+ "default": 64,
112
+ "range": {
113
+ "min": 1,
114
+ "max": null
115
+ },
116
+ "type": "integer",
117
+ "required": true
118
+ }
119
+ },
120
+ "predict": {
121
+ "batch_size": {
122
+ "text": "Tamanho do batch",
123
+ "Help": "Tamanho do batch usado na predição.",
124
+ "default": 64,
125
+ "range": {
126
+ "min": 1,
127
+ "max": null
128
+ },
129
+ "type": "integer",
130
+ "required": true
131
+ }
132
+ }
133
+ }
model/mpl_pequeno_torch/main.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Entrypoint do pipeline ``atualizado`` (MLP tabular em PyTorch).
3
+
4
+ Toda a orquestração (modos train/test/predict, leitura de config,
5
+ escrita dos artefatos) vive em ``docker/base_main.py``. Aqui só
6
+ registramos as peças concretas desta arquitetura:
7
+
8
+ - ``TrainingDataset`` (de :mod:`dataset`)
9
+ - ``create_model`` (de :mod:`model`)
10
+
11
+ Como o input é tabular, o ``predict_input_loader`` default do
12
+ ``base_main`` (que lê CSV/XLSX) já serve — não precisa passar nada.
13
+ Arquiteturas futuras (ex.: CNN para imagem) podem passar um loader
14
+ próprio na chamada de ``run_pipeline``.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import os
20
+ import sys
21
+
22
+ # Permite importar base_main.py de ../
23
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
24
+
25
+ from base_main import run_pipeline # noqa: E402
26
+ from dataset import TrainingDataset # noqa: E402
27
+ from model import create_model # noqa: E402
28
+
29
+
30
+ if __name__ == "__main__":
31
+ sys.exit(
32
+ run_pipeline(
33
+ dataset_cls=TrainingDataset,
34
+ model_factory=create_model,
35
+ )
36
+ )
model/mpl_pequeno_torch/model.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Implementação concreta (PyTorch) do modelo treinado pelo pipeline.
3
+
4
+ Arquitetura: MLP simples para dados tabulares. A configuração de
5
+ camadas, dropout, otimizador, etc. vem de ``config`` (lido do
6
+ ``config.json`` do treino) ou de defaults razoáveis.
7
+
8
+ A classe ``TabularMLP`` herda de ``BaseModel`` (em ``docker/base_model.py``)
9
+ para manter a API uniforme entre frameworks. Uma função ``create_model``
10
+ fábrica é exposta no fim do arquivo para que ``main.py`` continue
11
+ funcionando sem mudanças.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import os
17
+ import sys
18
+ from typing import Any, Dict, List, Optional
19
+
20
+ import numpy as np
21
+ import torch
22
+ import torch.nn as nn
23
+ import torch.optim as optim
24
+ from torch.utils.data import DataLoader
25
+
26
+ # Permite importar base_model.py de ../
27
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
28
+ from base_model import BaseModel # noqa: E402
29
+ from utils import emit_progress # noqa: E402
30
+
31
+
32
+ # ---------------------------------------------------------------------------
33
+ # Arquitetura MLP
34
+ # ---------------------------------------------------------------------------
35
+ class _MLP(nn.Module):
36
+ def __init__(
37
+ self,
38
+ input_size: int,
39
+ hidden_dims: List[int],
40
+ num_classes: int,
41
+ dropout: float = 0.0,
42
+ ) -> None:
43
+ super().__init__()
44
+ layers: List[nn.Module] = []
45
+ prev = input_size
46
+ for h in hidden_dims:
47
+ layers.append(nn.Linear(prev, h))
48
+ layers.append(nn.ReLU())
49
+ if dropout and dropout > 0:
50
+ layers.append(nn.Dropout(dropout))
51
+ prev = h
52
+ layers.append(nn.Linear(prev, num_classes))
53
+ self.net = nn.Sequential(*layers)
54
+
55
+ def forward(self, x: torch.Tensor) -> torch.Tensor: # noqa: D401
56
+ return self.net(x)
57
+
58
+
59
+ # ---------------------------------------------------------------------------
60
+ # Wrapper que implementa a API de BaseModel
61
+ # ---------------------------------------------------------------------------
62
+ class TabularMLP(BaseModel):
63
+ """MLP tabular em PyTorch, plugável no pipeline."""
64
+
65
+ def build_model(self) -> nn.Module:
66
+ hp = self.config.get("hyperparameters", {})
67
+ hidden_dims = self.config.get("hidden_dims") or hp.get("hidden_dims") or [
68
+ self.config.get("hidden_dim1", 32),
69
+ self.config.get("hidden_dim2", 16),
70
+ ]
71
+ dropout = float(hp.get("dropout", self.config.get("dropout", 0.0)))
72
+
73
+ # device
74
+ self.device = torch.device(
75
+ "cuda"
76
+ if torch.cuda.is_available() and self.config.get("use_cuda", True)
77
+ else "cpu"
78
+ )
79
+
80
+ model = _MLP(
81
+ input_size=self.input_size,
82
+ hidden_dims=list(hidden_dims),
83
+ num_classes=self.num_classes,
84
+ dropout=dropout,
85
+ ).to(self.device)
86
+
87
+ self.criterion = nn.CrossEntropyLoss()
88
+ self._hidden_dims = list(hidden_dims)
89
+ self._dropout = dropout
90
+ return model
91
+
92
+ # ---------------- treinamento ----------------
93
+ def train_model(
94
+ self,
95
+ train_loader: DataLoader,
96
+ val_loader: Optional[DataLoader],
97
+ epochs: int,
98
+ lr: float,
99
+ **kwargs: Any,
100
+ ) -> Dict[str, list]:
101
+ hp = self.config.get("hyperparameters", {})
102
+ epochs = int(hp.get("epochs", epochs))
103
+ lr = float(hp.get("learning_rate", lr))
104
+ weight_decay = float(hp.get("weight_decay", 0.0))
105
+ optimizer_name = str(hp.get("optimizer", "adam")).lower()
106
+
107
+ optimizer = self._build_optimizer(optimizer_name, lr, weight_decay)
108
+
109
+ history = {
110
+ "train_loss": [], "train_acc": [],
111
+ "val_loss": [], "val_acc": [],
112
+ }
113
+
114
+ n_batches = max(len(train_loader), 1)
115
+ total_train_steps = max(epochs * n_batches, 1)
116
+ best_val_acc = -float("inf")
117
+ best_epoch = -1
118
+ for epoch in range(1, epochs + 1):
119
+ self.model.train()
120
+ run_loss = 0.0
121
+ correct = 0
122
+ total = 0
123
+ for batch_idx, (X, y) in enumerate(train_loader, start=1):
124
+ X = X.to(self.device)
125
+ y = y.to(self.device)
126
+
127
+ optimizer.zero_grad()
128
+ logits = self.model(X)
129
+ loss = self.criterion(logits, y)
130
+ loss.backward()
131
+ optimizer.step()
132
+
133
+ run_loss += float(loss.item()) * X.size(0)
134
+ preds = logits.argmax(dim=1)
135
+ correct += int((preds == y).sum().item())
136
+ total += int(y.size(0))
137
+
138
+ global_step = (epoch - 1) * n_batches
139
+ inner_pct = int(global_step * 100 / total_train_steps)
140
+ emit_progress(inner_pct, total_train_steps)
141
+
142
+ train_loss = run_loss / max(total, 1)
143
+ train_acc = correct / max(total, 1)
144
+ history["train_loss"].append(round(train_loss, 6))
145
+ history["train_acc"].append(round(train_acc, 6))
146
+
147
+ val_loss, val_acc = (float("nan"), float("nan"))
148
+ if val_loader is not None:
149
+ val_metrics = self.evaluate(val_loader)
150
+ val_loss = val_metrics["loss"]
151
+ val_acc = val_metrics["accuracy"]
152
+ if val_acc > best_val_acc:
153
+ best_val_acc = val_acc
154
+ best_epoch = epoch
155
+ history["val_loss"].append(round(val_loss, 6))
156
+ history["val_acc"].append(round(val_acc, 6))
157
+
158
+ print(
159
+ f"Epoch [{epoch:>3}/{epochs}] "
160
+ f"train_loss={train_loss:.4f} train_acc={train_acc:.4f} "
161
+ f"val_loss={val_loss:.4f} val_acc={val_acc:.4f}"
162
+ )
163
+
164
+ history["best_epoch"] = best_epoch
165
+ history["best_val_acc"] = round(best_val_acc, 6) if best_epoch > 0 else None
166
+ self.history = history
167
+ return history
168
+
169
+ # ---------------- avaliação ----------------
170
+ def evaluate(self, data_loader: DataLoader) -> Dict[str, float]:
171
+ self.model.eval()
172
+ loss_sum = 0.0
173
+ correct = 0
174
+ total = 0
175
+ with torch.no_grad():
176
+ for X, y in data_loader:
177
+ X = X.to(self.device)
178
+ y = y.to(self.device)
179
+ logits = self.model(X)
180
+ loss = self.criterion(logits, y)
181
+ loss_sum += float(loss.item()) * X.size(0)
182
+ preds = logits.argmax(dim=1)
183
+ correct += int((preds == y).sum().item())
184
+ total += int(y.size(0))
185
+ return {
186
+ "loss": loss_sum / max(total, 1),
187
+ "accuracy": correct / max(total, 1),
188
+ "n": total,
189
+ }
190
+
191
+ # ---------------- inferência ----------------
192
+ def predict(self, inputs: Any) -> np.ndarray:
193
+ self.model.eval()
194
+ with torch.no_grad():
195
+ if isinstance(inputs, DataLoader):
196
+ outs: List[np.ndarray] = []
197
+ for batch in inputs:
198
+ X = batch[0] if isinstance(batch, (tuple, list)) else batch
199
+ X = X.to(self.device)
200
+ outs.append(self.model(X).argmax(dim=1).cpu().numpy())
201
+ return np.concatenate(outs, axis=0)
202
+ if isinstance(inputs, np.ndarray):
203
+ X = torch.from_numpy(inputs.astype(np.float32)).to(self.device)
204
+ elif isinstance(inputs, torch.Tensor):
205
+ X = inputs.to(self.device)
206
+ else:
207
+ X = torch.tensor(inputs, dtype=torch.float32).to(self.device)
208
+ if X.ndim == 1:
209
+ X = X.unsqueeze(0)
210
+ return self.model(X).argmax(dim=1).cpu().numpy()
211
+
212
+ # ---------------- persistência ----------------
213
+ def save_model(self, filename: str) -> str:
214
+ path = os.path.join(self.model_dir, filename)
215
+ torch.save(
216
+ {
217
+ "state_dict": self.model.state_dict(),
218
+ "input_size": self.input_size,
219
+ "num_classes": self.num_classes,
220
+ "hidden_dims": self._hidden_dims,
221
+ "dropout": self._dropout,
222
+ "project_name": self.project_name,
223
+ },
224
+ path,
225
+ )
226
+ print(f"✓ Model saved to {path}")
227
+ return path
228
+
229
+ def load_model(self, filename: str) -> None:
230
+ path = filename if os.path.isabs(filename) else os.path.join(
231
+ self.model_dir, filename
232
+ )
233
+ ckpt = torch.load(path, map_location=self.device)
234
+ self._hidden_dims = ckpt.get("hidden_dims", self._hidden_dims)
235
+ self._dropout = ckpt.get("dropout", self._dropout)
236
+ self.model = _MLP(
237
+ input_size=ckpt["input_size"],
238
+ hidden_dims=self._hidden_dims,
239
+ num_classes=ckpt["num_classes"],
240
+ dropout=self._dropout,
241
+ ).to(self.device)
242
+ self.model.load_state_dict(ckpt["state_dict"])
243
+
244
+ # ---------------- helpers ----------------
245
+ def _build_optimizer(
246
+ self, name: str, lr: float, weight_decay: float
247
+ ) -> optim.Optimizer:
248
+ params = self.model.parameters()
249
+ if name == "sgd":
250
+ return optim.SGD(params, lr=lr, momentum=0.9, weight_decay=weight_decay)
251
+ if name == "rmsprop":
252
+ return optim.RMSprop(params, lr=lr, weight_decay=weight_decay)
253
+ # default: adam
254
+ return optim.Adam(params, lr=lr, weight_decay=weight_decay)
255
+
256
+
257
+ # ---------------------------------------------------------------------------
258
+ # Fábrica usada pelo main.py
259
+ # ---------------------------------------------------------------------------
260
+ def create_model(
261
+ input_size: int,
262
+ num_classes: int,
263
+ project_name: str,
264
+ base_path: str,
265
+ config: Optional[Dict[str, Any]] = None,
266
+ ) -> TabularMLP:
267
+ """Cria um ``TabularMLP`` pronto pra uso pelo main.py."""
268
+ return TabularMLP(
269
+ input_size=input_size,
270
+ num_classes=num_classes,
271
+ project_name=project_name,
272
+ base_path=base_path,
273
+ framework="pytorch",
274
+ config=config or {},
275
+ )
model/mpl_pequeno_torch/python_version.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.10
model/mpl_pequeno_torch/requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ --extra-index-url https://download.pytorch.org/whl/cpu
2
+
3
+ pandas
4
+ scikit-learn
5
+ joblib
6
+ torch
7
+ openpyxl
8
+ numpy
projects/dataset/base.xlsx ADDED
Binary file (49 kB). View file
 
projects/dataset/dataset.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "location": "projects/02d37d373e/dataset/base.xlsx",
3
+ "type": "local_file",
4
+ "data_type": "default",
5
+ "size": 0,
6
+ "dataset_id": "b47c8290-51e4-49a3-86f5-a2d4aede765e",
7
+ "name": "",
8
+ "config": {
9
+ "config_id": "c30aceca-d507-477c-a03c-d41620af73cb",
10
+ "filename": "base.xlsx",
11
+ "file_type": "xlsx",
12
+ "total_records": 768,
13
+ "source": "teste",
14
+ "target_column": "Outcome",
15
+ "features": [
16
+ "Pregnancies",
17
+ "Glucose",
18
+ "BloodPressure",
19
+ "SkinThickness",
20
+ "Insulin",
21
+ "BMI",
22
+ "DiabetesPedigreeFunction",
23
+ "Age"
24
+ ],
25
+ "classes": [
26
+ 1,
27
+ 0
28
+ ],
29
+ "problem_type": "classification",
30
+ "columns": [
31
+ "Pregnancies",
32
+ "Glucose",
33
+ "BloodPressure",
34
+ "SkinThickness",
35
+ "Insulin",
36
+ "BMI",
37
+ "DiabetesPedigreeFunction",
38
+ "Age",
39
+ "Outcome"
40
+ ],
41
+ "is_saved": true
42
+ }
43
+ }
projects/dataset/metadata.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "config_id": "c30aceca-d507-477c-a03c-d41620af73cb",
3
+ "filename": "base.xlsx",
4
+ "file_type": "xlsx",
5
+ "total_records": 768,
6
+ "source": "teste",
7
+ "target_column": "Outcome",
8
+ "features": [
9
+ "Pregnancies",
10
+ "Glucose",
11
+ "BloodPressure",
12
+ "SkinThickness",
13
+ "Insulin",
14
+ "BMI",
15
+ "DiabetesPedigreeFunction",
16
+ "Age"
17
+ ],
18
+ "classes": [
19
+ 1,
20
+ 0
21
+ ],
22
+ "problem_type": "classification",
23
+ "columns": [
24
+ "Pregnancies",
25
+ "Glucose",
26
+ "BloodPressure",
27
+ "SkinThickness",
28
+ "Insulin",
29
+ "BMI",
30
+ "DiabetesPedigreeFunction",
31
+ "Age",
32
+ "Outcome"
33
+ ],
34
+ "is_saved": true
35
+ }
projects/project.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "testando",
3
+ "description": "teste",
4
+ "models": [
5
+ "mpl_pequeno_torch"
6
+ ],
7
+ "created_at": "2026-10-28T21:41:45.427718",
8
+ "project_id": "02d37d37-3e4c-4407-90ff-e3a71bb7e33a"
9
+ }
projects/trains/1/config.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "teste2",
3
+ "created_at": "2026-10-28T21:42:30.149694",
4
+ "model": "mpl_pequeno_torch",
5
+ "split": {
6
+ "type": "holdout",
7
+ "ratio": "80/0/20",
8
+ "stratify": false,
9
+ "random_state": 42
10
+ },
11
+ "hyperparameters": {
12
+ "batch_size": 32,
13
+ "epochs": 10,
14
+ "learning_rate": 0.001,
15
+ "weight_decay": 0.0001,
16
+ "optimizer": "adam",
17
+ "dropout": 0.0
18
+ }
19
+ }
projects/trains/1/history.json ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "train_loss": [
3
+ 3.750382,
4
+ 0.987682,
5
+ 0.829776,
6
+ 0.739012,
7
+ 0.802033,
8
+ 0.729789,
9
+ 0.723826,
10
+ 0.700537,
11
+ 0.648181,
12
+ 0.632008
13
+ ],
14
+ "train_acc": [
15
+ 0.47557,
16
+ 0.630293,
17
+ 0.586319,
18
+ 0.625407,
19
+ 0.628664,
20
+ 0.638436,
21
+ 0.620521,
22
+ 0.65798,
23
+ 0.667752,
24
+ 0.684039
25
+ ],
26
+ "val_loss": [
27
+ 0.918344,
28
+ 0.9168,
29
+ 0.680144,
30
+ 0.655112,
31
+ 0.62473,
32
+ 0.655485,
33
+ 0.692047,
34
+ 0.614565,
35
+ 0.605267,
36
+ 0.618784
37
+ ],
38
+ "val_acc": [
39
+ 0.519481,
40
+ 0.62987,
41
+ 0.642857,
42
+ 0.655844,
43
+ 0.701299,
44
+ 0.662338,
45
+ 0.675325,
46
+ 0.694805,
47
+ 0.701299,
48
+ 0.688312
49
+ ],
50
+ "best_epoch": 5,
51
+ "best_val_acc": 0.701299
52
+ }
projects/trains/1/model.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:85e73dccbe10418d638f892691a4c9b77c3bcf31fc4e84c7655e30c67d56c953
3
+ size 6269
projects/trains/1/predict/predict_config.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "input_file": "predict_dataset.xlsx"
3
+ }
projects/trains/1/predict/predict_dataset.xlsx ADDED
Binary file (15.5 kB). View file
 
projects/trains/1/predict/predict_dataset_predito.xlsx ADDED
Binary file (9.11 kB). View file
 
projects/trains/1/predict/predict_result.json ADDED
@@ -0,0 +1,492 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "index": 0,
4
+ "pred_idx": 1,
5
+ "pred_label": "0"
6
+ },
7
+ {
8
+ "index": 1,
9
+ "pred_idx": 1,
10
+ "pred_label": "0"
11
+ },
12
+ {
13
+ "index": 2,
14
+ "pred_idx": 1,
15
+ "pred_label": "0"
16
+ },
17
+ {
18
+ "index": 3,
19
+ "pred_idx": 1,
20
+ "pred_label": "0"
21
+ },
22
+ {
23
+ "index": 4,
24
+ "pred_idx": 1,
25
+ "pred_label": "0"
26
+ },
27
+ {
28
+ "index": 5,
29
+ "pred_idx": 1,
30
+ "pred_label": "0"
31
+ },
32
+ {
33
+ "index": 6,
34
+ "pred_idx": 1,
35
+ "pred_label": "0"
36
+ },
37
+ {
38
+ "index": 7,
39
+ "pred_idx": 0,
40
+ "pred_label": "1"
41
+ },
42
+ {
43
+ "index": 8,
44
+ "pred_idx": 1,
45
+ "pred_label": "0"
46
+ },
47
+ {
48
+ "index": 9,
49
+ "pred_idx": 1,
50
+ "pred_label": "0"
51
+ },
52
+ {
53
+ "index": 10,
54
+ "pred_idx": 1,
55
+ "pred_label": "0"
56
+ },
57
+ {
58
+ "index": 11,
59
+ "pred_idx": 1,
60
+ "pred_label": "0"
61
+ },
62
+ {
63
+ "index": 12,
64
+ "pred_idx": 1,
65
+ "pred_label": "0"
66
+ },
67
+ {
68
+ "index": 13,
69
+ "pred_idx": 1,
70
+ "pred_label": "0"
71
+ },
72
+ {
73
+ "index": 14,
74
+ "pred_idx": 1,
75
+ "pred_label": "0"
76
+ },
77
+ {
78
+ "index": 15,
79
+ "pred_idx": 0,
80
+ "pred_label": "1"
81
+ },
82
+ {
83
+ "index": 16,
84
+ "pred_idx": 1,
85
+ "pred_label": "0"
86
+ },
87
+ {
88
+ "index": 17,
89
+ "pred_idx": 1,
90
+ "pred_label": "0"
91
+ },
92
+ {
93
+ "index": 18,
94
+ "pred_idx": 1,
95
+ "pred_label": "0"
96
+ },
97
+ {
98
+ "index": 19,
99
+ "pred_idx": 1,
100
+ "pred_label": "0"
101
+ },
102
+ {
103
+ "index": 20,
104
+ "pred_idx": 1,
105
+ "pred_label": "0"
106
+ },
107
+ {
108
+ "index": 21,
109
+ "pred_idx": 1,
110
+ "pred_label": "0"
111
+ },
112
+ {
113
+ "index": 22,
114
+ "pred_idx": 1,
115
+ "pred_label": "0"
116
+ },
117
+ {
118
+ "index": 23,
119
+ "pred_idx": 1,
120
+ "pred_label": "0"
121
+ },
122
+ {
123
+ "index": 24,
124
+ "pred_idx": 1,
125
+ "pred_label": "0"
126
+ },
127
+ {
128
+ "index": 25,
129
+ "pred_idx": 1,
130
+ "pred_label": "0"
131
+ },
132
+ {
133
+ "index": 26,
134
+ "pred_idx": 1,
135
+ "pred_label": "0"
136
+ },
137
+ {
138
+ "index": 27,
139
+ "pred_idx": 1,
140
+ "pred_label": "0"
141
+ },
142
+ {
143
+ "index": 28,
144
+ "pred_idx": 1,
145
+ "pred_label": "0"
146
+ },
147
+ {
148
+ "index": 29,
149
+ "pred_idx": 1,
150
+ "pred_label": "0"
151
+ },
152
+ {
153
+ "index": 30,
154
+ "pred_idx": 1,
155
+ "pred_label": "0"
156
+ },
157
+ {
158
+ "index": 31,
159
+ "pred_idx": 1,
160
+ "pred_label": "0"
161
+ },
162
+ {
163
+ "index": 32,
164
+ "pred_idx": 1,
165
+ "pred_label": "0"
166
+ },
167
+ {
168
+ "index": 33,
169
+ "pred_idx": 1,
170
+ "pred_label": "0"
171
+ },
172
+ {
173
+ "index": 34,
174
+ "pred_idx": 1,
175
+ "pred_label": "0"
176
+ },
177
+ {
178
+ "index": 35,
179
+ "pred_idx": 1,
180
+ "pred_label": "0"
181
+ },
182
+ {
183
+ "index": 36,
184
+ "pred_idx": 1,
185
+ "pred_label": "0"
186
+ },
187
+ {
188
+ "index": 37,
189
+ "pred_idx": 1,
190
+ "pred_label": "0"
191
+ },
192
+ {
193
+ "index": 38,
194
+ "pred_idx": 1,
195
+ "pred_label": "0"
196
+ },
197
+ {
198
+ "index": 39,
199
+ "pred_idx": 1,
200
+ "pred_label": "0"
201
+ },
202
+ {
203
+ "index": 40,
204
+ "pred_idx": 1,
205
+ "pred_label": "0"
206
+ },
207
+ {
208
+ "index": 41,
209
+ "pred_idx": 1,
210
+ "pred_label": "0"
211
+ },
212
+ {
213
+ "index": 42,
214
+ "pred_idx": 1,
215
+ "pred_label": "0"
216
+ },
217
+ {
218
+ "index": 43,
219
+ "pred_idx": 1,
220
+ "pred_label": "0"
221
+ },
222
+ {
223
+ "index": 44,
224
+ "pred_idx": 1,
225
+ "pred_label": "0"
226
+ },
227
+ {
228
+ "index": 45,
229
+ "pred_idx": 1,
230
+ "pred_label": "0"
231
+ },
232
+ {
233
+ "index": 46,
234
+ "pred_idx": 1,
235
+ "pred_label": "0"
236
+ },
237
+ {
238
+ "index": 47,
239
+ "pred_idx": 1,
240
+ "pred_label": "0"
241
+ },
242
+ {
243
+ "index": 48,
244
+ "pred_idx": 1,
245
+ "pred_label": "0"
246
+ },
247
+ {
248
+ "index": 49,
249
+ "pred_idx": 0,
250
+ "pred_label": "1"
251
+ },
252
+ {
253
+ "index": 50,
254
+ "pred_idx": 1,
255
+ "pred_label": "0"
256
+ },
257
+ {
258
+ "index": 51,
259
+ "pred_idx": 1,
260
+ "pred_label": "0"
261
+ },
262
+ {
263
+ "index": 52,
264
+ "pred_idx": 1,
265
+ "pred_label": "0"
266
+ },
267
+ {
268
+ "index": 53,
269
+ "pred_idx": 1,
270
+ "pred_label": "0"
271
+ },
272
+ {
273
+ "index": 54,
274
+ "pred_idx": 1,
275
+ "pred_label": "0"
276
+ },
277
+ {
278
+ "index": 55,
279
+ "pred_idx": 1,
280
+ "pred_label": "0"
281
+ },
282
+ {
283
+ "index": 56,
284
+ "pred_idx": 1,
285
+ "pred_label": "0"
286
+ },
287
+ {
288
+ "index": 57,
289
+ "pred_idx": 1,
290
+ "pred_label": "0"
291
+ },
292
+ {
293
+ "index": 58,
294
+ "pred_idx": 1,
295
+ "pred_label": "0"
296
+ },
297
+ {
298
+ "index": 59,
299
+ "pred_idx": 1,
300
+ "pred_label": "0"
301
+ },
302
+ {
303
+ "index": 60,
304
+ "pred_idx": 0,
305
+ "pred_label": "1"
306
+ },
307
+ {
308
+ "index": 61,
309
+ "pred_idx": 1,
310
+ "pred_label": "0"
311
+ },
312
+ {
313
+ "index": 62,
314
+ "pred_idx": 1,
315
+ "pred_label": "0"
316
+ },
317
+ {
318
+ "index": 63,
319
+ "pred_idx": 1,
320
+ "pred_label": "0"
321
+ },
322
+ {
323
+ "index": 64,
324
+ "pred_idx": 1,
325
+ "pred_label": "0"
326
+ },
327
+ {
328
+ "index": 65,
329
+ "pred_idx": 1,
330
+ "pred_label": "0"
331
+ },
332
+ {
333
+ "index": 66,
334
+ "pred_idx": 1,
335
+ "pred_label": "0"
336
+ },
337
+ {
338
+ "index": 67,
339
+ "pred_idx": 1,
340
+ "pred_label": "0"
341
+ },
342
+ {
343
+ "index": 68,
344
+ "pred_idx": 1,
345
+ "pred_label": "0"
346
+ },
347
+ {
348
+ "index": 69,
349
+ "pred_idx": 1,
350
+ "pred_label": "0"
351
+ },
352
+ {
353
+ "index": 70,
354
+ "pred_idx": 1,
355
+ "pred_label": "0"
356
+ },
357
+ {
358
+ "index": 71,
359
+ "pred_idx": 1,
360
+ "pred_label": "0"
361
+ },
362
+ {
363
+ "index": 72,
364
+ "pred_idx": 1,
365
+ "pred_label": "0"
366
+ },
367
+ {
368
+ "index": 73,
369
+ "pred_idx": 1,
370
+ "pred_label": "0"
371
+ },
372
+ {
373
+ "index": 74,
374
+ "pred_idx": 1,
375
+ "pred_label": "0"
376
+ },
377
+ {
378
+ "index": 75,
379
+ "pred_idx": 1,
380
+ "pred_label": "0"
381
+ },
382
+ {
383
+ "index": 76,
384
+ "pred_idx": 1,
385
+ "pred_label": "0"
386
+ },
387
+ {
388
+ "index": 77,
389
+ "pred_idx": 1,
390
+ "pred_label": "0"
391
+ },
392
+ {
393
+ "index": 78,
394
+ "pred_idx": 0,
395
+ "pred_label": "1"
396
+ },
397
+ {
398
+ "index": 79,
399
+ "pred_idx": 1,
400
+ "pred_label": "0"
401
+ },
402
+ {
403
+ "index": 80,
404
+ "pred_idx": 1,
405
+ "pred_label": "0"
406
+ },
407
+ {
408
+ "index": 81,
409
+ "pred_idx": 0,
410
+ "pred_label": "1"
411
+ },
412
+ {
413
+ "index": 82,
414
+ "pred_idx": 1,
415
+ "pred_label": "0"
416
+ },
417
+ {
418
+ "index": 83,
419
+ "pred_idx": 1,
420
+ "pred_label": "0"
421
+ },
422
+ {
423
+ "index": 84,
424
+ "pred_idx": 1,
425
+ "pred_label": "0"
426
+ },
427
+ {
428
+ "index": 85,
429
+ "pred_idx": 1,
430
+ "pred_label": "0"
431
+ },
432
+ {
433
+ "index": 86,
434
+ "pred_idx": 1,
435
+ "pred_label": "0"
436
+ },
437
+ {
438
+ "index": 87,
439
+ "pred_idx": 1,
440
+ "pred_label": "0"
441
+ },
442
+ {
443
+ "index": 88,
444
+ "pred_idx": 1,
445
+ "pred_label": "0"
446
+ },
447
+ {
448
+ "index": 89,
449
+ "pred_idx": 1,
450
+ "pred_label": "0"
451
+ },
452
+ {
453
+ "index": 90,
454
+ "pred_idx": 1,
455
+ "pred_label": "0"
456
+ },
457
+ {
458
+ "index": 91,
459
+ "pred_idx": 1,
460
+ "pred_label": "0"
461
+ },
462
+ {
463
+ "index": 92,
464
+ "pred_idx": 1,
465
+ "pred_label": "0"
466
+ },
467
+ {
468
+ "index": 93,
469
+ "pred_idx": 1,
470
+ "pred_label": "0"
471
+ },
472
+ {
473
+ "index": 94,
474
+ "pred_idx": 1,
475
+ "pred_label": "0"
476
+ },
477
+ {
478
+ "index": 95,
479
+ "pred_idx": 1,
480
+ "pred_label": "0"
481
+ },
482
+ {
483
+ "index": 96,
484
+ "pred_idx": 1,
485
+ "pred_label": "0"
486
+ },
487
+ {
488
+ "index": 97,
489
+ "pred_idx": 1,
490
+ "pred_label": "0"
491
+ }
492
+ ]
projects/trains/1/test/acuracia.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "accuracy": 0.688312,
3
+ "n": 154
4
+ }
projects/trains/1/test/matriz_confusao.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "classes": [
3
+ "1",
4
+ "0"
5
+ ],
6
+ "matrix": [
7
+ [
8
+ 9,
9
+ 42
10
+ ],
11
+ [
12
+ 6,
13
+ 97
14
+ ]
15
+ ],
16
+ "description": "linha=real, coluna=predito"
17
+ }
projects/trains/1/test/precisao.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "per_class": [
3
+ {
4
+ "class": "1",
5
+ "precision": 0.6,
6
+ "recall": 0.176471,
7
+ "f1_score": 0.272727,
8
+ "support": 51
9
+ },
10
+ {
11
+ "class": "0",
12
+ "precision": 0.697842,
13
+ "recall": 0.941748,
14
+ "f1_score": 0.801653,
15
+ "support": 103
16
+ }
17
+ ],
18
+ "macro_avg": {
19
+ "precision": 0.648921,
20
+ "recall": 0.559109,
21
+ "f1_score": 0.53719
22
+ }
23
+ }
projects/trains/1/train_result.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "status": "concluido",
3
+ "epochs_run": 10,
4
+ "best_epoch": 5,
5
+ "train_loss": 0.632008,
6
+ "val_loss": 0.618784,
7
+ "val_accuracy": 0.701299,
8
+ "started_at": "2026-10-29T00:42:36Z",
9
+ "finished_at": "2026-10-29T00:42:37Z",
10
+ "duration_seconds": 1
11
+ }