Yusiko commited on
Commit
b399ea6
·
verified ·
1 Parent(s): 53b7ad8

Upload 9 files

Browse files
README.md CHANGED
@@ -1,3 +1,156 @@
1
- ---
2
- license: apache-2.0
3
- ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <p align="center">
2
+ <img src="./assets/khazri-2-preview-banner.png" alt="Khazri 2 Preview — flagship open-weight language model" width="100%">
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="./assets/khazri-wordmark.png" alt="Khazri 2" width="280">
7
+ </p>
8
+
9
+ # Khazri 2 Preview
10
+
11
+ **Khazri 2 Preview** is the flagship preview checkpoint in the Khazri language-model family. It pairs the Khazri model with the project’s **SYNAPSE** architecture and route-aware inference system, making it suitable for research, controlled experimentation and evaluation before a full production release.
12
+
13
+ [Khazri website](https://khazri.dev) · [Contact the Khazri team](mailto:contact@khazri.dev)
14
+
15
+ > **Preview release:** Treat this checkpoint as a research preview. Validate it on your own tasks and do not make high-stakes decisions solely from its output.
16
+
17
+ ## At a glance
18
+
19
+ | Item | Detail |
20
+ | --- | --- |
21
+ | Model | Khazri 2 Preview |
22
+ | Family position | Flagship model in the current Khazri 2 generation |
23
+ | Parameters | ~250M (release <code>config.json</code> is the final source of truth) |
24
+ | Architecture | Khazri model with SYNAPSE components |
25
+ | Inference export context limit | 512 tokens |
26
+ | Default maximum generation | 128 new tokens |
27
+ | Loading | Transformers with custom model code |
28
+ | Web-search route | Disabled by default in the supplied notebook |
29
+
30
+ ## SYNAPSE-aware inference
31
+
32
+ The supplied Khazri 2 Preview notebook expects the following model-side files:
33
+
34
+ ~~~text
35
+ config.json
36
+ generation_config.json
37
+ model.safetensors
38
+ tokenizer.json
39
+ tokenizer_config.json
40
+ modeling_synapse.py
41
+ synapse_controller.py
42
+ inference.py
43
+ ~~~
44
+
45
+ The notebook loads the model with <code>trust_remote_code=True</code> and provides a fallback route system with:
46
+
47
+ - <code>NSR_CALCULATOR</code> for safe numeric calculation;
48
+ - <code>MATH_SOLVER</code> for symbolic math tasks;
49
+ - <code>TMS_CONTEXT</code> for context-grounded answers;
50
+ - <code>UQM_ABSTAIN</code> for abstention when information is insufficient or inappropriate;
51
+ - <code>WEB_SEARCH</code>, disabled by default; and
52
+ - <code>MODEL_FALLBACK</code> for standard generation.
53
+
54
+ The exact routing decision is implementation-dependent. Inspect the shipped Python files before enabling remote code, and pin a revision in production.
55
+
56
+ ## Training data
57
+
58
+ The supplied **Khazri 2 Preview inference notebook does not disclose the training dataset composition**. It contains runtime, tokenizer and SYNAPSE inference logic—not a training manifest—so this model card does not infer a source list from it.
59
+
60
+ A separate Khazri Mini training notebook documents a custom BBPE-tokenized Arrow corpus with 2B packed tokens, but that notebook alone is **not evidence** that Khazri 2 Preview used the same data, proportions or post-training steps. For that reason, the Preview release should include a dedicated <code>DATASET.md</code> before or at publication.
61
+
62
+ At minimum, the public data card should list:
63
+
64
+ 1. dataset names, owners and licences;
65
+ 2. language coverage and source proportions;
66
+ 3. collection dates, filtering and deduplication methods;
67
+ 4. known limitations, bias and personal-data controls;
68
+ 5. pre-training versus instruction-tuning sources; and
69
+ 6. the exact relationship, if any, between the Preview checkpoint and the Mini training corpus.
70
+
71
+ This distinction protects both users and the project: it makes the open-weight release auditable without overstating what the supplied files prove.
72
+
73
+ ## Installation
74
+
75
+ ~~~bash
76
+ pip install -U torch transformers accelerate safetensors
77
+ ~~~
78
+
79
+ ## Quick start
80
+
81
+ Replace <code>YOUR_ORG/Khazri-2-Preview</code> with the final Hugging Face repository ID. The release must include the custom SYNAPSE Python files before the following example can work.
82
+
83
+ ~~~python
84
+ import torch
85
+ from transformers import AutoModelForCausalLM, AutoTokenizer
86
+
87
+ MODEL_ID = "YOUR_ORG/Khazri-2-Preview"
88
+
89
+ # Review and trust modeling_synapse.py before enabling remote code.
90
+ tokenizer = AutoTokenizer.from_pretrained(
91
+ MODEL_ID,
92
+ trust_remote_code=True,
93
+ use_fast=True,
94
+ )
95
+ model = AutoModelForCausalLM.from_pretrained(
96
+ MODEL_ID,
97
+ torch_dtype="auto",
98
+ device_map="auto",
99
+ trust_remote_code=True,
100
+ )
101
+
102
+ prompt = "Summarize the following text in two concise sentences: ..."
103
+ inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=384)
104
+ inputs = {key: value.to(model.device) for key, value in inputs.items()}
105
+
106
+ with torch.inference_mode():
107
+ output = model.generate(
108
+ **inputs,
109
+ max_new_tokens=128,
110
+ do_sample=False,
111
+ pad_token_id=tokenizer.eos_token_id,
112
+ )
113
+
114
+ print(tokenizer.decode(output[0], skip_special_tokens=True))
115
+ ~~~
116
+
117
+ The notebook treats 512 tokens as a safe total context limit for the current export. Reserve generation tokens accordingly; for example, 384 input tokens plus 128 generated tokens.
118
+
119
+ ## Compact-model comparison
120
+
121
+ The following numbers are the project-provided **Khazri 2 Preview** comparison across selected compact-model tests. Higher is better.
122
+
123
+ | Model | Parameters | Context extraction | Mixed speed/proxy | Arithmetic | Word problems | Abstention |
124
+ | --- | ---: | ---: | ---: | ---: | ---: | ---: |
125
+ | **Khazri 2 Preview** | ~250M | **100%** | **62%** | **99%** | **99%** | **97.4%** |
126
+ | Gemma 3 | 270M | 100% | 36% | 0% | 0% | 18% |
127
+ | Qwen 2.5 | 0.5B | 89% | 45% | 14% | 28% | 46% |
128
+ | Pythia | 160M | 22% | 10% | 0% | 2% | 1% |
129
+
130
+ ### How to read this table
131
+
132
+ These are internal preview results, not an independently audited benchmark. The supplied material does not include all prompts, task definitions, scoring rules, versions, seeds, hardware, sampling settings or full evaluation set. They therefore describe the reported tests only; they do not prove general superiority or predict performance on every downstream task. Reproducible evaluation assets should accompany any future public benchmark announcement.
133
+
134
+ ## Responsible use
135
+
136
+ Khazri 2 Preview may hallucinate, make reasoning errors, reflect training-data bias or abstain incorrectly. Use retrieval, verification and human review for consequential work. Do not rely on outputs alone for medical, legal, financial, security, safety, education, employment or other high-impact decisions. Keep confidential data within an approved environment and review any enabled external-tool route.
137
+
138
+ ## Release checklist
139
+
140
+ Before the repository is public:
141
+
142
+ - [ ] replace the placeholder model ID;
143
+ - [ ] ship the weights, config, tokenizer and all required SYNAPSE files;
144
+ - [ ] add a <code>LICENSE</code> file; no licence is claimed in this README before one is chosen;
145
+ - [ ] publish <code>DATASET.md</code> with source/licence information;
146
+ - [ ] publish an evaluation card with prompts, versions and scoring code;
147
+ - [ ] pin a version/revision and publish file checksums;
148
+ - [ ] test fresh installation in a clean environment.
149
+
150
+ ## Roadmap
151
+
152
+ Khazri 2 Preview represents the current flagship stage. The next goal is **Khazri 3**: a model with a larger parameter count and stronger results, developed with transparent data and evaluation documentation.
153
+
154
+ ## Contact
155
+
156
+ To discuss research, access or partnerships, visit [khazri.dev](https://khazri.dev) or email [contact@khazri.dev](mailto:contact@khazri.dev).
config.json ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "activation_function": "gelu_new",
3
+ "add_cross_attention": false,
4
+ "architectures": [
5
+ "SynapseGPT2LMHeadModel"
6
+ ],
7
+ "attn_pdrop": 0.1,
8
+ "bos_token_id": 2,
9
+ "dtype": "float32",
10
+ "embd_pdrop": 0.1,
11
+ "eos_token_id": 22,
12
+ "initializer_range": 0.02,
13
+ "layer_norm_epsilon": 1e-05,
14
+ "model_type": "gpt2",
15
+ "n_ctx": 512,
16
+ "n_embd": 768,
17
+ "n_head": 12,
18
+ "n_inner": null,
19
+ "n_layer": 32,
20
+ "n_positions": 512,
21
+ "pad_token_id": 1,
22
+ "reorder_and_upcast_attn": false,
23
+ "resid_pdrop": 0.1,
24
+ "scale_attn_by_inverse_layer_idx": false,
25
+ "scale_attn_weights": true,
26
+ "summary_activation": null,
27
+ "summary_first_dropout": 0.1,
28
+ "summary_proj_to_labels": true,
29
+ "summary_type": "cls_index",
30
+ "summary_use_proj": true,
31
+ "tie_word_embeddings": true,
32
+ "transformers_version": "5.10.1",
33
+ "use_cache": false,
34
+ "vocab_size": 32000,
35
+ "auto_map": {
36
+ "AutoModelForCausalLM": "modeling_synapse.SynapseGPT2LMHeadModel"
37
+ },
38
+ "synapse": {
39
+ "version": "v4_from_scratch",
40
+ "requires_controller_for_best_results": true,
41
+ "routes": [
42
+ "NSR_CALCULATOR",
43
+ "UQM_ABSTAIN",
44
+ "TMS_CONTEXT",
45
+ "MODEL_FALLBACK"
46
+ ],
47
+ "pure_model_note": "Use generate() for pure model; use synapse_generate() for controlled inference."
48
+ }
49
+ }
generation_config.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 2,
4
+ "eos_token_id": 22,
5
+ "output_attentions": false,
6
+ "output_hidden_states": false,
7
+ "pad_token_id": 1,
8
+ "transformers_version": "5.10.1",
9
+ "use_cache": true
10
+ }
inference.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from transformers import AutoTokenizer, AutoModelForCausalLM
3
+ import torch
4
+
5
+ MODEL_DIR = "."
6
+
7
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_DIR, trust_remote_code=True)
8
+ model = AutoModelForCausalLM.from_pretrained(
9
+ MODEL_DIR,
10
+ trust_remote_code=True,
11
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
12
+ device_map="auto" if torch.cuda.is_available() else None
13
+ )
14
+
15
+ question = "Calculate: 8603 + 2303"
16
+ print(model.synapse_generate(tokenizer, question, return_trace=True))
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:809edc6a35090373a796d47f85ccaaf85976bfeb51e4866e99eab592f1c68c03
3
+ size 1007170264
modeling_synapse.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+
2
+ from transformers import GPT2LMHeadModel
3
+
4
+ class SynapseGPT2LMHeadModel(GPT2LMHeadModel):
5
+ def synapse_generate(self, tokenizer, question, return_trace=True, **kwargs):
6
+ from synapse_controller import SynapseController
7
+ controller = SynapseController(model=self, tokenizer=tokenizer)
8
+ return controller.generate(question, return_trace=return_trace, **kwargs)
synapse_controller.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import re
3
+ import time
4
+ import torch
5
+
6
+ class SynapseController:
7
+ def __init__(self, model, tokenizer):
8
+ self.model = model
9
+ self.tokenizer = tokenizer
10
+ self.device = next(model.parameters()).device
11
+ self.eot_id = tokenizer.convert_tokens_to_ids("<|eot|>")
12
+
13
+ def _prompt(self, question):
14
+ return f"<|user|>\n{question}\n<|assistant|>\n"
15
+
16
+ def _clean(self, text):
17
+ text = str(text)
18
+ if "<|eot|>" in text:
19
+ text = text.split("<|eot|>")[0]
20
+ if "<|final|>" in text:
21
+ text = text.split("<|final|>")[-1]
22
+ return text.strip()
23
+
24
+ def _model(self, question, max_new_tokens=140):
25
+ inputs = self.tokenizer(self._prompt(question), return_tensors="pt").to(self.device)
26
+ input_len = inputs["input_ids"].shape[-1]
27
+ start = time.time()
28
+ with torch.no_grad():
29
+ out = self.model.generate(
30
+ **inputs,
31
+ max_new_tokens=max_new_tokens,
32
+ min_new_tokens=4,
33
+ do_sample=False,
34
+ pad_token_id=self.tokenizer.pad_token_id,
35
+ eos_token_id=self.eot_id,
36
+ repetition_penalty=1.12,
37
+ no_repeat_ngram_size=4,
38
+ )
39
+ raw = self.tokenizer.decode(out[0][input_len:], skip_special_tokens=False).strip()
40
+ return self._clean(raw), raw, round(time.time() - start, 3)
41
+
42
+ def _nsr(self, question):
43
+ q = str(question).strip()
44
+ m = re.search(r"Calculate:\s*(-?\d+)\s*([\+\-\*])\s*(-?\d+)", q)
45
+ if m:
46
+ a, op, b = int(m.group(1)), m.group(2), int(m.group(3))
47
+ val = a + b if op == "+" else a - b if op == "-" else a * b
48
+ return True, f"Final answer: {val}", f"{a} {op} {b} = {val}"
49
+ m = re.search(r"A shop has\s+(\d+)\s+boxes\. Each box has\s+(\d+)\s+pencils\.\s+(\d+)\s+pencils are lost", q)
50
+ if m:
51
+ boxes, items, lost = int(m.group(1)), int(m.group(2)), int(m.group(3))
52
+ val = boxes * items - lost
53
+ return True, f"Final answer: {val}", f"{boxes} * {items} - {lost} = {val}"
54
+ return False, "", ""
55
+
56
+ def _uqm(self, question):
57
+ q = str(question).lower()
58
+ risky = ["private password", "hidden bank pin", "silently think", "lost private letter", "unpublished diary", "unknown person"]
59
+ if any(x in q for x in risky):
60
+ return True, "I do not have sufficient information.", "Insufficient evidence or unknowable/private information."
61
+ return False, "", ""
62
+
63
+ def _tms(self, question):
64
+ q = str(question)
65
+ if "Context:" not in q or "Question:" not in q:
66
+ return False, "", ""
67
+ context = q.split("Context:", 1)[1].split("Question:", 1)[0].strip()
68
+ patterns = [
69
+ r"called\s+([A-Z][A-Za-z0-9\-]+(?:\s+[A-Z][A-Za-z0-9\-]+)*)",
70
+ r"named\s+([A-Z][A-Za-z0-9\-]+(?:\s+[A-Z][A-Za-z0-9\-]+)*)",
71
+ r"in\s+([A-Z][A-Za-z0-9\-]+)\s+in\s+\d{4}",
72
+ r"code name\s+([A-Z][A-Za-z0-9\-]+(?:\-[A-Z][A-Za-z0-9\-]+)*)",
73
+ ]
74
+ for pat in patterns:
75
+ m = re.search(pat, context)
76
+ if m:
77
+ ans = m.group(1).strip()
78
+ return True, ans, f"Extracted from context: {ans}"
79
+ return False, "", ""
80
+
81
+ def generate(self, question, return_trace=True, **kwargs):
82
+ for route_name, fn in [("UQM_ABSTAIN", self._uqm), ("NSR_CALCULATOR", self._nsr), ("TMS_CONTEXT", self._tms)]:
83
+ ok, ans, trace = fn(question)
84
+ if ok:
85
+ result = {"answer": ans, "route": route_name, "trace": trace}
86
+ return result if return_trace else ans
87
+
88
+ ans, raw, latency = self._model(question, max_new_tokens=kwargs.get("max_new_tokens", 140))
89
+ result = {"answer": ans, "route": "MODEL_FALLBACK", "trace": "Used pure model fallback.", "raw_answer": raw, "latency_sec": latency}
90
+ return result if return_trace else ans
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|bos|>",
4
+ "eos_token": "<|eos|>",
5
+ "extra_special_tokens": [
6
+ "<|system|>",
7
+ "<|user|>",
8
+ "<|assistant|>",
9
+ "<|memory|>",
10
+ "<|tool|>",
11
+ "<|tool_call|>",
12
+ "<|tool_result|>",
13
+ "<|evidence|>",
14
+ "<|reasoning|>",
15
+ "<|uncertain|>",
16
+ "<|abstain|>",
17
+ "<|final|>",
18
+ "<|route:MODEL|>",
19
+ "<|route:NSR|>",
20
+ "<|route:UQM|>",
21
+ "<|route:TMS|>",
22
+ "<|route:PCE|>",
23
+ "<|route:SHE|>",
24
+ "<|eot|>"
25
+ ],
26
+ "is_local": true,
27
+ "local_files_only": false,
28
+ "model_max_length": 512,
29
+ "pad_token": "<|pad|>",
30
+ "tokenizer_class": "TokenizersBackend",
31
+ "unk_token": "<|unk|>"
32
+ }