File size: 18,361 Bytes
8b525f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# 🧬 Self-Evolving Neural Network β€” Project Plan & Status

## Current Status: βœ… Core Complete, GUI Working, Dataset Integrated, πŸ”¬ English Training RUNNING

### Active Training Runs (Aug 1)
| Run | Command | Status | Checkpoints |
|-----|---------|--------|-------------|
| FABLE numeric regression | `--dataset fable --n-samples 10000 --generations 30 --pop-size 6 --train-epochs 10` | βœ… RUNNING (PID 22047, 120-min budget) | `evo_checkpoints/` |
| **English understanding** | `--text-dataset cornell-movie-review-data/rotten_tomatoes --n-samples 3000 --generations 10 --pop-size 4 --train-epochs 5` | πŸ”¬ RUNNING (PID 33878, 90-min budget) | `evo_checkpoints_text/` |

> ⚠️ Note: the newer `huggingface_hub` (β‰₯1.26) requires **namespaced** dataset ids β€” use
> `cornell-movie-review-data/rotten_tomatoes`, NOT bare `rotten_tomatoes` (that errors with `HfUriError`).
> The FABLE id `Crownelius/Complete-FABLE.5-traces-2M` already has a namespace, so it's unaffected.

### πŸ› Critical data bug found & fixed (Aug 1)
The first English run scored **50% (chance) on held-out reviews** despite high training fitness.
Root cause: `rotten_tomatoes` train split is **sorted by label** (rows 0–4000 all-positive,
6000+ all-negative). `load_text_dataset` used `split="train[:3000]"` β†’ the model trained on a
**single class** and learned "always predict positive" (100% on that slice, 50% on balanced test).

**Fix:** `load_text_dataset` now loads the full split and draws a **seeded random sample**
(`np.random.RandomState(42).choice(..., replace=False)`) instead of a head-slice.
Verified: 3000-sample draw is now 50.0% positive. ⚠️ Same hazard applies to any HF dataset
with sorted labels β€” never head-slice without checking label distribution.

### πŸ”§ Evolution-engine upgrades (Aug 1)
- **Classification fitness is now validation-accuracy based** (`best_val_accΒ² Γ— 100 / penalty`)
  instead of `1/val_loss` β€” loss-only fitness rewarded memorization (the cause of the
  first run's 100% train / 50% test split). Regression fitness unchanged.
- **LR scheduling**: `ReduceLROnPlateau` (factor 0.5, patience 2) during each eval.
- **Diversity pressure** (`apply_diversity_pressure`): exact duplicate configs β†’ fitness
  Γ—0.5; near-identical-to-best topologies β†’ Γ—0.9. The current champion is exempt so
  stagnation tracking and best-genome re-selection stay valid.
- **`--continue` is text-aware**: `SelfTrainer.continue_evolution` now passes
  `task_type`/`vectorizer`/`embed_dim`/`checkpoint_dir` through, and `run()` only
  initializes a fresh population when none was pre-seeded (fixes the old bug where
  `--continue` clobbered the seeded population and rebuilt a regression engine).
- **`load_fable_dataset`** also now random-samples (seeded) instead of head-slicing.

### 🌍 English text path β€” end-to-end raw-English inference (Aug 1)
- `save_best_model` now **bakes the fitted TextVectorizer into `best_model.keras`** for
  text runs β†’ the saved model accepts **raw English strings** (no separate tokenizer needed).
  Also saves `best_model_ids.keras` (token-id core) and `vectorizer_config.json`
  (incl. the exact fitted vocab list for token-id parity in eval).
- `eval_text_model.py` scores the best model on held-out test reviews in 3 auto modes:
  1) serving (raw strings), 2) token-id (reuses saved vocab), 3) rebuild preview.
- `auto_pipeline.sh` (running): waits for FABLE + TEXT to finish β†’ evals the text run β†’
  launches scaled-up run `evo_checkpoints_text_v2` (8K samples, vocab 20k, embed 128) β†’ evals it.
- `check_progress.py`: prints generation-by-generation fitness for both checkpoint dirs.


### 🧠 v3-Gemma strategy (Aug 1) β€” "extract the GPT of Gemma + self-evolve on FABLE"

**Discovery:** FABLE.5-traces-2M's `row_json` contains REAL ENGLISH β€” it's 229K AI
coding-session traces with actual user prompts (`message.content`) + completions.
So a pretrained language model CAN read FABLE β€” the earlier "FABLE is numeric-only"
assumption was wrong (only our hand-engineered 10 features were numeric).

