ramnet 0.1.0rc0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ramnet/__init__.py ADDED
@@ -0,0 +1,11 @@
1
+ from .layers import RAMNetAttention, RAMCache, RAMState
2
+ from .models import RAMNetConfig, RAMNetModel, RAMNetForCausalLM
3
+
4
+ __all__ = [
5
+ 'RAMCache',
6
+ 'RAMState',
7
+ 'RAMNetAttention',
8
+ 'RAMNetConfig',
9
+ 'RAMNetModel',
10
+ 'RAMNetForCausalLM',
11
+ ]
@@ -0,0 +1,4 @@
1
+ from .ram_attn_block import RAMNetAttention
2
+ from .cache import RAMCacheLayer, RAMCache, RAMState
3
+
4
+ __all__ = ['RAMNetAttention', 'RAMCacheLayer', 'RAMCache', 'RAMState']
ramnet/layers/cache.py ADDED
@@ -0,0 +1,140 @@
1
+ from typing import Any, Callable, NamedTuple
2
+
3
+ import torch
4
+ from transformers.cache_utils import Cache, CacheLayerMixin
5
+
6
+
7
+ class RAMState(NamedTuple):
8
+ """Recurrent memory contents and mass."""
9
+
10
+ slot: torch.Tensor # (..., H, A, C)
11
+ mass: torch.Tensor # (..., H, A)
12
+
13
+
14
+ class RAMCacheLayer(CacheLayerMixin):
15
+ """One recurrent state, its physical length, and per-sample CAPE positions."""
16
+
17
+ is_compileable = False
18
+ is_sliding = False
19
+ is_croppable = False
20
+ supports_early_init = False
21
+ max_cache_len = -1
22
+
23
+ def __init__(self):
24
+ super().__init__()
25
+ self.state: RAMState | None = None
26
+ self.next_position: torch.Tensor | None = None
27
+ self.cache_length = 0
28
+ self.is_initialized = False
29
+ self.device = None
30
+
31
+ def lazy_initialization(self, recurrent_state: RAMState) -> None:
32
+ self.device = recurrent_state.slot.device
33
+ self.is_initialized = True
34
+
35
+ def update(
36
+ self,
37
+ recurrent_state: RAMState | tuple[torch.Tensor, torch.Tensor],
38
+ offset: int = 1,
39
+ cache_kwargs: dict[str, Any] | None = None,
40
+ ) -> RAMState:
41
+ state = RAMState(*recurrent_state)
42
+ if not self.is_initialized:
43
+ self.lazy_initialization(state)
44
+
45
+ # Assign functional outputs directly to preserve autograd across chunks.
46
+ self.state = state
47
+ self.cache_length += offset
48
+ if cache_kwargs is not None:
49
+ self.next_position = cache_kwargs.get('next_position', self.next_position)
50
+ return state
51
+
52
+ def get_seq_length(self) -> int:
53
+ return self.cache_length
54
+
55
+ def get_mask_sizes(self, query_length: int | torch.Tensor) -> tuple[int, int]:
56
+ if isinstance(query_length, torch.Tensor):
57
+ query_length = query_length.numel()
58
+ return self.cache_length + query_length, 0
59
+
60
+ def get_max_cache_shape(self) -> int:
61
+ return -1
62
+
63
+ def get_max_length(self) -> int:
64
+ return -1
65
+
66
+ @property
67
+ def batch_size(self) -> int:
68
+ return self.state.slot.size(0) if self.state is not None else -1
69
+
70
+ @property
71
+ def max_batch_size(self) -> int:
72
+ return self.batch_size
73
+
74
+ def _map_tensors(self, fn: Callable[[torch.Tensor], torch.Tensor]) -> None:
75
+ if self.state is not None:
76
+ self.state = RAMState(*(fn(value) for value in self.state))
77
+ if self.next_position is not None:
78
+ self.next_position = fn(self.next_position)
79
+
80
+ def offload(self) -> None:
81
+ self._map_tensors(lambda value: value.to('cpu', non_blocking=True))
82
+
83
+ def prefetch(self) -> None:
84
+ if self.is_initialized:
85
+ self._map_tensors(lambda value: value.to(self.device, non_blocking=True))
86
+
87
+ def reorder_cache(self, beam_idx: torch.LongTensor) -> None:
88
+ self.batch_select_indices(beam_idx)
89
+
90
+ def batch_select_indices(self, indices: torch.LongTensor) -> None:
91
+ self._map_tensors(lambda value: value.index_select(0, indices.to(value.device)))
92
+
93
+ def batch_repeat_interleave(self, repeats: int) -> None:
94
+ self._map_tensors(lambda value: value.repeat_interleave(repeats, dim=0))
95
+
96
+ def crop(self, max_length: int) -> None:
97
+ raise ValueError('RAMCache cannot roll back recurrent states; replay the retained prefix instead.')
98
+
99
+ def reset(self) -> None:
100
+ self.state = None
101
+ self.next_position = None
102
+ self.cache_length = 0
103
+ self.is_initialized = False
104
+
105
+
106
+ class RAMCache(Cache):
107
+ """A Hugging Face cache with FLA-style ``recurrent_state`` layer entries.
108
+
109
+ Storage is allocated by attention on first use, in the operator's state dtype.
110
+ Cache length counts all processed tokens; CAPE positions count valid tokens.
111
+ """
112
+
113
+ def __init__(self) -> None:
114
+ super().__init__(layer_class_to_replicate=RAMCacheLayer)
115
+
116
+ def get_layer(self, layer_idx: int) -> RAMCacheLayer:
117
+ if layer_idx < 0:
118
+ raise ValueError('layer_idx must be non-negative.')
119
+ while len(self.layers) <= layer_idx:
120
+ self.layers.append(RAMCacheLayer())
121
+ return self.layers[layer_idx]
122
+
123
+ def update(
124
+ self,
125
+ recurrent_state: RAMState | tuple[torch.Tensor, torch.Tensor],
126
+ layer_idx: int,
127
+ offset: int = 1,
128
+ cache_kwargs: dict[str, Any] | None = None,
129
+ ) -> RAMState:
130
+ return self.get_layer(layer_idx).update(recurrent_state, offset, cache_kwargs)
131
+
132
+ def get_max_length(self, layer_idx: int | None = None) -> int:
133
+ return -1
134
+
135
+ def __getitem__(self, layer_idx: int) -> dict[str, RAMState | None]:
136
+ return {'recurrent_state': self.layers[layer_idx].state}
137
+
138
+ def __iter__(self):
139
+ for layer_idx in range(len(self.layers)):
140
+ yield self[layer_idx]
@@ -0,0 +1,351 @@
1
+ import torch
2
+ import einops
3
+ from typing import Literal
4
+ from torch.distributed.tensor import DTensor, distribute_tensor
5
+
6
+ from .cache import RAMCache, RAMState
7
+ from ramnet_ops import random_access_memory_attention
8
+
9
+ Activation_mapping = {
10
+ 'relu': torch.nn.ReLU,
11
+ 'sigmoid': torch.nn.Sigmoid,
12
+ 'silu': torch.nn.SiLU,
13
+ 'swish': torch.nn.SiLU,
14
+ 'gelu': torch.nn.GELU,
15
+ }
16
+ OutputGateType = Literal['relu', 'sigmoid', 'silu', 'swish', 'gelu']
17
+
18
+
19
+ class RAMNetAttention(torch.nn.Module):
20
+ """
21
+ the layer of RAM Net Attention for [RAM-Net: Expressive Linear Attention with Selectively Addressable Memory] (https://arxiv.org/abs/2602.11958)
22
+
23
+ :param hidden_size: Dimensionality of the input and output layers.
24
+ :param n_heads: Number of attention heads.
25
+
26
+ :param addr_order: Order U of the address space (U-order product softmax).
27
+ :param addr_radix: Address radix P (paper d_p): choices per digit, giving P^U memory slots.
28
+ :param value_chs: Dimensionality of value channels (d_v), total state size = d_p^U * d_v. Default: hidden_size // num_attention_heads.
29
+
30
+ :param gamma: prior forget-rate control. Negative values favor retention, zero balances writing and forgetting, and positive values favor forgetting.
31
+ :param gamma_mode: Mode for gamma: 'fixed' (non-trainable constant), 'learnable' (per-head learnable parameter), 'dynamic' (input-conditioned via linear map).
32
+
33
+ :param init_mass: Persistence strength of the initial zero state. None defaults to 1 / (addr_radix ** addr_order).
34
+
35
+ :param embed_num: Number of heads applying Cyclic Address Positional Embedding (CAPE). 0 disables CAPE; explicit values must be in ``[0, n_heads]``.
36
+
37
+ :param addr_temperature: Temperature for address localization; smaller values precise memory access.
38
+ :param top_k: Limits sparsity of the address vector. A two-item tuple/list applies separately to (write_k, read_k); int applies to both. Active state per token is proportional to k * d_v.
39
+ :param top_k_re_norm: Whether to re-normalize the address vector after top-k filtering, forcing the top-k entries to sum to 1.0.
40
+ A bool applies to both write and read; a two-item tuple/list specifies separate (write, read) bools.
41
+
42
+ :param mass_aware: Weight reads by updated memory mass with epsilon-stabilized normalization.
43
+ :param output_gate: Element-wise output gate function: 'relu', 'sigmoid', 'silu', 'swish', 'gelu', or None.
44
+ :param output_norm: Whether to enable head-wise output RMS-norm.
45
+
46
+ :param addr_proj_bias: Whether to enable bias in address projection layers (bias = address prior).
47
+ :param value_proj_bias: Whether to enable bias in the value projection layer.
48
+ :param address_scaling: Whether to re-parameterize address projection with learnable scaling (w = exp(alpha) * w' for training).
49
+
50
+ :param ram_attn_eps: Epsilon value for RAM read out and proxy backward limit in the forget gate.
51
+ """
52
+
53
+ # noinspection PyTypeChecker
54
+ def __init__(
55
+ self,
56
+ # === Model Architecture ===
57
+ hidden_size: int,
58
+ n_heads: int,
59
+ # === RAM Structure ===
60
+ addr_order: int = 5,
61
+ addr_radix: int = 4,
62
+ value_chs: int | None = None,
63
+ # === Forgetting Modulation ===
64
+ gamma: float = 2.197,
65
+ gamma_mode: Literal['fixed', 'learnable', 'dynamic'] = 'dynamic',
66
+ # === RAM initial mass ===
67
+ init_mass: float | None = None,
68
+ # === Positional Encoding (CAPE) ===
69
+ embed_num: int = 0,
70
+ # === Address Decoder ===
71
+ addr_temperature: float = 2.2,
72
+ top_k: tuple[int, int] | list[int] | int | None = 8,
73
+ top_k_re_norm: bool | tuple[bool, bool] | list[bool] = False,
74
+ # === Readout ===
75
+ mass_aware: bool = False,
76
+ output_gate: OutputGateType | None = 'sigmoid',
77
+ output_norm: bool = False,
78
+ # === Projection ===
79
+ addr_proj_bias: bool = True,
80
+ value_proj_bias: bool = False,
81
+ address_scaling: bool = True,
82
+ # === Numerical Stability ===
83
+ ram_attn_eps: float = 1e-12,
84
+ layer_idx: int | None = None,
85
+ ) -> None:
86
+ super().__init__()
87
+
88
+ if gamma_mode not in ('fixed', 'learnable', 'dynamic'):
89
+ raise ValueError(f"Unsupported gamma_mode: {gamma_mode!r}.")
90
+ if output_gate is not None and output_gate not in Activation_mapping:
91
+ raise ValueError(f"Unsupported output_gate: {output_gate!r}.")
92
+ assert hidden_size > 0 and n_heads > 0 and addr_order > 0 and addr_radix > 0, f"Expected positive dimensions, got {hidden_size=}, {n_heads=}, {addr_order=}, {addr_radix=}."
93
+ assert addr_temperature > 0, f"Expected addr_temperature > 0, got {addr_temperature}."
94
+ assert isinstance(embed_num, int) and 0 <= embed_num <= n_heads, f"Expected embed_num in [0, {n_heads}], got {embed_num!r}."
95
+ assert ram_attn_eps > 0, f"Expected ram_attn_eps > 0, got {ram_attn_eps}."
96
+ if layer_idx is not None and layer_idx < 0:
97
+ raise ValueError('layer_idx must be non-negative.')
98
+
99
+ if value_chs is None:
100
+ value_chs = int(hidden_size // n_heads)
101
+ assert value_chs > 0, f"Expected value_chs > 0, got {value_chs}."
102
+
103
+ self.layer_idx = layer_idx
104
+ self.n_heads = n_heads
105
+ self.addr_order = addr_order
106
+ self.addr_radix = addr_radix
107
+ self.value_chs = value_chs
108
+ self.gamma = gamma
109
+ self.gamma_mode = gamma_mode
110
+ self.addr_temperature = addr_temperature
111
+ self.embed_num = embed_num
112
+ self.init_mass = addr_radix ** (- addr_order) if init_mass is None else init_mass
113
+ self.top_k = top_k
114
+ self.top_k_re_norm = top_k_re_norm
115
+ self.mass_aware = mass_aware
116
+ self.addr_proj_bias = addr_proj_bias
117
+ self.value_proj_bias = value_proj_bias
118
+ self.ram_attn_eps = ram_attn_eps
119
+
120
+ proj_v_chs: int = self.n_heads * self.value_chs
121
+ proj_addr_chs: int = self.n_heads * self.addr_radix * self.addr_order
122
+
123
+ self.r_proj = torch.nn.Linear(hidden_size, proj_addr_chs, bias=self.addr_proj_bias)
124
+ self.w_proj = torch.nn.Linear(hidden_size, proj_addr_chs, bias=self.addr_proj_bias)
125
+ self.r_proj._ramnet_address = (self.n_heads, self.addr_order, self.addr_radix)
126
+ self.w_proj._ramnet_address = (self.n_heads, self.addr_order, self.addr_radix)
127
+ self.v_proj = torch.nn.Linear(hidden_size, proj_v_chs, bias=self.value_proj_bias)
128
+ self.o_proj = torch.nn.Linear(proj_v_chs, hidden_size, bias=self.value_proj_bias)
129
+
130
+ if gamma_mode == 'learnable':
131
+ self.gamma_modifier = torch.nn.Parameter(torch.zeros(self.n_heads))
132
+ if gamma_mode == 'dynamic':
133
+ self.gamma_modifier = torch.nn.Linear(hidden_size, self.n_heads)
134
+
135
+ self.o_norm = torch.nn.RMSNorm(self.value_chs) if output_norm else None
136
+ self.o_gate = torch.nn.Sequential(torch.nn.Linear(hidden_size, proj_v_chs), Activation_mapping[output_gate]()) if output_gate else None
137
+ if self.o_gate is not None:
138
+ self.o_gate[0]._ramnet_output_gate = True
139
+
140
+ if address_scaling:
141
+ self.r_scale = torch.nn.Parameter(torch.zeros(self.n_heads, self.addr_order))
142
+ self.w_scale = torch.nn.Parameter(torch.zeros(self.n_heads, self.addr_order))
143
+ else:
144
+ self.r_scale = None
145
+ self.w_scale = None
146
+
147
+ @torch.no_grad()
148
+ def _init_weights(self, *, initializer_range: float = 0.02, addr_prior_range: float = 1.5, gate_initializer_bias: float = 3.0) -> None:
149
+ """Initialize all parameters and submodules owned by this attention layer."""
150
+ for module in self.modules():
151
+ self._init_module_weights(
152
+ module,
153
+ initializer_range=initializer_range,
154
+ addr_prior_range=addr_prior_range,
155
+ gate_initializer_bias=gate_initializer_bias,
156
+ )
157
+
158
+ @staticmethod
159
+ @torch.no_grad()
160
+ def _init_module_weights(
161
+ module: torch.nn.Module,
162
+ *,
163
+ initializer_range: float,
164
+ addr_prior_range: float,
165
+ gate_initializer_bias: float,
166
+ ) -> None:
167
+ """Initialize one module; leave traversal and initialization tracking to the caller."""
168
+ if isinstance(module, torch.nn.Linear):
169
+ torch.nn.init.normal_(module.weight, mean=0.0, std=initializer_range)
170
+ if module.bias is not None:
171
+ address_shape = getattr(module, '_ramnet_address', None)
172
+ if address_shape is not None:
173
+ H, U, P = address_shape
174
+ assert module.out_features == H * U * P, "Address projection shape mismatch."
175
+ bias = torch.linspace(0, addr_prior_range, U)[:, None] * torch.linspace(-1, 1, P)[None, :]
176
+ bias = bias.expand(H, U, P).flatten()
177
+ if isinstance(module.bias, DTensor):
178
+ bias = distribute_tensor(bias, module.bias.device_mesh, module.bias.placements)
179
+ module.bias.to_local().copy_(bias.to_local())
180
+ else:
181
+ module.bias.copy_(bias.to(module.bias))
182
+ elif getattr(module, '_ramnet_output_gate', False):
183
+ torch.nn.init.constant_(module.bias, gate_initializer_bias)
184
+ else:
185
+ torch.nn.init.zeros_(module.bias)
186
+ elif isinstance(module, torch.nn.RMSNorm):
187
+ module.reset_parameters()
188
+ elif isinstance(module, RAMNetAttention):
189
+ for parameter in (module.r_scale, module.w_scale, getattr(module, 'gamma_modifier', None)):
190
+ if isinstance(parameter, torch.nn.Parameter):
191
+ torch.nn.init.zeros_(parameter)
192
+
193
+ def forward(
194
+ self,
195
+ hidden_states: torch.Tensor,
196
+ attention_mask: torch.Tensor | None = None,
197
+ past_key_values: RAMCache | None = None,
198
+ use_cache: bool = False,
199
+ output_attentions: bool = False,
200
+ position_ids: torch.Tensor | None = None,
201
+ ) -> tuple[torch.Tensor, None, RAMCache | None]:
202
+ """Run attention on (B, T, D) inputs using the model cache protocol."""
203
+ if hidden_states.ndim != 3:
204
+ raise ValueError('forward expects (B, T, D); use forward_with_state for other layouts.')
205
+ if output_attentions:
206
+ raise ValueError('RAMNetAttention does not materialize attention matrices.')
207
+ if use_cache and self.layer_idx is None:
208
+ raise ValueError('layer_idx is required when use_cache=True.')
209
+
210
+ if use_cache and past_key_values is None:
211
+ past_key_values = RAMCache()
212
+ cache_layer = None
213
+ if past_key_values is not None:
214
+ if self.layer_idx is None:
215
+ raise ValueError('layer_idx is required when reading a cache.')
216
+ if len(past_key_values) > self.layer_idx:
217
+ cache_layer = past_key_values.get_layer(self.layer_idx)
218
+
219
+ B, T, _ = hidden_states.shape
220
+ if T == 0:
221
+ raise ValueError('The sequence must contain at least one token.')
222
+ device = hidden_states.device
223
+ if cache_layer is not None and cache_layer.next_position is not None:
224
+ offset = cache_layer.next_position
225
+ else:
226
+ cache_length = cache_layer.get_seq_length() if cache_layer is not None else 0
227
+ offset = torch.full((B, 1), cache_length, device=device, dtype=torch.long)
228
+
229
+ mask = None
230
+ if attention_mask is not None:
231
+ if attention_mask.ndim != 2 or attention_mask.size(-1) < T:
232
+ raise ValueError('attention_mask must be a (B, T) token mask or include the cached prefix.')
233
+ attention_mask = attention_mask.to(device=device, dtype=torch.bool).expand(B, -1)
234
+ mask = attention_mask[:, -T:]
235
+
236
+ if position_ids is not None:
237
+ if position_ids.ndim not in (1, 2) or position_ids.size(-1) < T:
238
+ raise ValueError('position_ids must cover the current query.')
239
+ position_ids = position_ids.to(device=device, dtype=torch.long)[..., -T:].expand(B, T)
240
+ elif attention_mask is not None:
241
+ position_ids = attention_mask.long().cumsum(-1)[:, -T:] - 1
242
+ if attention_mask.size(-1) == T: # in case mask don't include prefix
243
+ position_ids = position_ids + offset
244
+ else:
245
+ position_ids = offset + torch.arange(T, device=device)
246
+
247
+ if mask is not None:
248
+ position_ids = position_ids.masked_fill(~mask, 0)
249
+
250
+ output, state = self.forward_with_state(
251
+ hidden_states,
252
+ init_ram=None if cache_layer is None else cache_layer.state,
253
+ mask=mask,
254
+ position_ids=position_ids,
255
+ inplace=None if use_cache else False,
256
+ )
257
+
258
+ if use_cache:
259
+ next_position = position_ids[:, -1:] + 1
260
+ if mask is not None:
261
+ # Keep the last valid position, including for fully masked chunks.
262
+ indices = torch.arange(T, device=device).expand(B, T).masked_fill(~mask, -1)
263
+ last = indices.amax(-1, keepdim=True)
264
+ next_position = torch.where(last >= 0, position_ids.gather(-1, last.clamp_min(0)) + 1, offset)
265
+ past_key_values.update(
266
+ recurrent_state=state,
267
+ layer_idx=self.layer_idx,
268
+ offset=T,
269
+ cache_kwargs={'next_position': next_position},
270
+ )
271
+
272
+ return output, None, past_key_values if use_cache else None
273
+
274
+ def forward_with_state(
275
+ self,
276
+ hidden_states: torch.Tensor,
277
+ init_ram: RAMState | tuple[torch.Tensor, torch.Tensor] | None = None,
278
+
279
+ mask: torch.Tensor | None = None,
280
+ position_ids: torch.Tensor | None = None,
281
+
282
+ t_dim: int = 1,
283
+ inplace: bool | None = False,
284
+ ) -> tuple[torch.Tensor, RAMState]:
285
+ """Return output and explicit state, without creating or updating a cache.
286
+
287
+ A (slot, mass) pair initializes RAM directly.
288
+ t_dim indexes a non-channel axis of hidden_states and its metadata.
289
+ """
290
+ if not -(hidden_states.ndim - 1) <= t_dim < hidden_states.ndim - 1:
291
+ raise ValueError('t_dim must index a non-channel axis of hidden_states.')
292
+ if hidden_states.size(t_dim) == 0:
293
+ raise ValueError('The sequence must contain at least one token.')
294
+ match init_ram:
295
+ case None:
296
+ init_slot, init_mass = None, self.init_mass
297
+ case (init_slot, init_mass):
298
+ pass
299
+ case _:
300
+ raise TypeError('init_ram must be None or a (slot, mass) pair.')
301
+
302
+ # project address and value
303
+ r_addr = einops.rearrange(self.r_proj(hidden_states), '... (h u p) -> ... h u p', h=self.n_heads, u=self.addr_order, p=self.addr_radix)
304
+ w_addr = einops.rearrange(self.w_proj(hidden_states), '... (h u p) -> ... h u p', h=self.n_heads, u=self.addr_order, p=self.addr_radix)
305
+ values = einops.rearrange(self.v_proj(hidden_states), '... (h c) -> ... h c', h=self.n_heads)
306
+
307
+ # apply address scale and temperature
308
+ r_addr = (torch.exp(self.r_scale) / self.addr_temperature).to(dtype=r_addr.dtype).unsqueeze(-1) * r_addr if self.r_scale is not None else r_addr / self.addr_temperature
309
+ w_addr = (torch.exp(self.w_scale) / self.addr_temperature).to(dtype=w_addr.dtype).unsqueeze(-1) * w_addr if self.r_scale is not None else w_addr / self.addr_temperature
310
+
311
+ # project forgetting modulator
312
+ gamma = self.gamma
313
+ if self.gamma_mode == 'learnable':
314
+ gamma = (self.gamma_modifier + gamma).to(dtype=values.dtype).expand(*values.shape[:-1])
315
+ if self.gamma_mode == 'dynamic':
316
+ gamma = self.gamma_modifier(hidden_states) + gamma
317
+
318
+ if inplace is None:
319
+ inplace = (
320
+ not self.training
321
+ and init_slot is not None
322
+ and all(not value.requires_grad for value in (r_addr, w_addr, values, gamma, init_slot, init_mass) if isinstance(value, torch.Tensor))
323
+ )
324
+
325
+ # run RAM-Attn
326
+ outputs, (slot, mass) = random_access_memory_attention(
327
+ w_addr=w_addr, r_addr=r_addr,
328
+ values=values, gamma=gamma,
329
+ init_ram=(init_slot, init_mass),
330
+ mask=mask, embed_num=self.embed_num, position_ids=position_ids,
331
+ top_k=self.top_k, top_k_re_norm=self.top_k_re_norm,
332
+ mass_aware=self.mass_aware, eps=self.ram_attn_eps,
333
+ t_dim=t_dim, inplace=inplace, impl_backend='cuda',
334
+ )
335
+
336
+ if self.o_norm is not None:
337
+ outputs = self.o_norm(outputs)
338
+
339
+ outputs = einops.rearrange(outputs, '... h c -> ... (h c)')
340
+
341
+ if self.o_gate is not None:
342
+ outputs = self.o_gate(hidden_states) * outputs
343
+
344
+ return self.o_proj(outputs), RAMState(slot, mass)
345
+
346
+ def extra_repr(self) -> str:
347
+ return (
348
+ f"{self.n_heads=}, U={self.addr_order}, P={self.addr_radix}, slots={self.addr_radix ** self.addr_order}, C={self.value_chs}, "
349
+ f"{self.addr_temperature=:.1f}, {self.gamma=:.1f}, {self.gamma_mode=}, "
350
+ f"{self.embed_num=}, {self.top_k=}, {self.top_k_re_norm=}"
351
+ ).replace("self.", '')
@@ -0,0 +1,10 @@
1
+ from transformers import AutoConfig, AutoModel, AutoModelForCausalLM
2
+
3
+ from .config_ramnet import RAMNetConfig
4
+ from .modeling_ramnet import RAMNetModel, RAMNetForCausalLM
5
+
6
+ AutoConfig.register(RAMNetConfig.model_type, RAMNetConfig, exist_ok=True)
7
+ AutoModel.register(RAMNetConfig, RAMNetModel, exist_ok=True)
8
+ AutoModelForCausalLM.register(RAMNetConfig, RAMNetForCausalLM, exist_ok=True)
9
+
10
+ __all__ = ['RAMNetConfig', 'RAMNetModel', 'RAMNetForCausalLM', ]