--- title: curbcheck emoji: 🅿️ colorFrom: red colorTo: gray sdk: gradio app_file: app.py pinned: true license: mit tags: - build-small-hackathon - backyard-ai - vision-language-model - qlora - qwen2.5-vl - track:backyard - sponsor:modal - achievement:welltuned - achievement:fieldnotes short_description: Can a small VLM tell you if you can legally park in SF? --- # 🅿️ curbcheck **Can a small vision-language model tell you if you can legally park in San Francisco?** Upload a photo of a parking-sign pole, pick a day and time, and a QLoRA-tuned **Qwen2.5-VL-3B** reads each sign into structured rules. A tiny deterministic resolver then applies them to that moment and returns the verdict, showing you *both* what the model read and why. Read-then-resolve: the VLM only perceives; the logic is exact. I came to SF for a week in April 2026 and left with two parking tickets, both because I couldn't parse a pole holding four stacked signs. curbcheck is the model that gets it. ## Demo video [▶ Watch the demo](https://huggingface.co/spaces/build-small-hackathon/curbcheck/resolve/main/curbcheck_demo.mp4) ## Track & badges - **Track:** Backyard AI (a real, local, personal problem solved with a small model) - A 3B model, well under the 32B cap, runs on ZeroGPU. ## How it works ``` photo ─▶ VLM (reads each sign to JSON) ─▶ deterministic resolver ─▶ verdict + reason ``` - The model only **reads** the pole into structured restrictions (kind, days, hours, limits, permits). - A deterministic resolver (`rules.py`, no model in the loop) applies them to the current time. - Both halves are shown, so misreads are visible, not buried in a confident sentence. ## The result A stock Qwen2.5-VL-3B scores 0.16 on "can I park here right now", below random. One QLoRA run takes it to **0.82 reasoning** and **0.98 read accuracy** on the synthetic benchmark; on real SF photos the read-then-resolve pipeline reasons at **0.89**. Full benchmark, training, and honest results: **https://github.com/shubhamgoel27/curbcheck** ## Results in brief | | base Qwen2.5-VL-3B | tuned (QLoRA) | |---|:---:|:---:| | Read F1 (synthetic) | 0.34 | **0.98** | | Reasoning (synthetic) | 0.16 | **0.82** | | Read F1 (real SF photos) | 0.04 | **0.34** | | Pipeline reasoning (real) | 0.78 | **0.89** | The honest part: more real data barely moved real-photo reading (0.33 to 0.34), so that gap is model capacity, not data volume. The deterministic resolver keeps pipeline reasoning at 0.89 even when reading is hard. Full, honest results in the repo. ## Links - **Live demo (this Space):** https://huggingface.co/spaces/build-small-hackathon/curbcheck - **Demo video:** https://huggingface.co/spaces/build-small-hackathon/curbcheck/resolve/main/curbcheck_demo.mp4 - **Code + benchmark (GitHub):** https://github.com/shubhamgoel27/curbcheck - **Fine-tuned model (QLoRA adapter):** https://huggingface.co/shubhamgoel27/curbcheck-qwen25vl3b-v4-lora - **Base model:** https://huggingface.co/Qwen/Qwen2.5-VL-3B-Instruct - **Writeup:** https://shubham.gg/artifold-share/30da5524.html