**New plan (v3, Colab GPU):**
1. Load `Qwen/Qwen2.5-0.5B-Instruct` (open GPT-class transformer, Apache 2.0, un-gated
   repo, ~1.1 GB FP16 β€” the "GPT" we borrow English from; frozen, forward-only).
   (Swapped from gemma-3-270m for reliability: no gated terms acceptance needed,
   standard Qwen2 architecture, no `trust_remote_code`, 896-dim hidden state.)
2. Extract FABLE text (`row_json` β†’ content + completion) β†’ mean-pooled Gemma last
   hidden state = per-row English-understanding embeddings (input_dim β‰ˆ 1152).
3. Feed embeddings as X into `EvolutionEngine` (task_type=regression, target =
   `log1p(seen_count)`) β€” the SAME engine as local runs, now on a T4 GPU (10-20Γ— faster).
4. Eval held-out RΒ²/MAE β†’ push `evo_checkpoints_gemma/` back to HF.

**Deliverable:** `evo_gemma_fable_colab.ipynb` (18 cells, generated by
`make_gemma_colab_notebook.py` β€” run it to regenerate). Prereqs: HF token (only for
pushing results back; model download is un-gated) + project code pushed to REPO_ID
via `hf_upload.py`.
This is the bridge toward a true mini-GPT: attention + generative head come later (v4/v5).

### Files Created
| File | Lines | Description |
|------|-------|-------------|
| `self_evolving_model.py` | 996+ | Core evolution engine with genome system, training, checkpointing |
| `evo_gui.py` | 578+ | Flask web GUI with real-time monitoring, Chart.js fitness plots |
| `hf_upload.py` | β€” | Upload model/genome/history + auto-generated model card to Hugging Face |
| `make_gemma_colab_notebook.py` | β€” | Generates `evo_gemma_fable_colab.ipynb` (v3-Qwen strategy) |
| `evo_gemma_fable_colab.ipynb` | β€” | Colab GPU: Qwen2.5-0.5B embeddings β†’ self-evolved head on FABLE text |
| `evo_v2_colab.ipynb` | β€” | Ready-to-run Google Colab notebook (v2/v3 GPU training, scale-up, push-back) |
| `make_growth_chart.py` | β€” | Generates `growth_limit.html` β€” theoretical parameter-growth line chart |
| `growth_limit.html` | β€” | Dependency-free SVG chart: max growth 4,216 β†’ 345,352 params (extrap. to 1M @ ~16 layers) |
| `requirements.txt` | β€” | Pinned dependencies for laptop/Colab reproducibility |
| `PLAN.md` | β€” | This file β€” project plan and continuation guide |

### Checkpoints (from previous test runs)
| File | Description |
|------|-------------|
| `evo_checkpoints/checkpoint.pkl` | Serialized evolution state |
| `evo_checkpoints/best_model.keras` | Best evolved model |
| `evo_checkpoints/best_genome.json` | Best genome architecture config |
| `evo_checkpoints/evolution_history.json` | Fitness history across generations |

---

## What's Been Built

### 1. Genome System (`Genome` class)
- Neural network architecture encoded as mutable genome
- Layers, units, activations, dropout, batch norm, learning rate, optimizer
- **Mutation operators**: add/remove layers, change units, swap activations, perturb LR
- **Crossover**: layer-by-layer parent mixing with hyperparameter inheritance

### 2. Evolution Engine (`EvolutionEngine` class)
- Population-based evolutionary optimization
- Elitism selection (top 30% survive)
- Reproduction via mutation + crossover
- Automatic checkpointing every generation
- Stop event for GUI integration (`threading.Event`)
- Generation callback for real-time GUI updates

### 3. Dataset Integration (`DataHandler.load_fable_dataset`)
- Loads `Crownelius/Complete-FABLE.5-traces-2M` from HuggingFace (228K rows)
- Extracts 10-dimensional feature vectors from heterogeneous JSON coding traces:
  - Message length, word count, code keyword frequency
  - Completion length, chain-of-thought length
  - Tool use indicators, output complexity
  - Session entropy (deterministic md5 hash)
  - Special character ratio
- StandardScaler normalization on features
- Log-normalization on target (seen_count)

