claytonwang commited on
Commit
85c2d06
·
verified ·
1 Parent(s): 01b1a38

Add Qwen3-8B-CalibSFT-RLCR

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ base_model: SUSTech/Qwen3-8B-CalibSFT
4
+ base_model_relation: finetune
5
+ library_name: transformers
6
+ pipeline_tag: text-generation
7
+ language:
8
+ - en
9
+ datasets:
10
+ - SUSTech/CalibSFT-DeepScaleR
11
+ tags:
12
+ - reasoning
13
+ - math
14
+ - confidence-calibration
15
+ - verbalized-confidence
16
+ ---
17
+
18
+ # Qwen3-8B-CalibSFT-RLCR
19
+
20
+ Qwen3-8B trained with **CalibSFT followed by RLCR**, from the paper [On the Pitfalls of Verbalized Confidence Priors for Calibrating Large Reasoning Models](https://arxiv.org/abs/XXXX.XXXXX). The model solves a problem, then states its answer and a verbalized confidence between 0 and 1. It is initialized from [SUSTech/Qwen3-8B-CalibSFT](https://huggingface.co/SUSTech/Qwen3-8B-CalibSFT).
21
+
22
+ - **Code:** https://github.com/ml-stat-Sustech/verbalized-confidence-training
23
+ - **Training data:** [SUSTech/CalibSFT-DeepScaleR](https://huggingface.co/datasets/SUSTech/CalibSFT-DeepScaleR)
24
+
25
+ ## Usage
26
+
27
+ The model expects the system prompt and user format used during training:
28
+
29
+ ```python
30
+ from transformers import AutoModelForCausalLM, AutoTokenizer
31
+
32
+ model_id = "SUSTech/Qwen3-8B-CalibSFT-RLCR"
33
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
34
+ model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype="auto", device_map="auto")
35
+
36
+ SYSTEM_PROMPT = (
37
+ "A conversation between User and Assistant. The user asks a question, and the Assistant solves it. "
38
+ "The assistant first thinks about the reasoning process in the mind and analyzes its confidence about "
39
+ "the solution and then provides the user with the final answer as well as its confidence level. "
40
+ "The confidence level indicates how certain the Assistant is about its answer, expressed as a decimal "
41
+ "between 0 and 1 with exactly two decimal places, enclosed within <confidence> </confidence> tags. "
42
+ "The response must strictly follow this format: <think> reasoning process here </think> "
43
+ "<answer> final short answer only </answer> <confidence> 0.xx </confidence>. "
44
+ "The <answer> tag must contain only the final answer string needed for exact-match evaluation, "
45
+ "not a full sentence, explanation, or reasoning."
46
+ )
47
+ question = "What is the smallest positive integer n such that n^2 + n is divisible by 12?"
48
+ messages = [
49
+ {"role": "system", "content": SYSTEM_PROMPT},
50
+ {"role": "user", "content": f"\n\nPROBLEM: {question}\n\n"},
51
+ ]
52
+
53
+ text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
54
+ inputs = tokenizer(text, return_tensors="pt").to(model.device)
55
+ outputs = model.generate(**inputs, max_new_tokens=16384, do_sample=True, temperature=0.6, top_p=0.95, top_k=20)
56
+ print(tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True))
57
+ # Output format: <think> ... </think> <answer> ... </answer> <confidence> 0.xx </confidence>
58
+ ```
59
+
60
+ ## Training
61
+
62
+ The model starts from [SUSTech/Qwen3-8B-CalibSFT](https://huggingface.co/SUSTech/Qwen3-8B-CalibSFT) and is trained with RLCR on DeepScaleR. RLCR rewards answer correctness and format together with a Brier calibration reward on the stated confidence. Training follows the DAPO recipe with dynamic sampling, and questions that the base model already solves in every sampled response are removed beforehand.
63
+
64
+ | Hyperparameter | Value |
65
+ | --- | --- |
66
+ | Responses per question | 8 |
67
+ | Questions per batch | 64 |
68
+ | Mini-batch size | 32 |
69
+ | Steps | 160 |
70
+ | Learning rate | 2e-6, cosine decay to 1e-6 after 10 warm-up steps |
71
+ | Clip ratio (low / high) | 0.2 / 0.28 |
72
+ | KL coefficient | 0 |
73
+ | Max response length | 8,192 tokens |
74
+ | Seed | 45 |
75
+
76
+ ## Evaluation
77
+
78
+ Temperature 0.6, 4 responses per question (32 on AIME). Metrics are percentages averaged over 8 in-distribution math benchmarks (DeepScaleR-Eval, MATH-500, MinervaMath, OlympiadBench, GSM8K, AIME 2024–2026) and 8 out-of-distribution benchmarks (HotpotQA, TriviaQA, DROP, MuSiQue, LiveBenchReasoning, NQOpen, PopQA, WebQuestions).
79
+
80
+ | Model | ID Pass@1 ↑ | ID AUROC ↑ | ID Brier ↓ | ID ECE ↓ | OOD Pass@1 ↑ | OOD AUROC ↑ | OOD Brier ↓ | OOD ECE ↓ |
81
+ | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
82
+ | Qwen3-8B | 59.32 | 71.90 | 33.20 | 34.36 | 45.36 | 65.71 | 45.15 | 46.94 |
83
+ | Qwen3-8B-RLCR | 65.33 | 82.36 | 14.43 | 14.46 | 43.96 | 69.38 | 31.14 | 31.17 |
84
+ | Qwen3-8B-CalibSFT | 58.51 | 79.93 | 17.30 | 14.23 | 46.37 | 61.20 | 29.15 | 25.49 |
85
+ | **Qwen3-8B-CalibSFT-RLCR** | 67.20 | 86.32 | 12.77 | 8.59 | 45.71 | 71.31 | 23.24 | 18.20 |
86
+
87
+ Qwen3-8B and CalibSFT were evaluated with up to 6,144 generated tokens and the RLCR models with up to 16,384.
88
+
89
+ ## Citation
90
+
91
+ ```bibtex
92
+ @article{wang2026pitfalls,
93
+ title={On the Pitfalls of Verbalized Confidence Priors for Calibrating Large Reasoning Models},
94
+ author={Wang, Shuoyuan and Luo, Beier and Zeng, Hao and Yu, Chengyao and Zhang, Songxin and Xie, Zejian and Jing, Bingyi and Wei, Hongxin},
95
+ journal={arXiv preprint arXiv:XXXX.XXXXX},
96
+ year={2026}
97
+ }
98
+ ```
chat_template.jinja ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- if tools %}
2
+ {{- '<|im_start|>system\n' }}
3
+ {%- if messages[0].role == 'system' %}
4
+ {{- messages[0].content + '\n\n' }}
5
+ {%- endif %}
6
+ {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
7
+ {%- for tool in tools %}
8
+ {{- "\n" }}
9
+ {{- tool | tojson }}
10
+ {%- endfor %}
11
+ {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
12
+ {%- else %}
13
+ {%- if messages[0].role == 'system' %}
14
+ {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
15
+ {%- endif %}
16
+ {%- endif %}
17
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
18
+ {%- for message in messages[::-1] %}
19
+ {%- set index = (messages|length - 1) - loop.index0 %}
20
+ {%- if ns.multi_step_tool and message.role == "user" and message.content is string and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
21
+ {%- set ns.multi_step_tool = false %}
22
+ {%- set ns.last_query_index = index %}
23
+ {%- endif %}
24
+ {%- endfor %}
25
+ {%- for message in messages %}
26
+ {%- if message.content is string %}
27
+ {%- set content = message.content %}
28
+ {%- else %}
29
+ {%- set content = '' %}
30
+ {%- endif %}
31
+ {%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
32
+ {{- '<|im_start|>' + message.role + '\n' + content + '<|im_end|>' + '\n' }}
33
+ {%- elif message.role == "assistant" %}
34
+ {%- set reasoning_content = '' %}
35
+ {%- if message.reasoning_content is string %}
36
+ {%- set reasoning_content = message.reasoning_content %}
37
+ {%- else %}
38
+ {%- if '</think>' in content %}
39
+ {%- set reasoning_content = content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
40
+ {%- set content = content.split('</think>')[-1].lstrip('\n') %}
41
+ {%- endif %}
42
+ {%- endif %}
43
+ {%- if loop.index0 > ns.last_query_index %}
44
+ {%- if loop.last or (not loop.last and reasoning_content) %}
45
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
46
+ {%- else %}
47
+ {{- '<|im_start|>' + message.role + '\n' + content }}
48
+ {%- endif %}
49
+ {%- else %}
50
+ {{- '<|im_start|>' + message.role + '\n' + content }}
51
+ {%- endif %}
52
+ {%- if message.tool_calls %}
53
+ {%- for tool_call in message.tool_calls %}
54
+ {%- if (loop.first and content) or (not loop.first) %}
55
+ {{- '\n' }}
56
+ {%- endif %}
57
+ {%- if tool_call.function %}
58
+ {%- set tool_call = tool_call.function %}
59
+ {%- endif %}
60
+ {{- '<tool_call>\n{"name": "' }}
61
+ {{- tool_call.name }}
62
+ {{- '", "arguments": ' }}
63
+ {%- if tool_call.arguments is string %}
64
+ {{- tool_call.arguments }}
65
+ {%- else %}
66
+ {{- tool_call.arguments | tojson }}
67
+ {%- endif %}
68
+ {{- '}\n</tool_call>' }}
69
+ {%- endfor %}
70
+ {%- endif %}
71
+ {{- '<|im_end|>\n' }}
72
+ {%- elif message.role == "tool" %}
73
+ {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
74
+ {{- '<|im_start|>user' }}
75
+ {%- endif %}
76
+ {{- '\n<tool_response>\n' }}
77
+ {{- content }}
78
+ {{- '\n</tool_response>' }}
79
+ {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
80
+ {{- '<|im_end|>\n' }}
81
+ {%- endif %}
82
+ {%- endif %}
83
+ {%- endfor %}
84
+ {%- if add_generation_prompt %}
85
+ {{- '<|im_start|>assistant\n' }}
86
+ {%- if enable_thinking is defined and enable_thinking is false %}
87
+ {{- '<think>\n\n</think>\n\n' }}
88
+ {%- endif %}
89
+ {%- endif %}
config.json ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "Qwen3ForCausalLM"
4
+ ],
5
+ "attention_bias": false,
6
+ "attention_dropout": 0.0,
7
+ "attn_implementation": "flash_attention_2",
8
+ "bos_token_id": null,
9
+ "dtype": "bfloat16",
10
+ "eos_token_id": 151645,
11
+ "head_dim": 128,
12
+ "hidden_act": "silu",
13
+ "hidden_size": 4096,
14
+ "initializer_range": 0.02,
15
+ "intermediate_size": 12288,
16
+ "layer_types": [
17
+ "full_attention",
18
+ "full_attention",
19
+ "full_attention",
20
+ "full_attention",
21
+ "full_attention",
22
+ "full_attention",
23
+ "full_attention",
24
+ "full_attention",
25
+ "full_attention",
26
+ "full_attention",
27
+ "full_attention",
28
+ "full_attention",
29
+ "full_attention",
30
+ "full_attention",
31
+ "full_attention",
32
+ "full_attention",
33
+ "full_attention",
34
+ "full_attention",
35
+ "full_attention",
36
+ "full_attention",
37
+ "full_attention",
38
+ "full_attention",
39
+ "full_attention",
40
+ "full_attention",
41
+ "full_attention",
42
+ "full_attention",
43
+ "full_attention",
44
+ "full_attention",
45
+ "full_attention",
46
+ "full_attention",
47
+ "full_attention",
48
+ "full_attention",
49
+ "full_attention",
50
+ "full_attention",
51
+ "full_attention",
52
+ "full_attention"
53
+ ],
54
+ "max_position_embeddings": 40960,
55
+ "max_window_layers": 36,
56
+ "model_type": "qwen3",
57
+ "num_attention_heads": 32,
58
+ "num_hidden_layers": 36,
59
+ "num_key_value_heads": 8,
60
+ "pad_token_id": 151643,
61
+ "rms_norm_eps": 1e-06,
62
+ "rope_parameters": {
63
+ "rope_theta": 1000000,
64
+ "rope_type": "default"
65
+ },
66
+ "sliding_window": null,
67
+ "tie_word_embeddings": false,
68
+ "transformers_version": "5.13.0",
69
+ "use_cache": true,
70
+ "use_sliding_window": false,
71
+ "vocab_size": 151936
72
+ }
generation_config.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 151643,
3
+ "do_sample": true,
4
+ "eos_token_id": [
5
+ 151645,
6
+ 151643
7
+ ],
8
+ "pad_token_id": 151643,
9
+ "temperature": 0.6,
10
+ "top_k": 20,
11
+ "top_p": 0.95,
12
+ "transformers_version": "5.13.0"
13
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5dec4e32ffbacfb7df6e69c89b7812600080141175b51b68342fb928bfe2851b
3
+ size 16381517208
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be75606093db2094d7cd20f3c2f385c212750648bd6ea4fb2bf507a6a4c55506
3
+ size 11422650
tokenizer_config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "backend": "tokenizers",
4
+ "bos_token": null,
5
+ "clean_up_tokenization_spaces": false,
6
+ "eos_token": "<|im_end|>",
7
+ "errors": "replace",
8
+ "extra_special_tokens": [
9
+ "<|im_start|>",
10
+ "<|im_end|>",
11
+ "<|object_ref_start|>",
12
+ "<|object_ref_end|>",
13
+ "<|box_start|>",
14
+ "<|box_end|>",
15
+ "<|quad_start|>",
16
+ "<|quad_end|>",
17
+ "<|vision_start|>",
18
+ "<|vision_end|>",
19
+ "<|vision_pad|>",
20
+ "<|image_pad|>",
21
+ "<|video_pad|>"
22
+ ],
23
+ "is_local": true,
24
+ "local_files_only": true,
25
+ "model_max_length": 131072,
26
+ "pad_token": "<|endoftext|>",
27
+ "split_special_tokens": false,
28
+ "tokenizer_class": "Qwen2Tokenizer",
29
+ "unk_token": null
30
+ }