Lyte commited on
Commit
caf5b91
·
verified ·
1 Parent(s): 786c6af

Upload nanochat-darija-73m-instruct NanoChat HF export

Browse files
README.md ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - ary
4
+ license: mit
5
+ library_name: transformers
6
+ pipeline_tag: text-generation
7
+ tags:
8
+ - nanochat
9
+ - darija
10
+ - moroccan-arabic
11
+ - causal-lm
12
+ - custom-code
13
+ - preview
14
+ - test-run
15
+ base_model: Lyte/nanochat-darija-73m-base
16
+ ---
17
+
18
+ # nanochat-darija-73m-instruct
19
+
20
+ Instruction-tuned NanoChat causal language model for Moroccan Darija.
21
+
22
+ This repo is exported in Hugging Face Transformers format with custom model code. Load it with `trust_remote_code=True`.
23
+
24
+ ## Preview Checkpoint Notice
25
+
26
+ This is a **pilot/test checkpoint**, not the final full-data model. It was trained to validate the Darija data pipeline, tokenizer, NanoChat architecture export, and SFT workflow before a larger billion-plus-token training run.
27
+
28
+ The cleaned base corpus contains **5M Darija rows** and approximately **2B tokens** with the included tokenizer. That number describes the available cleaned corpus; this checkpoint was intentionally trained on a much smaller/shorter schedule.
29
+
30
+ ## Model Details
31
+
32
+ - Parameters: **73.5M** (73,531,538)
33
+ - Context length: `2048`
34
+ - Vocab size: `32768`
35
+ - Layers: `6`
36
+ - Hidden size: `384`
37
+ - Attention heads: `3`
38
+ - Checkpoint tag: `d6_target12`
39
+ - Checkpoint step: `10000`
40
+ - Export dtype: `bfloat16`
41
+ - Base checkpoint: `Lyte/nanochat-darija-73m-base`
42
+
43
+ ## Training
44
+
45
+ Continued with supervised fine-tuning on Moroccan Darija instruction data.
46
+
47
+ The instruction-tuned variant is small and experimental. It is useful for lightweight Darija chat tests, but it is not reliable for math, factuality, code debugging, translation fidelity, or safety-critical decisions.
48
+
49
+ ## Usage
50
+
51
+ ```python
52
+ import torch
53
+ from transformers import AutoModelForCausalLM, AutoTokenizer
54
+
55
+ model_id = "Lyte/nanochat-darija-73m-instruct"
56
+ tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
57
+ model = AutoModelForCausalLM.from_pretrained(
58
+ model_id,
59
+ trust_remote_code=True,
60
+ torch_dtype=torch.bfloat16,
61
+ device_map="auto",
62
+ )
63
+
64
+ messages = [{"role": "user", "content": "جاوبني بالدارجة: شنو هي أحسن طريقة نتعلم بها البرمجة؟"}]
65
+ inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device)
66
+ if not hasattr(inputs, "shape"):
67
+ inputs = inputs["input_ids"]
68
+ outputs = model.generate(
69
+ inputs,
70
+ max_new_tokens=256,
71
+ temperature=0.6,
72
+ top_k=100,
73
+ top_p=0.85,
74
+ repetition_penalty=1.1,
75
+ do_sample=True,
76
+ )
77
+ print(tokenizer.decode(outputs[0], skip_special_tokens=False))
78
+ ```
79
+
80
+ ## Files
81
+
82
+ - `model.safetensors`: model weights
83
+ - `config.json`: NanoChat architecture config
84
+ - `generation_config.json`: default sampling config
85
+ - `tokenizer.json`, `tokenizer_config.json`, `special_tokens_map.json`: tokenizer files
86
+ - `configuration_nanochat.py`, `modeling_nanochat.py`: custom Transformers code
87
+ - `nanochat_export.json`: source checkpoint metadata
88
+
89
+ ## Limitations
90
+
91
+ This is a tiny model. Expect fluent-looking but wrong answers, repetition on some prompts, and brittle instruction following. Use it as a research artifact or local baseline, not as a production assistant.
chat_template.jinja ADDED
@@ -0,0 +1 @@
 
 
1
+ {% for message in messages %}{% if loop.first %}<|bos|>{% endif %}{% if message['role'] == 'user' %}<|user_start|>{{ message['content'] }}<|user_end|>{% endif %}{% if message['role'] == 'assistant' %}<|assistant_start|>{{ message['content'] }}<|assistant_end|>{% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant_start|>{% endif %}
config.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "NanochatForCausalLM"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_nanochat.NanochatConfig",
7
+ "AutoModelForCausalLM": "modeling_nanochat.NanochatForCausalLM"
8
+ },
9
+ "bos_token_id": 32759,
10
+ "dtype": "bfloat16",
11
+ "eos_token_id": 32763,
12
+ "model_type": "nanochat",
13
+ "n_embd": 384,
14
+ "n_head": 3,
15
+ "n_kv_head": 3,
16
+ "n_layer": 6,
17
+ "pad_token_id": 32759,
18
+ "pad_vocab_size_to": 64,
19
+ "sequence_len": 2048,
20
+ "smear_gate_channels": 24,
21
+ "tie_word_embeddings": false,
22
+ "transformers_version": "5.8.0",
23
+ "use_cache": false,
24
+ "ve_gate_channels": 12,
25
+ "vocab_size": 32768,
26
+ "window_pattern": "L"
27
+ }
configuration_nanochat.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import PretrainedConfig
2
+
3
+
4
+ class NanochatConfig(PretrainedConfig):
5
+ model_type = "nanochat"
6
+
7
+ def __init__(
8
+ self,
9
+ sequence_len=2048,
10
+ vocab_size=32768,
11
+ n_layer=12,
12
+ n_head=6,
13
+ n_kv_head=6,
14
+ n_embd=768,
15
+ window_pattern="SSSL",
16
+ pad_vocab_size_to=64,
17
+ ve_gate_channels=12,
18
+ smear_gate_channels=24,
19
+ use_cache=True,
20
+ output_hidden_states=False,
21
+ bos_token_id=None,
22
+ eos_token_id=None,
23
+ pad_token_id=None,
24
+ tie_word_embeddings=False,
25
+ **kwargs,
26
+ ):
27
+ self.sequence_len = sequence_len
28
+ self.vocab_size = vocab_size
29
+ self.n_layer = n_layer
30
+ self.n_head = n_head
31
+ self.n_kv_head = n_kv_head
32
+ self.n_embd = n_embd
33
+ self.window_pattern = window_pattern
34
+ self.pad_vocab_size_to = pad_vocab_size_to
35
+ self.ve_gate_channels = ve_gate_channels
36
+ self.smear_gate_channels = smear_gate_channels
37
+ self.use_cache = use_cache
38
+ self.output_hidden_states = output_hidden_states
39
+ super().__init__(
40
+ bos_token_id=bos_token_id,
41
+ eos_token_id=eos_token_id,
42
+ pad_token_id=pad_token_id,
43
+ tie_word_embeddings=tie_word_embeddings,
44
+ **kwargs,
45
+ )
46
+
47
+ @property
48
+ def num_hidden_layers(self):
49
+ return self.n_layer
50
+
51
+ @property
52
+ def head_dim(self):
53
+ return self.n_embd // self.n_head
54
+
55
+ @property
56
+ def padded_vocab_size(self):
57
+ multiple = self.pad_vocab_size_to
58
+ return ((self.vocab_size + multiple - 1) // multiple) * multiple
generation_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_sample": true,
3
+ "eos_token_id": 32763,
4
+ "max_new_tokens": 256,
5
+ "pad_token_id": 32759,
6
+ "repetition_penalty": 1.1,
7
+ "temperature": 0.6,
8
+ "top_k": 100,
9
+ "top_p": 0.85,
10
+ "transformers_version": "5.8.0",
11
+ "use_cache": false
12
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ac5950a3f5d1a3fb94e28e06354f25e6677f0d5d992788977fa4c4ea0d05c38a
3
+ size 147068388
modeling_nanochat.py ADDED
@@ -0,0 +1,508 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from typing import Optional, Tuple
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from transformers import DynamicCache, PreTrainedModel
9
+ from transformers.generation.utils import GenerationMixin
10
+ from transformers.modeling_outputs import BaseModelOutputWithPast, CausalLMOutputWithPast
11
+
12
+ try:
13
+ from .configuration_nanochat import NanochatConfig
14
+ except ImportError:
15
+ from configuration_nanochat import NanochatConfig
16
+
17
+
18
+ def norm(x: torch.Tensor) -> torch.Tensor:
19
+ return F.rms_norm(x, (x.size(-1),))
20
+
21
+
22
+ def dynamic_cache_to_legacy(past_key_values: DynamicCache):
23
+ if hasattr(past_key_values, "to_legacy_cache"):
24
+ return past_key_values.to_legacy_cache()
25
+
26
+ if hasattr(past_key_values, "layers"):
27
+ legacy_cache = []
28
+ for layer in past_key_values.layers:
29
+ keys = getattr(layer, "keys", None)
30
+ values = getattr(layer, "values", None)
31
+ if keys is None or values is None:
32
+ continue
33
+ if keys.numel() == 0 or values.numel() == 0:
34
+ continue
35
+ legacy_cache.append((keys, values))
36
+ return tuple(legacy_cache)
37
+
38
+ n_layers = len(past_key_values)
39
+ if hasattr(past_key_values, "key_cache"):
40
+ return tuple(
41
+ (past_key_values.key_cache[i], past_key_values.value_cache[i])
42
+ for i in range(n_layers)
43
+ )
44
+
45
+ return tuple(past_key_values[i] for i in range(n_layers))
46
+
47
+
48
+ def legacy_cache_to_dynamic(past_key_values):
49
+ if hasattr(DynamicCache, "from_legacy_cache"):
50
+ return DynamicCache.from_legacy_cache(past_key_values)
51
+
52
+ cache = DynamicCache()
53
+ for layer_idx, (k, v) in enumerate(past_key_values):
54
+ cache.update(k, v, layer_idx)
55
+ return cache
56
+
57
+
58
+ class Linear(nn.Linear):
59
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
60
+ return F.linear(x, self.weight.to(dtype=x.dtype))
61
+
62
+
63
+ def has_ve(layer_idx: int, n_layer: int) -> bool:
64
+ return layer_idx % 2 == (n_layer - 1) % 2
65
+
66
+
67
+ def apply_rotary_emb(x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
68
+ half = x.shape[-1] // 2
69
+ x1, x2 = x[..., :half], x[..., half:]
70
+ y1 = x1 * cos + x2 * sin
71
+ y2 = x1 * (-sin) + x2 * cos
72
+ return torch.cat([y1, y2], dim=-1)
73
+
74
+
75
+ class NanochatAttention(nn.Module):
76
+ def __init__(self, config: NanochatConfig, layer_idx: int):
77
+ super().__init__()
78
+ self.layer_idx = layer_idx
79
+ self.n_head = config.n_head
80
+ self.n_kv_head = config.n_kv_head
81
+ self.n_embd = config.n_embd
82
+ self.head_dim = config.head_dim
83
+ self.ve_gate_channels = config.ve_gate_channels
84
+ self.c_q = Linear(self.n_embd, self.n_head * self.head_dim, bias=False)
85
+ self.c_k = Linear(self.n_embd, self.n_kv_head *
86
+ self.head_dim, bias=False)
87
+ self.c_v = Linear(self.n_embd, self.n_kv_head *
88
+ self.head_dim, bias=False)
89
+ self.c_proj = Linear(self.n_embd, self.n_embd, bias=False)
90
+ self.ve_gate = Linear(self.ve_gate_channels, self.n_kv_head, bias=False) if has_ve(
91
+ layer_idx, config.n_layer) else None
92
+
93
+ def _build_attn_mask(
94
+ self,
95
+ batch_size: int,
96
+ query_len: int,
97
+ key_len: int,
98
+ past_len: int,
99
+ window_size: int,
100
+ attention_mask: Optional[torch.Tensor],
101
+ device: torch.device,
102
+ ) -> torch.Tensor:
103
+ query_positions = torch.arange(
104
+ past_len, past_len + query_len, device=device)
105
+ key_positions = torch.arange(key_len, device=device)
106
+ mask = key_positions.unsqueeze(0) <= query_positions.unsqueeze(1)
107
+ if window_size < key_len:
108
+ min_key = query_positions.unsqueeze(1) - window_size + 1
109
+ mask = mask & (key_positions.unsqueeze(0) >= min_key)
110
+ mask = mask.unsqueeze(0).unsqueeze(1).expand(
111
+ batch_size, 1, query_len, key_len)
112
+ if attention_mask is not None:
113
+ key_mask = attention_mask[:, -
114
+ key_len:].to(dtype=torch.bool, device=device)
115
+ mask = mask & key_mask[:, None, None, :]
116
+ return mask
117
+
118
+ def forward(
119
+ self,
120
+ x: torch.Tensor,
121
+ ve: Optional[torch.Tensor],
122
+ cos: torch.Tensor,
123
+ sin: torch.Tensor,
124
+ window_size: int,
125
+ attention_mask: Optional[torch.Tensor],
126
+ past_key_value: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
127
+ use_cache: bool = False,
128
+ ) -> Tuple[torch.Tensor, Optional[Tuple[torch.Tensor, torch.Tensor]]]:
129
+ batch_size, query_len, _ = x.shape
130
+ q = self.c_q(x).view(batch_size, query_len, self.n_head, self.head_dim)
131
+ k = self.c_k(x).view(batch_size, query_len,
132
+ self.n_kv_head, self.head_dim)
133
+ v = self.c_v(x).view(batch_size, query_len,
134
+ self.n_kv_head, self.head_dim)
135
+
136
+ if ve is not None:
137
+ ve = ve.view(batch_size, query_len, self.n_kv_head, self.head_dim)
138
+ gate = 3 * \
139
+ torch.sigmoid(self.ve_gate(x[..., :self.ve_gate_channels]))
140
+ v = v + gate.unsqueeze(-1) * ve
141
+
142
+ q = norm(apply_rotary_emb(q, cos, sin))
143
+ k = norm(apply_rotary_emb(k, cos, sin))
144
+ q = q * 1.2
145
+ k = k * 1.2
146
+
147
+ q = q.transpose(1, 2)
148
+ k = k.transpose(1, 2)
149
+ v = v.transpose(1, 2)
150
+
151
+ past_len = 0
152
+ if past_key_value is not None:
153
+ past_k, past_v = past_key_value
154
+ past_len = past_k.size(-2)
155
+ k = torch.cat((past_k, k), dim=-2)
156
+ v = torch.cat((past_v, v), dim=-2)
157
+
158
+ present = (k, v) if use_cache else None
159
+
160
+ if self.n_kv_head != self.n_head:
161
+ repeats = self.n_head // self.n_kv_head
162
+ k_for_attn = k.repeat_interleave(repeats, dim=1)
163
+ v_for_attn = v.repeat_interleave(repeats, dim=1)
164
+ else:
165
+ k_for_attn = k
166
+ v_for_attn = v
167
+
168
+ key_len = k_for_attn.size(-2)
169
+ attn_mask = self._build_attn_mask(
170
+ batch_size=batch_size,
171
+ query_len=query_len,
172
+ key_len=key_len,
173
+ past_len=past_len,
174
+ window_size=window_size,
175
+ attention_mask=attention_mask,
176
+ device=x.device,
177
+ )
178
+ y = F.scaled_dot_product_attention(
179
+ q, k_for_attn, v_for_attn, attn_mask=attn_mask)
180
+ y = y.transpose(1, 2).contiguous().view(
181
+ batch_size, query_len, self.n_embd)
182
+ y = self.c_proj(y)
183
+ return y, present
184
+
185
+
186
+ class NanochatMLP(nn.Module):
187
+ def __init__(self, config: NanochatConfig):
188
+ super().__init__()
189
+ self.c_fc = Linear(config.n_embd, 4 * config.n_embd, bias=False)
190
+ self.c_proj = Linear(4 * config.n_embd, config.n_embd, bias=False)
191
+
192
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
193
+ return self.c_proj(F.relu(self.c_fc(x)).square())
194
+
195
+
196
+ class NanochatBlock(nn.Module):
197
+ def __init__(self, config: NanochatConfig, layer_idx: int):
198
+ super().__init__()
199
+ self.attn = NanochatAttention(config, layer_idx)
200
+ self.mlp = NanochatMLP(config)
201
+
202
+ def forward(
203
+ self,
204
+ x: torch.Tensor,
205
+ ve: Optional[torch.Tensor],
206
+ cos: torch.Tensor,
207
+ sin: torch.Tensor,
208
+ window_size: int,
209
+ attention_mask: Optional[torch.Tensor],
210
+ past_key_value: Optional[Tuple[torch.Tensor, torch.Tensor]] = None,
211
+ use_cache: bool = False,
212
+ ) -> Tuple[torch.Tensor, Optional[Tuple[torch.Tensor, torch.Tensor]]]:
213
+ attn_out, present = self.attn(
214
+ norm(x),
215
+ ve=ve,
216
+ cos=cos,
217
+ sin=sin,
218
+ window_size=window_size,
219
+ attention_mask=attention_mask,
220
+ past_key_value=past_key_value,
221
+ use_cache=use_cache,
222
+ )
223
+ x = x + attn_out
224
+ x = x + self.mlp(norm(x))
225
+ return x, present
226
+
227
+
228
+ class NanochatPreTrainedModel(PreTrainedModel):
229
+ config_class = NanochatConfig
230
+ base_model_prefix = "model"
231
+ supports_gradient_checkpointing = False
232
+ _no_split_modules = ["NanochatBlock"]
233
+
234
+ def _init_weights(self, module: nn.Module) -> None:
235
+ return None
236
+
237
+
238
+ class NanochatModel(NanochatPreTrainedModel):
239
+ def __init__(self, config: NanochatConfig):
240
+ super().__init__(config)
241
+ self.window_sizes = self._compute_window_sizes(config)
242
+ padded_vocab_size = config.padded_vocab_size
243
+ self.transformer = nn.ModuleDict(
244
+ {
245
+ "wte": nn.Embedding(padded_vocab_size, config.n_embd),
246
+ "h": nn.ModuleList([NanochatBlock(config, layer_idx) for layer_idx in range(config.n_layer)]),
247
+ }
248
+ )
249
+ self.resid_lambdas = nn.Parameter(torch.ones(config.n_layer))
250
+ self.x0_lambdas = nn.Parameter(torch.zeros(config.n_layer))
251
+ self.smear_gate = Linear(config.smear_gate_channels, 1, bias=False)
252
+ self.smear_lambda = nn.Parameter(torch.zeros(1))
253
+ self.backout_lambda = nn.Parameter(0.2 * torch.ones(1))
254
+ kv_dim = config.n_kv_head * config.head_dim
255
+ self.value_embeds = nn.ModuleDict(
256
+ {str(i): nn.Embedding(padded_vocab_size, kv_dim)
257
+ for i in range(config.n_layer) if has_ve(i, config.n_layer)}
258
+ )
259
+ self._rope_cos: Optional[torch.Tensor] = None
260
+ self._rope_sin: Optional[torch.Tensor] = None
261
+
262
+ def _precompute_rotary_embeddings(
263
+ self,
264
+ seq_len: int,
265
+ head_dim: int,
266
+ base: int = 100000,
267
+ device: Optional[torch.device] = None,
268
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
269
+ if device is None:
270
+ device = self.transformer["wte"].weight.device
271
+ channel_range = torch.arange(
272
+ 0, head_dim, 2, dtype=torch.float32, device=device)
273
+ inv_freq = 1.0 / (base ** (channel_range / head_dim))
274
+ t = torch.arange(seq_len, dtype=torch.float32, device=device)
275
+ freqs = torch.outer(t, inv_freq)
276
+ cos, sin = freqs.cos(), freqs.sin()
277
+ return cos[None, :, None, :], sin[None, :, None, :]
278
+
279
+ def _compute_window_sizes(self, config: NanochatConfig) -> list[int]:
280
+ pattern = config.window_pattern.upper()
281
+ long_window = config.sequence_len
282
+ short_window = -(-long_window // 4 // 128) * 128
283
+ sizes = []
284
+ for layer_idx in range(config.n_layer):
285
+ char = pattern[layer_idx % len(pattern)]
286
+ sizes.append(short_window if char == "S" else long_window)
287
+ sizes[-1] = long_window
288
+ return sizes
289
+
290
+ def get_input_embeddings(self) -> nn.Embedding:
291
+ return self.transformer["wte"]
292
+
293
+ def set_input_embeddings(self, value: nn.Embedding) -> None:
294
+ self.transformer["wte"] = value
295
+
296
+ def forward(
297
+ self,
298
+ input_ids: torch.LongTensor,
299
+ attention_mask: Optional[torch.Tensor] = None,
300
+ past_key_values: Optional[Tuple[Tuple[torch.Tensor,
301
+ torch.Tensor], ...]] = None,
302
+ token_type_ids: Optional[torch.Tensor] = None,
303
+ use_cache: Optional[bool] = None,
304
+ output_hidden_states: Optional[bool] = None,
305
+ return_dict: Optional[bool] = None,
306
+ **kwargs,
307
+ ):
308
+ use_cache = self.config.use_cache if use_cache is None else use_cache
309
+ output_hidden_states = self.config.output_hidden_states if output_hidden_states is None else output_hidden_states
310
+ return_dict = self.config.use_return_dict if return_dict is None else return_dict
311
+ batch_size, seq_len = input_ids.shape
312
+
313
+ # Convert DynamicCache to tuple-of-tuples for internal use
314
+ _input_was_dynamic_cache = isinstance(past_key_values, DynamicCache)
315
+ if _input_was_dynamic_cache:
316
+ if past_key_values.get_seq_length() == 0:
317
+ past_key_values = None
318
+ else:
319
+ past_key_values = dynamic_cache_to_legacy(past_key_values)
320
+
321
+ past_len = 0
322
+ if past_key_values is not None and len(past_key_values) > 0:
323
+ past_len = past_key_values[0][0].size(-2)
324
+ end = past_len + seq_len
325
+ need_recompute = (
326
+ self._rope_cos is None
327
+ or self._rope_cos.device.type == "meta"
328
+ or end > self._rope_cos.size(1)
329
+ )
330
+ if need_recompute:
331
+ rope_len = max(end * 2, self.config.sequence_len * 10)
332
+ self._rope_cos, self._rope_sin = self._precompute_rotary_embeddings(
333
+ rope_len, self.config.head_dim, device=input_ids.device)
334
+ cos = self._rope_cos[:, past_len:end].to(
335
+ dtype=self.transformer["wte"].weight.dtype, device=input_ids.device)
336
+ sin = self._rope_sin[:, past_len:end].to(
337
+ dtype=self.transformer["wte"].weight.dtype, device=input_ids.device)
338
+
339
+ hidden_states = self.transformer["wte"](input_ids)
340
+ hidden_states = hidden_states.to(
341
+ dtype=self.transformer["wte"].weight.dtype)
342
+ hidden_states = norm(hidden_states)
343
+
344
+ if seq_len > 1:
345
+ channels = self.config.smear_gate_channels
346
+ gate = self.smear_lambda.to(hidden_states.dtype) * torch.sigmoid(
347
+ self.smear_gate(hidden_states[:, 1:, :channels])
348
+ )
349
+ hidden_states = torch.cat(
350
+ [hidden_states[:, :1], hidden_states[:, 1:] + gate * hidden_states[:, :-1]],
351
+ dim=1,
352
+ )
353
+ x0 = hidden_states
354
+
355
+ all_hidden_states = () if output_hidden_states else None
356
+ presents = () if use_cache else None
357
+ backout_layer = self.config.n_layer // 2
358
+ x_backout = None
359
+ for layer_idx, block in enumerate(self.transformer["h"]):
360
+ if output_hidden_states:
361
+ all_hidden_states = all_hidden_states + (hidden_states,)
362
+ hidden_states = self.resid_lambdas[layer_idx] * \
363
+ hidden_states + self.x0_lambdas[layer_idx] * x0
364
+ ve = self.value_embeds[str(layer_idx)](input_ids).to(
365
+ hidden_states.dtype) if str(layer_idx) in self.value_embeds else None
366
+ layer_past = None if past_key_values is None else past_key_values[layer_idx]
367
+ hidden_states, present = block(
368
+ hidden_states,
369
+ ve=ve,
370
+ cos=cos,
371
+ sin=sin,
372
+ window_size=self.window_sizes[layer_idx],
373
+ attention_mask=attention_mask,
374
+ past_key_value=layer_past,
375
+ use_cache=use_cache,
376
+ )
377
+ if use_cache:
378
+ presents = presents + (present,)
379
+ if layer_idx == backout_layer:
380
+ x_backout = hidden_states
381
+
382
+ if x_backout is not None:
383
+ hidden_states = hidden_states - self.backout_lambda.to(hidden_states.dtype) * x_backout
384
+ hidden_states = norm(hidden_states)
385
+ if output_hidden_states:
386
+ all_hidden_states = all_hidden_states + (hidden_states,)
387
+
388
+ # Convert presents back to DynamicCache if that's what was passed in
389
+ if _input_was_dynamic_cache and presents is not None:
390
+ presents = legacy_cache_to_dynamic(presents)
391
+
392
+ if not return_dict:
393
+ outputs = (hidden_states, presents, all_hidden_states)
394
+ return tuple(output for output in outputs if output is not None)
395
+ return BaseModelOutputWithPast(
396
+ last_hidden_state=hidden_states,
397
+ past_key_values=presents,
398
+ hidden_states=all_hidden_states,
399
+ )
400
+
401
+
402
+ class NanochatForCausalLM(NanochatPreTrainedModel, GenerationMixin):
403
+ _tied_weights_keys = []
404
+ all_tied_weights_keys = {}
405
+
406
+ def __init__(self, config: NanochatConfig):
407
+ super().__init__(config)
408
+ self.model = NanochatModel(config)
409
+ self.lm_head = Linear(
410
+ config.n_embd, config.padded_vocab_size, bias=False)
411
+
412
+ def get_input_embeddings(self) -> nn.Embedding:
413
+ return self.model.get_input_embeddings()
414
+
415
+ def set_input_embeddings(self, value: nn.Embedding) -> None:
416
+ self.model.set_input_embeddings(value)
417
+
418
+ def get_output_embeddings(self) -> nn.Module:
419
+ return self.lm_head
420
+
421
+ def set_output_embeddings(self, new_embeddings: nn.Module) -> None:
422
+ self.lm_head = new_embeddings
423
+
424
+ def forward(
425
+ self,
426
+ input_ids: torch.LongTensor,
427
+ attention_mask: Optional[torch.Tensor] = None,
428
+ past_key_values: Optional[Tuple[Tuple[torch.Tensor,
429
+ torch.Tensor], ...]] = None,
430
+ token_type_ids: Optional[torch.Tensor] = None,
431
+ labels: Optional[torch.LongTensor] = None,
432
+ use_cache: Optional[bool] = None,
433
+ output_hidden_states: Optional[bool] = None,
434
+ return_dict: Optional[bool] = None,
435
+ **kwargs,
436
+ ):
437
+ return_dict = self.config.use_return_dict if return_dict is None else return_dict
438
+ outputs = self.model(
439
+ input_ids=input_ids,
440
+ attention_mask=attention_mask,
441
+ past_key_values=past_key_values,
442
+ token_type_ids=token_type_ids,
443
+ use_cache=use_cache,
444
+ output_hidden_states=output_hidden_states,
445
+ return_dict=True,
446
+ **kwargs,
447
+ )
448
+ logits = self.lm_head(
449
+ outputs.last_hidden_state)[..., : self.config.vocab_size]
450
+ logits = logits.float()
451
+
452
+ softcap = 15.0
453
+ logits = softcap * torch.tanh(logits / softcap)
454
+
455
+ loss = None
456
+ if labels is not None:
457
+ shift_logits = logits[:, :-1, :].contiguous()
458
+ shift_labels = labels[:, 1:].contiguous()
459
+ loss = F.cross_entropy(
460
+ shift_logits.view(-1, shift_logits.size(-1)),
461
+ shift_labels.view(-1),
462
+ ignore_index=-100,
463
+ )
464
+
465
+ if not return_dict:
466
+ result = (logits, outputs.past_key_values, outputs.hidden_states)
467
+ return ((loss,) + result) if loss is not None else result
468
+ return CausalLMOutputWithPast(
469
+ loss=loss,
470
+ logits=logits,
471
+ past_key_values=outputs.past_key_values,
472
+ hidden_states=outputs.hidden_states,
473
+ )
474
+
475
+ def prepare_inputs_for_generation(
476
+ self,
477
+ input_ids: torch.LongTensor,
478
+ past_key_values: Optional[Tuple[Tuple[torch.Tensor,
479
+ torch.Tensor], ...]] = None,
480
+ attention_mask: Optional[torch.Tensor] = None,
481
+ **kwargs,
482
+ ):
483
+ if attention_mask is None:
484
+ attention_mask = torch.ones_like(input_ids, dtype=torch.long)
485
+ has_past = (
486
+ past_key_values is not None
487
+ and hasattr(past_key_values, "get_seq_length")
488
+ and past_key_values.get_seq_length() > 0
489
+ )
490
+ if has_past:
491
+ input_ids = input_ids[:, -1:]
492
+ return {
493
+ "input_ids": input_ids,
494
+ "attention_mask": attention_mask,
495
+ "past_key_values": past_key_values,
496
+ "use_cache": kwargs.get("use_cache", True),
497
+ }
498
+
499
+ @staticmethod
500
+ def _reorder_cache(
501
+ past_key_values: Tuple[Tuple[torch.Tensor, torch.Tensor], ...],
502
+ beam_idx: torch.LongTensor,
503
+ ) -> Tuple[Tuple[torch.Tensor, torch.Tensor], ...]:
504
+ reordered = []
505
+ for key_states, value_states in past_key_values:
506
+ reordered.append((key_states.index_select(
507
+ 0, beam_idx), value_states.index_select(0, beam_idx)))
508
+ return tuple(reordered)
nanochat_export.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "checkpoint_dir": "dev\\nanochat_darija_v3\\chatsft_checkpoints\\d6_target12",
3
+ "step": 10000,
4
+ "source": "sft",
5
+ "model_tag": "d6_target12",
6
+ "source_dtype": "torch.bfloat16",
7
+ "repo_id": "Lyte/nanochat-darija-73m-instruct"
8
+ }
tiktoken/tokenizer.model ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:70cb4234d3ce376201850e94d32276800de9590dda2be0edc085606eab6062ea
3
+ size 704723
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|bos|>",
4
+ "clean_up_tokenization_spaces": false,
5
+ "eos_token": "<|assistant_end|>",
6
+ "extra_special_tokens": [
7
+ "<|user_start|>",
8
+ "<|user_end|>",
9
+ "<|assistant_start|>",
10
+ "<|python_start|>",
11
+ "<|python_end|>",
12
+ "<|output_start|>",
13
+ "<|output_end|>"
14
+ ],
15
+ "model_max_length": 1000000000000000019884624838656,
16
+ "pad_token": "<|bos|>",
17
+ "tokenizer_class": "TokenizersBackend"
18
+ }