daichi812 commited on
Commit
6a0cf5a
·
verified ·
1 Parent(s): 5241395

final model (main)

Browse files
config.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "LoopedForCausalLM"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_babyloop.BabyloopConfig",
7
+ "AutoModelForCausalLM": "modeling_babyloop.LoopedForCausalLM"
8
+ },
9
+ "bias": false,
10
+ "bos_token_id": 1,
11
+ "d_model": 768,
12
+ "dropout": 0.0,
13
+ "eos_token_id": 2,
14
+ "ffn_hidden": 2048,
15
+ "fusion": null,
16
+ "hidden_size": 768,
17
+ "inject_input": true,
18
+ "k": 4,
19
+ "max_position_embeddings": 512,
20
+ "max_seq_len": 512,
21
+ "model_type": "babyloop",
22
+ "n_coda": 0,
23
+ "n_core": 12,
24
+ "n_heads": 12,
25
+ "n_layers": 12,
26
+ "n_prelude": 0,
27
+ "num_attention_heads": 12,
28
+ "num_hidden_layers": 12,
29
+ "pad_token_id": 0,
30
+ "rms_eps": 1e-05,
31
+ "rope_base": 10000.0,
32
+ "tie_embeddings": true,
33
+ "torch_dtype": "float32",
34
+ "transformers_version": "4.51.3",
35
+ "vocab_size": 16000
36
+ }
configuration_babyloop.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """BabyloopConfig — HF ``PretrainedConfig`` 互換のモデル設定。
2
+
3
+ このファイルは ``save_pretrained`` 時に checkpoint ディレクトリへ複製され、
4
+ 公式 evaluation-pipeline 側(別プロセス)から ``trust_remote_code=True`` で
5
+ import される。そのため **transformers と標準ライブラリ以外に依存しない**
6
+ (``babyloop`` パッケージ内部を import しない)こと。
7
+
8
+ フィールドと configs/model/*.yaml の対応は docs/architecture.md §6 を参照。
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from transformers import PretrainedConfig
14
+
15
+
16
+ class BabyloopConfig(PretrainedConfig):
17
+ """ループドTransformer(K=1で標準に縮退)の設定。
18
+
19
+ 軸A(標準 vs 再帰)は ``k`` のみで切り替える単一実装。視覚(②④)の口も
20
+ 持つが、テキストのみ(①③)では ``fusion=None`` で無効。
21
+ """
22
+
23
+ model_type = "babyloop"
24
+
25
+ def __init__(
26
+ self,
27
+ d_model: int = 768,
28
+ n_layers: int = 12,
29
+ n_heads: int = 12,
30
+ ffn_hidden: int = 2048,
31
+ n_prelude: int = 0,
32
+ n_core: int = 12,
33
+ n_coda: int = 0,
34
+ k: int = 1,
35
+ inject_input: bool = False,
36
+ vocab_size: int = 16000,
37
+ max_seq_len: int = 512,
38
+ rope_base: float = 10000.0,
39
+ rms_eps: float = 1e-5,
40
+ tie_embeddings: bool = True,
41
+ bias: bool = False,
42
+ dropout: float = 0.0,
43
+ fusion: str | None = None,
44
+ pad_token_id: int | None = None,
45
+ bos_token_id: int | None = None,
46
+ eos_token_id: int | None = None,
47
+ **kwargs,
48
+ ):
49
+ self.d_model = d_model
50
+ self.n_layers = n_layers
51
+ self.n_heads = n_heads
52
+ self.ffn_hidden = ffn_hidden
53
+ self.n_prelude = n_prelude
54
+ self.n_core = n_core
55
+ self.n_coda = n_coda
56
+ self.k = k
57
+ self.inject_input = inject_input
58
+ self.vocab_size = vocab_size
59
+ self.max_seq_len = max_seq_len
60
+ self.rope_base = rope_base
61
+ self.rms_eps = rms_eps
62
+ self.tie_embeddings = tie_embeddings
63
+ self.bias = bias
64
+ self.dropout = dropout
65
+ self.fusion = fusion
66
+
67
+ # HF 汎用ユーティリティが参照するエイリアス。
68
+ self.hidden_size = d_model
69
+ self.num_attention_heads = n_heads
70
+ self.num_hidden_layers = n_layers
71
+ self.max_position_embeddings = max_seq_len
72
+
73
+ super().__init__(
74
+ pad_token_id=pad_token_id,
75
+ bos_token_id=bos_token_id,
76
+ eos_token_id=eos_token_id,
77
+ tie_word_embeddings=tie_embeddings,
78
+ **kwargs,
79
+ )
80
+
81
+ @property
82
+ def head_dim(self) -> int:
83
+ return self.d_model // self.n_heads
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e01d999d493ddf35b6090074ec6b77a3e0fccb455726d2f7e84be83431145ae9
3
+ size 388976400
modeling_babyloop.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ループドTransformer本体(HF ``PreTrainedModel`` 互換・単一実装)。
2
+
3
+ 設計 docs/architecture.md §2 の Llama 系レシピ(RMSNorm / RoPE / SwiGLU /
4
+ bias なし / weight tying)を素の PyTorch で実装。``forward`` は K 回ループする
5
+ 形で書き、``k=1`` で標準Transformerに厳密に縮退する(``tests/test_k1_equivalence.py``)。
6
+
7
+ このファイルは ``save_pretrained`` 時に checkpoint へ複製され、公式
8
+ evaluation-pipeline(別プロセス・``trust_remote_code=True``)から import される。
9
+ そのため **torch / transformers / 標準ライブラリ以外に依存しない**こと。
10
+ probing 用のループ毎中間表現は HF 標準 ``hidden_states``(層ごと)と混ぜず、
11
+ 別フィールド ``loop_hidden_states`` に格納する。
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import math
17
+ from dataclasses import dataclass
18
+
19
+ import torch
20
+ import torch.nn.functional as F
21
+ from torch import nn
22
+ from transformers.modeling_outputs import ModelOutput
23
+ from transformers.modeling_utils import PreTrainedModel
24
+
25
+ from .configuration_babyloop import BabyloopConfig
26
+
27
+
28
+ # --- ビルディングブロック(Llama系レシピ)---------------------------------
29
+
30
+
31
+ class RMSNorm(nn.Module):
32
+ def __init__(self, dim: int, eps: float):
33
+ super().__init__()
34
+ self.eps = eps
35
+ self.weight = nn.Parameter(torch.ones(dim))
36
+
37
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
38
+ dtype = x.dtype
39
+ x = x.float()
40
+ x = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
41
+ return (x.to(dtype)) * self.weight
42
+
43
+
44
+ def _rotate_half(x: torch.Tensor) -> torch.Tensor:
45
+ x1, x2 = x.chunk(2, dim=-1)
46
+ return torch.cat((-x2, x1), dim=-1)
47
+
48
+
49
+ def _apply_rope(x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
50
+ # x: (B, H, T, head_dim); cos/sin: (1, 1, T, head_dim)
51
+ return x * cos + _rotate_half(x) * sin
52
+
53
+
54
+ class Attention(nn.Module):
55
+ """RoPE 付き causal Multi-Head Attention(dropout なし)。"""
56
+
57
+ def __init__(self, config: BabyloopConfig):
58
+ super().__init__()
59
+ self.n_heads = config.n_heads
60
+ self.head_dim = config.d_model // config.n_heads
61
+ self.qkv_proj = nn.Linear(config.d_model, 3 * config.d_model, bias=config.bias)
62
+ self.o_proj = nn.Linear(config.d_model, config.d_model, bias=config.bias)
63
+
64
+ def forward(self, x, cos, sin, attn_bias):
65
+ B, T, C = x.shape
66
+ q, k, v = self.qkv_proj(x).split(C, dim=-1)
67
+ q = q.view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
68
+ k = k.view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
69
+ v = v.view(B, T, self.n_heads, self.head_dim).transpose(1, 2)
70
+ q = _apply_rope(q, cos, sin)
71
+ k = _apply_rope(k, cos, sin)
72
+ out = F.scaled_dot_product_attention(
73
+ q, k, v, attn_mask=attn_bias, is_causal=attn_bias is None
74
+ )
75
+ out = out.transpose(1, 2).reshape(B, T, C)
76
+ return self.o_proj(out)
77
+
78
+
79
+ class SwiGLU(nn.Module):
80
+ def __init__(self, config: BabyloopConfig):
81
+ super().__init__()
82
+ self.gate_proj = nn.Linear(config.d_model, config.ffn_hidden, bias=config.bias)
83
+ self.up_proj = nn.Linear(config.d_model, config.ffn_hidden, bias=config.bias)
84
+ self.down_proj = nn.Linear(config.ffn_hidden, config.d_model, bias=config.bias)
85
+
86
+ def forward(self, x):
87
+ return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
88
+
89
+
90
+ class Block(nn.Module):
91
+ """Pre-Norm 残差ブロック: h += Attn(RMSNorm(h)); h += SwiGLU(RMSNorm(h))。"""
92
+
93
+ def __init__(self, config: BabyloopConfig):
94
+ super().__init__()
95
+ self.attn_norm = RMSNorm(config.d_model, config.rms_eps)
96
+ self.attn = Attention(config)
97
+ self.mlp_norm = RMSNorm(config.d_model, config.rms_eps)
98
+ self.mlp = SwiGLU(config)
99
+
100
+ def forward(self, h, cos, sin, attn_bias):
101
+ h = h + self.attn(self.attn_norm(h), cos, sin, attn_bias)
102
+ h = h + self.mlp(self.mlp_norm(h))
103
+ return h
104
+
105
+
106
+ # --- 出力コンテナ -----------------------------------------------------------
107
+
108
+
109
+ @dataclass
110
+ class LoopedModelOutput(ModelOutput):
111
+ last_hidden_state: torch.FloatTensor | None = None
112
+ hidden_states: tuple[torch.FloatTensor, ...] | None = None
113
+ loop_hidden_states: tuple[torch.FloatTensor, ...] | None = None
114
+
115
+
116
+ @dataclass
117
+ class LoopedCausalLMOutput(ModelOutput):
118
+ loss: torch.FloatTensor | None = None
119
+ logits: torch.FloatTensor | None = None
120
+ hidden_states: tuple[torch.FloatTensor, ...] | None = None
121
+ loop_hidden_states: tuple[torch.FloatTensor, ...] | None = None
122
+
123
+
124
+ # --- PreTrainedModel ラッパ -------------------------------------------------
125
+
126
+
127
+ class LoopedPreTrainedModel(PreTrainedModel):
128
+ config_class = BabyloopConfig
129
+ base_model_prefix = "model"
130
+ supports_gradient_checkpointing = False
131
+
132
+ def _init_weights(self, module):
133
+ std = 0.02
134
+ if isinstance(module, nn.Linear):
135
+ nn.init.normal_(module.weight, mean=0.0, std=std)
136
+ if module.bias is not None:
137
+ nn.init.zeros_(module.bias)
138
+ elif isinstance(module, nn.Embedding):
139
+ nn.init.normal_(module.weight, mean=0.0, std=std)
140
+ elif isinstance(module, RMSNorm):
141
+ nn.init.ones_(module.weight)
142
+
143
+
144
+ class LoopedModel(LoopedPreTrainedModel):
145
+ """重み共有 core ブロックを K 回反復するバックボーン(lm_head なし)。"""
146
+
147
+ def __init__(self, config: BabyloopConfig):
148
+ super().__init__(config)
149
+ self.config = config
150
+ self.embed_tokens = nn.Embedding(config.vocab_size, config.d_model)
151
+ self.prelude = nn.ModuleList(Block(config) for _ in range(config.n_prelude))
152
+ self.core = nn.ModuleList(Block(config) for _ in range(config.n_core))
153
+ self.coda = nn.ModuleList(Block(config) for _ in range(config.n_coda))
154
+ self.final_norm = RMSNorm(config.d_model, config.rms_eps)
155
+
156
+ head_dim = config.d_model // config.n_heads
157
+ inv_freq = 1.0 / (
158
+ config.rope_base ** (torch.arange(0, head_dim, 2, dtype=torch.float32) / head_dim)
159
+ )
160
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
161
+ self.post_init()
162
+
163
+ def get_input_embeddings(self):
164
+ return self.embed_tokens
165
+
166
+ def set_input_embeddings(self, value):
167
+ self.embed_tokens = value
168
+
169
+ def _rope(self, T: int, device, dtype):
170
+ t = torch.arange(T, device=device, dtype=torch.float32)
171
+ freqs = torch.outer(t, self.inv_freq.to(device))
172
+ emb = torch.cat((freqs, freqs), dim=-1)
173
+ return emb.cos().to(dtype)[None, None], emb.sin().to(dtype)[None, None]
174
+
175
+ def _attn_bias(self, attention_mask, T, device, dtype):
176
+ # padding が無ければ None を返し、SDPA の is_causal 経路(高速)に乗せる。
177
+ if attention_mask is None or bool((attention_mask == 1).all()):
178
+ return None
179
+ causal = torch.ones(T, T, device=device, dtype=torch.bool).triu(1)
180
+ key_pad = attention_mask.to(device) == 0 # (B, T)
181
+ mask = causal[None, None] | key_pad[:, None, None, :]
182
+ bias = torch.zeros(mask.shape, device=device, dtype=dtype)
183
+ return bias.masked_fill(mask, torch.finfo(dtype).min)
184
+
185
+ def forward(
186
+ self,
187
+ input_ids=None,
188
+ attention_mask=None,
189
+ inputs_embeds=None,
190
+ output_hidden_states=False,
191
+ **kwargs,
192
+ ) -> LoopedModelOutput:
193
+ if inputs_embeds is None:
194
+ inputs_embeds = self.embed_tokens(input_ids)
195
+ h = inputs_embeds
196
+ residual_input = inputs_embeds # inject_input 用(③で本格化、①は false)
197
+ B, T, _ = h.shape
198
+ cos, sin = self._rope(T, h.device, h.dtype)
199
+ attn_bias = self._attn_bias(attention_mask, T, h.device, h.dtype)
200
+
201
+ all_hidden = [h] if output_hidden_states else None
202
+ loop_hidden = []
203
+
204
+ for block in self.prelude:
205
+ h = block(h, cos, sin, attn_bias)
206
+ if output_hidden_states:
207
+ all_hidden.append(h)
208
+ for _ in range(self.config.k):
209
+ for block in self.core:
210
+ h = block(h, cos, sin, attn_bias)
211
+ if output_hidden_states:
212
+ all_hidden.append(h)
213
+ if self.config.inject_input:
214
+ h = h + residual_input
215
+ loop_hidden.append(h)
216
+ for block in self.coda:
217
+ h = block(h, cos, sin, attn_bias)
218
+ if output_hidden_states:
219
+ all_hidden.append(h)
220
+
221
+ h = self.final_norm(h)
222
+ return LoopedModelOutput(
223
+ last_hidden_state=h,
224
+ hidden_states=tuple(all_hidden) if output_hidden_states else None,
225
+ loop_hidden_states=tuple(loop_hidden),
226
+ )
227
+
228
+
229
+ class LoopedForCausalLM(LoopedPreTrainedModel):
230
+ """言語モデリングヘッド付き(``AutoModelForCausalLM`` 互換)。"""
231
+
232
+ _tied_weights_keys = ["lm_head.weight"]
233
+
234
+ def __init__(self, config: BabyloopConfig):
235
+ super().__init__(config)
236
+ self.model = LoopedModel(config)
237
+ self.lm_head = nn.Linear(config.d_model, config.vocab_size, bias=False)
238
+ self.post_init()
239
+
240
+ def get_input_embeddings(self):
241
+ return self.model.embed_tokens
242
+
243
+ def set_input_embeddings(self, value):
244
+ self.model.embed_tokens = value
245
+
246
+ def get_output_embeddings(self):
247
+ return self.lm_head
248
+
249
+ def set_output_embeddings(self, new):
250
+ self.lm_head = new
251
+
252
+ def forward(
253
+ self,
254
+ input_ids=None,
255
+ attention_mask=None,
256
+ inputs_embeds=None,
257
+ labels=None,
258
+ output_hidden_states=False,
259
+ **kwargs,
260
+ ) -> LoopedCausalLMOutput:
261
+ out = self.model(
262
+ input_ids=input_ids,
263
+ attention_mask=attention_mask,
264
+ inputs_embeds=inputs_embeds,
265
+ output_hidden_states=output_hidden_states,
266
+ )
267
+ logits = self.lm_head(out.last_hidden_state)
268
+
269
+ loss = None
270
+ if labels is not None:
271
+ shift_logits = logits[:, :-1, :].contiguous()
272
+ shift_labels = labels[:, 1:].contiguous()
273
+ loss = F.cross_entropy(
274
+ shift_logits.view(-1, shift_logits.size(-1)),
275
+ shift_labels.view(-1),
276
+ ignore_index=-100,
277
+ )
278
+
279
+ return LoopedCausalLMOutput(
280
+ loss=loss,
281
+ logits=logits,
282
+ hidden_states=out.hidden_states,
283
+ loop_hidden_states=out.loop_hidden_states,
284
+ )
285
+
286
+
287
+ # 公式 evaluation-pipeline が trust_remote_code で AutoModel 系から読めるよう登録。
288
+ # save_pretrained 時に auto_map と本ファイル群が checkpoint へ複製される。
289
+ BabyloopConfig.register_for_auto_class()
290
+ LoopedModel.register_for_auto_class("AutoModel")
291
+ LoopedForCausalLM.register_for_auto_class("AutoModelForCausalLM")
special_tokens_map.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": {
3
+ "content": "<|bos|>",
4
+ "lstrip": false,
5
+ "normalized": false,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "eos_token": {
10
+ "content": "<|eos|>",
11
+ "lstrip": false,
12
+ "normalized": false,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "pad_token": {
17
+ "content": "<|pad|>",
18
+ "lstrip": false,
19
+ "normalized": false,
20
+ "rstrip": false,
21
+ "single_word": false
22
+ },
23
+ "unk_token": {
24
+ "content": "<|unk|>",
25
+ "lstrip": false,
26
+ "normalized": false,
27
+ "rstrip": false,
28
+ "single_word": false
29
+ }
30
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "<|pad|>",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "1": {
12
+ "content": "<|bos|>",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "2": {
20
+ "content": "<|eos|>",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "3": {
28
+ "content": "<|unk|>",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ }
35
+ },
36
+ "bos_token": "<|bos|>",
37
+ "clean_up_tokenization_spaces": false,
38
+ "eos_token": "<|eos|>",
39
+ "extra_special_tokens": {},
40
+ "model_max_length": 512,
41
+ "pad_token": "<|pad|>",
42
+ "tokenizer_class": "PreTrainedTokenizer",
43
+ "unk_token": "<|unk|>"
44
+ }