### 4. Web GUI (`evo_gui.py`)
- **Flask** server with single-page HTML/JS frontend
- **Dark theme** with monospace font (GitHub-style)
- **Chart.js** real-time fitness line chart (best + avg)
- **Controls**: Start/Stop buttons, parameter inputs
- **Statistics panel**: generation, fitness, improvement %, population
- **Genome visualization**: layer chips, architecture display
- **Population leaderboard**: sorted by fitness with medals
- **Evolution log**: scrolling text log
- **API endpoints**:
  - `GET /` β€” HTML dashboard
  - `GET /api/status` β€” JSON state
  - `POST /api/start` β€” Start evolution with params
  - `POST /api/stop` β€” Stop evolution

### 5. Model Building (`ModelEvaluator`)
- Builds Keras models from genome configs
- Supports 4 optimizers: Adam, SGD, RMSprop, AdamW
- 7 activation functions: relu, tanh, sigmoid, elu, selu, swish, linear
- Batch normalization and dropout support
- Fitness = 1 / (val_loss Γ— complexity_penalty)

### 6. Gated Feature Architecture (`top3_features`)
- Each genome encodes which **3 features** (by index) feed layer 1
- The remaining features are concatenated into **every layer after the first** (incl. output)
- Feature selection **evolves** via mutation/crossover (e.g. `top3=[1,3,7]`)
- Old checkpoints without the field default to `[0,1,2]` (backward compatible)

### 7. β›” Safety Gates (`SafetyGates` class) β€” the AI CANNOT change these
- **Hard walls**: max 16 layers, 2048 units/layer, 5M total params β€” enforced on EVERY
  evaluation via `enforce_genome()` (even corrupt/old checkpoints get clamped)
- **Failure gates**: NaN/Inf or exploded val_loss β†’ fitness 0; over-param wall β†’ fitness 0
- **Fitness clamp**: fitness bounded to `[0, 1e9]`
- **Runtime gates**: `--max-minutes` wall-clock budget; `--stagnation-limit` (default 12 gens
  without improvement β†’ halt) β€” both trip safely and log to `safety_trips`
- Safety constants live OUTSIDE the genome (module-level), never checkpointed,
  never mutated by evolution β€” editing `SafetyGates` requires source-code changes

### 8. English understanding β€” honest status
- The model does **NOT** understand English. It is a numeric regressor: FABLE traces are
  converted to 10 numbers (message length, word count, code-keyword freq, ...) and it
  predicts a count. There is no language model in this stack.
- Making it "understand English" requires a different architecture (embedding/text model),
  which is beyond this neuroevolution setup.

## Scaling Pipeline (v1 β†’ HF β†’ v2/v3)

```
LOCAL CPU (v1) ──▢ hf_upload.py ──▢ Hugging Face ──▢ evo_v2_colab.ipynb (GPU, bigger caps) ──▢ push back
   small models        model card        durable backup      scale to 512-1024 units / 8-10 layers
```

- **Local (this box):** fast CPU iterations; checkpoints auto-save every generation
- **HF upload:** `python3 hf_upload.py --repo user/repo --token $HF_TOKEN` (dry-run with `--dry-run`)
- **Colab v2/v3:** open `evo_v2_colab.ipynb` β†’ Runtime β–Έ Run all β†’ paste HF_TOKEN. It pulls the repo,
  continues evolution with `--max-units/--max-layers`, and pushes results back
- **Laptop:** `pip install -r requirements.txt` then run as normal
- ⚠️ This cloud VM resets ~20 min after session end β€” push checkpoints to HF early and often

### Genome Search Space (scalable)
- Default: max 6 layers Γ— 256 units (~345K params ceiling)
- `--max-units 512 --max-layers 8` β†’ ~1.1M params ceiling (v2)
- `--max-units 1024 --max-layers 10` β†’ larger (v3, GPU)
- See `growth_limit.html` for the theoretical growth line
- β›” All of the above are still capped by `SafetyGates` hard walls (16 layers / 2048 units / 5M params)

---

## Scaling Pipeline (v1 β†’ HF β†’ v2/v3)

```
LOCAL CPU (v1) ──▢ hf_upload.py ──▢ Hugging Face ──▢ evo_v2_colab.ipynb (GPU, bigger caps) ──▢ push back
   small models        model card        durable backup      scale to 512-1024 units / 8-10 layers
```

- **Local (this box):** fast CPU iterations; checkpoints auto-save every generation
- **HF upload:** `python3 hf_upload.py --repo user/repo --token $HF_TOKEN` (dry-run with `--dry-run`)
- **Colab v2/v3:** open `evo_v2_colab.ipynb` β†’ Runtime β–Έ Run all β†’ paste HF_TOKEN. It pulls the repo,
  continues evolution with `--max-units/--max-layers`, and pushes results back
