| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| """Model Architecture.""" |
|
|
| import functools |
| from typing import Any, Callable |
|
|
| from flax import linen as nn |
| from flax import struct |
| from jax import numpy as jnp |
|
|
| @struct.dataclass |
| class TransformerConfig: |
| """Global hyperparameters used to minimize obnoxious kwarg plumbing.""" |
| vocab_size: int = 1 |
| dtype: Any = jnp.float32 |
| emb_dim: int = 512 |
| num_heads: int = 8 |
| num_layers: int = 6 |
| qkv_dim: int = 512 |
| mlp_dim: int = 2048 |
| seq_len: int = 2048 |
| dropout_rate: float = 0.1 |
| attention_dropout_rate: float = 0.1 |
| deterministic: bool = False |
| num_latent_slots: int = 0 |
| |
| |
| |
| |
| inject_latents: bool = True |
|
|
| |
| class TransformerBlock(nn.Module): |
| config: Any = None |
|
|
| def setup(self): |
| self.vocab_size = self.config.vocab_size |
| self.emb_dim = self.config.emb_dim |
| self.num_layers = self.config.num_layers |
|
|
| @nn.compact |
| def __call__(self, inputs, causal_mask_inputs, training=True): |
| """ |
| Transformer Block call function. |
| |
| Args: |
| inputs: Input tensor. |
| causal_mask_inputs: Causal mask for the inputs. |
| training: Whether the model is in training mode. |
| |
| Returns: |
| Transformed tensor after self-attention and MLP layers. |
| """ |
| |
| x = inputs + nn.SelfAttention( |
| num_heads=self.config.num_heads, dtype=self.config.dtype, |
| qkv_features=self.config.qkv_dim, |
| kernel_init=nn.initializers.xavier_uniform(), |
| bias_init=nn.initializers.normal(stddev=1e-6), |
| use_bias=False, broadcast_dropout=False, |
| dropout_rate=self.config.attention_dropout_rate, normalize_qk=True, |
| deterministic=self.config.deterministic)(inputs, causal_mask_inputs) |
|
|
| def mlp(x): |
| """ |
| Multi-Layer Perceptron function. |
| |
| Args: |
| x: Input tensor. |
| |
| Returns: |
| Transformed tensor after applying MLP layers. |
| """ |
| dense_with_init = functools.partial( |
| nn.Dense, |
| kernel_init=nn.initializers.xavier_uniform(), |
| bias_init=nn.initializers.normal(stddev=1e-6) |
| ) |
| x = dense_with_init(features=self.config.mlp_dim)(x) |
| x = nn.gelu(x) |
| x = dense_with_init(features=self.config.emb_dim)(x) |
| x = nn.Dropout(rate=self.config.dropout_rate, |
| deterministic=self.config.deterministic)(x) |
| return x |
|
|
| x = x + mlp(x) |
| return x |
|
|
|
|
| class TransformerLMHeadModel(nn.Module): |
| config: Any = None |
|
|
| def setup(self): |
| self.vocab_size = self.config.vocab_size |
| self.emb_dim = self.config.emb_dim |
| self.num_layers = self.config.num_layers |
|
|
| @nn.compact |
| def __call__(self, inputs, latent_values=None, latent_positions=None, |
| latent_active=None, training=True): |
| """ |
| Transformer LM Head call function. |
| |
| Args: |
| inputs: Input token ids (batch, seq). |
| latent_values: Optional (batch, K, emb_dim) continuous thought |
| vectors (raw last-layer hiddens fed back, Coconut/ATC style). |
| latent_positions: Optional (batch, K) int positions of the latent |
| slots in the sequence (per-example, after the clue block). |
| latent_active: Optional (batch, K) bool; slot j uses the projected |
| latent vector when True, otherwise keeps the placeholder |
| token embedding. |
| training: Whether the model is in training mode. |
| |
| Returns: |
| (logits, hidden): LM logits and final (post-LayerNorm) hidden |
| states, the latter used to build the next continuous thought. |
| """ |
| batch_size, seq_size = inputs.shape |
|
|
| causal_mask_x = nn.make_causal_mask(inputs, dtype=self.config.dtype) |
|
|
| |
| embed_with_init = functools.partial( |
| nn.Embed, embedding_init=nn.initializers.normal(stddev=0.02)) |
| token_embeddings = embed_with_init( |
| num_embeddings=self.config.vocab_size, |
| features=self.config.emb_dim, |
| )(inputs) |
|
|
| |
| assert token_embeddings.shape == (batch_size, seq_size, |
| self.config.emb_dim) |
|
|
| |
| |
| |
| |
| |
| |
| if latent_values is not None and self.config.inject_latents: |
| proj = nn.Dense(features=self.config.emb_dim, |
| kernel_init=nn.initializers.xavier_uniform(), |
| name="latent_proj_in")(latent_values) |
| proj = nn.gelu(proj) |
| proj = nn.Dense(features=self.config.emb_dim, |
| kernel_init=nn.initializers.xavier_uniform(), |
| name="latent_proj_out")(proj) |
| bidx = jnp.arange(batch_size)[:, None] |
| cur = token_embeddings[bidx, latent_positions] |
| new = jnp.where(latent_active[..., None], |
| proj.astype(cur.dtype), cur) |
| token_embeddings = token_embeddings.at[ |
| bidx, latent_positions].set(new) |
|
|
| |
| pos_embedding_variable = self.variable( |
| "params", |
| "position_embeddings", |
| jnp.zeros, |
| (self.config.seq_len, self.config.emb_dim), |
| ) |
|
|
| |
| pos_embeddings = pos_embedding_variable.value[:seq_size, :] |
|
|
| |
| output_tuple = (pos_embeddings.shape, token_embeddings.shape[1:]) |
| assert pos_embeddings.shape == token_embeddings.shape[1:], output_tuple |
|
|
| |
| x = token_embeddings + pos_embeddings[None, :, :] |
|
|
| |
| x = nn.Dropout(rate=self.config.dropout_rate, |
| deterministic=self.config.deterministic)(x) |
|
|
| |
| |
| RematBlock = nn.remat(TransformerBlock) |
| for i in range(self.num_layers): |
| x = RematBlock(config=self.config)( |
| x, causal_mask_x, training=training) |
| |
| self.sow('intermediates', 'feature_' + str(i), x) |
|
|
| |
| x = nn.LayerNorm()(x) |
|
|
| |
| logits = nn.Dense(features=self.config.vocab_size, |
| kernel_init=nn.initializers.xavier_uniform(), |
| bias_init=nn.initializers.normal(stddev=1e-6), |
| use_bias=False)(x) |
|
|
| |
| assert logits.shape == (batch_size, seq_size, self.config.vocab_size) |
|
|
| |
| |
| |
| |
| |
| cand_logits = None |
| if latent_positions is not None: |
| bidx = jnp.arange(batch_size)[:, None] |
| slot_hidden = x[bidx, latent_positions] |
| h = nn.Dense(features=self.config.emb_dim, |
| kernel_init=nn.initializers.xavier_uniform(), |
| name="cand_head_in")(slot_hidden) |
| h = nn.gelu(h) |
| cand_logits = nn.Dense(features=81 * 9, |
| kernel_init=nn.initializers.xavier_uniform(), |
| name="cand_head_out")(h) |
| cand_logits = cand_logits.reshape( |
| batch_size, -1, 81, 9) |
|
|
| return logits, x, cand_logits |
|
|