Views
No views yet

Image → SigLIP Vision Encoder → Projection Layer → SmolLM + LoRA → Captionmodel.safetensors file (984 MB) contains all weights needed for inference:vision_encoder.*projection.*language_model.base_model.model.*language_model.*.lora_A.default.weight, language_model.*.lora_B.default.weightpython compare_inference.py --model-dir . --onnx-dir onnx --image cat.jpg --prompt "A photo of" --max-new-tokens 15compare_inference.py:1vision_encoder, projection, language_model, _ = load_models(args.model_dir, device)
2pixel_values = preprocess(args.image, processor, device)
3
4torch_caption = torch_generate(
5 vision_encoder, projection, language_model, tokenizer, pixel_values, args.prompt, args.max_new_tokens
6)
7
8vision_sess, proj_sess, lm_sess = load_onnx_sessions(args.onnx_dir)
9onnx_caption = onnx_generate(
10 vision_sess, proj_sess, lm_sess, language_model, tokenizer, pixel_values, args.prompt, args.max_new_tokens
11)--image defaults to cat.jpg in the repo if you do not pass one. The script prints both captions so you can verify parity between torch and ONNX.demo/:cd demo && python -m http.server 8000demo/main.js drives the full pipeline fully on-device:1await loadAll(); // downloads tokenizer/processor assets and ONNX models from ./demo/models
2
3const pixelData = await preprocessImage(currentImage);
4const visionHidden = await runVision(pixelData);
5const projected = await runProjection(visionHidden);
6
7const prompt = ''; // not needed
8const encoded = await tokenizer(prompt);
9const initFeeds = {
10 prefix_embeddings: projected,
11 input_ids: new ort.Tensor('int64', BigInt64Array.from(encoded.input_ids.data.map(BigInt)), [1, encoded.input_ids.data.length]),
12};
13const initOutputs = await prefixInitSession.run(initFeeds);
14// then decode step-by-step with cached past:
15const feeds = buildDecoderInputs([BigInt(nextToken)], attention, position, past);
16const outputs = await lmSession.run(feeds);http://localhost:8000, drop an image, and click Generate caption to watch the vision → projection → prefix-init → decode flow run in the browser.| Component | Size | Parameters | Status |
|---|---|---|---|
| Vision Encoder | 768 hidden | ~87M | Frozen |
| Projection | 768→576 | ~443K | Trainable |
| Language Model | 576 hidden, 30 layers | ~134M | Base frozen |
| LoRA Adapters | rank=16 | ~1.8M | Trainable |
| Total | ~221M | 2.2M trainable |
model.safetensors; ONNX runtime uses three files in onnx/demo/ and runs the ONNX exports via ort.js + transformers.js (vision encoder → projection → prefix_init → decoder). The demo/models directory points to the ONNX files in onnx/, so make sure those exports are present locally.cd demo && python -m http.server 8000http://localhost:8000, drop an image, and click Generate caption to see the model run fully on-device. No remote fetches are required.