NandaMatt commited on
Commit
8a16d4b
·
verified ·
1 Parent(s): 6d552f2

testdevelop

Browse files
model/mpl_pequeno_keras/dataset.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Dataset concreto do pipeline ``mpl_pequeno_keras`` — dados tabulares + Keras.
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 tuplas de arrays (X_train, y_train, X_val, y_val)
10
+ compatíveis com Keras/TensorFlow.
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 tensorflow as tf
24
+ _TF_AVAILABLE = True
25
+ except ImportError: # pragma: no cover
26
+ _TF_AVAILABLE = False
27
+
28
+ # Importa BaseDataset de ../base_dataset.py
29
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
30
+ from base_dataset import BaseDataset # noqa: E402
31
+
32
+
33
+ class TrainingDataset(BaseDataset):
34
+ """Dataset tabular para o pipeline em ``docker/mpl_pequeno_keras``."""
35
+
36
+ # ------------------------------------------------------------------
37
+ # Hooks da base
38
+ # ------------------------------------------------------------------
39
+ def build_features(self) -> None:
40
+ if self.df is None:
41
+ raise RuntimeError("self.df está vazio; load_raw_data() não rodou.")
42
+
43
+ # Prioridade: lista explícita no metadata.json
44
+ explicit = self.metadata.get("features")
45
+ if explicit:
46
+ missing = [c for c in explicit if c not in self.df.columns]
47
+ if missing:
48
+ raise ValueError(
49
+ f"Colunas declaradas em metadata['features'] não encontradas no DataFrame: {missing}"
50
+ )
51
+ self.feature_columns = list(explicit)
52
+ self.X = self.df[self.feature_columns].to_numpy(dtype=np.float32)
53
+ return
54
+
55
+ # Fallback: inferência automática de colunas numéricas
56
+ feats = []
57
+ for col in self.df.columns:
58
+ if col == self.target_column:
59
+ continue
60
+ if col.lower() in self.NON_FEATURE_COLS:
61
+ continue
62
+ if not pd.api.types.is_numeric_dtype(self.df[col]):
63
+ continue
64
+ feats.append(col)
65
+
66
+ if not feats:
67
+ raise ValueError(
68
+ "Nenhuma coluna numérica encontrada para usar como feature."
69
+ )
70
+
71
+ self.feature_columns = feats
72
+ self.X = self.df[feats].to_numpy(dtype=np.float32)
73
+
74
+ def get_data_loader(
75
+ self,
76
+ batch_size: int = 32,
77
+ train_ratio: Optional[float] = None,
78
+ seed: Optional[int] = None,
79
+ ) -> Tuple:
80
+ if not _TF_AVAILABLE:
81
+ raise RuntimeError(
82
+ "TensorFlow não está instalado; instale-o ou use get_arrays()."
83
+ )
84
+
85
+ train_ratio, seed = self._resolve_split_params(train_ratio, seed)
86
+ idx_train, idx_val = self._split_indices(train_ratio, seed)
87
+
88
+ assert self.X is not None and self.y is not None # pra mypy
89
+
90
+ X_train = self.X[idx_train].astype(np.float32)
91
+ y_train = self.y[idx_train].astype(np.int32)
92
+ X_val = self.X[idx_val].astype(np.float32)
93
+ y_val = self.y[idx_val].astype(np.int32)
94
+
95
+ bs = self._resolve_batch_size(batch_size)
96
+
97
+ print(
98
+ f" - Train samples: {len(X_train)} | Val samples: {len(X_val)}"
99
+ f" | Batch size: {bs}"
100
+ )
101
+
102
+ # Retorna tuplas (X, y) para compatibilidade com base_main.py unpacking
103
+ # train_loader, val_loader = get_data_loader() desempacota corretamente
104
+ train_loader = (X_train, y_train)
105
+ val_loader = (X_val, y_val)
106
+ return train_loader, val_loader
model/mpl_pequeno_keras/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_keras/hyperparameters.json ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "setting": {
3
+ "name": {
4
+ "text": "Nome do modelo",
5
+ "value": "mpl_pequeno_keras",
6
+ "Help": "Identificação do modelo. Pode ser usado para salvar checkpoints ou registros.",
7
+ "default": "mpl_pequeno_keras",
8
+ "type": "string",
9
+ "required": true
10
+ },
11
+ "architecture": {
12
+ "text": "Arquitetura do modelo",
13
+ "value": "MLP tabular",
14
+ "Help": "A arquitetura da rede neural, como ResNet, VGG, ou qualquer modelo personalizado.",
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 utilizado durante o treinamento. Valores maiores podem acelerar o treinamento, mas exigem mais memória.",
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 vezes que o conjunto de treinamento será iterado.",
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": "Controla o quão rápido o modelo ajusta os pesos durante o treinamento.",
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 para evitar overfitting.",
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. Campo fixo.",
84
+ "default": "adam",
85
+ "type": "string",
86
+ "required": true,
87
+ "constant": true
88
+ }
89
+ },
90
+ "test": {
91
+ "batch_size": {
92
+ "text": "Tamanho do batch",
93
+ "Help": "Tamanho do batch para avaliação. Deve ser otimizado para memória disponível.",
94
+ "default": 64,
95
+ "range": {
96
+ "min": 1,
97
+ "max": null
98
+ },
99
+ "type": "integer",
100
+ "required": true
101
+ }
102
+ },
103
+ "predict": {
104
+ "batch_size": {
105
+ "text": "Tamanho do batch",
106
+ "Help": "Tamanho do batch para a previsão. Ajuste conforme necessário para memória.",
107
+ "default": 64,
108
+ "range": {
109
+ "min": 1,
110
+ "max": null
111
+ },
112
+ "type": "integer",
113
+ "required": true
114
+ }
115
+ }
116
+ }
model/mpl_pequeno_keras/main.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Entrypoint do pipeline ``mpl_pequeno_keras`` (MLP tabular em Keras/TensorFlow).
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_keras/model.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Implementação concreta (Keras/TensorFlow) 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, Tuple
19
+
20
+ import numpy as np
21
+ import tensorflow as tf
22
+ from tensorflow import keras
23
+ from tensorflow.keras import layers
24
+
25
+ # Permite importar base_model.py de ../
26
+ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
27
+ from base_model import BaseModel # noqa: E402
28
+ from utils import emit_progress # noqa: E402
29
+
30
+
31
+ # ---------------------------------------------------------------------------
32
+ # Wrapper que implementa a API de BaseModel para Keras
33
+ # ---------------------------------------------------------------------------
34
+ class TabularMLP(BaseModel):
35
+ """MLP tabular em Keras/TensorFlow, plugável no pipeline."""
36
+
37
+ def build_model(self) -> keras.Model:
38
+ hp = self.config.get("hyperparameters", {})
39
+ hidden_dims = self.config.get("hidden_dims") or hp.get("hidden_dims") or [
40
+ self.config.get("hidden_dim1", 32),
41
+ self.config.get("hidden_dim2", 16),
42
+ ]
43
+ dropout = float(hp.get("dropout", self.config.get("dropout", 0.0)))
44
+
45
+ # Constrói o modelo Sequential
46
+ model = keras.Sequential()
47
+ model.add(layers.InputLayer(input_shape=(self.input_size,)))
48
+
49
+ # Adiciona camadas ocultas
50
+ for h in hidden_dims:
51
+ model.add(layers.Dense(h, activation="relu"))
52
+ if dropout and dropout > 0:
53
+ model.add(layers.Dropout(dropout))
54
+
55
+ # Camada de saída
56
+ model.add(layers.Dense(self.num_classes, activation="softmax"))
57
+
58
+ self._hidden_dims = list(hidden_dims)
59
+ self._dropout = dropout
60
+ return model
61
+
62
+ # ---------------- treinamento ----------------
63
+ def train_model(
64
+ self,
65
+ train_loader: Any,
66
+ val_loader: Optional[Any],
67
+ epochs: int,
68
+ lr: float,
69
+ **kwargs: Any,
70
+ ) -> Dict[str, list]:
71
+ hp = self.config.get("hyperparameters", {})
72
+ epochs = int(hp.get("epochs", epochs))
73
+ lr = float(hp.get("learning_rate", lr))
74
+ weight_decay = float(hp.get("weight_decay", 0.0))
75
+ optimizer_name = str(hp.get("optimizer", "adam")).lower()
76
+
77
+ # Desempacota tuplas (X, y) do dataset
78
+ if isinstance(train_loader, tuple) and len(train_loader) == 2:
79
+ X_train, y_train = train_loader
80
+ else:
81
+ raise ValueError(f"train_loader deve ser tupla (X, y), recebeu {type(train_loader)}")
82
+
83
+ if isinstance(val_loader, tuple) and len(val_loader) == 2:
84
+ X_val, y_val = val_loader
85
+ else:
86
+ raise ValueError(f"val_loader deve ser tupla (X, y), recebeu {type(val_loader)}")
87
+
88
+ # Compila o modelo
89
+ optimizer = self._build_optimizer(optimizer_name, lr, weight_decay)
90
+ self.model.compile(
91
+ optimizer=optimizer,
92
+ loss="sparse_categorical_crossentropy",
93
+ metrics=["accuracy"],
94
+ )
95
+
96
+ history = {
97
+ "train_loss": [],
98
+ "train_acc": [],
99
+ "val_loss": [],
100
+ "val_acc": [],
101
+ }
102
+
103
+ n_batches = max((len(X_train) + 31) // 32, 1) # Batches por epoch
104
+ total_train_steps = max(epochs * n_batches, 1)
105
+ batch_size = int(hp.get("batch_size", 32))
106
+ best_val_acc = -float("inf")
107
+ best_epoch = -1
108
+
109
+ for epoch in range(1, epochs + 1):
110
+ # Treina 1 época
111
+ hist = self.model.fit(
112
+ X_train,
113
+ y_train,
114
+ batch_size=batch_size,
115
+ epochs=1,
116
+ validation_data=(X_val, y_val),
117
+ verbose=0,
118
+ )
119
+
120
+ # Extrai histórico
121
+ train_loss = float(hist.history["loss"][0])
122
+ train_acc = float(hist.history["accuracy"][0])
123
+ val_loss = float(hist.history["val_loss"][0])
124
+ val_acc = float(hist.history["val_accuracy"][0])
125
+
126
+ history["train_loss"].append(round(train_loss, 6))
127
+ history["train_acc"].append(round(train_acc, 6))
128
+ history["val_loss"].append(round(val_loss, 6))
129
+ history["val_acc"].append(round(val_acc, 6))
130
+
131
+ # Emite progresso por batch (simula progresso contínuo por época)
132
+ for batch_idx in range(1, n_batches + 1):
133
+ global_step = (epoch - 1) * n_batches + batch_idx
134
+ inner_pct = int(global_step * 100 / total_train_steps)
135
+ emit_progress(inner_pct, 1)
136
+
137
+ # Rastreia melhor validação
138
+ if val_acc > best_val_acc:
139
+ best_val_acc = val_acc
140
+ best_epoch = epoch
141
+
142
+ print(
143
+ f"Epoch [{epoch:>3}/{epochs}] "
144
+ f"train_loss={train_loss:.4f} train_acc={train_acc:.4f} "
145
+ f"val_loss={val_loss:.4f} val_acc={val_acc:.4f}"
146
+ )
147
+
148
+ history["best_epoch"] = best_epoch
149
+ history["best_val_acc"] = round(best_val_acc, 6) if best_epoch > 0 else None
150
+ self.history = history
151
+ return history
152
+
153
+ # ---------------- avaliação ----------------
154
+ def evaluate(self, data_loader: Any) -> Dict[str, float]:
155
+ if isinstance(data_loader, tuple) and len(data_loader) == 2:
156
+ X_val, y_val = data_loader
157
+ else:
158
+ X_val, y_val = data_loader[2], data_loader[3]
159
+
160
+ loss, accuracy = self.model.evaluate(X_val, y_val, verbose=0)
161
+ return {
162
+ "loss": float(loss),
163
+ "accuracy": float(accuracy),
164
+ "n": len(X_val),
165
+ }
166
+
167
+ # ---------------- inferência ----------------
168
+ def predict(self, inputs: Any) -> np.ndarray:
169
+ if isinstance(inputs, tuple):
170
+ # Se for tuple de (X_train, y_train, X_val, y_val), usa X_val
171
+ X = inputs[2].astype(np.float32)
172
+ elif isinstance(inputs, np.ndarray):
173
+ X = inputs.astype(np.float32)
174
+ else:
175
+ X = np.array(inputs, dtype=np.float32)
176
+
177
+ if X.ndim == 1:
178
+ X = X.reshape(1, -1)
179
+
180
+ # Predições como classe
181
+ logits = self.model.predict(X, verbose=0)
182
+ return np.argmax(logits, axis=1)
183
+
184
+ # ---------------- persistência ----------------
185
+ def save_model(self, filename: str) -> str:
186
+ path = os.path.join(self.model_dir, filename)
187
+ # Remove extensão se for .pt (compatibilidade)
188
+ if path.endswith(".pt"):
189
+ path = path[:-3] + ".keras"
190
+
191
+ self.model.save(path)
192
+ print(f"✓ Model saved to {path}")
193
+ return path
194
+
195
+ def load_model(self, filename: str) -> None:
196
+ path = filename if os.path.isabs(filename) else os.path.join(
197
+ self.model_dir, filename
198
+ )
199
+ # Converte .pt para .keras
200
+ if path.endswith(".pt"):
201
+ path = path[:-3] + ".keras"
202
+
203
+ self.model = keras.models.load_model(path)
204
+
205
+ # ---------------- helpers ----------------
206
+ def _build_optimizer(
207
+ self, name: str, lr: float, weight_decay: float
208
+ ) -> keras.optimizers.Optimizer:
209
+ if name == "sgd":
210
+ return keras.optimizers.SGD(learning_rate=lr, weight_decay=weight_decay)
211
+ if name == "rmsprop":
212
+ return keras.optimizers.RMSprop(learning_rate=lr, weight_decay=weight_decay)
213
+ # default: adam
214
+ return keras.optimizers.Adam(learning_rate=lr, weight_decay=weight_decay)
215
+
216
+
217
+ # ---------------------------------------------------------------------------
218
+ # Fábrica usada pelo main.py
219
+ # ---------------------------------------------------------------------------
220
+ def create_model(
221
+ input_size: int,
222
+ num_classes: int,
223
+ project_name: str,
224
+ base_path: str,
225
+ config: Optional[Dict[str, Any]] = None,
226
+ ) -> TabularMLP:
227
+ """Cria um ``TabularMLP`` pronto pra uso pelo main.py."""
228
+ return TabularMLP(
229
+ input_size=input_size,
230
+ num_classes=num_classes,
231
+ project_name=project_name,
232
+ base_path=base_path,
233
+ framework="keras",
234
+ config=config or {},
235
+ )
model/mpl_pequeno_keras/python_version.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.10
model/mpl_pequeno_keras/requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ pandas
2
+ scikit-learn
3
+ joblib
4
+ tensorflow
5
+ openpyxl
6
+ numpy
project/project.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "testDevelop",
3
+ "description": "foo",
4
+ "models": [
5
+ "mpl_pequeno_keras"
6
+ ],
7
+ "created_at": "2026-06-15T22:46:26.302605",
8
+ "project_id": "079cc401-e6ba-41e9-84c8-3c743ac104c6"
9
+ }