ChanBeDu commited on
Commit
90b87f4
·
verified ·
1 Parent(s): 91cf8ce

Delete sudoku/trm.py

Browse files
Files changed (1) hide show
  1. sudoku/trm.py +0 -645
sudoku/trm.py DELETED
@@ -1,645 +0,0 @@
1
- from typing import Tuple, List, Dict, Optional
2
- from dataclasses import dataclass
3
- import math
4
- import torch
5
- import copy
6
- import torch.nn.functional as F
7
- from torch import nn
8
- from pydantic import BaseModel
9
- import random
10
- from models.common import trunc_normal_init_
11
- from models.layers import rms_norm, LinearSwish, SwiGLU, Attention, RotaryEmbedding, CosSin, CastedEmbedding, CastedLinear
12
- from models.sparse_embedding import CastedSparseEmbedding
13
-
14
- IGNORE_LABEL_ID = -100
15
-
16
- @dataclass
17
- class TinyRecursiveReasoningModel_ACTV1InnerCarry:
18
- z_H: torch.Tensor
19
- z_L: torch.Tensor
20
-
21
- @dataclass
22
- class TinyRecursiveReasoningModel_ACTV1Carry:
23
- inner_carry: TinyRecursiveReasoningModel_ACTV1InnerCarry
24
-
25
- steps: torch.Tensor
26
- halted: torch.Tensor
27
-
28
- current_data: Dict[str, torch.Tensor]
29
-
30
- @dataclass
31
- class TinyRecursiveReasoningModel_ACTVClipCarry:
32
- inner_carry: TinyRecursiveReasoningModel_ACTV1InnerCarry
33
-
34
- oldlogits: torch.Tensor
35
-
36
- steps: torch.Tensor
37
- halted: torch.Tensor
38
-
39
- current_data: Dict[str, torch.Tensor]
40
-
41
-
42
- class TinyRecursiveReasoningModel_ACTV1Config(BaseModel):
43
- batch_size: int
44
- seq_len: int
45
- puzzle_emb_ndim: int = 0
46
- universal_emb_len: int = 0
47
- group_emb_len: int = 0
48
- num_puzzle_identifiers: int
49
- num_groups: int
50
- vocab_size: int
51
-
52
- H_cycles: int
53
- L_cycles: int
54
-
55
- H_layers: int # ignored
56
- L_layers: int
57
-
58
- # Transformer config
59
- hidden_size: int
60
- expansion: float
61
- num_heads: int
62
- pos_encodings: str
63
-
64
- rms_norm_eps: float = 1e-5
65
- rope_theta: float = 10000.0
66
-
67
- # Halting Q-learning config
68
- halt_max_steps: int
69
- halt_exploration_prob: float
70
- puzzle_emb_len: int = 16 # if non-zero, its specified to this value
71
- forward_dtype: str = "bfloat16"
72
-
73
- # Alexia: added
74
- mlp_t: bool = False # use mlp on L instead of transformer
75
- no_ACT_continue: bool = True # No continue ACT loss, only use the sigmoid of the halt which makes much more sense
76
-
77
- # chan edit
78
- eval_with_ACT: bool = False # During evaluation, whether to use ACT halting or just run max steps. Using ACT halting will cause more variance in evaluation results, but is a more realistic evaluation of the model performance when deployed.
79
- ACT_threshold: float = 0 # Threshold for ACT halting during evaluation, only used if eval_with_ACT is True
80
-
81
- class TinyRecursiveReasoningModel_ACTGymConfig(BaseModel):
82
- replace_halt_threshold: int = 1
83
- target_latent_for_reinit: str = "L"
84
- reinit_variance: float = 1.0 # Variance for reinitializing the latent when halted. This is a hyperparameter that can be tuned. Setting it to 0 will reinitialize to the same value, which may cause the model to learn to rely on this specific value and not learn effectively. Setting it to a very large value will make the reinitialized latent too random, which may also harm learning. A moderate value can help the model learn to recover from halting and continue learning effectively.
85
-
86
-
87
- class TinyRecursiveReasoningModel_ACTV1Block(nn.Module):
88
- def __init__(self, config: TinyRecursiveReasoningModel_ACTV1Config, puzzle_emb_len: int) -> None:
89
- super().__init__()
90
-
91
- self.config = config
92
- if self.config.mlp_t:
93
- self.puzzle_emb_len = puzzle_emb_len
94
- self.mlp_t = SwiGLU(
95
- hidden_size=self.config.seq_len + self.puzzle_emb_len, # L
96
- expansion=config.expansion,
97
- )
98
- else:
99
- self.self_attn = Attention(
100
- hidden_size=config.hidden_size,
101
- head_dim=config.hidden_size // config.num_heads,
102
- num_heads=config.num_heads,
103
- num_key_value_heads=config.num_heads,
104
- causal=False
105
- )
106
- self.mlp = SwiGLU(
107
- hidden_size=config.hidden_size,
108
- expansion=config.expansion,
109
- )
110
- self.norm_eps = config.rms_norm_eps
111
-
112
- def forward(self, cos_sin: CosSin, hidden_states: torch.Tensor) -> torch.Tensor:
113
- # B, L, D = hidden_states.shape
114
- # Post Norm
115
- if self.config.mlp_t:
116
- hidden_states = hidden_states.transpose(1,2)
117
- out = self.mlp_t(hidden_states)
118
- hidden_states = rms_norm(hidden_states + out, variance_epsilon=self.norm_eps)
119
- hidden_states = hidden_states.transpose(1,2)
120
- else:
121
- # Self Attention
122
- hidden_states = rms_norm(hidden_states + self.self_attn(cos_sin=cos_sin, hidden_states=hidden_states), variance_epsilon=self.norm_eps)
123
- # Fully Connected
124
- out = self.mlp(hidden_states)
125
- hidden_states = rms_norm(hidden_states + out, variance_epsilon=self.norm_eps)
126
- return hidden_states
127
-
128
- class TinyRecursiveReasoningModel_ACTV1ReasoningModule(nn.Module):
129
- def __init__(self, layers: List[TinyRecursiveReasoningModel_ACTV1Block]):
130
- super().__init__()
131
- self.layers = torch.nn.ModuleList(layers)
132
-
133
- def forward(self, hidden_states: torch.Tensor, input_injection: torch.Tensor, **kwargs) -> torch.Tensor:
134
- hidden_states = hidden_states + input_injection
135
- for layer in self.layers:
136
- hidden_states = layer(hidden_states=hidden_states, **kwargs)
137
- return hidden_states
138
-
139
- class TinyRecursiveReasoningModel_ACTV1_Inner(nn.Module):
140
- def __init__(self, config: TinyRecursiveReasoningModel_ACTV1Config) -> None:
141
- super().__init__()
142
- self.config = config
143
- self.forward_dtype = getattr(torch, self.config.forward_dtype)
144
-
145
- # I/O
146
-
147
- self.embed_scale = math.sqrt(self.config.hidden_size)
148
- embed_init_std = 1.0 / self.embed_scale
149
-
150
- self.embed_tokens = CastedEmbedding(self.config.vocab_size, self.config.hidden_size, init_std=embed_init_std, cast_to=self.forward_dtype)
151
- self.lm_head = CastedLinear(self.config.hidden_size, self.config.vocab_size, bias=False)
152
- self.q_head = CastedLinear(self.config.hidden_size, 2, bias=True)
153
-
154
- if self.config.puzzle_emb_ndim > 0:
155
- # Zero init puzzle embeddings
156
- self.puzzle_emb = CastedSparseEmbedding(self.config.num_puzzle_identifiers, self.config.puzzle_emb_ndim,
157
- batch_size=self.config.batch_size, init_std=0, cast_to=self.forward_dtype)
158
-
159
- self.group_embedding_dim = self.config.group_emb_len * self.config.hidden_size
160
- if self.group_embedding_dim > 0:
161
- # Zero init group embeddings
162
- self.group_emb = CastedSparseEmbedding(self.config.num_groups, self.group_embedding_dim,
163
- batch_size=self.config.batch_size, init_std=0, cast_to=self.forward_dtype)
164
-
165
- self.universal_emb_ndim = self.config.universal_emb_len * self.config.hidden_size
166
- if self.universal_emb_ndim > 0:
167
- # Universal embedding, shared between tokens and puzzles, with non-zero init
168
- self.universal_emb = CastedEmbedding(1, self.universal_emb_ndim, init_std=embed_init_std, cast_to=self.forward_dtype)
169
-
170
- print("Puzzle embedding ndim:", self.config.puzzle_emb_ndim)
171
- print("Group embedding ndim:", self.group_embedding_dim)
172
- print("Universal embedding ndim:", self.universal_emb_ndim)
173
- print("Puzzle embed length:", self.config.puzzle_emb_len)
174
- total_puzzle_emb_dim = self.config.puzzle_emb_ndim + self.group_embedding_dim + self.universal_emb_ndim
175
- self.puzzle_emb_len = max(-(total_puzzle_emb_dim // -self.config.hidden_size), self.config.puzzle_emb_len) # ceil div
176
- print("Total puzzle embedding dim:", total_puzzle_emb_dim)
177
- print("Final puzzle embedding length (in tokens):", self.puzzle_emb_len)
178
-
179
- # LM Blocks
180
- if self.config.pos_encodings == "rope":
181
- self.rotary_emb = RotaryEmbedding(dim=self.config.hidden_size // self.config.num_heads,
182
- max_position_embeddings=self.config.seq_len + self.puzzle_emb_len,
183
- base=self.config.rope_theta)
184
- elif self.config.pos_encodings == "learned":
185
- self.embed_pos = CastedEmbedding(self.config.seq_len + self.puzzle_emb_len, self.config.hidden_size, init_std=embed_init_std, cast_to=self.forward_dtype)
186
- else:
187
- pass
188
-
189
- # Reasoning Layers
190
- self.L_level = TinyRecursiveReasoningModel_ACTV1ReasoningModule(layers=[TinyRecursiveReasoningModel_ACTV1Block(self.config, self.puzzle_emb_len) for _i in range(self.config.L_layers)])
191
-
192
- # Initial states
193
- self.H_init = self.init_latent_buffer(self.config.hidden_size, self.forward_dtype)
194
- self.L_init = self.init_latent_buffer(self.config.hidden_size, self.forward_dtype)
195
-
196
- # Q head special init
197
- # Init Q to (almost) zero for faster learning during bootstrapping
198
- with torch.no_grad():
199
- self.q_head.weight.zero_()
200
- self.q_head.bias.fill_(-5) # type: ignore
201
-
202
- @staticmethod
203
- def init_latent_buffer(
204
- hidden_size: int,
205
- forward_dtype: torch.dtype,
206
- persistent: bool = True,
207
- device: Optional[torch.device] = None,
208
- std: float = 1.0
209
- ) -> torch.Tensor:
210
- return nn.Buffer(
211
- trunc_normal_init_(torch.empty(hidden_size, dtype=forward_dtype, device=device), std=std),
212
- persistent=persistent,
213
- )
214
-
215
-
216
- @staticmethod
217
- def init_latent_buffer_around_state(
218
- state: torch.Tensor,
219
- forward_dtype: torch.dtype,
220
- persistent: bool = True,
221
- device: Optional[torch.device] = None,
222
- std: float = 1.0
223
- ) -> torch.Tensor:
224
- return nn.Buffer(
225
- state + trunc_normal_init_(torch.empty_like(state, dtype=forward_dtype, device=device), std=std),
226
- persistent=persistent,
227
- )
228
-
229
-
230
-
231
- def _input_embeddings(self, input: torch.Tensor, puzzle_identifiers: torch.Tensor, group_indices: torch.Tensor):
232
- # Token embedding
233
- embedding = self.embed_tokens(input.to(torch.int32))
234
-
235
- # Puzzle embeddings
236
- if self.config.puzzle_emb_ndim > 0:
237
- puzzle_embedding = self.puzzle_emb(puzzle_identifiers)
238
-
239
- if self.config.group_emb_len > 0:
240
- group_embedding = self.group_emb(group_indices)
241
-
242
- # concat along feature dim -> (B, Dp + Dg)
243
- puzzle_embedding = torch.cat([puzzle_embedding, group_embedding], dim=-1)
244
-
245
- if self.config.universal_emb_len > 0:
246
- # universal_embedding: (B, Du)
247
- universal_embedding = self.universal_emb(torch.zeros(puzzle_embedding.size(0), device=puzzle_embedding.device, dtype=torch.long))
248
-
249
- # concat along feature dim -> (B, Dp + (Dg) + Du)
250
- puzzle_embedding = torch.cat([puzzle_embedding, universal_embedding], dim=-1)
251
-
252
- pad_count = self.puzzle_emb_len * self.config.hidden_size - puzzle_embedding.shape[-1]
253
- if pad_count > 0:
254
- puzzle_embedding = F.pad(puzzle_embedding, (0, pad_count))
255
-
256
- embedding = torch.cat((puzzle_embedding.view(-1, self.puzzle_emb_len, self.config.hidden_size), embedding), dim=-2)
257
-
258
- # Position embeddings
259
- if self.config.pos_encodings == "learned":
260
- # scale by 1/sqrt(2) to maintain forward variance
261
- embedding = 0.707106781 * (embedding + self.embed_pos.embedding_weight.to(self.forward_dtype))
262
-
263
- # Scale
264
- return self.embed_scale * embedding
265
-
266
- def empty_carry(self, batch_size: int):
267
- return TinyRecursiveReasoningModel_ACTV1InnerCarry(
268
- z_H=torch.empty(batch_size, self.config.seq_len + self.puzzle_emb_len, self.config.hidden_size, dtype=self.forward_dtype),
269
- z_L=torch.empty(batch_size, self.config.seq_len + self.puzzle_emb_len, self.config.hidden_size, dtype=self.forward_dtype),
270
- )
271
-
272
- def reset_carry(self, reset_flag: torch.Tensor, carry: TinyRecursiveReasoningModel_ACTV1InnerCarry):
273
- return TinyRecursiveReasoningModel_ACTV1InnerCarry(
274
- z_H=torch.where(reset_flag.view(-1, 1, 1), self.H_init, carry.z_H),
275
- z_L=torch.where(reset_flag.view(-1, 1, 1), self.L_init, carry.z_L),
276
- )
277
-
278
- def re_inittialize_carry(
279
- self,
280
- reset_flag: torch.Tensor,
281
- carry: TinyRecursiveReasoningModel_ACTV1InnerCarry,
282
- target_latent: Optional[str] = None,
283
- init_std: float = 1.0
284
- ):
285
- target_device = carry.z_L.device
286
- if target_latent == "LH":
287
- return TinyRecursiveReasoningModel_ACTV1InnerCarry(
288
- z_H=torch.where(
289
- reset_flag.view(-1, 1, 1),
290
- self.init_latent_buffer(self.config.hidden_size, self.forward_dtype, device=target_device, std=init_std),
291
- carry.z_H,
292
- ),
293
- z_L=torch.where(
294
- reset_flag.view(-1, 1, 1),
295
- self.init_latent_buffer(self.config.hidden_size, self.forward_dtype, device=target_device, std=init_std),
296
- carry.z_L,
297
- ),
298
- )
299
- elif target_latent == "H":
300
- return TinyRecursiveReasoningModel_ACTV1InnerCarry(
301
- z_H=torch.where(
302
- reset_flag.view(-1, 1, 1),
303
- self.init_latent_buffer(self.config.hidden_size, self.forward_dtype, device=target_device, std=init_std),
304
- carry.z_H,
305
- ),
306
- z_L=carry.z_L
307
- )
308
- elif target_latent == "L":
309
- return TinyRecursiveReasoningModel_ACTV1InnerCarry(
310
- z_H=carry.z_H,
311
- z_L=torch.where(
312
- reset_flag.view(-1, 1, 1),
313
- self.init_latent_buffer(self.config.hidden_size, self.forward_dtype, device=target_device, std=init_std),
314
- carry.z_L,
315
- )
316
- )
317
- else:
318
- raise ValueError(f"Invalid target_latent value: {target_latent}")
319
-
320
-
321
- def forward(self, carry: TinyRecursiveReasoningModel_ACTV1InnerCarry, batch: Dict[str, torch.Tensor]) -> Tuple[TinyRecursiveReasoningModel_ACTV1InnerCarry, Dict[str, torch.Tensor]]:
322
- seq_info = dict(
323
- cos_sin=self.rotary_emb() if hasattr(self, "rotary_emb") else None,
324
- )
325
-
326
- # Input encoding
327
- input_embeddings = self._input_embeddings(batch["inputs"], batch["puzzle_identifiers"], batch["group_indices"])
328
-
329
- # Forward iterations
330
- it = 0
331
- z_H, z_L = carry.z_H, carry.z_L
332
- # H_cycles-1 without grad
333
- with torch.no_grad():
334
- for _H_step in range(self.config.H_cycles-1):
335
- for _L_step in range(self.config.L_cycles):
336
- z_L = self.L_level(z_L, z_H + input_embeddings, **seq_info)
337
- z_H = self.L_level(z_H, z_L, **seq_info)
338
- # 1 with grad
339
- for _L_step in range(self.config.L_cycles):
340
- z_L = self.L_level(z_L, z_H + input_embeddings, **seq_info)
341
- z_H = self.L_level(z_H, z_L, **seq_info)
342
-
343
- # LM Outputs
344
- new_carry = TinyRecursiveReasoningModel_ACTV1InnerCarry(z_H=z_H.detach(), z_L=z_L.detach()) # New carry no grad
345
- logits = self.lm_head(z_H)[:, self.puzzle_emb_len:]
346
- q_logits = self.q_head(z_H[:, 0]).to(torch.float32) # Q-head; uses the first puzzle_emb position
347
- outputs = {
348
- "logits": logits,
349
- "q_halt_logits": q_logits[..., 0],
350
- "q_continue_logits": q_logits[..., 1] if not self.config.no_ACT_continue else None
351
- }
352
-
353
- return new_carry, outputs
354
-
355
- class TinyRecursiveReasoningModel_PPOInner(TinyRecursiveReasoningModel_ACTV1_Inner):
356
- def __init__(self, config: TinyRecursiveReasoningModel_ACTV1Config) -> None:
357
- super().__init__(config)
358
- self.v_head = CastedLinear(self.config.hidden_size, 1, bias=True) # Unbounded PPO value function regression
359
-
360
- with torch.no_grad():
361
- self.v_head.weight.normal_(std=0.02)
362
- self.v_head.bias.zero_() # Clean zero-start for reward expectation
363
-
364
- def forward(
365
- self,
366
- carry: TinyRecursiveReasoningModel_ACTV1InnerCarry,
367
- batch: Dict[str, torch.Tensor],
368
- ) -> Tuple[TinyRecursiveReasoningModel_ACTV1InnerCarry, Dict[str, torch.Tensor]]:
369
- seq_info = dict(
370
- cos_sin=self.rotary_emb() if hasattr(self, "rotary_emb") else None,
371
- )
372
-
373
- input_embeddings = self._input_embeddings(batch["inputs"], batch["puzzle_identifiers"], batch["group_indices"])
374
-
375
- z_H, z_L = carry.z_H, carry.z_L
376
- trajectory_logits = []
377
- trajectory_values = []
378
-
379
- with torch.no_grad():
380
- for _H_step in range(self.config.H_cycles - 1):
381
- for _L_step in range(self.config.L_cycles):
382
- z_L = self.L_level(z_L, z_H + input_embeddings, **seq_info)
383
- z_H = self.L_level(z_H, z_L, **seq_info)
384
-
385
- logits = self.lm_head(z_H)[:, self.puzzle_emb_len:]
386
- values = self.v_head(z_H[:, 0]).to(torch.float32)
387
- trajectory_logits.append(logits.detach())
388
- trajectory_values.append(values.detach())
389
-
390
- for _L_step in range(self.config.L_cycles):
391
- z_L = self.L_level(z_L, z_H + input_embeddings, **seq_info)
392
- z_H = self.L_level(z_H, z_L, **seq_info)
393
-
394
- logits = self.lm_head(z_H)[:, self.puzzle_emb_len:]
395
- # q_logits = self.q_head(z_H[:, 0]).to(torch.float32)
396
- values = self.v_head(z_H[:, 0]).to(torch.float32)
397
- trajectory_logits.append(logits)
398
- trajectory_values.append(values)
399
-
400
- new_carry = TinyRecursiveReasoningModel_ACTV1InnerCarry(z_H=z_H.detach(), z_L=z_L.detach())
401
- outputs = {
402
- "logits": logits,
403
- "trajectory_logits": torch.stack(trajectory_logits, dim=1),
404
- "trajectory_values": torch.stack(trajectory_values, dim=1)
405
- }
406
-
407
- return new_carry, outputs
408
-
409
-
410
- class TinyRecursiveReasoningModel_ACTV1(nn.Module):
411
- """ACT wrapper."""
412
-
413
- def __init__(self, config_dict: dict):
414
- super().__init__()
415
- self.config = TinyRecursiveReasoningModel_ACTV1Config(**config_dict)
416
- self.inner = TinyRecursiveReasoningModel_ACTV1_Inner(self.config)
417
-
418
- @property
419
- def puzzle_emb(self):
420
- return self.inner.puzzle_emb
421
-
422
- @property
423
- def group_emb(self):
424
- return self.inner.group_emb
425
-
426
- def initial_carry(self, batch: Dict[str, torch.Tensor]):
427
- batch_size = batch["inputs"].shape[0]
428
-
429
- return TinyRecursiveReasoningModel_ACTV1Carry(
430
- inner_carry=self.inner.empty_carry(batch_size), # Empty is expected, it will be reseted in first pass as all sequences are halted.
431
-
432
- steps=torch.zeros((batch_size, ), dtype=torch.int32),
433
- halted=torch.ones((batch_size, ), dtype=torch.bool), # Default to halted
434
-
435
- current_data={k: torch.empty_like(v) for k, v in batch.items()}
436
- )
437
-
438
- def step_inner_carry(self, carry: TinyRecursiveReasoningModel_ACTV1Carry, batch: Dict[str, torch.Tensor]):
439
- new_inner_carry = self.inner.reset_carry(carry.halted, carry.inner_carry)
440
- return new_inner_carry
441
-
442
- def step_current_data(self, carry: TinyRecursiveReasoningModel_ACTV1Carry, batch: Dict[str, torch.Tensor]):
443
- new_current_data = {k: torch.where(carry.halted.view((-1, ) + (1, ) * (batch[k].ndim - 1)), batch[k], v) for k, v in carry.current_data.items()}
444
- return new_current_data
445
-
446
- def step_carry(self, carry: TinyRecursiveReasoningModel_ACTV1Carry, batch: Dict[str, torch.Tensor]):
447
- # Step inner carry
448
- new_inner_carry = self.step_inner_carry(carry, batch)
449
-
450
- new_steps = torch.where(carry.halted, 0, carry.steps)
451
-
452
- # Update data, carry (removing halted sequences)
453
- new_current_data = self.step_current_data(carry, batch)
454
-
455
- return new_inner_carry, new_steps, new_current_data
456
-
457
-
458
- def forward(self, carry: TinyRecursiveReasoningModel_ACTV1Carry, batch: Dict[str, torch.Tensor]) -> Tuple[TinyRecursiveReasoningModel_ACTV1Carry, Dict[str, torch.Tensor]]:
459
-
460
- new_inner_carry, new_steps, new_current_data = self.step_carry(carry, batch)
461
-
462
- # Forward inner model
463
- new_inner_carry, outputs = self.inner(new_inner_carry, new_current_data)
464
-
465
-
466
- with torch.no_grad():
467
- # Step
468
- new_steps = new_steps + 1
469
- is_last_step = new_steps >= self.config.halt_max_steps
470
-
471
- halted = is_last_step
472
-
473
- # if training, and ACT is enabled
474
- if self.training and (self.config.halt_max_steps > 1) or (self.config.eval_with_ACT):
475
-
476
- # Halt signal
477
- # NOTE: During evaluation, always use max steps, this is to guarantee the same halting steps inside a batch for batching purposes
478
-
479
- if self.config.no_ACT_continue:
480
- halted = halted | (outputs["q_halt_logits"] > self.config.ACT_threshold)
481
- else:
482
- halted = halted | (outputs["q_halt_logits"] > outputs["q_continue_logits"])
483
-
484
- # Exploration
485
- min_halt_steps = (torch.rand_like(outputs["q_halt_logits"]) < self.config.halt_exploration_prob) * torch.randint_like(new_steps, low=2, high=self.config.halt_max_steps + 1)
486
- halted = halted & (new_steps >= min_halt_steps)
487
-
488
- if not self.config.no_ACT_continue:
489
- # Compute target Q
490
- # NOTE: No replay buffer and target networks for computing target Q-value.
491
- # As batch_size is large, there're many parallel envs.
492
- # Similar concept as PQN https://arxiv.org/abs/2407.04811
493
- _, _, (next_q_halt_logits, next_q_continue_logits), _, _ = self.inner(new_inner_carry, new_current_data)
494
- outputs["target_q_continue"] = torch.sigmoid(torch.where(is_last_step, next_q_halt_logits, torch.maximum(next_q_halt_logits, next_q_continue_logits)))
495
-
496
- return TinyRecursiveReasoningModel_ACTV1Carry(new_inner_carry, new_steps, halted, new_current_data), outputs
497
-
498
-
499
- class TinyRecursiveReasoningModel_ACTVClip(nn.Module):
500
- """ACT wrapper."""
501
-
502
- def __init__(self, config_dict: dict):
503
- super().__init__()
504
- self.config = TinyRecursiveReasoningModel_ACTV1Config(**config_dict)
505
- self.inner = TinyRecursiveReasoningModel_ACTV1_Inner(self.config)
506
-
507
- @property
508
- def puzzle_emb(self):
509
- return self.inner.puzzle_emb
510
-
511
- @property
512
- def group_emb(self):
513
- return self.inner.group_emb
514
-
515
- def initial_carry(self, batch: Dict[str, torch.Tensor]):
516
- batch_size = batch["inputs"].shape[0]
517
-
518
- return TinyRecursiveReasoningModel_ACTVClipCarry(
519
- inner_carry=self.inner.empty_carry(batch_size), # Empty is expected, it will be reseted in first pass as all sequences are halted.
520
-
521
- oldlogits=torch.zeros((batch_size, self.config.seq_len, self.config.vocab_size), dtype=self.inner.forward_dtype),
522
- steps=torch.zeros((batch_size, ), dtype=torch.int32),
523
- halted=torch.ones((batch_size, ), dtype=torch.bool), # Default to halted
524
-
525
- current_data={k: torch.empty_like(v) for k, v in batch.items()}
526
- )
527
-
528
- def step_inner_carry(self, carry: TinyRecursiveReasoningModel_ACTVClipCarry, batch: Dict[str, torch.Tensor]):
529
- new_inner_carry = self.inner.reset_carry(carry.halted, carry.inner_carry)
530
- return new_inner_carry
531
-
532
- def step_current_data(self, carry: TinyRecursiveReasoningModel_ACTVClipCarry, batch: Dict[str, torch.Tensor]):
533
- new_current_data = {k: torch.where(carry.halted.view((-1, ) + (1, ) * (batch[k].ndim - 1)), batch[k], v) for k, v in carry.current_data.items()}
534
- return new_current_data
535
-
536
- def step_carry(self, carry: TinyRecursiveReasoningModel_ACTVClipCarry, batch: Dict[str, torch.Tensor]):
537
- # Step inner carry
538
- new_inner_carry = self.step_inner_carry(carry, batch)
539
-
540
- # new policy is assumed to start from equal probability
541
- old_logits = torch.where(carry.halted.view((-1, 1, 1)), torch.zeros_like(carry.oldlogits), carry.oldlogits)
542
-
543
- new_steps = torch.where(carry.halted, 0, carry.steps)
544
-
545
- # Update data, carry (removing halted sequences)
546
- new_current_data = self.step_current_data(carry, batch)
547
-
548
- return new_inner_carry, old_logits, new_steps, new_current_data
549
-
550
-
551
- def forward(self, carry: TinyRecursiveReasoningModel_ACTVClipCarry, batch: Dict[str, torch.Tensor]) -> Tuple[TinyRecursiveReasoningModel_ACTVClipCarry, Dict[str, torch.Tensor]]:
552
-
553
- new_inner_carry, old_logits, new_steps, new_current_data = self.step_carry(carry, batch)
554
-
555
- # Forward inner model
556
- new_inner_carry, outputs = self.inner(new_inner_carry, new_current_data)
557
-
558
-
559
- with torch.no_grad():
560
- # Step
561
- new_steps = new_steps + 1
562
- is_last_step = new_steps >= self.config.halt_max_steps
563
-
564
- halted = is_last_step
565
-
566
- # if training, and ACT is enabled
567
- if self.training and (self.config.halt_max_steps > 1) or (self.config.eval_with_ACT):
568
-
569
- # Halt signal
570
- # NOTE: During evaluation, always use max steps, this is to guarantee the same halting steps inside a batch for batching purposes
571
-
572
- if self.config.no_ACT_continue:
573
- halted = halted | (outputs["q_halt_logits"] > self.config.ACT_threshold)
574
- else:
575
- halted = halted | (outputs["q_halt_logits"] > outputs["q_continue_logits"])
576
-
577
- # Exploration
578
- min_halt_steps = (torch.rand_like(outputs["q_halt_logits"]) < self.config.halt_exploration_prob) * torch.randint_like(new_steps, low=2, high=self.config.halt_max_steps + 1)
579
- halted = halted & (new_steps >= min_halt_steps)
580
-
581
- if not self.config.no_ACT_continue:
582
- # Compute target Q
583
- # NOTE: No replay buffer and target networks for computing target Q-value.
584
- # As batch_size is large, there're many parallel envs.
585
- # Similar concept as PQN https://arxiv.org/abs/2407.04811
586
- _, _, (next_q_halt_logits, next_q_continue_logits), _, _ = self.inner(new_inner_carry, new_current_data)
587
- outputs["target_q_continue"] = torch.sigmoid(torch.where(is_last_step, next_q_halt_logits, torch.maximum(next_q_halt_logits, next_q_continue_logits)))
588
-
589
- return TinyRecursiveReasoningModel_ACTVClipCarry(new_inner_carry, old_logits, new_steps, halted, new_current_data), outputs
590
-
591
- class TinyRecursiveReasoningModel_ACTGym(TinyRecursiveReasoningModel_ACTV1):
592
- """ACT wrapper."""
593
-
594
- def __init__(self, config_dict: dict):
595
- super().__init__(config_dict)
596
- self.GymConfig = TinyRecursiveReasoningModel_ACTGymConfig(**config_dict)
597
-
598
- def step_inner_carry(self, carry: TinyRecursiveReasoningModel_ACTV1Carry, batch: Dict[str, torch.Tensor]):
599
- # check the first step where all halted and steps is 0
600
- new_inner_carry = self.inner.reset_carry(carry.halted & (carry.steps > self.GymConfig.replace_halt_threshold), carry.inner_carry)
601
-
602
- new_inner_carry = self.inner.re_inittialize_carry(carry.halted & (carry.steps <= self.GymConfig.replace_halt_threshold), new_inner_carry, target_latent=self.GymConfig.target_latent_for_reinit, init_std=self.GymConfig.reinit_variance)
603
- return new_inner_carry
604
-
605
- def step_carry(self, carry: TinyRecursiveReasoningModel_ACTV1Carry, batch: Dict[str, torch.Tensor]):
606
- # Step inner carry
607
- new_inner_carry = None
608
- if (carry.halted & (carry.steps == 0)).all():
609
- new_inner_carry = self.inner.reset_carry(carry.halted, carry.inner_carry)
610
- else:
611
- new_inner_carry = self.step_inner_carry(carry, batch)
612
- carry.halted = carry.halted & (carry.steps > self.GymConfig.replace_halt_threshold)
613
-
614
- new_steps = torch.where(carry.halted, 0, carry.steps)
615
-
616
- # Update data, carry (removing halted sequences)
617
- new_current_data = self.step_current_data(carry, batch)
618
-
619
- return new_inner_carry, new_steps, new_current_data
620
-
621
-
622
- class TinyRecursiveReasoningModel_TRMPPO(TinyRecursiveReasoningModel_ACTV1):
623
- """TRM PPO-style wrapper."""
624
-
625
- def __init__(self, config_dict: dict):
626
- super().__init__(config_dict)
627
- self.config = TinyRecursiveReasoningModel_ACTV1Config(**config_dict)
628
- self.inner = TinyRecursiveReasoningModel_PPOInner(self.config)
629
-
630
- def forward(self, carry: TinyRecursiveReasoningModel_ACTV1Carry, batch: Dict[str, torch.Tensor]) -> Tuple[TinyRecursiveReasoningModel_ACTV1Carry, Dict[str, torch.Tensor]]:
631
-
632
- new_inner_carry, new_steps, new_current_data = self.step_carry(carry, batch)
633
-
634
- # Forward inner model
635
- new_inner_carry, outputs = self.inner(new_inner_carry, new_current_data)
636
-
637
-
638
- with torch.no_grad():
639
- # Step
640
- new_steps = new_steps + 1
641
- is_last_step = new_steps >= self.config.halt_max_steps
642
-
643
- halted = is_last_step
644
-
645
- return TinyRecursiveReasoningModel_ACTV1Carry(new_inner_carry, new_steps, halted, new_current_data), outputs