Ministral 3 14B, think symbolic image
Ministral 3 14B, think symbolic image is a LoRA adapter of mistralai/Ministral-3-14B-Instruct-2512-BF16, Mistral AI's 14-billion-parameter vision model (a 0.4B Pixtral vision encoder of 24 layers and the Ministral 3 language model of 40 layers), that looks at a picture and writes the row of thought-symbolic-image-captions: a short chain of plain-language thoughts, one named step per line, then the wordings (a caption, a prompt, tags, a critique, by depth), then the questions a careful looker would still ask, each with its answer and what settles it. It is one of five model families trained beside the Lucia line (Qwen3.5) and the Ulisse line (Gemma 4) under Lucia v1's recipe and read on the same held-out sets; it is not named yet. Every looker is taught the same rows under the same recipe; the base models differ in what they can hold, and the reads below say what this one holds. It names the medium at Lucia's level and says as much of a picture as she does; less of what it says is backed by the picture's own captions, the lowest of the five.
see: A single figure, seated, holding a book, in three-quarter view.
place: The figure sits at the centre, the book held low against the lap.
form: The sitter fills the frame from the knees up, the background a plain dark wash.
colour: Brown ink over graphite, the paper a warm cream.
mood: The lowered eyes and the still hands suggest absorption, a reader lost in the page.
caption: A seated figure reads a book held in the lap, drawn in brown ink over graphite.
prompt: drawing, seated figure reading, three-quarter view, brown ink over graphite, cream paper, plain dark wash
question: thing name -> book [record]
question: medium -> ink and graphite [record]
question: mood tone -> absorbed [chain]
question: sitter identity -> unknown [unknown]
The steps a chain may use, in the order a careful looker takes them: see, name, place, count, relate, form, light, colour, mood,
mean, intend, story, compare, change, check, say. A quick look holds 1 to 2 thoughts, a closer look 3 to 5, a long look 6 to 10.
Questions end in [record] (the answer is a fact of the picture), [chain] (the chain worked it out) or [unknown]. The prompt
line's first term names the kind of picture (painting, print, drawing, photograph).
Loading
This repository holds the LoRA adapter (rank 32, 121.9 M trainable parameters, saved in fp32); there is no full fine-tune. Needs transformers 5 (the reads ran on 5.21.0) and peft 0.18 or newer.
Run it as it was trained: no system prompt of your own (its template inserts Mistral's default system message when none is given, and every training row carried it), greedy decoding; the Instruct model does not think. Its rows end with </s>, the id its generation config stops on. Its tokenizer prints transformers' warning about an incorrect pre-tokenizer pattern (fix_mistral_regex); on these rows the flag changes no token (1,000 rows, 142,575 tokens either way), and the adapter was trained without it.
The base model, the adapter merged into it, the processor from this repository (the base processor's files are kept here):
import torch
from peft import PeftModel
from transformers import AutoModelForMultimodalLM, AutoProcessor
processor = AutoProcessor.from_pretrained("AbstractPhil/ministral-3-14b-think-symbolic-image")
model = AutoModelForMultimodalLM.from_pretrained("mistralai/Ministral-3-14B-Instruct-2512-BF16", dtype=torch.bfloat16, device_map="cuda")
model = PeftModel.from_pretrained(model, "AbstractPhil/ministral-3-14b-think-symbolic-image").merge_and_unload().eval()
Then:
from PIL import Image
image = Image.open("picture.jpg").convert("RGB")
prompt = ("Look at this picture and think it through in writing, a closer look; then write a caption and a "
"prompt or tags, and the questions a careful looker would still ask, each as `question: what -> "
"answer [record, chain or unknown]`.")
messages = [{"role": "user", "content": [{"type": "image", "image": image}, {"type": "text", "text": prompt}]}]
text = processor.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
inputs = processor(text=[text], images=[image], return_tensors="pt").to(model.device)
out = model.generate(**inputs, max_new_tokens=800, do_sample=False)
print(processor.batch_decode(out[:, inputs["input_ids"].shape[1]:], skip_special_tokens=True)[0])
Reading many pictures in one batch. Its vision tower packs every picture of a batch into one sequence. In a batch of 64 on an RTX PRO 6000 (bf16) the pictures after the first few came out wrong (the medium named 322 times in 500, against 415 one picture at a time); single pictures and the training batches of 8 read right. For large batches, run the vision tower one picture at a time and let the image processor pad pictures of different sizes (its configuration leaves padding unset): the package's family.prepare_model(model) and family.prepare_processor(processor, model) (from v0.1.38) do both; at batch 64 the medium then reads 414.
The prompts it was trained on
The adapter was trained on these exact asks (the trained forms of the package's prompts.full and prompts.short); a reworded
ask is a different input. The reads below use the whole row at each picture's depth.
| depth | the whole row (the form these reads use) | the short form |
|---|---|---|
| a quick look | Look at this picture and think it through in writing, a quick look; then write a caption, and the questions a careful looker would still ask, each as question: what -> answer [record, chain or unknown]. |
Look at this picture and think it through in writing, a quick look, ending with a caption. |
| a closer look | Look at this picture and think it through in writing, a closer look; then write a caption and a prompt or tags, and the questions a careful looker would still ask, each as question: what -> answer [record, chain or unknown]. |
Look at this picture and think it through in writing, a closer look, ending with a caption. |
| a long look | Look at this picture and think it through in writing, a long look; then write a caption, a prompt, tags and a critique, and the questions a careful looker would still ask, each as question: what -> answer [record, chain or unknown]. |
Look at this picture and think it through in writing, a long look, ending with a caption. |
The depth words: "a quick look" (1 to 2 thoughts), "a closer look" (3 to 5), "a long look" (6 to 10). The parser, the scorer and
the trainer are in qwen-symbolic-thinking
(qwen_symbolic_thinking.chain.parse, chain.score); the same package extracted every number below.
The reads
Read the same way as the Lucia and Ulisse lines, by the same reader, beside Lucia v1 (the model the recipe was made for) and Ulisse 12B. First a screen: 60 pictures and 40 specifications no training row came from, scored against the dataset's own rows. Row shape is the share of rows written in the row's form; at its depth, the share whose chain holds the number of thoughts its depth asks for; said is the share of a picture's own captions' content words that the thoughts and the caption say, and backed the share of the model's content words those captions back; a definition is a thought that defines a word instead of looking. Then the medium term on two sets no training row came from, from the picture list AbstractPhil/qwen-thinking-images: 500 National Gallery of Art pictures (100 drawings, prints, paintings, photographs and objects each), the prompt line's first term read against the catalogue's kind, and 200 pictures of the Art Institute of Chicago, the National Gallery, the Cleveland Museum of Art and the Met.
| read | Ministral 3 14B | Lucia v1 (Qwen3.5-9B) | Ulisse 12B (Gemma 4 12B) |
|---|---|---|---|
| row shape, pictures / specifications | 1.00 / 1.00 | 1.00 / 1.00 | 1.00 / 1.00 |
| at its depth: pictures, whole row / short form; specifications | 1.00 / 1.00; 0.93 | 1.00 / 1.00; 0.95 | 1.00 / 1.00; 0.93 |
| said / backed, whole rows (short form) | 0.19 / 0.23 (0.23 / 0.26) | 0.19 / 0.30 (0.23 / 0.30) | 0.18 / 0.27 (0.21 / 0.27) |
| rows with a definition: pictures / specifications | 0 of 60 / 6 of 40 | 1 of 60 / 3 of 40 | 1 of 60 / 5 of 40 |
| 500 held-out pictures: painting / print / drawing / photograph / object named rightly of 100 (sum) | 83 / 78 / 81 / 82 / 91 (415) | 83 / 76 / 86 / 80 / 90 (415) | 83 / 74 / 80 / 81 / 91 (409) |
| 200 museum pictures: painting / print / drawing / photograph / object | 14 of 27 / 38 of 39 / 12 of 13 / 12 of 13 / 65 of 66 | 13 of 27 / 38 of 39 / 12 of 13 / 11 of 13 / 66 of 66 | 13 of 27 / 36 of 39 / 12 of 13 / 11 of 13 / 66 of 66 |
| time a picture on one RTX PRO 6000 (batch 64, 800 new tokens a row) | 0.89 s (the 500) | 0.27 s | 0.36 s |
What this says: It names the medium at Lucia's level: 415 of the 500 held-out pictures read one picture at a time (her sum; drawings 81 against her 86), and the museum pictures within 1 a kind of hers. Its first reads, in batches of 64, were wrong (322), and the fault was the batching, not the adapter (see the batching note above; the training batches of 8 read 414). The form is whole (the specification rows 0.93), and it says as much of a picture's own captions as Lucia does (0.19). Its backing is the five's lowest: 0.23 of what it says against her 0.30 (its base 0.16), 0.26 on the short form; the rest of what it writes is the picture as it sees it, less often in the captions' words. It is the slowest to train (20.4 seconds a step, 15.4 hours) and reads at 0.89 seconds a picture at batch 64 with its vision tower one picture at a time (3.64 seconds a picture alone). The table's medium and museum rows are its one-picture-at-a-time reads.
Before training the base model wrote the row's form from the plain ask (0.93) at its depth (0.92), 3.4 thoughts a picture, and backed 0.16 of what it said; it wrapped each line of a specification row in backticks (form 0.15 there), a habit the training took away. The training taught it the row's shape at each depth, the backing and the house vocabulary.
Limits, shared with the family: quick looks are the fragile depth, where one thought can name a wrong thing; the museum painting
row understates every model, because watercolours and gouaches on paper are named drawings, as the National Gallery's own catalogue
does; English only; the row's conventions (the steps, the depths, the question form) are the dataset's. The specification-row
definitions are counted on 40 rows, the noisiest line of the table. The reads are made with qwen_symbolic_thinking.tools
(probe_read, museum_read, museum_mismatch, screen_conflicts), so any adapter can be read the same way.
How it was trained
| base | mistralai/Ministral-3-14B-Instruct-2512-BF16, bf16; pictures at the processor's default: about 1,406 picture tokens with the row breaks for a square 1,024-pixel picture (14-pixel patches merged 2 x 2, up to 1,540 pixels); its vision encoder frozen, outside the adapter |
| adapter | LoRA rank 32, alpha 64, dropout 0.05 on the language model's q, k, v, o, gate, up and down projections of all 40 layers; 121.9 M trainable parameters, saved in fp32 |
| data | Lucia v1's rows exactly: 951 picture rows taught twice, 500 long-look drawn rows, 2,000 synthetic closer looks and 17,385 museum rows whose catalogue gives the medium, the prompt line's first term set to it (6,606 drawings, 3,523 paintings, 3,000 prints, 2,016 photographs, 2,240 objects); 20,836 items, 21,787 examples (18,336 whole rows, 2,951 short forms, 500 specification rows); the 500 held-out probe pictures never trained |
| optimiser | plain Adam 2e-4, cosine schedule, 3% warmup, batch 8 x 2, two epochs (2,724 steps, 20.41 s a step, 927 minutes on one RTX PRO 6000), the loss on the answer only, seed 20261030; final training loss 0.410 (each family's own tokens, so not comparable across families) |
| length | max_len 2,560; no example of the 43,574 collated was cut (the longest 2,231 tokens) |
| thinking and turn end | the Instruct model does not think; its template's default system message is on every row; the rows end with </s> |
| record | qwen-symbolic-thinking v0.1.32 on transformers 5.21.0, run_queue("lane2") from notebooks/lane2.ipynb; the run's full log is train_summary.json beside the weights |
Where it was trained
- The code: qwen-symbolic-thinking on GitHub: the trainer, the screens, the reads and what each model family
needs (
qwen_symbolic_thinking/family.py). This adapter was trained by v0.1.32 (tagv0.1.32); the batching and loading notes on this card hold for v0.1.38. - The run's record: the model repository AbstractPhil/qwen-symbolic-thinking-image-training (a model repository, not a
dataset): this adapter with its step checkpoints under
lora/Ministral-3-14B-Instruct-2512-BF16/r32/20261102_060730_G_med4_2ep_mi14/, the training sets it read (sft/pictures_v2.json,sft/drawn_deep_v2.json,synth/S_synth.json,sft/medium_v4.json) and the screens underscreens/. - The rows: the dataset thought-symbolic-image-captions (the row's form and the picture rows) and the picture list AbstractPhil/qwen-thinking-images (the museum pictures and the held-out probe).
Versions
| version | where | tag |
|---|---|---|
| Ministral 3 14B, think symbolic image v1 | the root of this repository | v1 |
The lookers
The Lucia line is Qwen3.5 and starts at AbstractPhil/qwen3.5-9b-think-symbolic-image; the Ulisse line is Gemma 4. The five families below them (North-Micro-Vision, GLM-4.6V-Flash, Molmo2-O-7B, Ministral 3 14B and Phi-4-reasoning-vision-15B) are trained under Lucia v1's recipe at her learning rate (each has its own vision encoder, frozen under the adapter) and read on the same sets.
License
Apache-2.0, the base model's licence. The rows it was taught come from the datasets above under their own terms.