# Validation record — merged weights Everything below was actually executed on this machine, not assumed. ## 1. Weight integrity | Check | Result | |---|---| | `model.safetensors` | 4,426,558,864 bytes (4.43 GB), bf16 | | Origin | `outputs/exp_R7_grpo_remine/best_merged` (merged from `best/` adapter + `Qwen/Qwen3.5-2B`) | | `config.json` | `architectures: ["Qwen3_5ForConditionalGeneration"]`, `model_type: qwen3_5`, `dtype: bfloat16` | | Tokenizer / processor files | `tokenizer.json` (20.0 MB), `tokenizer_config.json`, `chat_template.jinja`, `processor_config.json` — all present | | `adapter_config.json` | **absent**, as required for a merged (non-LoRA) model | ## 2. End-to-end smoke test on the merged weights Environment: `torch 2.5.1+cu124`, `transformers 5.3.0`, 1 GPU. ``` python inference/infer_mdpbench.py --model . --local-files-only \ --image-dir .../MDPBench_img_sub408 --out-dir /tmp/merged_out --limit 2 ``` Result: `2/2 pages, 0 empty, 21.1 s/page`. The merged model loaded through plain `Qwen3_5ForConditionalGeneration.from_pretrained(path)` — no adapter, no `peft` needed at load time. Output is correct Arabic Markdown. ## 3. Merged vs adapter vs stored predictions (same 2 pages) Character-level similarity (`difflib.SequenceMatcher.ratio`): | Pair | page 1 | page 2 | |---|---:|---:| | merged vs unmerged adapter run | 99.951 % | 99.610 % | | merged vs Sep-18 stored predictions | **99.967 %** | 99.629 % | | merged vs repo script re-run | 99.935 % | 99.590 % | | (for reference) unmerged adapter vs Sep-18 stored | 99.951 % | 99.863 % | Absolute differences are a handful of characters (e.g. `insert`/`delete` of one Arabic letter, a missing `.` in `et al.`). The merged weights are in fact **as close to the stored predictions as the unmerged adapter is**. Why any difference at all: merging computes `W + (alpha/r)·B·A` in float32 and rounds the result back to bf16, whereas the adapter path computes the LoRA delta at runtime and adds it in bf16. Different rounding order → a token flips occasionally under greedy decoding. Impact on the aggregate score is negligible: MDPBench's `clean_string` drops non-word characters before scoring, and the affected characters are < 0.4 % of the output. ## 4. Notes / known warnings - `Keyword argument 'enable_thinking' is not a valid argument for this processor and will be ignored.` — harmless; the original reference script passes the same flag, so behaviour is identical to how the reported numbers were produced. - `The fast path is not available ... Falling back to torch implementation.` — refers to optional `flash-linear-attention` / `causal-conv1d`; installing them only speeds things up, it does not change results. - Requires `transformers>=5.3.0`. `torch>=2.4` recommended. - Output is deterministic for a fixed environment (two runs of the same weights produced byte-identical files during the adapter-package validation), but not bit-identical across different torch/CUDA versions.