A3 stays the dense-captioning specialist. A3-Instruct is the one to reach for when you want conversation, VQA, multi-turn image grounding, tool-call drafting, identity-preserving chat, or creative writing.
| Architecture | Qwen3-VL ViT (frozen, ~0.41 B) + 2-layer MLP projector (trained, 37 M) + A2 Mistral decoder (full FFT, 12.25 B) |
| Total params | 12.69 B |
| Trainable in Stage-2 | 12.28 B (96.8%) — ViT frozen |
| Base | schneewolflabs/A3 |
| Training corpus | schneewolflabs/ArtemisMix-v1.1 (364,816 rows; 333,001 after the 4096-token filter) |
| Epochs | 1 |
| Effective batch | 16 (bs 1 × grad-accum 16) |
| Optimizer | paged AdamW 8-bit |
| Learning rate | 1e-5, cosine, warmup 3% |
| Max seq length | 4096 |
| Hardware | 1× NVIDIA GB10 (DGX Spark, 128 GB unified) |
| Wall-clock | ~7.4 days |
| Final eval loss | 0.7516 (down from 0.85 at the first eval) |
Schneewolf-Labs/llama.cpp fork's Artemis VLM mmproj graft (same path as A3).<think> gate is currently underdeveloped. Even with enable_thinking=True, the model tends to emit an empty <think></think> and put reasoning in the answer body rather than fill the wrapper. The model can reason — it just doesn't use the dedicated block. Likely because the training data had <think>...</think> embedded in assistant content and the model learned to close, not fill, the template-injected wrapper. Under investigation.<tool_call> syntax drifted. A2's tool-call format (<tool_call> blocks with JSON) was rehearsed via 30 K oversampled A2-tool-orpo rows, but A3-Instruct emits the concept of an API call (e.g. an OpenWeatherMap GET URL with params) rather than the structured token format. The behavior is reasonable; the format isn't.transformers ArtemisVLMForConditionalGeneration interface from the artemis-vlm package (PyPI: artemis-vlm >= 0.1.3). Also runs in llama.cpp via the Schneewolf-Labs/llama.cpp fork's mtmd support (decoder GGUF + Artemis mmproj GGUF — same pattern as A3).1from transformers import AutoConfig, AutoTokenizer
2from artemis_vlm import ArtemisVLMForConditionalGeneration, ArtemisVLMProcessor
3import torch
4
5ckpt = "schneewolflabs/A3-Instruct"
6model = ArtemisVLMForConditionalGeneration.from_pretrained(ckpt, dtype=torch.bfloat16).to("cuda")
7cfg = AutoConfig.from_pretrained(ckpt, trust_remote_code=True)
8tok = AutoTokenizer.from_pretrained(ckpt, trust_remote_code=True)
9proc = ArtemisVLMProcessor(tokenizer=tok, vision_config=cfg.vision_config)schneewolflabs/A3 — Stage-1 base (projector-only alignment, 1 M BLIP3o samples)schneewolflabs/A2 — text decoder (Mistral 12.3 B, hidden 5120, Tekken vocab)schneewolflabs/ArtemisMix-v1.1 — training corpusschneewolflabs/Athanorlite-DPO — creative-writing source (collapsed to SFT, non-reasoning bucket)schneewolflabs/i-DPO — identity/voice anti-drift bedrock