ereniko commited on
Commit
5974fd0
·
verified ·
1 Parent(s): 7651d63

Add safetensors + Transformers (AutoModelForCausalLM) support

Browse files
NEW_FILES.md ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Transformers / safetensors support
2
+
3
+ This model can now be loaded with `AutoModelForCausalLM` instead of the
4
+ manual pickle-loading workflow, and weights are available as
5
+ `model.safetensors`.
6
+
7
+ ```python
8
+ import torch
9
+ from transformers import AutoModelForCausalLM, AutoTokenizer
10
+
11
+ model = AutoModelForCausalLM.from_pretrained(
12
+ "IvmeLabs/Ivme-Conversate-v2-Base", trust_remote_code=True, dtype=torch.float32,
13
+ )
14
+ tokenizer = AutoTokenizer.from_pretrained("IvmeLabs/Ivme-Conversate-v2-Base", trust_remote_code=True)
15
+ model.eval()
16
+
17
+ inputs = tokenizer("Once upon a time, there was a", return_tensors="pt")
18
+ out = model.generate(
19
+ **inputs, max_new_tokens=200, do_sample=True,
20
+ temperature=0.8, top_k=50, pad_token_id=tokenizer.pad_token_id,
21
+ )
22
+ print(tokenizer.decode(out[0], skip_special_tokens=True))
23
+ ```
24
+
25
+ `trust_remote_code=True` is required (custom architecture: RoPE + SwiGLU +
26
+ RMSNorm dense decoder). The original `ckpt_final.pt` pickle checkpoint and
27
+ `model/` architecture source remain in this repo unchanged for backwards
28
+ compatibility.
29
+
30
+ **Note on batch generation:** use left-padding
31
+ (`tokenizer.padding_side = "left"`) — the model doesn't use an explicit
32
+ attention mask over padded positions, so right-padding within a batch will
33
+ give incorrect results.
config.json ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "IvmeForCausalLM"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_ivme.IvmeConfig",
7
+ "AutoModelForCausalLM": "modeling_ivme.IvmeForCausalLM"
8
+ },
9
+ "context_len": 1024,
10
+ "dropout": 0.0,
11
+ "dtype": "float32",
12
+ "ffn_mult": 4.0,
13
+ "hidden_dim": 384,
14
+ "hidden_size": 384,
15
+ "max_position_embeddings": 1024,
16
+ "model_type": "ivme",
17
+ "n_heads": 6,
18
+ "n_layers": 10,
19
+ "norm_eps": 1e-05,
20
+ "num_attention_heads": 6,
21
+ "num_hidden_layers": 10,
22
+ "rope_theta": 10000.0,
23
+ "tie_word_embeddings": true,
24
+ "transformers_version": "5.13.1",
25
+ "vocab_size": 16000
26
+ }
configuration_ivme.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HuggingFace Transformers config for Ivme-Conversate-v2."""
2
+
3
+ from transformers import PretrainedConfig
4
+
5
+
6
+ class IvmeConfig(PretrainedConfig):
7
+ model_type = "ivme"
8
+
9
+ def __init__(
10
+ self,
11
+ vocab_size: int = 16_000,
12
+ hidden_dim: int = 384,
13
+ n_layers: int = 10,
14
+ n_heads: int = 6,
15
+ context_len: int = 1024,
16
+ ffn_mult: float = 4.0,
17
+ rope_theta: float = 10_000.0,
18
+ norm_eps: float = 1e-5,
19
+ tie_embeddings: bool = True,
20
+ dropout: float = 0.0,
21
+ **kwargs,
22
+ ):
23
+ self.vocab_size = vocab_size
24
+ self.hidden_dim = hidden_dim
25
+ self.n_layers = n_layers
26
+ self.n_heads = n_heads
27
+ self.context_len = context_len
28
+ self.ffn_mult = ffn_mult
29
+ self.rope_theta = rope_theta
30
+ self.norm_eps = norm_eps
31
+ self.dropout = dropout
32
+
33
+ assert hidden_dim % n_heads == 0, "hidden_dim must be divisible by n_heads"
34
+
35
+ self.max_position_embeddings = context_len
36
+ self.num_hidden_layers = n_layers
37
+ self.num_attention_heads = n_heads
38
+ self.hidden_size = hidden_dim
39
+
40
+ kwargs.setdefault("tie_word_embeddings", tie_embeddings)
41
+ super().__init__(**kwargs)
42
+
43
+ @property
44
+ def head_dim(self) -> int:
45
+ return self.hidden_dim // self.n_heads
generation_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token_id": 0,
3
+ "eos_token_id": 0,
4
+ "pad_token_id": 1,
5
+ "do_sample": true,
6
+ "temperature": 0.8,
7
+ "top_k": 50,
8
+ "max_new_tokens": 200
9
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:30faf39956673139dc2321a95624c14bc1345ec62f685b71366802dcd4c677f3
3
+ size 119972856
modeling_ivme.py ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """HuggingFace Transformers model for Ivme-Conversate-v2.
2
+
3
+ Reimplements the original IvmeConversateV2 architecture as a PreTrainedModel
4
+ so it works with AutoModelForCausalLM, .generate(), and safetensors. Math
5
+ (RMSNorm, RoPE, SwiGLU, tied embeddings, full causal attention) is unchanged
6
+ from the original; adds an optional KV cache for efficient generation.
7
+ """
8
+
9
+ from typing import Optional
10
+
11
+ import torch
12
+ import torch.nn as nn
13
+ import torch.nn.functional as F
14
+ from transformers import PreTrainedModel, GenerationMixin
15
+ from transformers.modeling_outputs import CausalLMOutputWithPast
16
+ from transformers.cache_utils import Cache, DynamicCache
17
+
18
+ from .configuration_ivme import IvmeConfig
19
+
20
+
21
+ class IvmeRMSNorm(nn.Module):
22
+ def __init__(self, dim: int, eps: float = 1e-5):
23
+ super().__init__()
24
+ self.eps = eps
25
+ self.weight = nn.Parameter(torch.ones(dim))
26
+
27
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
28
+ dtype = x.dtype
29
+ x = x.float()
30
+ rms = torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps)
31
+ out = x * rms
32
+ return (out.to(dtype)) * self.weight
33
+
34
+
35
+ def _precompute_rope_freqs(head_dim: int, max_seq_len: int, theta: float, device=None):
36
+ assert head_dim % 2 == 0, "RoPE requires an even head_dim"
37
+ freqs = 1.0 / (theta ** (torch.arange(0, head_dim, 2, device=device).float() / head_dim))
38
+ positions = torch.arange(max_seq_len, device=device).float()
39
+ angles = torch.outer(positions, freqs)
40
+ return torch.polar(torch.ones_like(angles), angles)
41
+
42
+
43
+ def _apply_rope(x: torch.Tensor, rope_freqs: torch.Tensor) -> torch.Tensor:
44
+ B, H, T, D = x.shape
45
+ x_complex = torch.view_as_complex(x.float().reshape(B, H, T, D // 2, 2))
46
+ freqs = rope_freqs.view(1, 1, T, D // 2)
47
+ x_rotated = x_complex * freqs
48
+ out = torch.view_as_real(x_rotated).reshape(B, H, T, D)
49
+ return out.type_as(x)
50
+
51
+
52
+ class IvmeSelfAttention(nn.Module):
53
+ def __init__(self, config: IvmeConfig, layer_idx: int):
54
+ super().__init__()
55
+ self.layer_idx = layer_idx
56
+ hidden_dim = config.hidden_dim
57
+ self.n_heads = config.n_heads
58
+ self.head_dim = hidden_dim // config.n_heads
59
+ self.dropout = config.dropout
60
+
61
+ self.q_proj = nn.Linear(hidden_dim, hidden_dim, bias=False)
62
+ self.k_proj = nn.Linear(hidden_dim, hidden_dim, bias=False)
63
+ self.v_proj = nn.Linear(hidden_dim, hidden_dim, bias=False)
64
+ self.out_proj = nn.Linear(hidden_dim, hidden_dim, bias=False)
65
+
66
+ def forward(self, x, rope_freqs, past_key_value=None):
67
+ B, T, C = x.shape
68
+
69
+ q = self.q_proj(x).view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
70
+ k = self.k_proj(x).view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
71
+ v = self.v_proj(x).view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
72
+
73
+ q = _apply_rope(q, rope_freqs)
74
+ k = _apply_rope(k, rope_freqs)
75
+
76
+ if past_key_value is not None:
77
+ k, v = past_key_value.update(k, v, self.layer_idx)
78
+
79
+ is_causal = past_key_value is None or k.shape[2] == q.shape[2]
80
+
81
+ out = F.scaled_dot_product_attention(
82
+ q, k, v, is_causal=is_causal,
83
+ dropout_p=self.dropout if self.training else 0.0,
84
+ )
85
+ out = out.transpose(1, 2).contiguous().view(B, T, C)
86
+ return self.out_proj(out)
87
+
88
+
89
+ class IvmeSwiGLU(nn.Module):
90
+ def __init__(self, config: IvmeConfig):
91
+ super().__init__()
92
+ hidden_dim = config.hidden_dim
93
+ inner_dim = int(hidden_dim * config.ffn_mult * 2 / 3)
94
+ inner_dim = ((inner_dim + 7) // 8) * 8
95
+ self.gate_proj = nn.Linear(hidden_dim, inner_dim, bias=False)
96
+ self.up_proj = nn.Linear(hidden_dim, inner_dim, bias=False)
97
+ self.down_proj = nn.Linear(inner_dim, hidden_dim, bias=False)
98
+
99
+ def forward(self, x):
100
+ return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
101
+
102
+
103
+ class IvmeBlock(nn.Module):
104
+ def __init__(self, config: IvmeConfig, layer_idx: int):
105
+ super().__init__()
106
+ self.attn_norm = IvmeRMSNorm(config.hidden_dim, eps=config.norm_eps)
107
+ self.attn = IvmeSelfAttention(config, layer_idx)
108
+ self.ffn_norm = IvmeRMSNorm(config.hidden_dim, eps=config.norm_eps)
109
+ self.ffn = IvmeSwiGLU(config)
110
+
111
+ def forward(self, x, rope_freqs, past_key_value=None):
112
+ x = x + self.attn(self.attn_norm(x), rope_freqs, past_key_value=past_key_value)
113
+ x = x + self.ffn(self.ffn_norm(x))
114
+ return x
115
+
116
+
117
+ class IvmePreTrainedModel(PreTrainedModel):
118
+ config_class = IvmeConfig
119
+ base_model_prefix = "model"
120
+ supports_gradient_checkpointing = False
121
+ _no_split_modules = ["IvmeBlock"]
122
+ _supports_cache_class = True
123
+ _supports_sdpa = True
124
+
125
+ def _init_weights(self, module):
126
+ if isinstance(module, nn.Linear):
127
+ nn.init.normal_(module.weight, mean=0.0, std=0.02)
128
+ if module.bias is not None:
129
+ nn.init.zeros_(module.bias)
130
+ elif isinstance(module, nn.Embedding):
131
+ nn.init.normal_(module.weight, mean=0.0, std=0.02)
132
+
133
+
134
+ class IvmeModel(IvmePreTrainedModel):
135
+ def __init__(self, config: IvmeConfig):
136
+ super().__init__(config)
137
+ self.tok_embed = nn.Embedding(config.vocab_size, config.hidden_dim)
138
+ self.blocks = nn.ModuleList(
139
+ [IvmeBlock(config, layer_idx=i) for i in range(config.n_layers)]
140
+ )
141
+ self.final_norm = IvmeRMSNorm(config.hidden_dim, eps=config.norm_eps)
142
+ self.post_init()
143
+
144
+ def get_input_embeddings(self):
145
+ return self.tok_embed
146
+
147
+ def set_input_embeddings(self, value):
148
+ self.tok_embed = value
149
+
150
+ def forward(self, input_ids, past_key_values=None, use_cache=False, **kwargs):
151
+ B, T = input_ids.shape
152
+
153
+ past_len = 0
154
+ if past_key_values is not None and len(past_key_values) > 0:
155
+ past_len = past_key_values.get_seq_length()
156
+
157
+ if past_len + T > self.config.context_len:
158
+ raise ValueError(
159
+ f"sequence length {past_len + T} exceeds context_len {self.config.context_len}"
160
+ )
161
+
162
+ full_rope_freqs = _precompute_rope_freqs(
163
+ self.config.head_dim, self.config.context_len, self.config.rope_theta,
164
+ device=input_ids.device,
165
+ )
166
+ rope_freqs = full_rope_freqs[past_len: past_len + T]
167
+
168
+ x = self.tok_embed(input_ids)
169
+ for block in self.blocks:
170
+ x = block(x, rope_freqs, past_key_value=past_key_values)
171
+ x = self.final_norm(x)
172
+ return x
173
+
174
+
175
+ class IvmeForCausalLM(IvmePreTrainedModel, GenerationMixin):
176
+ _tied_weights_keys = {"lm_head.weight": "model.tok_embed.weight"}
177
+
178
+ def __init__(self, config: IvmeConfig):
179
+ super().__init__(config)
180
+ self.model = IvmeModel(config)
181
+ self.lm_head = nn.Linear(config.hidden_dim, config.vocab_size, bias=False)
182
+ self.post_init()
183
+ if config.tie_word_embeddings:
184
+ self.tie_weights()
185
+
186
+ def get_input_embeddings(self):
187
+ return self.model.tok_embed
188
+
189
+ def set_input_embeddings(self, value):
190
+ self.model.tok_embed = value
191
+
192
+ def get_output_embeddings(self):
193
+ return self.lm_head
194
+
195
+ def set_output_embeddings(self, new_embeddings):
196
+ self.lm_head = new_embeddings
197
+
198
+ def forward(
199
+ self, input_ids, attention_mask=None, past_key_values=None,
200
+ labels=None, use_cache=None, return_dict=True, **kwargs,
201
+ ):
202
+ if use_cache and past_key_values is None:
203
+ past_key_values = DynamicCache()
204
+
205
+ hidden_states = self.model(
206
+ input_ids,
207
+ past_key_values=past_key_values if use_cache else None,
208
+ use_cache=use_cache,
209
+ )
210
+ logits = self.lm_head(hidden_states)
211
+
212
+ loss = None
213
+ if labels is not None:
214
+ shift_logits = logits[..., :-1, :].contiguous()
215
+ shift_labels = labels[..., 1:].contiguous()
216
+ loss = F.cross_entropy(
217
+ shift_logits.view(-1, shift_logits.size(-1)),
218
+ shift_labels.view(-1),
219
+ ignore_index=-100,
220
+ )
221
+
222
+ return CausalLMOutputWithPast(
223
+ loss=loss,
224
+ logits=logits,
225
+ past_key_values=past_key_values if use_cache else None,
226
+ )
227
+
228
+
229
+ __all__ = ["IvmeConfig", "IvmeModel", "IvmeForCausalLM"]
tokenizer_config.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "bos_token": "<|endoftext|>",
4
+ "eos_token": "<|endoftext|>",
5
+ "model_max_length": 1000000000000000019884624838656,
6
+ "pad_token": "<|pad|>",
7
+ "tokenizer_class": "TokenizersBackend",
8
+ "unk_token": "<|unk|>"
9
+ }