- **Laptop:** `pip install -r requirements.txt` then run as normal
- ⚠️ This cloud VM resets ~20 min after session end β€” push checkpoints to HF early and often

### Genome Search Space (scalable)
- Default: max 6 layers Γ— 256 units (~345K params ceiling)
- `--max-units 512 --max-layers 8` β†’ ~1.1M params ceiling (v2)
- `--max-units 1024 --max-layers 10` β†’ larger (v3, GPU)
- See `growth_limit.html` for the theoretical growth line

## How to Run

### CLI Mode (terminal)
```bash
# Quick run with synthetic data
python3 self_evolving_model.py --generations 20 --pop-size 8

# With FABLE dataset
python3 self_evolving_model.py --dataset fable --n-samples 10000 --generations 30

# Continue from previous best
python3 self_evolving_model.py --continue --generations 50
```

### GUI Mode (web browser)
```bash
# Standalone (loads dataset on demand)
python3 evo_gui.py --port 5000 --n-samples 5000

# Via CLI flag (pre-loads dataset)
python3 self_evolving_model.py --gui --gui-port 5000 --n-samples 5000
```
Then open `http://localhost:5000` in browser.

---

## Verified Working βœ…
- [x] Genome mutation/crossover
- [x] Model building from genomes
- [x] Evolution loop with elitism
- [x] Checkpoint save/load/resume
- [x] CLI argument parsing
- [x] Dataset loading from HuggingFace
- [x] Feature extraction from JSON traces
- [x] Flask GUI serving HTML
- [x] GUI API endpoints (start/stop/status)
- [x] Background thread evolution
- [x] Real-time GUI updates via polling
- [x] Chart.js fitness visualization
- [x] Population leaderboard
- [x] Stop signal from GUI β†’ engine

---

## Next Steps (TODO)

### Priority 1: Run Full Training
```bash
# Start GUI with full dataset
python3 evo_gui.py --port 5000 --n-samples 10000
```
Then in browser: set Generations=30, Pop=6, Train Epochs=10, click Start.

### Priority 2: Potential Improvements
1. **Streaming dataset loading** β€” current approach downloads full 228K rows then slices. Use HF streaming for faster loads.
2. **GPU support** β€” if CUDA available, use `tf.distribute.MirroredStrategy` for faster training.
3. **Dataset reload button** in GUI β€” allow changing sample count without restart.
4. **Export best model** β€” add button to download the best evolved model.
5. **Diversity pressure** β€” penalize genomes too similar to prevent convergence to local optima.
6. **Learning rate scheduling** β€” add cosine annealing or step decay to genome.

### Priority 3: Architecture Enhancements
1. **Multi-objective evolution** β€” optimize both fitness AND model size.
2. **Transfer learning** β€” start from pre-trained model weights.
3. **Neural Architecture Search (NAS)** β€” add skip connections, attention layers.
4. **Distributed evolution** β€” run populations across multiple machines.

---

## Architecture Diagram

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    evo_gui.py                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Flask    β”‚  β”‚  Chart.jsβ”‚  β”‚  HTML Dashboard  β”‚  β”‚
β”‚  β”‚  Routes   │──│  Live UI │──│  Controls/Stats  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚       β”‚ /api/start                                   β”‚
β”‚       β–Ό                                              β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
β”‚  β”‚  Background Thread                        β”‚        β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚        β”‚
β”‚  β”‚  β”‚  DataHandler β”‚  β”‚ EvolutionEngine  β”‚  β”‚        β”‚
β”‚  β”‚  β”‚  (HF Dataset)│──│  (Population)    β”‚  β”‚        β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚        β”‚
β”‚  β”‚                             β”‚ callback    β”‚        β”‚
β”‚  β”‚                             β–Ό             β”‚        β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚        β”‚
β”‚  β”‚  β”‚  ModelEvaluator                     β”‚ β”‚        β”‚
β”‚  β”‚  β”‚  Genome β†’ Keras Model β†’ Fitness     β”‚ β”‚        β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚        β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              self_evolving_model.py                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Genome   β”‚  β”‚  Data     β”‚  β”‚  Evolution      β”‚  β”‚
β”‚  β”‚  (config) β”‚  β”‚  Handler  β”‚  β”‚  Engine         β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

---

## Dependencies
- Python 3.12+
- TensorFlow 2.21.0
- NumPy 2.4.6
- Flask 3.1.3
- datasets 5.0.1 (HuggingFace)
- huggingface_hub 1.26.0

All installed and verified working.