Configuration Parsing Warning:In config.json: "quantization_config.modules_to_not_convert" must be an array

IOL-AI 2026 — Qwen2.5-14B-Instruct-AWQ

Submission for the IOL-AI 2026 Linguistics Olympiad Challenge.

The weights are an unmodified copy of Qwen/Qwen2.5-14B-Instruct-AWQ (Apache-2.0, redistributable), shipped in-repo because the evaluation sandbox has no internet access. All of the work is in script.py.

Approach

The eval budget is 30 minutes on a 16 GB T4 for a test set of only ~90 sub-questions, so compute per problem is abundant while reliability is scarce. The script is built around that asymmetry.

1. Alignment first. Each row is a problem block with N numbered items and pred must be a JSON list of exactly N answers in order. A single missing line shifts every later answer and zeroes the whole block on both exact-match and chrF. detect_n_items recovers N from the query — handling numbered lines, (1) blank markers, stated ranges, lettered items, unnumbered one-per-line lists, and the match_letters shape whose items live in the shared context. Measured on the 160 public Linguini problems it puts 98.4% of items in correctly-sized blocks. Model output is then force-fitted to N, preferring the model's own numbering when it supplies it.

2. Never emit an empty answer. The final score is a geometric mean of exact match and chrF, so a blank scores zero on both and is strictly worse than a wrong guess. Every path ends in a non-empty string.

2b. Answer style: a hypothesis that was tested and rejected. Gold answers do follow the conventions of whatever language the answer is in (measured over the 920 public Linguini answers, into-English golds that are full sentences are 99% capitalised, while the 157 that are bare clauses are only 10% capitalised, and the style matches the problem's own glosses in 36/36 measurable cases). Encoding that as prompt guidance nevertheless lowered exact match on the hidden set twice (0.0250 -> 0.0218 -> 0.0000). It is therefore not in the shipped script. The lesson recorded here for anyone rerunning this: a correct statistical description of the gold format did not translate into a better prompt.

3. Monotone improvement under a hard deadline. A complete, correctly-shaped submission.csv is written before the model is loaded, then overwritten after every improvement: greedy pass → each self-consistency pass → explanations. A crash or a timeout leaves the best result reached so far on disk rather than nothing. The script tracks its own remaining budget and stops adding passes when one more would not fit.

4. Greedy-anchored voting. After the greedy pass, sampled passes (T=0.5) run while budget remains, but the greedy answer is the default and sampled answers may only displace it when at least two of them agree on the same normalised form and that form outpolls the greedy one.

The asymmetry is empirical. A symmetric version — majority, else "most central by chrF" — was measurably worse than not voting at all: with only a handful of samples the centrality fallback is ill-defined (with two candidates pairwise chrF is symmetric, so it degenerated into preferring the shorter string) and it swapped the greedy answer for a sampled one about half the time. On the mock set that cost 4x exact match (EM 0.044 -> 0.011). Anchoring makes the procedure monotone: it can only fire on genuine agreement. chrF is implemented inline so the script carries no dependency the sandbox might lack.

5. match_letters as an assignment problem. Free-form generation answers this task type with the identity permutation (A, B, C, ...), which is a valid permutation, so duplicate-repair never fires and it scores ~0. solve_matching instead scores every (item, option) pair from the next-token distribution and takes the optimal one-to-one assignment, enforcing the bijection exactly. Duplicate-repair is retained only as a fallback for when that solver declines.

Human Evaluation Challenge

submission.csv includes an explanation column: a short, human-readable statement of the rules behind each answer (not a raw reasoning trace), generated after the answers are fixed.

Reproducing

python script.py            # reads /tmp/data/test.csv, writes submission.csv

Environment knobs (all optional, defaults match the platform): IOL_TEST_CSV, IOL_OUT_CSV, IOL_MODEL, IOL_TIME_LIMIT, IOL_BATCH, IOL_EXPLAIN.

Revision history (measured on the hidden set, not guessed)

submission change score chrF exact match
1 symmetric self-consistency vote 0.0686 0.1882 0.0250
2 greedy-anchored voting (vote no longer fires) 0.0712 0.2029 0.0250
3 + "capitalise English answers" style rule 0.0679 0.2117 0.0218
4 + mirror-gloss-style, answer normalisation, equation hints 0.0000 0.1527 0.0000
5 revert to 2, plus the match_letters assignment solver
6 + repetition_penalty=1.0 (the model ships 1.05)

Every layer of prompt/post-processing cleverness measurably hurt. Submission 5 therefore reverts to the configuration of submission 2 and adds exactly one change, motivated by a specific measured failure:

match_letters was being answered with the identity permutation. Replaying seven parser variants over saved raw generations gave exact match 0.0000 for all seven, which exonerates the parser — the model simply was not solving the task, emitting the option labels in order (A, B, C, ...). Because the identity is a valid permutation, repair_bijection never fired. solve_matching replaces free-form generation for this task type: it scores every (item, option) pair from the next-token distribution and takes the optimal one-to-one assignment, so the bijection constraint is enforced exactly rather than hoped for.

The silent decoding bug

Qwen/Qwen2.5-14B-Instruct-AWQ ships generation_config.json containing repetition_penalty: 1.05. Greedy decoding ignores temperature, top_p and top_k — and transformers emits a warning for each of those — but a repetition penalty is applied under greedy decoding, with no warning at all.

That matters here specifically: 34% of the 920 public gold answers repeat some letter three or more times, because these languages are agglutinative and the answers look like ɨmpʼuhurʼu and ɨŋɡɨrʼɨ. A 5% penalty on repeated tokens biases the model away from exactly the strings the task requires. The script now passes repetition_penalty=1.0 explicitly.

NFC normalisation of answers was considered and rejected: 98.15% of public golds are already NFC, but 13 of them are NFD-and-not-NFC, so forcing NFC would break those for an unmeasured gain.

v8 — faithful baseline replication

The organizers' reference script reaches exact match 0.0729 on the hidden set with these exact weights. Our best is 0.0333. Before adding anything further we need to know whether that number is reproducible by us at all, so v8 replicates their script literally — trivial system prompt, no chain-of-thought, batch 1 (no padding at all), naive line split, and no forcing to N answers — changing exactly one thing: repetition_penalty=1.0. Generation is EOS-limited rather than cap-limited: without chain-of-thought the model emits a few short answer lines and stops.

Result: 0.2245 (chrF 0.3150, exact match 0.1600) — first place of 43 teams.

That is 2.7x our best engineered pipeline (0.0830) and +83% on the organizers' own baseline (0.1227), the entire delta over their number being repetition_penalty=1.0.

The lesson is uncomfortable and worth recording plainly: every layer we added on top of the reference structure — chain-of-thought, an ANSWERS: block, answer style rules, output normalisation, forcing exactly N answers — reduced exact match. Submissions 2 -> 3 -> 4 fell 0.0712 -> 0.0679 -> 0.0000 as more engineering went in. The winning move was deleting all of it and fixing one decoding flag.

Downloads last month
19
Safetensors
Model size
15B params
Tensor type
I32
·
F16
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for arvindcr4/iolai-2026-qwen25-14b-awq-b

Base model

Qwen/Qwen2.5-14B
Quantized
(4)
this model