Views
No views yet
<thought> tags.<calculator> tags.| Model | Before RL | After RL (GRPO) | Absolute Improvement |
|---|---|---|---|
| Llama 3.2-1B Instruct | 4.46% | 14.56% | +10.10% |
| Qwen 2.5-1.5B Instruct | 15.77% | 23.50% | +7.73% |
| Qwen3-0.6B (Thinking) | ~0.00% | 49.50% | +49.50% |
<think> tokens often denoting stable reasoning process.| Parameter | Value |
|---|---|
| Method | GRPO |
| Dataset | GSM8K (7,470 training samples) |
| Learning Rate | 1e-5 (Cosine scheduler, 0.1 warmup) |
| Rollouts (G) | 4 generations per prompt |
| Batch Size | 4 |
| Max Output Length | 512 |
| Precision | BF16 |
| Sampling Temperature | 0.6 |
transformers>4.51.0 to avoid 'qwen3' keyword error.1import torch
2import re
3import yaml
4import math
5from transformers import AutoModelForCausalLM, AutoTokenizer
6
7MODEL_PATH = "AbleCredit/Qwen3-0.6B-Calculator"
8
9SYSTEM_PROMPT = """You are a mathematical reasoning agent.
101. Break down the problem into logical steps inside <thought> tags.
112. Convert the final expression into a SINGLE, VALID, NESTED calculator tool call inside <calculator> tags using YAML.
12
13Operations: add, subtract, multiply, divide.
14Example:
15<thought>Natalia sold 48 clips in April. In May she sold half: 48/2=24. Total: 48+24=72.</thought>
16<calculator>
17operation: "add"
18operands:
19 - 48
20 - operation: "divide"
21 operands: [48, 2]
22</calculator>"""
23
24# calculator
25def clean_yaml_load(text):
26 text = re.sub(r'#.*', '', text)
27 return yaml.safe_load(text)
28
29def calculate_recursive(data):
30 if isinstance(data, (int, float)): return float(data)
31 if not isinstance(data, dict):
32 try: return float(str(data))
33 except: return 0.0
34
35 op = data.get('operation', '').lower()
36 operands = data.get('operands', [])
37 if not operands: return 0.0
38
39 vals = [calculate_recursive(o) for o in operands]
40
41 if op == 'add': return sum(vals)
42 if op == 'subtract': return vals[0] - (vals[1] if len(vals) > 1 else 0)
43 if op == 'multiply':
44 res = 1
45 for x in vals: res *= x
46 return res
47 if op == 'divide': return vals[0] / vals[1] if (len(vals) > 1 and vals[1] != 0) else 0
48 return 0.0
49
50def get_calculator_result(content_text):
51 try:
52 match = re.search(r'<calculator>(.*?)</calculator>', content_text, re.DOTALL)
53 if not match: return None
54 data = clean_yaml_load(match.group(1).strip())
55 return calculate_recursive(data)
56 except:
57 return None
58
59# inference
60tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)
61model = AutoModelForCausalLM.from_pretrained(MODEL_PATH, torch_dtype="auto", device_map="auto")
62
63question = "Janet has 30 apples. She gives 5 to her sister and 3 to her brother. Then she buys twice as many as she has left. How many apples does she have now?"
64
65messages = [
66 {"role": "system", "content": SYSTEM_PROMPT},
67 {"role": "user", "content": question}
68]
69
70text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
71model_inputs = tokenizer([text], return_tensors="pt").to(model.device)
72
73generated_ids = model.generate(**model_inputs, max_new_tokens=512, temperature=0.6)
74output_ids = generated_ids[0][len(model_inputs.input_ids[0]):]
75response = tokenizer.decode(output_ids, skip_special_tokens=True)
76
77# execute
78predicted_val = get_calculator_result(response)
79
80print(f"Model Response:\n{response}")
81print(f"Final Calculated Answer: {predicted_val}")