Text Generation
Transformers
Safetensors
Arabic
llama
arabic
reasoning
chain-of-thought
math
gsm8k
small-language-model
slm
sft
conversational
text-generation-inference
Instructions to use oddadmix/Nawah-Math-Reasoning with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use oddadmix/Nawah-Math-Reasoning with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="oddadmix/Nawah-Math-Reasoning") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("oddadmix/Nawah-Math-Reasoning") model = AutoModelForCausalLM.from_pretrained("oddadmix/Nawah-Math-Reasoning", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use oddadmix/Nawah-Math-Reasoning with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "oddadmix/Nawah-Math-Reasoning" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "oddadmix/Nawah-Math-Reasoning", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/oddadmix/Nawah-Math-Reasoning
- SGLang
How to use oddadmix/Nawah-Math-Reasoning 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 "oddadmix/Nawah-Math-Reasoning" \ --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": "oddadmix/Nawah-Math-Reasoning", "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 "oddadmix/Nawah-Math-Reasoning" \ --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": "oddadmix/Nawah-Math-Reasoning", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use oddadmix/Nawah-Math-Reasoning with Docker Model Runner:
docker model run hf.co/oddadmix/Nawah-Math-Reasoning
| """ | |
| Prepare Omartificial-Intelligence-Space/Arabic_Reasoning_Dataset for reasoning SFT. | |
| Each row (instruction, answer) becomes a ChatML sample where the derivation lives | |
| inside <think>...</think> and the conclusion follows it: | |
| <|im_start|>user\n{instruction}<|im_end|>\n<|im_start|>assistant\n<think>\n{reasoning}\n</think>\n{answer}<|im_end|> | |
| Only rows whose derivation ends in an explicit conclusion line ("إذن، ...") are kept. | |
| Expository rows without one have no real "final answer" to place after </think> — their | |
| closing paragraph is a side remark, so training on them would teach the model to think and | |
| then trail off. They are dropped rather than force-split. | |
| Writes data/train.jsonl and data/eval.jsonl. | |
| """ | |
| import json, re, random, unicodedata, collections | |
| from pathlib import Path | |
| import pyarrow.parquet as pq | |
| SRC = Path("data/data/train-00000-of-00001.parquet") | |
| OUT_DIR = Path("data") | |
| EVAL_N = 400 | |
| SEED = 42 | |
| # Lines that mark the final conclusion of a derivation. | |
| CONCLUSION = ["إذن،", "إذن ", "لذا،", "لذلك،", "باختصار،", "وبالتالي،", "في النهاية،", | |
| "الخلاصة", "النتيجة النهائية", "النتيجة:", "الإجابة", "الجواب", "بالتالي،"] | |
| # Chatty sign-offs that are not part of the answer. | |
| FLUFF = ["تذكر", "آمل", "أتمنى", "يرجى", "لا تتردد", "إذا كان لديك أي", "هل لديك", | |
| "أرجو", "نصيحة:", "ملاحظة:", "إذا كانت لديك"] | |
| # Prompt suffix present on a subset of instructions; stripped so reasoning is unconditional. | |
| SUFFIX_RE = re.compile(r"\s*خذ\s+نفسًا?\s+عميقًا.*$", re.S) | |
| MIN_THINK_CHARS = 60 | |
| MIN_ANSWER_CHARS = 10 | |
| MD_NOISE_RE = re.compile(r"\*\*|__|#{2,}") | |
| # Some source rows bundle several problems; the conclusion of one is followed by the next | |
| # problem's header. Anything from that header on is not part of the answer. | |
| NEXT_PROBLEM_RE = re.compile(r"^\s*(المشكلة|المسألة|السؤال|التمرين|مثال|Problem|Question|Example)\b") | |
| ANSWER_ARTIFACT_RE = re.compile(r"^\s*(\*\*)?Answer:\s*", re.I) | |
| def norm(text: str) -> str: | |
| text = unicodedata.normalize("NFC", text.replace("", "").replace("", "")) | |
| text = re.sub(r"[ \t]+", " ", text) | |
| text = re.sub(r"\n{3,}", "\n\n", text) | |
| return text.strip() | |
| def clean_instruction(text: str) -> str: | |
| return norm(SUFFIX_RE.sub("", norm(text))).rstrip(". ").strip() or norm(text) | |
| def is_fluff(line: str) -> bool: | |
| head = line.lstrip("*#- ").strip() | |
| return any(head.startswith(f) for f in FLUFF) | |
| def is_conclusion(line: str) -> bool: | |
| head = line.lstrip("*#- ").strip() | |
| return any(head.startswith(m) for m in CONCLUSION) | |
| def strip_markup(line: str) -> str: | |
| """Drop markdown emphasis and the stray "**Answer:" prefix some rows carry.""" | |
| return norm(MD_NOISE_RE.sub("", ANSWER_ARTIFACT_RE.sub("", line))) | |
| def split_answer(answer: str, instruction: str): | |
| """-> (reasoning, final_answer) or None when the row can't be split cleanly.""" | |
| lines = [strip_markup(l) for l in norm(answer).split("\n")] | |
| lines = [l for l in lines if l] | |
| if len(lines) < 2: | |
| return None | |
| # Drop trailing chatter first — it belongs to neither part. | |
| while lines and is_fluff(lines[-1]): | |
| lines.pop() | |
| if len(lines) < 2: | |
| return None | |
| # A leading restatement of the question adds nothing to the derivation. | |
| if lines and lines[0][:40] == instruction.strip()[:40]: | |
| lines.pop(0) | |
| idx = next((i for i in range(len(lines) - 1, 0, -1) if is_conclusion(lines[i])), None) | |
| if idx is None: | |
| return None | |
| reasoning = "\n".join(lines[:idx]) | |
| tail = lines[idx:] | |
| cut = next((i for i in range(1, len(tail)) if NEXT_PROBLEM_RE.match(tail[i])), len(tail)) | |
| final = "\n".join(tail[:cut]) | |
| if len(reasoning) < MIN_THINK_CHARS or len(final) < MIN_ANSWER_CHARS: | |
| return None | |
| # A "conclusion" longer than the derivation means the split went the wrong way. | |
| if len(final) > len(reasoning): | |
| return None | |
| return reasoning, final | |
| def main(): | |
| table = pq.read_table(SRC).to_pydict() | |
| rows = list(zip(table["instruction"], table["answer"])) | |
| stats = collections.Counter(total=len(rows)) | |
| seen, samples = set(), [] | |
| for raw_ins, raw_ans in rows: | |
| ins = clean_instruction(raw_ins) | |
| key = re.sub(r"\W+", "", ins) | |
| if key in seen: | |
| stats["dropped_duplicate"] += 1 | |
| continue | |
| seen.add(key) | |
| split = split_answer(raw_ans, ins) | |
| if split is None: | |
| stats["dropped_no_conclusion"] += 1 | |
| continue | |
| reasoning, final = split | |
| stats["kept"] += 1 | |
| samples.append({"instruction": ins, "reasoning": reasoning, "answer": final}) | |
| random.Random(SEED).shuffle(samples) | |
| eval_set, train_set = samples[:EVAL_N], samples[EVAL_N:] | |
| OUT_DIR.mkdir(exist_ok=True) | |
| for name, split in (("train", train_set), ("eval", eval_set)): | |
| with open(OUT_DIR / f"{name}.jsonl", "w", encoding="utf-8") as fh: | |
| for s in split: | |
| fh.write(json.dumps(s, ensure_ascii=False) + "\n") | |
| print(f"[+] {name}: {len(split)} samples -> {OUT_DIR / f'{name}.jsonl'}") | |
| print("[*] stats:", dict(stats)) | |
| if __name__ == "__main__": | |
| main() | |