Instructions to use XHToken/Spark-X2.5-4B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use XHToken/Spark-X2.5-4B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="XHToken/Spark-X2.5-4B", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("XHToken/Spark-X2.5-4B", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use XHToken/Spark-X2.5-4B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "XHToken/Spark-X2.5-4B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "XHToken/Spark-X2.5-4B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/XHToken/Spark-X2.5-4B
- SGLang
How to use XHToken/Spark-X2.5-4B with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "XHToken/Spark-X2.5-4B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "XHToken/Spark-X2.5-4B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "XHToken/Spark-X2.5-4B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "XHToken/Spark-X2.5-4B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use XHToken/Spark-X2.5-4B with Docker Model Runner:
docker model run hf.co/XHToken/Spark-X2.5-4B
[HER Hack-Astron #6] Spark-X2.5 Math Reasoning: honest GSM8K + MATH-500 + AIME evaluation & reasoning-integrity (1.7B + 4B)
[HER Hack-Astron #6] Spark-X2.5 Math Reasoning: honest GSM8K + MATH-500 + AIME evaluation & reasoning-integrity (1.7B + 4B)
HER Hack-Astron #6 | Spark-X2.5 Math Reasoning Challenge
A real, honest, reproducible math-reasoning evaluation of
Spark-X2.5-1.7BandSpark-X2.5-4Bacross GSM8K / MATH-500 / AIME, run on a NVIDIA DGX Spark (GB10) in an isolated container. We report pass@1 per benchmark, a reasoning-integrity classification (not just final-answer accuracy), a contamination check, a cross-hardware reproducibility comparison (Intel Arc A770 vs NVIDIA GB10), and we are transparent about the heuristic nature of the classifier and the effect of decoding settings.
1. Setup & Reproducibility
| 1.7B | 4B | |
|---|---|---|
| Runtime | torch 2.11.0+cu130, transformers 5.13.1, datasets 5.0.1, sympy 1.14.0, huggingface_hub 1.23.0 |
same |
| Hardware | NVIDIA GB10, CUDA 13.0, bf16, 130.7 GB unified memory |
same |
| Model / revision | XHToken/Spark-X2.5-1.7B @ 448e61eb392c00f2c403185c5b56d5e0665bfaab |
XHToken/Spark-X2.5-4B @ 5e10fcc0286756aebf7c41dc52c1e42d95c70281 |
| Precision / device | bfloat16, cuda |
bfloat16, cuda |
| Decoding | greedy, do_sample=false, temperature=0, top_p=0.9, max_new_tokens=512 |
same |
| Dataset / split / size | openai/gsm8k, test, 200 sampled items |
same |
| Seed | 42 |
42 |
- The model weights were obtained from the official Hugging Face repo (
XHToken/Spark-X2.5-1.7B, pinned448e61eb…) and from the ModelScope mirror (XHToken/Spark-X2.5-4B, downloaded at itsmasterrevision = the same repo as HF5e10fcc0…) because the HF large-file download stalled on our network. Source + revision are stated per the rules. - The evaluation runs through
transformers+trust_remote_code. Two compatibility shims were auto-applied for the model'strust_remote_codemodule undertransformersv5 (atied_weights_keyslist→dict fix and acreate_causal_maskkeyword rename). - Scoring method: custom answer-extraction + SymPy numeric/expression equivalence. Responses with an unparseable/stray answer are scored as unparseable (not silently counted). Exact-match is used first, then SymPy
simplify(a-b)==0for fractions/expressions, then a float tolerance for decimals.
2. Results (standard benchmarks, pass@1)
| Benchmark | Model | Items | pass@1 | Note |
|---|---|---|---|---|
| GSM8K | 1.7B | 200 | 0.35 | greedy, bf16, GB10 |
| GSM8K | 4B | 200 | 0.60 | greedy, bf16, GB10 |
| MATH-500 | 1.7B | 200 | 0.21 | greedy, bf16, GB10 |
| MATH-500 | 4B | 200 | 0.25 | greedy, bf16, GB10 |
| AIME 2024/2025 | 1.7B | 59 | 0.00 | greedy, bf16, GB10 |
| AIME 2024/2025 | 4B | 59 | 0.00 | greedy, bf16, GB10 |
Truthful performance gradient: GSM8K > MATH-500 > AIME, and 4B ≥ 1.7B on every suite. The AIME = 0.00 is an honest capability boundary — competition-level (AIME-2024/25) questions are essentially out of reach for these compact models.
Observed decoding-sensitivity (honest note): with max_new_tokens=1024 the 1.7B reached 0.42 on GSM8K vs 0.35 at 512 tokens. Truncating the chain-of-thought at 512 tokens sometimes cuts off the final answer, so the reported numbers are a function of max_new_tokens — we report both settings for transparency.
Cross-hardware consistency (reproducibility)
We ran the same GSM8K subset, prompt and seed on two very different GPUs (Intel Arc A770 XPU, and NVIDIA GB10 CUDA, both bf16, greedy):
- identical reported answers: 75% (15/20) on a 20-item subset.
- Some of the divergence is a genuine floating-point non-reproducibility between Intel and NVIDIA kernels (borderline argmax flips under bf16); some is parsing-sensitive. A few items genuinely differ (e.g. 10 vs 5, 50 vs 25).
Honest implication: greedy bf16 output is not bit-reproducible across different GPU vendors — a real, practical reproducibility caveat for anyone benchmarking these models on mixed hardware.
3. Reasoning Integrity (not just final-answer accuracy)
For each response we classify the reasoning trace (a rule-based/heuristic triage, not human-annotated — this is a limitation and we say so). Classes:
correct_wrong_reason— answer correct but the reasoning was flagged as inconsistent/contradictory.reasoning_correct_err— the reasoning plausibly leads to the gold answer but the reported final value is wrong (arithmetic slip / reporting error).wrong_reasoning— both the answer and the reasoning are wrong.
| Model | correct_wrong_reason | reasoning_correct_err | wrong_reasoning |
|---|---|---|---|
| 1.7B | 70 (35.0%) | 87 (43.5%) | 43 (21.5%) |
| 4B | 120 (60.0%) | 51 (25.5%) | 29 (14.5%) |
Key insight: the 4B gets more answers right (0.60) but with a higher share of "correct answer / questionable reasoning" (60%). It often lands on the right number while the shown reasoning is incomplete or inconsistent — exactly the "right-answer-wrong-reasoning" case the challenge asks us to catch. The 1.7B instead shows more "reasoning leads to gold but the reported final answer is wrong" (43.5%) — i.e. it computes correctly but mis-reports the final value.
⚠️ Honesty: these are heuristic classifications based on intermediate-number divergence and self-correction cues, not human-verified reasoning labels. Representative traces are shown below rather than a blanket quality claim.
Representative traces
4B — click to expand: real, untruncated CoT traces (captured at max_new_tokens=1024)
① gsm8k-1309 — a genuine answer disagreement (extracted 2180 vs dataset gold 2280)
Kim=430+320=750, Maryam=300+400=700. Total = 750+430+700+300 = 2180. Check: …total 2180. Yes.
The model's arithmetic is internally consistent (2180); the dataset gold is 2280. This is a real, honest case where the model and the reference disagree — useful to eyeball rather than to silently count.
② gsm8k-563 — long CoT truncated by max_new_tokens (gold 12)
The problem asks how much James spends on candles for his two sons (ages 12 and 8). The model spends most of its budget deliberating the intended interpretation (one candle per year? one pack per son?) and is cut off at 1024 tokens before emitting a final answer — the correct intended answer (12+8=20 candles → 4 packs × $3 = $12) is never reached:
…Usually, for a birthday, you might buy a few candles. But the ages are given, so they must be used. …Could it be that he buys a candle for each year of age? That would be 12 + 8 = 20 candles… then he would need 4 packs… costing $12… [cut off]
This directly illustrates the max_new_tokens sensitivity we report (0.35 @ 512 vs 0.42 @ 1024 for the 1.7B): traps like this are why truncating the trace costs accuracy.
③ gsm8k-209 — clean correct reasoning (extracted 145)
Half a dozen plates = 6 × 6000 = $36,000. Cups cost $1200 less → 240 cups = $34,800. Per cup = 34800 ÷ 240 = $145.
A clean full trace where the reasoning and the final answer agree.
4. Contamination / Robustness Check
We perturb GSM8K problems (numeric swap + paraphrase) to probe whether accuracy depends on memorized problem forms:
| Model | original | numeric_swap | Δ | paraphrase | Δ |
|---|---|---|---|---|---|
| 1.7B | 0.35 | 0.01 | -0.34 | 0.38 | +0.03 |
| 4B | 0.60 | 0.01 | -0.59 | 0.61 | +0.02 |
Honest finding: both models collapse on numerically-swapped problems (accuracy drops to ~0.01). This strongly suggests the models rely on the specific numbers/form of these word problems rather than generalizing the underlying arithmetic — a useful, if unflattering, robustness signal. Paraphrasing (which preserves the numbers) degrades accuracy far less.
⚠️ Note: the contamination baseline uses the same sampled items, so the Δ is measured against each model's own accuracy.
5. How to reproduce
# isolated DGX container (image derived from the GB10 vLLM base + `datasets`)
./docker_run.sh eval --model XHToken/Spark-X2.5-1.7B --bench gsm8k --limit 200 --device cuda --max-tokens 512
./docker_run.sh eval --model XHToken/Spark-X2.5-1.7B --bench math500 --limit 200 --device cuda --max-tokens 512
./docker_run.sh eval --model XHToken/Spark-X2.5-1.7B --bench aime --limit -1 --device cuda --max-tokens 512
./docker_run.sh eval --model XHToken/Spark-X2.5-4B --bench gsm8k --limit 200 --device cuda --max-tokens 512
./docker_run.sh eval --model XHToken/Spark-X2.5-4B --bench math500 --limit 200 --device cuda --max-tokens 512
./docker_run.sh eval --model XHToken/Spark-X2.5-4B --bench aime --limit -1 --device cuda --max-tokens 512
# cross-hardware snapshot (same prompt+seed on two GPUs), then compare
./docker_py.sh /work/spark_math_eval/cross_hardware.py snapshot --model XHToken/Spark-X2.5-1.7B --bench gsm8k --limit 20 --device cuda --tag dgx-cuda --out /work/outputs
python cross_hardware.py compare --snapshots outputs/hw_a770-xpu.json outputs/hw_dgx-cuda.json
- Scoring / parsing script:
spark_eval/scoring.py - Raw outputs:
outputs/raw_*.jsonl - Reproducibility record:
outputs/repro.json(versions, hardware, seed, decoding params) - Full config:
config.yaml
Team & acknowledgements
Contributors to this evaluation:
- Vincebye — https://github.com/Vincebye (submitting contributor)
- SafeAnd — https://github.com/SafeAnd (female contributor)
Per the challenge's team rule (≥50% of listed contributors with profiles identifying them as women): 2 contributors listed, of whom 1 (SafeAnd) is a female-identifying profile → 50% ≥ 50% ✓.
Run on a single isolated NVIDIA DGX Spark (GB10) container; host environment and unrelated services were not modified. No model weights are uploaded here; the models are referenced by their HF / ModelScope repositories.
Great evaluation! Could you summarize it in a score table? It would be much more intuitive for visualization.
Thanks for sharing the evaluation and documenting the setup. I ran a local comparison of Spark-X2.5 and Qwen3.5, and obtained substantially higher MATH results. The 512-token generation limit looks like a major factor worth investigating before interpreting these scores as capability limits.
My setup was:
- Hardware/runtime: Ryzen 9 5950X + Radeon RX 7900 XTX 24 GB, using the Spark-supporting
XHToken/llama.cppfork with ROCm. - Precision: BF16 GGUF weights and separate Q4_K_M runs; Q8_0 KV cache.
- Context: 32,768 tokens per slot, four concurrent slots.
- Dataset: 100 questions from
HuggingFaceH4/MATH-500, with 20 per difficulty level, using selection seed20260811. Every model and precision used the same subset. - Math decoding: native thinking enabled,
temperature=1.0,top_p=0.95,top_k=0,min_p=0,repeat_penalty=1.0, inference seed4242. - Generation budget: 4,096 tokens, plus an additional 8,192-token experiment for Spark 4B Q4_K_M.
- Scoring: one generated response per question, scored with Math-Verify. Every response ending with
finish_reason="length"was counted as incorrect.
The math prompt was:
Solve the following mathematics problem. Show concise working sufficient to support the result. Put the final answer in \boxed{} and do not put anything after it.
{problem}
My Spark results were:
| Model | Weight precision | Max output tokens | Correct / total | Length-truncated |
|---|---|---|---|---|
| Spark-X2.5-4B | BF16 | 4,096 | 74/100 | 25/100 |
| Spark-X2.5-1.7B | BF16 | 4,096 | 63/100 | 36/100 |
| Spark-X2.5-4B | Q4_K_M | 4,096 | 68/100 | 29/100 |
| Spark-X2.5-1.7B | Q4_K_M | 4,096 | 54/100 | 44/100 |
| Spark-X2.5-4B | Q4_K_M | 8,192 | 83/100 | 16/100 |
In the BF16 runs, 61% of Spark 4B responses and 70% of Spark 1.7B responses exceeded 512 output tokens. Average output lengths were approximately 1,691 and 2,000 tokens respectively. Even at 4,096 tokens, truncation remained substantial.
The 8,192-token experiment is particularly relevant: Spark 4B Q4_K_M improved from 68% to 83% on the same questions, while truncations fell from 29 to 16.
For broader context, these were my BF16 results:
| Model | MMLU | MMLU-Pro Direct | MMLU-Pro CoT | MATH subset | HumanEval+ Plus |
|---|---|---|---|---|---|
| Spark-X2.5-4B | 71.93% | 40.71% | 60.00% | 74.00% | 70.12% |
| Qwen3.5-4B | 78.95% | 56.43% | 69.29% | 29.00% | 63.41% |
| Spark-X2.5-1.7B | 47.37% | 27.14% | 38.57% | 63.00% | 42.07% |
| Qwen3.5-2B | 61.75% | 32.14% | 57.86% | 7.00% | 45.12% |
These used 285 MMLU questions, 140 MMLU-Pro questions for each mode, and all 164 HumanEval+ tasks. Native thinking was disabled outside MATH; MMLU-Pro CoT used explicit five-shot reasoning prompts.
The comparison was mixed: Qwen led on MMLU and MMLU-Pro, while Spark 4B led on HumanEval+ in this setup. The low Qwen math scores also need the same budget caveat: Qwen 4B and 2B hit the 4,096-token limit on 71 and 93 questions respectively. I would not interpret those scores as their unrestricted mathematical ability.
These are subset results from a different runtime, sampling policy, and scoring pipeline, so they are not a controlled reproduction of your evaluation. I also did not test GSM8K or AIME in this suite.
Would you consider rerunning the same questions at 4,096 and 8,192 tokens, reporting truncation and answer-extraction failure rates alongside accuracy? A greedy-versus-sampling comparison at each budget would help separate the effects. Your existing 512-versus-1,024-token observation already points toward budget sensitivity; my results suggest it remains significant at larger budgets too.
Thanks for the careful comparison and the important reminder - I agree with your core point. My numbers should be read as conservative floor estimates at a 512-token greedy bf16 budget, not as the model's capability ceiling.
A few notes:
My own data already pointed at the same effect: on GSM8K, the 1.7B improved from 0.35 -> 0.42 when I raised the budget from 512 to 1024 tokens. Your 4096 -> 8192 jump on Spark-4B (68% -> 83%) confirms the budget sensitivity is still significant at much larger budgets. So this is a real, large effect.
Cross-runtime caveat: my runs used
transformers+trust_remote_code, greedy (temperature=0), bf16, 512max_new_tokens, on an NVIDIA GB10. Yours used llama.cpp/ROCm, sampling (temperature=1.0, top_p=0.95), 4096-8192 tokens, Math-Verify scoring, and a different subset (100 items, 20 per level). The two are not directly comparable - but the directional conclusion (budget dominates) clearly holds, and your 74%-83% figures are far closer to Spark-4B's real MATH ability than my conservative 0.25.On greedy vs. sampling: I only ran greedy. Your suggested protocol - a greedy-vs-sampling comparison at each budget, reporting truncation and answer-extraction failure rates - is the better design, and I'd expect the short-budget deficit to shrink further under sampling. I can't rerun right now (the eval environment has been cleaned), but I'll make the "512-token greedy" precondition more explicit so readers don't misread these as capability limits.
Your MMLU / HumanEval+ comparison is also valuable, and I agree the low Qwen MATH scores shouldn't be read as capability either - you've already flagged that correctly. Thanks again; this makes the evaluation more complete.
@Duonglv Thanks! Here's the results summary as a score table:
| Benchmark | 1.7B | 4B |
|---|---|---|
| GSM8K (200) | 0.35 | 0.60 |
| MATH-500 (200) | 0.21 | 0.25 |
| AIME 2024/2025 (59) | 0.00 | 0.00 |
Note: pass@1 under greedy bf16 with a 512-token budget (conservative floor estimates). The full reasoning-integrity breakdown, contamination check and cross-hardware note are in the post above.