third-eye / FIXES_REPORT.md
mitvho09's picture
Upload folder using huggingface_hub
031e3f9 verified
|
Raw
History Blame Contribute Delete
7.44 kB
# Third Eye β€” Fixes Report (root causes + verification)
## TL;DR
- **STT was NOT inherently slow.** The Cohere card advertises RTFx ~500 ("blazing fast").
The ~5-minute transcriptions were a **configuration bug**: float32 + `device_map="auto"`
ran the model on CPU / partially offloaded (~1s per forward pass). **Keep Cohere β€” it wins the
Cohere prize. Do NOT switch to Whisper.**
- Vision hallucinations (`$20` for `$18`) came from **sampling**; switched to **greedy** + **bf16**.
- All other reported bugs were already fixed; verified in code. 3 minor issues closed.
- **38/38 unit tests pass** (CPU). **GPU fixes MEASURED on Modal A10G:** STT 5 min β†’ 0.6s warm;
vision now reads `$18` (not `$20`) and `mango lassi` (not `MANGOLAISSI`). See "Verification" below.
---
## Root cause analysis
### BUG 1 β€” STT slow (~5 min). FIXED (config) β€” `cohere_stt.py`
**Evidence:** logs show `1.01s/it` per forward pass. A 2B model on an A10G does a forward pass in
~10–30 ms, not ~1000 ms. The model card benchmarks RTFx ~524 (a 6 s clip β‰ˆ 0.01 s of compute).
The app was ~25,000Γ— slower than the model's own benchmark β†’ not the model, the config.
**Three compounding causes, all fixed:**
1. `from_pretrained(..., device_map="auto")` with **no `torch_dtype`** β†’ loaded in **float32**.
On a single-GPU container this both doubles memory and pushes layers toward CPU offload, which
streams weights per token. β†’ Now: `torch_dtype=bfloat16` and an explicit `.to("cuda")`.
2. No decoding flags β†’ if `generation_config` defaulted to beam search, every token costs N forward
passes (the repeated `6/6` progress bars). β†’ Now: `num_beams=1, do_sample=False` (greedy).
3. `max_new_tokens=256` β†’ trimmed to `128` (speech answers are short).
**Why this is the fix and not a guess:** greedy + half-precision + single-GPU pin is the standard
cure for "transformers `generate` is mysteriously 100Γ—+ too slow," and it directly removes every
mechanism the logs pointed at (per-forward CPU cost, per-token beam multiplier).
### BUG 1b β€” "Ask" mode answered the wrong question. FIXED β€” `cohere_stt.py`
**Symptom:** spoken questions weren't answered correctly. **Not a wiring bug** β€” the vision model
answers fine. The STT was **hallucinating a tail over trailing silence**:
```
SPOKEN: 'What is the cheapest item on the menu and how much does it cost?'
HEARD: 'What is the cheapest item on the menu and how much does it cost? Yes, sir. It was a clue.' ← fake
```
The fake tail corrupts the question handed to the vision model (here it survived because the real
text came first; with a shorter/noisier real-mic clip the tail dominates and the answer goes wrong).
**Fix:** trim leading/trailing silence with `librosa.effects.trim(top_db=30)` before transcription β€”
removes the silent padding the model hallucinates over. **Verified:**
```
HEARD: 'What is the cheapest item on the menu and how much does it cost?' (exact match, 39->29 tokens)
HEARD: 'How often should I take this medication?' -> ANSWER: 'take one capsule every 8 hours.' (correct)
clean-clip regression: 'Hello, this is a test...' still transcribes perfectly.
```
### Vision hallucination (`$20`β‰ `$18`). FIXED β€” `modal_backend.py`
`sampling=True, temperature=0.2` still lets the model invent plausible-but-wrong numbers. Switched
to **`sampling=False` (greedy)** β€” the faithful, repeatable choice for an accessibility/OCR tool β€”
and **bf16** (what the MiniCPM-V-2 card recommends; more stable than fp16 on small text).
### Temp-file leak. FIXED β€” `utils.py` + `app.py`
`bytes_to_wav()` left WAVs in temp forever. Added `prune_old_wavs()` (removes only Third-Eye WAVs
older than 10 min, so a clip still being served is never deleted), called at each pipeline start.
### Previously-reported bugs β€” verified fixed in code
- READ "s" output β†’ improved verbatim prompt (`app.py: resolve_question`). βœ“
- `repetition_penalty`/`max_new_tokens` removed from `model.chat` (they caused refusals). βœ“
- STT gated-model 403 β†’ specific, actionable error message. βœ“
- `safe_call` now surfaces exception type+message (truncated). βœ“
---
### Read Text OCR distortion (`MANGOLAISSI`). FIXED (mitigated) β€” `modal_backend.py`
**Root cause:** small text on a full 1024x1536 image exceeds a 2.8B VLM's effective OCR
resolution, so it merged `MANGO LASSI` -> `MANGOLAISSI`. Prompt engineering did NOT help
(tested: still `MANGOLIASSI` + a hallucinated price). **Validated cause:** cropping to the text
region fixed it (`Mango Lassi $5`), proving it's a resolution problem, not a knowledge problem.
**Fix:** automatic **tiled OCR** for Read Text mode (`describe_scene(..., tile=True)`): split the
image into two overlapping top/bottom bands, OCR each (enlarges relative text), and stitch the
results with word-overlap dedup (`stitch_overlapping_text`, unit-tested). **Automatic β€” no
box-drawing**, which matters because the user is blind and can't draw a selection box. Measured:
```
label: AMOXICILLIN 500 mg Take one capsule every 8 hours Finish all medication EXP 12/2027 (perfect)
sign: CENTRAL STATION 250 m PLATFORM 1-6 (perfect)
menu: ...GRILLED FISH $18 MANGOS LASSI $5 (space restored & readable; was "MANGOLAISSI")
```
**Residual honest limit:** the menu still shows a minor glyph error (`MANGOS`), the genuine 2.8B
ceiling. It is now legible speech, not gibberish. Cost: Read Text does 2 model calls (~6s).
## Faster-model question
Within Cohere's family this transcribe model **is** the ASR model, and once configured correctly it
*is* fast (RTFx ~500). No turbo variant is needed. Keeping Cohere keeps the Cohere award eligible.
---
## Verification β€” MEASURED on Modal GPU (A10G), 2026-06-14
**Local (CPU, this machine):**
- `38/38` unit tests pass (`python -m pytest -q`); `ruff check` clean; both modules import.
**STT benchmark** (`modal run modal_backend.py::stt_benchmark`):
```
[third-eye STT] loaded CohereLabs/cohere-transcribe-03-2026 | cuda_available=True | device=cuda:0 | dtype=torch.bfloat16
[COLD] total round-trip: 58.8s (one-time container + model load)
[third-eye STT] generate: 1.56s for 26 tokens (first call, includes CUDA warmup)
[third-eye STT] generate: 0.16s for 26 tokens (warm: ~160 tok/s β€” correct for 2B on A10G)
[WARM] total round-trip: 0.6s
transcript: 'Hello, this is a test of the third eye text to speech system.' (correct)
```
**Result: ~5 minutes β†’ 0.6s warm round-trip (~500-1000x). STT is now fast enough to demo live.**
**Vision/TTS smoke test** (`modal run modal_backend.py::smoke_test`):
```
[third-eye VISION] loaded openbmb/MiniCPM-V-2 | device=cuda:0 | dtype=torch.bfloat16
[third-eye VISION] chat: 3.85s
"...Prices range from $6 for a soup to $18 for grilled fish, with mango lassi priced at $5."
```
**Result:** greedy `sampling=False` works (no refusal); `$18` read correctly (was `$20`);
`mango lassi` spelled correctly (was `MANGOLAISSI`); all three models confirmed on cuda + bf16.
**Diagnostic safety net:** if `device=cpu` ever appears in the STT log, the STT image installed a
CPU-only torch β€” fix by pinning a CUDA wheel: `pip_install("torch>=2.5",
index_url="https://download.pytorch.org/whl/cu124")`. (Not needed currently β€” verified cuda:0.)
```