anicka commited on
Commit
1af7996
·
verified ·
1 Parent(s): 3435f74

Add model card

Browse files
Files changed (1) hide show
  1. README.md +337 -0
README.md ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ base_model: unsloth/Qwen3-Coder-30B-A3B-Instruct
3
+ library_name: peft
4
+ pipeline_tag: text-generation
5
+ license: apache-2.0
6
+ language:
7
+ - en
8
+ tags:
9
+ - security
10
+ - cve
11
+ - patches
12
+ - backporting
13
+ - opensuse
14
+ - suse
15
+ - linux
16
+ - code-generation
17
+ - lora
18
+ - qlora
19
+ - moe
20
+ - mixture-of-experts
21
+ - qwen3
22
+ - unsloth
23
+ datasets:
24
+ - anicka/cve-backport-codegen-dataset
25
+ model-index:
26
+ - name: cve-backport-codegen-v5-qwen3-coder-30b-a3b
27
+ results:
28
+ - task:
29
+ type: text-generation
30
+ name: Security Patch Backporting
31
+ dataset:
32
+ type: anicka/cve-backport-codegen-dataset
33
+ name: CVE Backport Codegen Dataset
34
+ metrics:
35
+ - name: Recall
36
+ type: recall
37
+ value: 0.919
38
+ - name: Precision
39
+ type: precision
40
+ value: 0.916
41
+ - name: Exact Match
42
+ type: exact_match
43
+ value: 0.87
44
+ ---
45
+
46
+ # CVE Backport Codegen v5 — Qwen3-Coder-30B-A3B QLoRA (MoE)
47
+
48
+ Fine-tuned code generation model for backporting upstream CVE security fixes
49
+ to older SUSE/openSUSE package versions. Given vulnerable source code and an
50
+ upstream fix description, the model outputs the corrected code. A separate
51
+ tool then diffs the output against the original to produce a patch.
52
+
53
+ This is the **MoE sibling** of the dense v5 model, available at
54
+ [openSUSE/CVE-Backport-Qwen2.5-Coder-32B](https://huggingface.co/openSUSE/CVE-Backport-Qwen2.5-Coder-32B)
55
+ (and mirrored at [anicka/cve-backport-codegen-v5-qwen25-32b](https://huggingface.co/anicka/cve-backport-codegen-v5-qwen25-32b)).
56
+ Same dataset, same task, same recall target — but built on Qwen3-Coder-30B-A3B's
57
+ sparse Mixture-of-Experts architecture (30B total params, 3B active, 128 experts,
58
+ top-8 routing). The result is **equivalent quality with roughly 10× faster
59
+ inference** because generation touches only ~3B parameters per token.
60
+
61
+ ## Why MoE?
62
+
63
+ v5 Qwen2.5-Coder-32B dense works well (93.1% recall on n=100) but is slow
64
+ to serve in batch CVE backport workflows. Qwen3-Coder-30B-A3B offers the
65
+ same code specialization with sparse activation, which is a big deal when
66
+ you need to process hundreds of CVEs in a maintenance cycle.
67
+
68
+ The open question was whether MoE would train cleanly under QLoRA on a
69
+ single GPU. It does, thanks to [unsloth](https://github.com/unslothai/unsloth)'s
70
+ dedicated fused-3D expert parameter LoRA code path (PEFT's `target_parameters=`
71
+ API applied to `mlp.experts.gate_up_proj` and `mlp.experts.down_proj`), which
72
+ sidesteps the per-expert `nn.Linear` layout of older transformers while still
73
+ reaching every expert in the network.
74
+
75
+ ## Evaluation
76
+
77
+ Evaluated on 100 held-out examples from the cve-backport-codegen-dataset's
78
+ official eval split, using the same diff-based recall/precision metric as
79
+ v5 dense. Inference at temperature 0, max_new_tokens 2048, via unsloth's
80
+ FastLanguageModel on a single H100 NVL (split across both H100s via two
81
+ eval workers for wall-time efficiency).
82
+
83
+ ### Overall (n=100)
84
+
85
+ | Metric | **Qwen3-Coder MoE (this model)** | v5 dense reference |
86
+ |--------|:---:|:---:|
87
+ | Avg recall | **91.9%** | 93.1% |
88
+ | Avg precision | **91.6%** | 94.4% |
89
+ | **Exact match** | **87/100** | 83/100 |
90
+ | Perfect (recall ≥ 95%) | 90/100 | 90/100 |
91
+ | Failures (recall < 10%) | 5/100 | 3/100 |
92
+
93
+ **Same apples-to-apples n=100 methodology as v5.** Recall is 1.2 pt below
94
+ v5 dense, precision is 2.8 pt below, but **exact-match count is actually
95
+ higher** (87 vs 83) — the MoE model nails more patches character-for-character
96
+ even though it has slightly more near-misses that cost a few recall points
97
+ overall.
98
+
99
+ ### By Tier (n=100)
100
+
101
+ | Tier | Count | **MoE recall** | v5 dense recall |
102
+ |------|:-----:|:--------------:|:---------------:|
103
+ | **Identical** (upstream applies as-is) | 85 | 92.1% | 93.7% |
104
+ | **Adapted** (requires modification) | 15 | **90.3%** | 90.0% |
105
+
106
+ **Adapted tier is a statistical tie** with v5 dense — the MoE model is
107
+ marginally ahead on the harder tier where structural reasoning matters
108
+ most. Identical tier is 1.6 pt behind.
109
+
110
+ ### The Training Trajectory (n=20 instrumentation)
111
+
112
+ During training we instrumented a separate n=20 eval at two intermediate
113
+ checkpoints to understand what fine-tuning actually does on a pretrained
114
+ code MoE. The n=20 set is a subsample of the n=100 eval (same sampling
115
+ step) so mid-training numbers are directly comparable to the n=20 slice
116
+ of the final n=100 result.
117
+
118
+ | Stage | n | Recall | Precision | Exact | Failures |
119
+ |-------|:-:|:------:|:---------:|:-----:|:--------:|
120
+ | **Base model** (no fine-tuning) | 20 | 19.8% | 15.8% | 0/20 | 11/20 |
121
+ | **Step 2800** (31% training) | 20 | 59.4% | 62.1% | 7/20 | 6/20 |
122
+ | **Step 9042** (final, n=20 slice) | 20 | 90.0% | 90.0% | 18/20 | 2/20 |
123
+ | **Step 9042** (final, full n=100) | **100** | **91.9%** | **91.6%** | **87/100** | **5/100** |
124
+
125
+ **The base model starts at 19.8% recall.** Despite a low teacher-forced
126
+ training loss even in early steps, autoregressive generation is poor
127
+ because the base model doesn't know this task's output convention (bare
128
+ code, no commentary, no markdown, no explanations). Fine-tuning's first
129
+ job is to teach that convention, which is visible in the precision
130
+ column: base precision 16% → mid 62% → final 92%. The precision jump
131
+ from 16 to 62 in the first 31% of training is almost entirely "stop
132
+ rambling"; the second half is "find all the changes reliably."
133
+
134
+ **3 of the 11 baseline failures recovered to perfect scores by the final
135
+ step** — examples where both the base model and the mid-training
136
+ checkpoint emitted zero correct changes, but the fully-trained model
137
+ produces the exact patch.
138
+
139
+ ### Failure Analysis
140
+
141
+ The 5 remaining zero-recall cases at n=100 (2 more than v5 dense) are
142
+ all on the identical tier and exhibit the same pattern: the model emits
143
+ output that doesn't relate to the expected patch region at all. Likely
144
+ causes: unusual patch structure, extremely long source context, or
145
+ function signatures the base model tokenizes in a way that decouples
146
+ generation from the input. These are candidates for an agentic retry
147
+ loop with error feedback.
148
+
149
+ ## Model Details
150
+
151
+ | | |
152
+ |---|---|
153
+ | **Base model** | [unsloth/Qwen3-Coder-30B-A3B-Instruct](https://huggingface.co/unsloth/Qwen3-Coder-30B-A3B-Instruct) |
154
+ | **Architecture** | Qwen3MoeForCausalLM (30B total / 3B active, 128 experts, top-8 routing) |
155
+ | **Method** | QLoRA via [unsloth](https://github.com/unslothai/unsloth) (4-bit NF4, double quantization, bf16 compute) |
156
+ | **LoRA rank / alpha** | 16 / 32 |
157
+ | **LoRA dropout** | 0 (required for LoRA on raw `nn.Parameter` tensors via PEFT's `target_parameters`) |
158
+ | **LoRA targets (user-facing)** | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
159
+ | **LoRA targets (actual, after MoE expansion)** | attention Linears **+** `mlp.experts.gate_up_proj`, `mlp.experts.down_proj` (fused 3D tensors per layer) |
160
+ | **Trainable params** | 642,514,944 (2.06% of 31.2B total) |
161
+ | **Training data** | 36,166 train / 100 eval (from the 1,834-example eval split, same sampling as v5 dense) |
162
+ | **Epochs** | 2 (9,042 optimizer steps) |
163
+ | **Effective batch size** | 8 (1 × grad_accum 8) |
164
+ | **Learning rate** | 1e-4 (cosine schedule, 5% warmup) |
165
+ | **Max sequence length** | 4,096 tokens |
166
+ | **Optimizer** | adamw_8bit |
167
+ | **Gradient checkpointing** | `unsloth` mode |
168
+ | **Hardware** | 1× NVIDIA H100 NVL 94GB |
169
+ | **Training time** | **10h 25m** (vs v5 dense: 46h on 2× H100) |
170
+ | **Peak VRAM** | ~75GB during training |
171
+ | **Final train loss** | 0.02838 |
172
+ | **unsloth version** | 2026.4.4 |
173
+ | **transformers** | 5.5.0 |
174
+ | **PEFT** | 0.18.1 |
175
+
176
+ ## Files
177
+
178
+ This repository contains:
179
+
180
+ - **LoRA adapter** (`adapter_model.safetensors`, `adapter_config.json`) — ~2.5GB, apply via PEFT
181
+ - **Tokenizer** files (the model's chat template is required — Qwen3 family chat format)
182
+
183
+ ## Reproduction via Teapot
184
+
185
+ This model was trained via the [teapot](https://github.com/anicka-net/teapot)
186
+ training pipeline. Reproduction is a four-command sequence once the
187
+ cve-backport dataset is prepared:
188
+
189
+ ```bash
190
+ git clone https://github.com/anicka-net/teapot
191
+ cd teapot
192
+ pip install -e .
193
+ pip install unsloth # provides FastLanguageModel + fused-3D LoRA
194
+
195
+ # 1. Compose training data from the cve-backport module
196
+ teapot compose configs/cve-backport-qwen3-coder-qlora.config \
197
+ --output train-cve-backport-qwen3-coder.jsonl
198
+
199
+ # 2. Generate the unsloth launch script
200
+ teapot train configs/cve-backport-qwen3-coder-qlora.config \
201
+ --backend unsloth \
202
+ --train-data train-cve-backport-qwen3-coder.jsonl \
203
+ --output train-cve-backport-qwen3-coder.sh
204
+
205
+ # 3. Train (single GPU; see note below on why)
206
+ CUDA_VISIBLE_DEVICES=0 bash train-cve-backport-qwen3-coder.sh
207
+
208
+ # 4. Final adapter is at
209
+ # output-teapot-cve-backport-qwen3-coder-qlora/final/
210
+ ```
211
+
212
+ The teapot config (`configs/cve-backport-qwen3-coder-qlora.config`) pins
213
+ all the hyperparameters: r=16, alpha=32, 2 epochs, lr=1e-4, max_length=4096,
214
+ batch=1, grad_accum=8. See the config file for the full declaration.
215
+
216
+ ### Note on single-GPU
217
+
218
+ `hardware.gpus: 1` in the config is deliberate. Multi-GPU model parallelism
219
+ (device_map="auto") across 2× H100 NVL triggers an assertion in
220
+ `torch._higher_order_ops.flex_attention.create_fw_bw_graph` when tensors
221
+ are split across devices. The single 94GB H100 fits comfortably (peak ~75GB
222
+ during training) so this isn't a practical constraint.
223
+
224
+ ## Usage
225
+
226
+ ### With transformers + PEFT + unsloth (recommended)
227
+
228
+ ```python
229
+ from unsloth import FastLanguageModel
230
+ from peft import PeftModel
231
+
232
+ base, tokenizer = FastLanguageModel.from_pretrained(
233
+ model_name="unsloth/Qwen3-Coder-30B-A3B-Instruct",
234
+ max_seq_length=4096,
235
+ load_in_4bit=True,
236
+ dtype=None,
237
+ device_map={"": 0},
238
+ attn_implementation="sdpa", # avoid flex_attention inference bug
239
+ )
240
+ model = PeftModel.from_pretrained(
241
+ base, "anicka/cve-backport-codegen-v5-qwen3-coder-30b-a3b"
242
+ )
243
+ FastLanguageModel.for_inference(model)
244
+ ```
245
+
246
+ ### With transformers + PEFT (stock, slower)
247
+
248
+ ```python
249
+ from peft import PeftModel
250
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
251
+ import torch
252
+
253
+ bnb = BitsAndBytesConfig(
254
+ load_in_4bit=True,
255
+ bnb_4bit_quant_type="nf4",
256
+ bnb_4bit_compute_dtype=torch.bfloat16,
257
+ bnb_4bit_use_double_quant=True,
258
+ )
259
+ base = AutoModelForCausalLM.from_pretrained(
260
+ "Qwen/Qwen3-Coder-30B-A3B-Instruct",
261
+ quantization_config=bnb,
262
+ device_map={"": 0},
263
+ attn_implementation="sdpa",
264
+ )
265
+ model = PeftModel.from_pretrained(
266
+ base, "anicka/cve-backport-codegen-v5-qwen3-coder-30b-a3b"
267
+ )
268
+ tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-Coder-30B-A3B-Instruct")
269
+ ```
270
+
271
+ ### With the CVE Backport Tool
272
+
273
+ The recommended way to use this model is via the
274
+ [cve-backport-tool](https://github.com/openSUSE/cve-backport-tool),
275
+ which handles patch parsing, source extraction, model inference, and
276
+ diff generation.
277
+
278
+ ### Prompt Template
279
+
280
+ The chat template is the standard Qwen3 chat format (ChatML-like).
281
+ `apply_chat_template` with the tokenizer handles this automatically.
282
+ The system prompt used during training:
283
+
284
+ ```
285
+ You are a security patch backporting assistant.
286
+
287
+ Given vulnerable source code and a description of the upstream fix,
288
+ output the FIXED version of the code.
289
+
290
+ Rules:
291
+ - Output ONLY the fixed code, nothing else
292
+ - Preserve all surrounding context exactly
293
+ - Apply only the described fix
294
+ ```
295
+
296
+ ## Limitations
297
+
298
+ - **5 failure modes** (5/100) — examples where recall drops to <10%, all
299
+ on the identical tier. These represent hard edge cases (unusual patch
300
+ structure, very long source context) and likely need an agentic retry
301
+ loop with error feedback. v5 dense has 3 such failures on the same
302
+ eval, so this model is slightly more prone to the catastrophic-output
303
+ failure mode.
304
+ - **Precision is ~3 pt below v5 dense**: the MoE occasionally produces
305
+ "partial rambles" that get the right fix but also emit extra unrelated
306
+ changes. The diff-based metric penalizes these with high recall but
307
+ low precision. In practice the tool can filter these with a precision
308
+ threshold.
309
+ - **No compilation feedback**: single-pass generation without verifying
310
+ the output compiles. Use `--retry` in the CVE backport CLI tool for
311
+ iterative correction.
312
+ - **Context window**: 4,096 token training limit. Very large functions
313
+ or cross-file adaptations may be truncated.
314
+ - **MoE inference requires unsloth or stock transformers 5.x**, because
315
+ the LoRA is attached to fused 3D parameter tensors in the MoE expert
316
+ blocks. Older transformers versions (<5.0) expect per-expert `nn.Linear`
317
+ modules and will not load this adapter correctly.
318
+ - Always review generated patches before applying to production systems.
319
+
320
+ ## Related
321
+
322
+ - **Dense sibling (openSUSE)**: [openSUSE/CVE-Backport-Qwen2.5-Coder-32B](https://huggingface.co/openSUSE/CVE-Backport-Qwen2.5-Coder-32B) — v5 Qwen2.5-Coder-32B dense, 93.1% recall on n=100 (1.2 pt higher recall, but this MoE model has 4 more exact matches)
323
+ - **Dense sibling (anicka mirror)**: [anicka/cve-backport-codegen-v5-qwen25-32b](https://huggingface.co/anicka/cve-backport-codegen-v5-qwen25-32b)
324
+ - **CLI tool**: [openSUSE/cve-backport-tool](https://github.com/openSUSE/cve-backport-tool)
325
+ - **Dataset**: [anicka/cve-backport-codegen-dataset](https://huggingface.co/datasets/anicka/cve-backport-codegen-dataset)
326
+ - **Training pipeline**: [teapot](https://github.com/anicka-net/teapot)
327
+
328
+ ## Citation
329
+
330
+ ```bibtex
331
+ @misc{cve-backport-codegen-v5-qwen3-coder-30b-a3b,
332
+ title={CVE Backport Codegen v5 (MoE): Fine-tuned Qwen3-Coder-30B-A3B for Security Patch Backporting},
333
+ author={Anna Maresova},
334
+ year={2026},
335
+ url={https://huggingface.co/anicka/cve-backport-codegen-v5-qwen3-coder-30b-a3b}
336
+ }
337
+ ```