Chinzhu commited on
Commit
431c7a5
·
verified ·
1 Parent(s): 804e2da

BirdAgent GSPO adapter + model card + figures

Browse files
README.md CHANGED
@@ -1,3 +1,216 @@
1
  ---
2
  license: apache-2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: apache-2.0
3
+ base_model: Qwen/Qwen3-VL-4B-Instruct
4
+ library_name: peft
5
+ pipeline_tag: image-text-to-text
6
+ language:
7
+ - en
8
+ tags:
9
+ - lora
10
+ - peft
11
+ - agentic
12
+ - tool-use
13
+ - function-calling
14
+ - vision-language
15
+ - bird-identification
16
+ - fine-grained-recognition
17
+ - gspo
18
+ - grpo
19
+ - rlvr
20
  ---
21
+
22
+ <h1 align="center">BirdAgent&nbsp;·&nbsp;Qwen3-VL-4B</h1>
23
+
24
+ <p align="center">
25
+ <b>A 4B vision–language agent that identifies birds by <i>orchestrating domain tools</i>,<br>
26
+ beating much larger models that are handed the very same tools.</b>
27
+ </p>
28
+
29
+ <p align="center">
30
+ 📄 <a href="https://github.com/xinzhuwang-wxz/Bird-Agent">Paper (under review)</a> &nbsp;·&nbsp;
31
+ 💻 <a href="https://github.com/xinzhuwang-wxz/Bird-Agent">Code</a> &nbsp;·&nbsp;
32
+ 📊 <a href="https://huggingface.co/datasets/Chinzhu/BirdAgent-Benchmarks">Benchmarks</a> &nbsp;·&nbsp;
33
+ 🧩 <a href="https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct">Base model</a>
34
+ </p>
35
+
36
+ ---
37
+
38
+ > **TL;DR** — Fine-grained bird ID is hard for *every* model class because the
39
+ > deciding evidence often is not in the image being looked at (it is in a
40
+ > diagnostic call, a range prior, or a magnified detail crop). Instead of scaling
41
+ > the model, we teach a small one to **orchestrate** the tools that recover that
42
+ > evidence. **BirdAgent** (a LoRA adapter on `Qwen3-VL-4B-Instruct`) reaches a
43
+ > pooled **solve** rate of **0.34**, *beating every same-tool API model*
44
+ > (Qwen3-235B + tools = 0.00, Doubao-2.1-Pro + tools = 0.17), beating Sonnet, and
45
+ > trailing only Opus (0.46) — at ~50–60× fewer parameters.
46
+
47
+ <p align="center">
48
+ <img src="assets/fig_main.png" width="620" alt="Pooled solve rate: our 4B agent beats every same-tool API model and Sonnet, second only to Opus."><br>
49
+ <em>Pooled solve rate (correct at the declared taxonomic grain). Our 4B agent
50
+ (orange/vermilion) beats every same-tool API model and Sonnet, and trails only
51
+ Opus. Dashed line = pure-recognition floor (T0).</em>
52
+ </p>
53
+
54
+ ## Highlights
55
+
56
+ - **Orchestration beats scale.** A trained 4B agent outperforms 30–235B API
57
+ models given the *identical* tool interface.
58
+ - **Having tools ≠ using tools.** Qwen3-235B *calls* the exact same tools yet
59
+ scores **0.00** — tool access does not confer tool *use*.
60
+ - **Calibrated, not reckless.** The agent names a species when the evidence
61
+ supports it and gracefully degrades to genus/family when it does not;
62
+ species-declaration precision rises to **1.0** with **overclaim = 0.00**.
63
+ - **Three-modality.** Image, sound-only, or image+sound (audio is tool-mediated).
64
+ - **Reproducible & honest.** All numbers are Δ-over-base under one identical tool
65
+ harness; no leaderboard gaming, no closed-model distillation.
66
+
67
+ ## Model at a glance
68
+
69
+ | | |
70
+ |---|---|
71
+ | **Base model** | [`Qwen/Qwen3-VL-4B-Instruct`](https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct) (Apache-2.0) |
72
+ | **This repo** | LoRA adapter (the **released** checkpoint = GSPO ckpt-200) |
73
+ | **Parameters** | 4B base + LoRA (`r=64`, `α=128`, `dropout=0.05`, bf16) |
74
+ | **Adapter targets** | language-model `q/k/v/o/gate/up/down_proj` (`peft ≥ 0.19`) |
75
+ | **Training** | SFT cold-start → on-policy DPO → **GSPO** (RLVR) |
76
+ | **Task** | agentic fine-grained bird identification with calibrated abstention |
77
+ | **Modalities** | image · sound · image+sound |
78
+ | **License** | Apache-2.0 (adapter); base is Apache-2.0 |
79
+
80
+ > ⚠️ **This repository is the policy only.** To run the full agent you also need
81
+ > the tool servers (Grounding-DINO, BioCLIP-2, Perch-2, SINR) and the evaluation
82
+ > harness — see the [code repository](https://github.com/xinzhuwang-wxz/Bird-Agent).
83
+ > Loaded standalone, the model emits Hermes-format `<tool_call>` turns that
84
+ > expect tool responses to be fed back; it is **not** a plain image→label classifier.
85
+
86
+ ## Results
87
+
88
+ Two self-built, tier-stratified benchmarks — an **agentic** (information-gap) set
89
+ and a **calibration** set — evaluated under an **identical tool harness** for
90
+ every model. Metric = **solve**: correct at the *declared* grain (a genus verdict
91
+ counts iff the genus is right; over-committed species are penalized).
92
+
93
+ | # | model / condition | common | uncommon | rare | **overall** | n |
94
+ |---|---|:--:|:--:|:--:|:--:|:--:|
95
+ | 1 | Opus · bare | 0.75 | 0.25 | 0.38 | **0.46** | 24 |
96
+ | 2 | Opus · web | 0.62 | 0.25 | 0.25 | 0.38 | 24 |
97
+ | 3 | **BirdAgent-DPO (4B) · tools** | 0.61 | 0.23 | 0.22 | **0.34** | 80 |
98
+ | 4 | Sonnet · bare | 0.62 | 0.12 | 0.25 | 0.33 | 24 |
99
+ | 5 | **BirdAgent-SFT (4B) · tools** | 0.42 | 0.25 | 0.22 | 0.29 | 90 |
100
+ | 6 | Sonnet · web | 0.50 | 0.25 | 0.12 | 0.29 | 24 |
101
+ | 7 | Doubao-2.1-Pro · bare | 0.41 | 0.21 | 0.08 | 0.23 | 70 |
102
+ | 8 | T0 tool floor | 0.46 | 0.10 | 0.03 | 0.20 | 900 |
103
+ | 9 | Doubao-2.1-Pro · our-tools | 0.45 | 0.04 | 0.04 | 0.17 | 70 |
104
+ | 10 | Qwen3-235B · bare | 0.14 | 0.00 | 0.08 | 0.07 | 70 |
105
+ | 11 | base-4B · tools | 0.12 | 0.06 | 0.00 | 0.06 | 90 |
106
+ | 12 | Qwen3-235B · web | 0.09 | 0.04 | 0.00 | 0.04 | 70 |
107
+ | 13 | Qwen3-235B · our-tools | 0.00 | 0.00 | 0.00 | 0.00 | 70 |
108
+
109
+ *Big models: C0 = bare, N = vendor web search, C1 = our exact tools. API baselines
110
+ run on cost-bounded stratified subsets; our models on the full sets. Vendor web
111
+ search does not help image ID (C0 ≈ N).*
112
+
113
+ ## Quickstart
114
+
115
+ ```python
116
+ from transformers import AutoProcessor, AutoModelForImageTextToText
117
+ from peft import PeftModel
118
+
119
+ base = "Qwen/Qwen3-VL-4B-Instruct"
120
+ model = AutoModelForImageTextToText.from_pretrained(
121
+ base, torch_dtype="bfloat16", device_map="auto")
122
+ model = PeftModel.from_pretrained(model, "Chinzhu/BirdAgent-Qwen3VL-4B")
123
+ processor = AutoProcessor.from_pretrained(base)
124
+
125
+ # BirdAgent is an *agent*: give it the BirdAgent system prompt + the nine tool
126
+ # schemas, then run a loop that answers its <tool_call> turns with real tool
127
+ # observations (detection boxes, classifier top-k, geo prior, ...). The full
128
+ # harness + tool servers are in the code repo:
129
+ # https://github.com/xinzhuwang-wxz/Bird-Agent
130
+ ```
131
+
132
+ ## How it works
133
+
134
+ ### The nine tools
135
+
136
+ | group | tools |
137
+ |---|---|
138
+ | **Perception** (local, deterministic) | `detect_bird` (Grounding-DINO) · `quality_gate` · `zoom_in` · `crop` · `enhance` · `audio_quality` |
139
+ | **Recognition** (served models) | `classify_image` (BioCLIP-2) · `classify_sound` (Perch-2) |
140
+ | **External** | `geo_prior` (SINR range × month) |
141
+
142
+ The agent plans a sequence of calls, accumulates the returns in an explicit
143
+ **evidence ledger**, and commits a verdict at a **calibrated taxonomic grain**.
144
+ All tools are Apache/MIT-licensed and deterministic given input (so their outputs
145
+ can be pre-cached for single-GPU RL).
146
+
147
+ ### Training recipe (SFT → DPO → GSPO)
148
+
149
+ <p align="center">
150
+ <img src="assets/fig_stage.png" width="300" alt="Stage chain: calibration solve and species-declaration precision across Base/SFT/DPO/GSPO.">
151
+ <img src="assets/fig_gspo.png" width="300" alt="GSPO-200 vs DPO initialization on both benchmark sets."><br>
152
+ <em>Left: DPO sharpens calibration (species-declaration precision 0.33→1.0),
153
+ then GSPO adds orchestration; overclaim stays 0.00 throughout. Right: GSPO lifts
154
+ both benchmark sets over its DPO initialization, apples-to-apples.</em>
155
+ </p>
156
+
157
+ - **SFT cold-start** on code-authored *blueprint* tool-use trajectories (loss on
158
+ assistant + tool-call tokens only; tool observations masked).
159
+ - **On-policy DPO** on soft preferences only (ledger discipline, call parsimony)
160
+ — sharpens calibration (species-declaration precision **0.33 → 1.0**).
161
+ - **GSPO** (sequence-level importance weighting; `β=0.04`, `lr=1e-6`,
162
+ `num_generations=4`) with a **grain-graded, reachability-aware** reward:
163
+ species `+1.0/−0.5`, genus `+0.4/−0.3`, family `+0.2/−0.1`, abstain `0`, with
164
+ full species credit gated on the truth being present in some tool's top-*k*.
165
+ GSPO improves over its DPO init apples-to-apples (pooled **0.34 → 0.35**) while
166
+ keeping **overclaim = 0.00** — bolder but not reckless.
167
+
168
+ ## Limitations & responsible use
169
+
170
+ <p align="center">
171
+ <img src="assets/fig_tier.png" width="560" alt="Tier-stratified solve: the common/uncommon/rare cliff is universal — even Opus collapses on the tail."><br>
172
+ <em>The common→rare cliff is universal — even Opus collapses on the tail —
173
+ because the true species leaves the classifiers' top-k. This is the tool
174
+ ceiling, orthogonal to the agent.</em>
175
+ </p>
176
+
177
+ - **Tool ceiling.** Species accuracy is capped by the classifiers: on hard
178
+ rare-tier items ~76% of errors are cases where the truth is absent from every
179
+ classifier's top-*k*. A stronger fine-grained recognizer is an *orthogonal*
180
+ lever (the agent already degrades honestly in this regime).
181
+ - **General-VLM regression (format lock).** Agentic training locks the model into
182
+ emitting tool calls; on generic MCQ probes it drops sharply (MMStar 0.51→0.04,
183
+ MMBench 0.89→0.15). Use it as a *bird agent*, not a general VLM, unless you mix
184
+ general trajectories back in.
185
+ - **Evaluation n.** API baselines were run on cost-bounded stratified subsets
186
+ (n = 12–40); numbers are Δ-over-base under one harness, not leaderboard ranks.
187
+ - **Responsible use.** Research / non-commercial for v0. The API models above are
188
+ **evaluation controls, not teachers** — no closed-model output was distilled
189
+ into this policy.
190
+
191
+ ## Related releases
192
+
193
+ - [`Chinzhu/BirdAgent-Qwen3VL-4B-DPO`](https://huggingface.co/Chinzhu/BirdAgent-Qwen3VL-4B-DPO) — on-policy DPO adapter (this model's GSPO initialization).
194
+ - [`Chinzhu/BirdAgent-Qwen3VL-4B-SFT`](https://huggingface.co/Chinzhu/BirdAgent-Qwen3VL-4B-SFT) — SFT cold-start adapter.
195
+ - [`Chinzhu/BirdAgent-Benchmarks`](https://huggingface.co/datasets/Chinzhu/BirdAgent-Benchmarks) — the agentic (500) and calibration (400) evaluation sets.
196
+
197
+ ## Citation
198
+
199
+ ```bibtex
200
+ @inproceedings{wang2026birdagent,
201
+ title = {BirdAgent: A Small Vision--Language Model that Orchestrates
202
+ Domain Tools Beats Large Models that Merely Hold Them},
203
+ author = {Wang, Xinzhu},
204
+ booktitle = {Under review},
205
+ year = {2026}
206
+ }
207
+ ```
208
+
209
+ ## Acknowledgements
210
+
211
+ Built on [Qwen3-VL](https://huggingface.co/Qwen/Qwen3-VL-4B-Instruct),
212
+ [BioCLIP-2](https://imageomics.github.io/bioclip-2/),
213
+ [Perch-2](https://github.com/google-research/perch),
214
+ [Grounding-DINO](https://github.com/IDEA-Research/GroundingDINO), and
215
+ [SINR](https://github.com/elijahcole/sinr). Trained with
216
+ [ms-swift](https://github.com/modelscope/ms-swift).
adapter_config.json ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "alora_invocation_tokens": null,
3
+ "alpha_pattern": {},
4
+ "arrow_config": null,
5
+ "auto_mapping": null,
6
+ "base_model_name_or_path": "Qwen/Qwen3-VL-4B-Instruct",
7
+ "bias": "none",
8
+ "corda_config": null,
9
+ "ensure_weight_tying": false,
10
+ "eva_config": null,
11
+ "exclude_modules": null,
12
+ "fan_in_fan_out": false,
13
+ "inference_mode": true,
14
+ "init_lora_weights": true,
15
+ "layer_replication": null,
16
+ "layers_pattern": null,
17
+ "layers_to_transform": null,
18
+ "loftq_config": {},
19
+ "lora_alpha": 128,
20
+ "lora_bias": false,
21
+ "lora_dropout": 0.05,
22
+ "lora_ga_config": null,
23
+ "megatron_config": null,
24
+ "megatron_core": "megatron.core",
25
+ "modules_to_save": [],
26
+ "peft_type": "LORA",
27
+ "peft_version": "0.19.1",
28
+ "qalora_group_size": 16,
29
+ "r": 64,
30
+ "rank_pattern": {},
31
+ "revision": null,
32
+ "target_modules": "^(model\\.language_model(?=\\.).*\\.(v_proj|k_proj|up_proj|o_proj|down_proj|q_proj|gate_proj))$",
33
+ "target_parameters": null,
34
+ "task_type": "CAUSAL_LM",
35
+ "trainable_token_indices": null,
36
+ "use_bdlora": null,
37
+ "use_dora": false,
38
+ "use_qalora": false,
39
+ "use_rslora": false
40
+ }
adapter_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5e44bc99dc44f5b207f3239298cdb33f84043884c46bb0c0dcd5d217b99f6cd7
3
+ size 264316960
additional_config.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "lora_dtype": null,
3
+ "lorap_lr_ratio": null,
4
+ "lorap_emb_lr": 1e-06
5
+ }
assets/fig_gspo.png ADDED
assets/fig_main.png ADDED
assets/fig_stage.png ADDED
assets/fig_tier.png ADDED