Minus-v0.1 โ€” a vision model that blocks ads by looking at them

Minus covering real ads on theverge.com with Spanish flashcards Minus-v0.1 running in the Chrome extension on theverge.com: the banner and sidebar ad slots are covered by language flashcards, each tagged with the model's confidence. The article itself is untouched.

Minus-v0.1 is a 450M-parameter visionโ€“language model fine-tuned to answer one question about an image: "Is this an advertisement?" It powers the Minus Chrome extension, where it runs entirely in the browser (transformers.js + ONNX Runtime Web on WebGPU) and covers detected ads with language flashcards โ€” no filter lists, no servers, no telemetry. It is the browser sibling of the minus HDMI ad-blocking device.

Instead of matching URLs or DOM patterns like a classic ad blocker, Minus classifies pixels: screenshots of page elements, video frames, and iframes. That means it generalizes to first-party ads, sponsored tiles, native placements and streaming-TV commercials that filter lists can't see โ€” and it keeps working when ad-tech rotates domains.

  • Base model: LiquidAI/LFM2.5-VL-450M
  • Task: binary ad / not-ad classification via a single-token answer (Yes / No), scored as p(ad) = P(Yes)
  • Prompt: Is this an advertisement? Answer Yes or No.
  • Format in this repo: ONNX, quantized for the browser (~430 MB total): q4 decoder, q8 token embeddings, q8 vision encoder. WebGPU required (the q4 decoder uses GatherBlockQuantized, which onnxruntime-web's WASM backend doesn't implement).

How it was trained

Minus-v0.1 is iteration 28 of a months-long training campaign (the first 27 iterations were exploration: base-model selection between FastVLM / SmolVLM / CLIP-style classifiers / LFM2.5-VL, then successive rounds of hard-negative and hard-positive mining, each gated by frozen benchmarks and live in-browser soak tests).

Recipe (frozen across late iterations): LoRA (r=16, ฮฑ=32) on the language-model blocks only โ€” vision tower and projector stay frozen โ€” lr 2e-4, 3 epochs, effective batch 32. Trained on a single NVIDIA Jetson AGX Thor (128 GB unified memory). The LoRA is merged before export.

Data (not released): ~81,600 training samples across two domains:

  • Streaming TV โ€” frames sampled by the minus HDMI device during real viewing sessions: commercials vs. program content, label-audited before training.
  • Web pages โ€” display/banner ad creatives vs. hard negatives mined from real browsing: editorial content, product photography (e-commerce tiles that look like ads), site self-promo and UI elements, cookie/consent banners, chat widgets, site headers, and scale-jittered variants of all of these to survive browser resampling.

Roughly 45% of the web-ad positives are native/chum-box style (Taboola/Outbrain-like), which classic blockers struggle with.

Evaluation

All gates are held-out sets that were frozen before this iteration trained; the live number comes from headed-browser soaks on real sites.

benchmark result
Streaming holdout (1,956 frames, hand-verified) 99.90% ad recall / 98.06% non-ad recall
Static-web bench (999 images) @ shipping gate 98.0% ad recall, 11 false positives
Product-image FP holdout (199 ad-look-alike product shots) 1/199 false positives
Live in-browser precision (month of soak tests, real sites) ~90โ€“94% of covered elements are actually ads

The static-web PR curve dominates or ties the previous production model at every operating point with non-ad recall โ‰ฅ 95%.

Every word shown over a blocked ad feeds the extension's built-in spaced-repetition review โ€” the ads you don't watch become vocabulary you keep:

The extension's spaced-repetition review page

Using the model

transformers.js (what the extension does)

import { AutoProcessor, AutoModelForVision2Seq, RawImage } from "@huggingface/transformers";

const processor = await AutoProcessor.from_pretrained("TheGarageDev/Minus-v0.1");
const model = await AutoModelForVision2Seq.from_pretrained("TheGarageDev/Minus-v0.1", {
  device: "webgpu",           // REQUIRED โ€” the q4 decoder is WebGPU-only
  dtype: { embed_tokens: "q8", vision_encoder: "q8", decoder_model_merged: "q4" },
});

const image = await RawImage.read(imageUrlOrCanvas);
const messages = [{ role: "user", content: [
  { type: "image" },
  { type: "text", text: "Is this an advertisement? Answer Yes or No." },
]}];
const prompt = processor.apply_chat_template(messages, { add_generation_prompt: true });
const inputs = await processor(prompt, image);

// One decode step; compare the logits of "Yes" vs "No" for a calibrated p(ad).
const { logits } = await model({ ...inputs });
// p_ad = softmax over {logit("Yes"), logit("No")} โ€” see the extension's engine
// (offscreen.js) for the exact token ids + scoring code.

Thresholding matters. The extension does not block at p โ‰ฅ 0.5 โ€” it uses per-context gates chosen from the PR curve: 0.60 for elements with ad context (iframes / ad-slot containers) and 0.88 for bare images. If you deploy this model, pick your own operating point for your precision target.

Python (reference / server-side)

The ONNX graphs run under onnxruntime too (CPU/CUDA execution providers support the quantized ops). For full-precision experiments, start from the base model and the recipe above.

Limitations & honest notes

  • Binary classifier, not a chat model. The fine-tune deliberately collapses the model onto Yes/No answers for one prompt; don't expect general VLM behavior.
  • Domain: English-centric web pages and US/EU streaming TV. Ads in other scripts/markets will work worse.
  • Preprocessing sensitivity: browser-side image resampling can shift scores on borderline UI-like inputs (we train with scale-jitter to mitigate; a handful of known residuals remain, e.g. certain consent banners).
  • Screenshots of ads vs. ads: the model sees pixels. Editorial about an ad, or a screenshot of an ad inside an article, can legitimately score high.
  • The training dataset is not released.

License

Inherits the LFM Open License v1.0 from the base model (LiquidAI/LFM2.5-VL-450M). The Minus extension source is at garagehq/Minus-chrome-extension.

Support

Minus is free and open-source โ€” the model above, the Chrome extension, and the device it grew out of. If it saves you from a few autoplay pre-rolls, you can buy me a coffee โ˜•:

Buy Me A Coffee

buymeacoffee.com/cyrilengmann

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for TheGarageDev/Minus-v0.1

Quantized
(26)
this model