Banaxi-Tech commited on
Commit
121fb22
·
verified ·
1 Parent(s): a917ee4

Upload 11 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ banner.png filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,3 +1,216 @@
1
  ---
2
  license: apache-2.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: apache-2.0
3
+ language:
4
+ - en
5
+ library_name: transformers
6
+ pipeline_tag: text-generation
7
+ base_model: BananaMind/BananaMind-2-Mini
8
+ datasets:
9
+ - HuggingFaceTB/smol-smoltalk
10
+ tags:
11
+ - causal-lm
12
+ - chat
13
+ - instruction-tuned
14
+ - full-finetune
15
+ - small-language-model
16
+ - bananamind
17
+ - bananamind2
18
+ - bananamind2-mini
19
+ - smoltalk
20
+ - pytorch
21
+ - safetensors
22
+ - custom-code
23
+ - trust-remote-code
24
  ---
25
+
26
+ ![BananaMind 2 Mini Chat](banner.png)
27
+
28
+ # BananaMind-2-Mini-Chat
29
+
30
+ BananaMind-2-Mini-Chat is the instruction-tuned version of [BananaMind-2-Mini](https://huggingface.co/BananaMind/BananaMind-2-Mini). It was fully fine-tuned on [HuggingFaceTB/smol-smoltalk](https://huggingface.co/datasets/HuggingFaceTB/smol-smoltalk) with loss applied only to assistant tokens and the assistant-ending EOS token.
31
+
32
+ The model has **25,178,752 parameters**, a **4,096-token context window**, and a custom **8,192-token digit-aware byte-level BPE tokenizer**. It supports system prompts, multi-turn conversations, and KV-cached generation.
33
+
34
+ ## Model Details
35
+
36
+ | Field | Value |
37
+ |---|---:|
38
+ | Parameters | 25,178,752 |
39
+ | Base model | `BananaMind/BananaMind-2-Mini` |
40
+ | Architecture | BananaMind2Mini decoder-only Transformer |
41
+ | Layers | 14 |
42
+ | Hidden size | 384 |
43
+ | Intermediate size | 1,024 |
44
+ | Attention heads | 6 |
45
+ | KV heads | 2 |
46
+ | Head dimension | 64 |
47
+ | Attention | Grouped-query attention with QK norm |
48
+ | MLP | SwiGLU |
49
+ | Position embeddings | RoPE, theta 100,000 |
50
+ | Vocabulary size | 8,192 |
51
+ | Context length | 4,096 |
52
+ | Embeddings | Tied input/output embeddings |
53
+ | Generation cache | KV cache supported |
54
+ | Weight format | safetensors |
55
+ | Training type | Full-parameter supervised fine-tuning |
56
+
57
+ ## Benchmarks
58
+
59
+ ### BananaMind Instruct Bench 1.1
60
+
61
+ Self-reported results from the official [BananaMind Instruct Bench 1.1](https://huggingface.co/datasets/BananaMind/BananaMind-Instruct-Bench-1.1) script. This is a 300-example, difficulty- and category-weighted instruction benchmark. Generation was deterministic with `repetition_penalty=1.1` and seed 42.
62
+
63
+ | Model | Overall ELO | General | Multi-turn | System Prompts | Context Recall | Code |
64
+ |---|---:|---:|---:|---:|---:|---:|
65
+ | BananaMind-2-Medium-Chat | 787 | 534 | 872 | 666 | 1,085 | 1,291 |
66
+ | **BananaMind-2-Mini-Chat** | **654** | **389** | **812** | **743** | **924** | **667** |
67
+ | Supra 1.5 50M Instruct* | 647 | 520 | 804 | 590 | 860 | 780 |
68
+ | BananaMind-2-Nano-Chat | 643 | 353 | 796 | 600 | 978 | 885 |
69
+ | Supra 1.0 50M Instruct* | 520 | 531 | 405 | 590 | 794 | 667 |
70
+
71
+ **Detailed BananaMind-2-Mini-Chat result**
72
+
73
+ | Scope | Examples | Passed | Weighted Score | ELO |
74
+ |---|---:|---:|---:|---:|
75
+ | **Overall** | **300** | **40** | **9.64%** | **654** |
76
+ | General | 120 | 6 | 3.42% | 389 |
77
+ | Multi-turn | 75 | 19 | 16.84% | 812 |
78
+ | System Prompts | 60 | 7 | 8.95% | 743 |
79
+ | Context Recall | 30 | 8 | 17.89% | 924 |
80
+ | Code | 15 | 0 | 0.00% | 667 |
81
+
82
+ | Difficulty | Examples | Passed | Weighted Score | ELO |
83
+ |---|---:|---:|---:|---:|
84
+ | Easy | 100 | 33 | 34.62% | 821 |
85
+ | Medium | 100 | 7 | 7.45% | 593 |
86
+ | Hard | 100 | 0 | 0.00% | 296 |
87
+
88
+ \* Supra 1.5 used the benchmark's Alpaca-style fallback, with conversation context supplied through its `### Input` field. Supra 1.0 used the same fallback and a copied checkpoint with 3.0x linear RoPE scaling, extending its context from 1,024 to 3,072 tokens without additional long-context training so it could fit the benchmark inputs.
89
+
90
+ These scores are self-evaluated and may vary with the benchmark revision, Transformers version, dtype, hardware, and generation settings.
91
+
92
+ ## Instruction Tuning
93
+
94
+ | Field | Value |
95
+ |---|---:|
96
+ | Dataset | `HuggingFaceTB/smol-smoltalk` |
97
+ | Dataset split | `train` |
98
+ | Dataset rows | 460,341 |
99
+ | Epochs | 1 |
100
+ | Final optimizer step | 3,193 |
101
+ | Packed tokens processed | 470,782,108 |
102
+ | Supervised assistant tokens | 360,967,001 |
103
+ | Sequence length | 4,096 |
104
+ | Micro batch | 12 |
105
+ | Gradient accumulation | 3 |
106
+ | Effective batch | 36 sequences |
107
+ | Peak learning rate | 2e-4 |
108
+ | Warmup | 100 steps |
109
+ | LR schedule | Constant after warmup |
110
+ | Optimizer | AdamW |
111
+ | Betas | 0.9, 0.95 |
112
+ | Weight decay | 0.1 |
113
+ | Gradient clipping | 1.0 |
114
+ | Seed | 1337 |
115
+
116
+ System and user messages were retained as context but masked from the loss. All parameters were trainable; no LoRA modules or adapters were used.
117
+
118
+ ## Chat Template
119
+
120
+ The tokenizer includes a Jinja template for `system`, `user`, and `assistant` messages:
121
+
122
+ ```text
123
+ <BOS><|system|>
124
+ {system message}
125
+ <|user|>
126
+ {user message}
127
+ <|assistant|>
128
+ {assistant response}<EOS>
129
+ ```
130
+
131
+ The role markers use the existing tokenizer vocabulary. Fine-tuning did not add new tokens.
132
+
133
+ ## Usage
134
+
135
+ This model uses custom architecture code and must be loaded with `trust_remote_code=True`.
136
+
137
+ ```bash
138
+ pip install -U transformers safetensors torch
139
+ ```
140
+
141
+ ```python
142
+ import torch
143
+ from transformers import AutoModelForCausalLM, AutoTokenizer
144
+
145
+ model_id = "BananaMind/BananaMind-2-Mini-Chat"
146
+ device = "cuda" if torch.cuda.is_available() else "cpu"
147
+ dtype = torch.bfloat16 if device == "cuda" and torch.cuda.is_bf16_supported() else torch.float32
148
+
149
+ tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
150
+ model = AutoModelForCausalLM.from_pretrained(
151
+ model_id,
152
+ trust_remote_code=True,
153
+ torch_dtype=dtype,
154
+ ).to(device).eval()
155
+
156
+ messages = [
157
+ {"role": "system", "content": "You are a concise and helpful assistant."},
158
+ {"role": "user", "content": "Write one Python line that prints 2 + 3."},
159
+ ]
160
+
161
+ inputs = tokenizer.apply_chat_template(
162
+ messages,
163
+ add_generation_prompt=True,
164
+ return_tensors="pt",
165
+ return_dict=True,
166
+ )
167
+ inputs = {name: tensor.to(device) for name, tensor in inputs.items()}
168
+
169
+ with torch.inference_mode():
170
+ output = model.generate(
171
+ **inputs,
172
+ max_new_tokens=192,
173
+ do_sample=False,
174
+ repetition_penalty=1.1,
175
+ eos_token_id=tokenizer.eos_token_id,
176
+ pad_token_id=tokenizer.eos_token_id,
177
+ use_cache=True,
178
+ )
179
+
180
+ new_tokens = output[0, inputs["input_ids"].shape[1]:]
181
+ print(tokenizer.decode(new_tokens, skip_special_tokens=True))
182
+ ```
183
+
184
+ For multi-turn chat, append the generated assistant response and the next user message to `messages`, then render the chat template again.
185
+
186
+ ## Suggested Generation Settings
187
+
188
+ - `do_sample=False`
189
+ - `repetition_penalty=1.1`
190
+ - `max_new_tokens=128` to `256`
191
+ - `use_cache=True`
192
+
193
+ Small models can hallucinate facts, fail arithmetic, produce invalid code, or enter repetitive continuations. Keep a finite generation limit and do not use the model for high-stakes decisions.
194
+
195
+ ## Repository Files
196
+
197
+ | File | Description |
198
+ |---|---|
199
+ | `config.json` | Transformers model configuration |
200
+ | `model.safetensors` | Fine-tuned model weights |
201
+ | `tokenizer.json` | Custom 8,192-token tokenizer |
202
+ | `tokenizer_config.json` | Tokenizer metadata |
203
+ | `chat_template.jinja` | System/user/assistant chat template |
204
+ | `generation_config.json` | Generation configuration |
205
+ | `configuration_bananamind2mini.py` | Custom Transformers config class |
206
+ | `modeling_bananamind2mini.py` | Custom Transformers model class |
207
+ | `sft_metadata.json` | Fine-tuning provenance and token counts |
208
+ | `banner.png` | Model-card banner |
209
+
210
+ ## Intended Use
211
+
212
+ This model is intended for compact-model research, local chat experiments, educational demonstrations, and instruction-tuning comparisons.
213
+
214
+ ## License
215
+
216
+ Apache 2.0
banner.png ADDED

Git LFS Details

  • SHA256: 0f6b4b66c81ff4eb9da3f2967886b4ae428f5b104c7ca1fe5f85f408b7413cc2
  • Pointer size: 132 Bytes
  • Size of remote file: 2.01 MB
chat_template.jinja ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {{ bos_token }}{% for message in messages %}{% if message['role'] == 'assistant' %}<|assistant|>
2
+ {{ message['content'] }}{{ eos_token }}
3
+ {% elif message['role'] == 'system' %}<|system|>
4
+ {{ message['content'] }}
5
+ {% elif message['role'] == 'user' %}<|user|>
6
+ {{ message['content'] }}
7
+ {% else %}<|{{ message['role'] }}|>
8
+ {{ message['content'] }}
9
+ {% endif %}{% endfor %}{% if add_generation_prompt %}<|assistant|>
10
+ {% endif %}
config.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "BananaMind2MiniForCausalLM"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_bananamind2mini.BananaMind2MiniConfig",
7
+ "AutoModelForCausalLM": "modeling_bananamind2mini.BananaMind2MiniForCausalLM"
8
+ },
9
+ "bos_token_id": 1,
10
+ "dtype": "float32",
11
+ "eos_token_id": 2,
12
+ "head_dim": 64,
13
+ "hidden_size": 384,
14
+ "intermediate_size": 1024,
15
+ "max_position_embeddings": 4096,
16
+ "model_type": "bananamind2_mini",
17
+ "num_attention_heads": 6,
18
+ "num_hidden_layers": 14,
19
+ "num_key_value_heads": 2,
20
+ "pad_token_id": 0,
21
+ "rms_norm_eps": 1e-06,
22
+ "rope_theta": 100000.0,
23
+ "tie_word_embeddings": true,
24
+ "transformers_version": "5.7.0",
25
+ "unk_token_id": 3,
26
+ "use_cache": true,
27
+ "vocab_size": 8192,
28
+ "z_loss_coeff": 0.0,
29
+ "_name_or_path": "BananaMind/BananaMind-2-Mini-Chat"
30
+ }
configuration_bananamind2mini.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """BananaMind 2 Mini configuration."""
2
+ from transformers import PretrainedConfig
3
+
4
+
5
+ class BananaMind2MiniConfig(PretrainedConfig):
6
+ model_type = "bananamind2_mini"
7
+
8
+ def __init__(
9
+ self,
10
+ vocab_size=8192,
11
+ hidden_size=384,
12
+ num_hidden_layers=14,
13
+ num_attention_heads=6,
14
+ num_key_value_heads=2,
15
+ head_dim=64,
16
+ intermediate_size=1024,
17
+ max_position_embeddings=4096,
18
+ rope_theta=100000.0,
19
+ rms_norm_eps=1e-6,
20
+ tie_word_embeddings=True,
21
+ use_cache=True,
22
+ z_loss_coeff=0.0,
23
+ bos_token_id=1,
24
+ eos_token_id=2,
25
+ pad_token_id=0,
26
+ unk_token_id=3,
27
+ **kwargs,
28
+ ):
29
+ self.vocab_size = vocab_size
30
+ self.hidden_size = hidden_size
31
+ self.num_hidden_layers = num_hidden_layers
32
+ self.num_attention_heads = num_attention_heads
33
+ self.num_key_value_heads = num_key_value_heads
34
+ self.head_dim = head_dim
35
+ self.intermediate_size = intermediate_size
36
+ self.max_position_embeddings = max_position_embeddings
37
+ self.rope_theta = rope_theta
38
+ self.rms_norm_eps = rms_norm_eps
39
+ self.use_cache = use_cache
40
+ self.z_loss_coeff = z_loss_coeff
41
+ super().__init__(
42
+ tie_word_embeddings=tie_word_embeddings,
43
+ bos_token_id=bos_token_id,
44
+ eos_token_id=eos_token_id,
45
+ pad_token_id=pad_token_id,
46
+ unk_token_id=unk_token_id,
47
+ **kwargs,
48
+ )
generation_config.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 1,
3
+ "eos_token_id": 2,
4
+ "max_length": 4096,
5
+ "pad_token_id": 0,
6
+ "transformers_version": "5.7.0",
7
+ "use_cache": true
8
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:eb4ad342c45820929ac72e5b778b2a1d7f7329ee57e51d63eaa012dfbd9d61ae
3
+ size 100731072
modeling_bananamind2mini.py ADDED
@@ -0,0 +1,310 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """BananaMind 2 Mini model implementation for Hugging Face Transformers."""
2
+ import math
3
+ from typing import Optional
4
+
5
+ import torch
6
+ import torch.nn as nn
7
+ import torch.nn.functional as F
8
+ from transformers import PreTrainedModel
9
+ from transformers.cache_utils import Cache, DynamicCache
10
+ from transformers.generation.utils import GenerationMixin
11
+ from transformers.modeling_outputs import CausalLMOutputWithPast
12
+
13
+ from .configuration_bananamind2mini import BananaMind2MiniConfig
14
+
15
+
16
+ class RMSNorm(nn.Module):
17
+ def __init__(self, dim, eps=1e-6):
18
+ super().__init__()
19
+ self.eps = eps
20
+ self.weight = nn.Parameter(torch.ones(dim))
21
+
22
+ def forward(self, x):
23
+ x_float = x.float()
24
+ rms = torch.rsqrt(x_float.pow(2).mean(-1, keepdim=True) + self.eps)
25
+ return (x_float * rms * self.weight.float()).type_as(x)
26
+
27
+
28
+ def build_rope_inv_freq(head_dim, theta=100000.0):
29
+ return 1.0 / (theta ** (torch.arange(0, head_dim, 2, dtype=torch.float32) / head_dim))
30
+
31
+
32
+ def precompute_freqs_cis(head_dim, seq_len, theta=100000.0):
33
+ freqs = build_rope_inv_freq(head_dim, theta)
34
+ t = torch.arange(seq_len, dtype=torch.float32)
35
+ freqs = torch.outer(t, freqs)
36
+ return torch.polar(torch.ones_like(freqs), freqs)
37
+
38
+
39
+ def apply_rotary_emb(q, k, freqs_cis):
40
+ q_complex = torch.view_as_complex(q.float().reshape(*q.shape[:-1], -1, 2))
41
+ k_complex = torch.view_as_complex(k.float().reshape(*k.shape[:-1], -1, 2))
42
+ freqs_cis = freqs_cis.unsqueeze(0).unsqueeze(0)
43
+ q_out = torch.view_as_real(q_complex * freqs_cis).flatten(-2)
44
+ k_out = torch.view_as_real(k_complex * freqs_cis).flatten(-2)
45
+ return q_out.type_as(q), k_out.type_as(k)
46
+
47
+
48
+ class BananaMind2MiniAttention(nn.Module):
49
+ def __init__(self, config, layer_idx):
50
+ super().__init__()
51
+ self.layer_idx = layer_idx
52
+ self.n_head = config.num_attention_heads
53
+ self.n_kv_heads = config.num_key_value_heads
54
+ self.head_dim = config.head_dim
55
+ self.n_rep = self.n_head // self.n_kv_heads
56
+
57
+ self.q_proj = nn.Linear(config.hidden_size, self.n_head * self.head_dim, bias=False)
58
+ self.k_proj = nn.Linear(config.hidden_size, self.n_kv_heads * self.head_dim, bias=False)
59
+ self.v_proj = nn.Linear(config.hidden_size, self.n_kv_heads * self.head_dim, bias=False)
60
+ self.o_proj = nn.Linear(self.n_head * self.head_dim, config.hidden_size, bias=False)
61
+ self.q_norm = RMSNorm(self.head_dim, eps=config.rms_norm_eps)
62
+ self.k_norm = RMSNorm(self.head_dim, eps=config.rms_norm_eps)
63
+
64
+ def forward(
65
+ self,
66
+ x,
67
+ freqs_cis,
68
+ attention_mask=None,
69
+ past_key_values=None,
70
+ use_cache=False,
71
+ ):
72
+ batch_size, seq_len, _ = x.shape
73
+ q = self.q_proj(x).view(
74
+ batch_size,
75
+ seq_len,
76
+ self.n_head,
77
+ self.head_dim,
78
+ ).transpose(1, 2)
79
+ k = self.k_proj(x).view(
80
+ batch_size,
81
+ seq_len,
82
+ self.n_kv_heads,
83
+ self.head_dim,
84
+ ).transpose(1, 2)
85
+ v = self.v_proj(x).view(
86
+ batch_size,
87
+ seq_len,
88
+ self.n_kv_heads,
89
+ self.head_dim,
90
+ ).transpose(1, 2)
91
+
92
+ q = self.q_norm(q)
93
+ k = self.k_norm(k)
94
+ q, k = apply_rotary_emb(q, k, freqs_cis)
95
+
96
+ past_length = 0
97
+ if use_cache and past_key_values is not None:
98
+ past_length = past_key_values.get_seq_length(self.layer_idx)
99
+ k, v = past_key_values.update(k, v, self.layer_idx)
100
+
101
+ kv_len = k.size(-2)
102
+ k = k.unsqueeze(2).expand(
103
+ batch_size,
104
+ self.n_kv_heads,
105
+ self.n_rep,
106
+ kv_len,
107
+ self.head_dim,
108
+ ).reshape(batch_size, self.n_head, kv_len, self.head_dim)
109
+ v = v.unsqueeze(2).expand(
110
+ batch_size,
111
+ self.n_kv_heads,
112
+ self.n_rep,
113
+ kv_len,
114
+ self.head_dim,
115
+ ).reshape(batch_size, self.n_head, kv_len, self.head_dim)
116
+
117
+ attn_mask = None
118
+ is_causal = past_length == 0 and attention_mask is None
119
+ if not is_causal:
120
+ query_positions = past_length + torch.arange(seq_len, device=x.device)
121
+ key_positions = torch.arange(kv_len, device=x.device)
122
+ causal = key_positions.unsqueeze(0) <= query_positions.unsqueeze(1)
123
+ attn_mask = causal[None, None, :, :]
124
+ if attention_mask is not None:
125
+ key_padding = attention_mask.to(torch.bool)
126
+ if key_padding.size(-1) < kv_len:
127
+ cached_padding = torch.ones(
128
+ key_padding.size(0),
129
+ kv_len - key_padding.size(-1),
130
+ dtype=torch.bool,
131
+ device=key_padding.device,
132
+ )
133
+ key_padding = torch.cat((cached_padding, key_padding), dim=-1)
134
+ else:
135
+ key_padding = key_padding[:, -kv_len:]
136
+ attn_mask = attn_mask & key_padding[:, None, None, :]
137
+ is_causal = False
138
+
139
+ y = F.scaled_dot_product_attention(
140
+ q,
141
+ k,
142
+ v,
143
+ attn_mask=attn_mask,
144
+ is_causal=is_causal,
145
+ )
146
+ y = y.transpose(1, 2).contiguous().view(
147
+ batch_size,
148
+ seq_len,
149
+ self.n_head * self.head_dim,
150
+ )
151
+ return self.o_proj(y)
152
+
153
+
154
+ class BananaMind2MiniSwiGLUMLP(nn.Module):
155
+ def __init__(self, config):
156
+ super().__init__()
157
+ self.w_gate = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
158
+ self.w_up = nn.Linear(config.hidden_size, config.intermediate_size, bias=False)
159
+ self.w_down = nn.Linear(config.intermediate_size, config.hidden_size, bias=False)
160
+
161
+ def forward(self, x):
162
+ return self.w_down(F.silu(self.w_gate(x)) * self.w_up(x))
163
+
164
+
165
+ class BananaMind2MiniBlock(nn.Module):
166
+ def __init__(self, config, layer_idx):
167
+ super().__init__()
168
+ self.ln_1 = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
169
+ self.attn = BananaMind2MiniAttention(config, layer_idx)
170
+ self.ln_2 = RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
171
+ self.mlp = BananaMind2MiniSwiGLUMLP(config)
172
+
173
+ def forward(
174
+ self,
175
+ x,
176
+ freqs_cis,
177
+ attention_mask=None,
178
+ past_key_values=None,
179
+ use_cache=False,
180
+ ):
181
+ x = x + self.attn(
182
+ self.ln_1(x),
183
+ freqs_cis,
184
+ attention_mask=attention_mask,
185
+ past_key_values=past_key_values,
186
+ use_cache=use_cache,
187
+ )
188
+ return x + self.mlp(self.ln_2(x))
189
+
190
+
191
+ class BananaMind2MiniPreTrainedModel(PreTrainedModel):
192
+ config_class = BananaMind2MiniConfig
193
+ base_model_prefix = "transformer"
194
+ supports_gradient_checkpointing = False
195
+
196
+ def _init_weights(self, module):
197
+ std = 0.02
198
+ if hasattr(module, "NANOGPT_SCALE_INIT"):
199
+ std *= 2 * self.config.num_hidden_layers ** -0.5
200
+ if isinstance(module, nn.Linear):
201
+ torch.nn.init.normal_(module.weight, mean=0.0, std=std)
202
+ elif isinstance(module, nn.Embedding):
203
+ torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)
204
+
205
+
206
+ class BananaMind2MiniForCausalLM(BananaMind2MiniPreTrainedModel, GenerationMixin):
207
+ _tied_weights_keys = {"lm_head.weight": "transformer.wte.weight"}
208
+
209
+ def __init__(self, config):
210
+ super().__init__(config)
211
+ self.config = config
212
+ self.transformer = nn.ModuleDict(
213
+ {
214
+ "wte": nn.Embedding(config.vocab_size, config.hidden_size),
215
+ "h": nn.ModuleList(
216
+ [
217
+ BananaMind2MiniBlock(config, layer_idx)
218
+ for layer_idx in range(config.num_hidden_layers)
219
+ ]
220
+ ),
221
+ "ln_f": RMSNorm(config.hidden_size, eps=config.rms_norm_eps),
222
+ }
223
+ )
224
+ self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
225
+ if config.tie_word_embeddings:
226
+ self.lm_head.weight = self.transformer["wte"].weight
227
+ self._embd_scale = math.sqrt(config.hidden_size)
228
+ self._freqs_cis_cache = None
229
+ self.post_init()
230
+
231
+ def get_input_embeddings(self):
232
+ return self.transformer["wte"]
233
+
234
+ def set_input_embeddings(self, value):
235
+ self.transformer["wte"] = value
236
+
237
+ def get_output_embeddings(self):
238
+ return self.lm_head
239
+
240
+ def set_output_embeddings(self, new_embeddings):
241
+ self.lm_head = new_embeddings
242
+
243
+ def _get_freqs_cis(self, seq_len, device):
244
+ cache = self._freqs_cis_cache
245
+ if cache is None or cache.device != device or cache.size(0) < seq_len:
246
+ # Keep the reusable RoPE table as a normal tensor even if its first
247
+ # construction happens inside torch.inference_mode().
248
+ with torch.inference_mode(False):
249
+ cache = precompute_freqs_cis(
250
+ self.config.head_dim,
251
+ seq_len,
252
+ self.config.rope_theta,
253
+ ).to(device)
254
+ self._freqs_cis_cache = cache
255
+ return cache[:seq_len]
256
+
257
+ def forward(
258
+ self,
259
+ input_ids,
260
+ attention_mask=None,
261
+ labels=None,
262
+ past_key_values: Optional[Cache] = None,
263
+ use_cache=None,
264
+ **kwargs,
265
+ ):
266
+ _, seq_len = input_ids.shape
267
+ if use_cache is None:
268
+ use_cache = self.config.use_cache and labels is None
269
+ if use_cache and past_key_values is None:
270
+ past_key_values = DynamicCache(config=self.config)
271
+
272
+ past_length = past_key_values.get_seq_length() if use_cache else 0
273
+ total_length = past_length + seq_len
274
+ if total_length > self.config.max_position_embeddings:
275
+ raise ValueError(
276
+ f"Sequence length {total_length} exceeds the configured maximum "
277
+ f"of {self.config.max_position_embeddings}"
278
+ )
279
+
280
+ x = self.transformer["wte"](input_ids) * self._embd_scale
281
+ freqs_cis = self._get_freqs_cis(total_length, input_ids.device)[past_length:]
282
+
283
+ for block in self.transformer["h"]:
284
+ x = block(
285
+ x,
286
+ freqs_cis,
287
+ attention_mask=attention_mask,
288
+ past_key_values=past_key_values,
289
+ use_cache=use_cache,
290
+ )
291
+
292
+ x = self.transformer["ln_f"](x)
293
+ logits = self.lm_head(x)
294
+
295
+ loss = None
296
+ if labels is not None:
297
+ shift_logits = logits[..., :-1, :].contiguous()
298
+ shift_labels = labels[..., 1:].contiguous()
299
+ loss = F.cross_entropy(
300
+ shift_logits.float().reshape(-1, shift_logits.size(-1)),
301
+ shift_labels.reshape(-1),
302
+ )
303
+ if self.config.z_loss_coeff:
304
+ loss = loss + self.config.z_loss_coeff * logits.float().pow(2).mean()
305
+
306
+ return CausalLMOutputWithPast(
307
+ loss=loss,
308
+ logits=logits,
309
+ past_key_values=past_key_values if use_cache else None,
310
+ )
sft_metadata.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "base_model": "BananaMind-2-Mini",
3
+ "dataset": "HuggingFaceTB/smol-smoltalk",
4
+ "dataset_config": "default",
5
+ "dataset_split": "train",
6
+ "training_type": "full_parameter_supervised_finetuning",
7
+ "loss_mask": "assistant_content_and_eos_only",
8
+ "global_step": 3193,
9
+ "tokens_seen": 470782108,
10
+ "supervised_tokens_seen": 360967001,
11
+ "repo_id": "BananaMind/BananaMind-2-Mini-Chat"
12
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|bos|>",
4
+ "eos_token": "<|eos|>",
5
+ "is_local": true,
6
+ "local_files_only": true,
7
+ "model_max_length": 4096,
8
+ "pad_token": "<|pad|>",
9
+ "tokenizer_class": "TokenizersBackend",
10
+ "unk_token": "<|unk|>"
11
+ }