A LoRA adapter for Qwen/Qwen3.5-9B, trained on scientific chart question answering.
Produced by an Adaption Labs AutoScientist run for the AutoScientist Part 2 challenge.
This repository contains a LoRA adapter. It is not a merged model and it is not a
standalone model. There are no base model weights here. The 15.7 MB
adapter_model.safetensors file holds 3,932,160 LoRA parameters and nothing else. You
must load the base model separately and apply this adapter on top of it with peft.
What you need to load it
The exact base model string is:
Qwen/Qwen3.5-9B
A note on the base model string, read this before you file an issue
Adaption's exporter wrote this into adapter_config.json, and it shipped that way until
2026-08-13:
I kept the original exported string verbatim in the same file rather than deleting it, so
the export stays auditable and you can see exactly what changed. No weight was touched.
The base is Qwen/Qwen3.5-9B, and here is the evidence beyond the string itself. The evidence is the config.json shipped alongside the
adapter in this repo. Flattening both configs and comparing all 66 keys, every
architecture-defining value is identical:
key
value
architectures
Qwen3_5ForConditionalGeneration
model_type
qwen3_5
hidden_size
4096
num_hidden_layers
32
num_attention_heads
16
num_key_value_heads
4
head_dim
256
intermediate_size
12288
vocab_size
248320
vision_config.depth
27
vision_config.hidden_size
1152
The only differences are serialization and training-time fields (transformers_version,
torch_dtype, use_cache, explicit token ids). The LoRA tensor shapes agree with this
too: lora_A is [16, 4096] against hidden_size 4096, and q_proj.lora_B is
[8192, 16], which is 16 heads times 256 head_dim times the 2x width of this model's
gated attention output.
So: pass Qwen/Qwen3.5-9B explicitly when you load, and everything lines up.
How to load it
python
1import torch
2from transformers import AutoModelForImageTextToText, AutoProcessor
3from peft import PeftModel
45BASE ="Qwen/Qwen3.5-9B"6ADAPTER ="manifesta/scientific-chart-qa-lora-qwen3.5-9b"78model = AutoModelForImageTextToText.from_pretrained(9 BASE,10 dtype=torch.bfloat16,11 device_map="auto",12)1314# Passing the already-loaded base model object is the safe route. The config now15# points at a base that resolves, but Qwen/Qwen3.5-9B is a large download either way.16model = PeftModel.from_pretrained(model, ADAPTER)17model.eval()1819# The processor is included in this repo, so you can load it from either place.20processor = AutoProcessor.from_pretrained(ADAPTER)2122messages =[{23"role":"user",24"content":[25{"type":"image","url":"https://upload.wikimedia.org/wikipedia/commons/2/26/Line_graph_example.png"},26{"type":"text","text":"What is the value on the y axis at x = 3?"},27],28}]2930inputs = processor.apply_chat_template(31 messages,32 add_generation_prompt=True,33 tokenize=True,34 return_dict=True,35 return_tensors="pt",36).to(model.device)3738out = model.generate(**inputs, max_new_tokens=256)39print(processor.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True))
If you want a single merged checkpoint instead of runtime adapter application:
Merging bakes the adapter into a full-size copy of the base weights. That copy is not
distributed here, you produce it yourself.
Tested against peft 0.15.1, which is the version that wrote this adapter.
transformers must be new enough to know the qwen3_5 architecture (the export was
written by transformers 5.13.0).
LoRA configuration
Taken verbatim from adapter_config.json.
setting
value
peft_type
LORA
task_type
CAUSAL_LM
r
16
lora_alpha
32 (scaling factor 2.0)
lora_dropout
0.0
target_modules
q_proj, k_proj, v_proj, o_proj
bias
none
use_rslora
false
use_dora
false
modules_to_save
null
init_lora_weights
true
inference_mode
true
What actually got adapted
Reading the tensor index of adapter_model.safetensors rather than trusting the config
prose:
64 tensors, all float32, 3,932,160 parameters total.
Every tensor is under base_model.model.model.language_model.layers.*.self_attn.*.
Only 8 of the 32 decoder layers carry LoRA: layers 3, 7, 11, 15, 19, 23, 27, 31.
Those are exactly the full_attention layers. This model interleaves linear attention
and full attention with full_attention_interval 4, and the linear attention layers do
not expose q_proj/k_proj/v_proj/o_proj, so they were skipped.
Zero vision tensors. The vision tower is completely untouched. adapter_config.json
carries a long exclude_modules list covering all 27 model.visual.blocks.*. The chart
reading behaviour that changed is language-side behaviour conditioned on vision features,
not a retrained vision encoder.
Practical consequence: only 8 attention blocks out of 32 layers were adapted, on a 9B
base. This is a small intervention, which is consistent with the small measured effect
described below.
Training run
Facts below come from trainer_state.json, included in this repo so you can check the
curve yourself.
Eval loss fell monotonically from 1.4545 to 1.3909 across the run, about 4.4 percent.
Training loss did not visibly trend, it stayed in a 1.37 to 1.59 band with one outlier at
step 12 (0.7522, a single batch at batch size 1, so it is one example and not a trend).
With train_batch_size 1 and 21 steps the per-step training loss is essentially a
per-example reading and is very noisy. The eval curve is the one worth reading.
21 optimizer steps at batch size 1 is 21 examples of gradient signal against a 6,976 row
dataset. This is a short run. Read the results section with that in mind.
Results, stated plainly
Adaption's head to head evaluation compared the adapted model against the unmodified base
model:
wins
adapted (this adapter)
51
base Qwen3.5-9B
49
51 versus 49 out of 100. That is a two point margin. On 100 paired comparisons the
one-sigma spread from coin flipping alone is about 5 points, so this result is well inside
noise and should be read as no measurable win, not as a win. The eval loss improvement
(1.4545 to 1.3909) is real and monotonic, but it did not convert into a preference margin
that survives its own error bars.
I am not going to dress this up. What this adapter demonstrates is a clean, completed,
fully documented adaptation run with a downward eval curve. It is not a demonstration of a
large capability gain on chart QA.
The other two runs in this batch, for context
Three AutoScientist runs were completed. Only this one had its weights exported, so only
this one is published. The other two are listed here for honesty about the full picture,
not as a claim of anything. No weights are published for them, and no repository exists
for them. Do not go looking for one.
run
dataset
steps
peak grad norm
win rate (adapted vs base)
this adapter, Qwen3.5-9B chart QA
46b5c093-a9e5-45a0-9265-412b003c1d28, 6,976 rows
21
4.44
51 vs 49
gemma-3-27b-it VLM chart QA 17k
3f347c8b-5724-4f96-9417-251623d8aaa5, 17,070 rows
34
0.79
50 vs 50, a dead tie
gemma-4-31b-it verified math and code
6ad1a83f-b806-4a20-ba6d-239029d30711, 17,586 rows
59
744.9
46 vs 54, a regression, the adapted model lost
The math and code run made the model worse. A peak gradient norm of 744.9 against 0.79 and
4.44 on the two chart runs is a roughly three orders of magnitude difference and is the
obvious thing to look at first when explaining why. That run is reported here because
suppressing a negative result would make the two positive-ish numbers meaningless.
Intended use and limits
Intended use: research on parameter efficient adaptation for chart and scientific figure
question answering, and as a reproducible artifact for the AutoScientist Part 2
submission. Load it, read trainer_state.json, check the numbers above against it.
Limits, all of them real:
The measured preference win is inside noise. Do not deploy this expecting better chart
reading than plain Qwen/Qwen3.5-9B.
21 optimizer steps at batch size 1. Under-trained by any normal standard.
Vision tower untouched, so nothing here improves figure perception itself.
Only 8 of 32 layers adapted, attention projections only, no MLP.
English only. Training data is English scientific chart QA.
Inherits every limitation, bias and failure mode of Qwen/Qwen3.5-9B. Chart QA models
in general will confidently misread axis values, mislabel series and invent gridline
numbers. Nothing in this adapter fixes that, and a 51 to 49 preference margin certainly
does not.
No safety tuning of any kind was performed.
Files in this repository
file
what it is
adapter_model.safetensors
the LoRA weights, 15.7 MB, 64 tensors, fp32
adapter_config.json
peft config, unedited from the export, including the unresolvable base repo id
trainer_state.json
the full training log, every step, every eval, the evidence for the loss table above
config.json
base architecture config as recorded at export time, the evidence for the base model identification
manifesta/scientific-chart-qa-17k on the Hugging Face Hub, and the same dataset on
Kaggle. The Adaption side ingested 6,976 rows into dataset
46b5c093-a9e5-45a0-9265-412b003c1d28 for this specific run.
Everything behind these weights is public
The dataset this adapter was trained on, the scripts that built it, and a verifier that rechecks
every number claimed here against the live artifacts:
Standard library only, no install step and no account. 16 checks, and the same 16 run on a daily
schedule in GitHub Actions, so the badge above goes red if any claim on this card stops being true.
The tensor facts in this card are among the checks: layer coverage is re-derived from the published
adapter_model.safetensors by name, not copied from the config.
The adapter weights are released under Apache 2.0. The base model
Qwen/Qwen3.5-9B carries its own license, which applies to you separately whenever you
load the base, and it is your responsibility to comply with it.
Citation
bibtex
1@misc{navardauskas2026chartqalora,
2 title = {scientific-chart-qa-lora-qwen3.5-9b: a LoRA adapter for scientific chart question answering},
3 author = {Navardauskas, Aivaras},
4 year = {2026},
5 note = {Adaption Labs AutoScientist Part 2. Trained on Adaption dataset 46b5c093-a9e5-45a0-9265-412b003c1d28.},
6 url = {https://huggingface.co/manifesta/scientific-chart-qa-lora-qwen3.5-9b}
7}