| import math |
| from functools import partial |
| from typing import Optional |
|
|
| import jax |
| import jax.numpy as jnp |
| import flax.linen as nn |
| from einops import rearrange, repeat |
|
|
|
|
| |
| |
| |
| |
| DEFAULT_KERNEL_INIT = nn.initializers.xavier_uniform() |
| DEFAULT_BIAS_INIT = nn.initializers.constant(0.0) |
| ZERO_INIT = nn.initializers.constant(0.0) |
| NORMAL_INIT_002 = nn.initializers.normal(stddev=0.02) |
|
|
|
|
| def rotate_half(x): |
| """Rotate half the hidden dims of the input.""" |
| x = rearrange(x, '... (d r) -> ... d r', r=2) |
| x1, x2 = jnp.split(x, 2, axis=-1) |
| x1 = x1.squeeze(-1) |
| x2 = x2.squeeze(-1) |
| x = jnp.stack((-x2, x1), axis=-1) |
| return rearrange(x, '... d r -> ... (d r)') |
|
|
|
|
| class TextRotaryEmbeddingFast(nn.Module): |
| """1D Rotary Position Embedding for text/sequence models in JAX/Flax.""" |
| dim: int |
| pt_seq_len: int = 512 |
| ft_seq_len: Optional[int] = None |
| theta: float = 10000 |
| num_empty_token: int = 0 |
|
|
| @nn.compact |
| def __call__(self, t): |
| dim = self.dim |
| pt_seq_len = self.pt_seq_len |
| ft_seq_len = self.ft_seq_len if self.ft_seq_len is not None else pt_seq_len |
|
|
| |
| freqs = 1. / (self.theta ** (jnp.arange(0, dim, 2)[:dim // 2].astype(jnp.float32) / dim)) |
|
|
| pos = jnp.arange(ft_seq_len) / ft_seq_len * pt_seq_len |
|
|
| |
| freqs_main = jnp.einsum('..., f -> ... f', pos, freqs) |
| freqs_main = repeat(freqs_main, '... n -> ... (n r)', r=2) |
|
|
| D = freqs_main.shape[-1] |
| cos_parts = [] |
| sin_parts = [] |
|
|
| |
| if self.num_empty_token > 0: |
| cos_parts.append(jnp.ones((self.num_empty_token, D), dtype=freqs.dtype)) |
| sin_parts.append(jnp.zeros((self.num_empty_token, D), dtype=freqs.dtype)) |
|
|
| |
| cos_parts.append(jnp.cos(freqs_main)) |
| sin_parts.append(jnp.sin(freqs_main)) |
|
|
| freqs_cos = jnp.concatenate(cos_parts, axis=0) if len(cos_parts) > 1 else cos_parts[0] |
| freqs_sin = jnp.concatenate(sin_parts, axis=0) if len(sin_parts) > 1 else sin_parts[0] |
|
|
| return t * freqs_cos + rotate_half(t) * freqs_sin |
|
|
|
|
| class RMSNorm(nn.Module): |
| """RMS Normalization layer for JAX/Flax.""" |
| hidden_size: int |
| eps: float = 1e-6 |
|
|
| @nn.compact |
| def __call__(self, hidden_states): |
| weight = self.param('weight', nn.initializers.ones, (self.hidden_size,)) |
|
|
| input_dtype = hidden_states.dtype |
| hidden_states = hidden_states.astype(jnp.float32) |
| variance = jnp.mean(hidden_states ** 2, axis=-1, keepdims=True) |
| hidden_states = hidden_states * jax.lax.rsqrt(variance + self.eps) |
| return (weight * hidden_states).astype(input_dtype) |
|
|
|
|
| class BottleneckTextProj(nn.Module): |
| """Text projection with bottleneck.""" |
| text_encoder_dim: int |
| hidden_size: int |
| bottleneck_dim: int |
|
|
| @nn.compact |
| def __call__(self, x): |
| x = nn.Dense(self.bottleneck_dim, use_bias=False, kernel_init=DEFAULT_KERNEL_INIT, name='proj1')(x) |
| return nn.Dense( |
| self.hidden_size, use_bias=True, |
| kernel_init=DEFAULT_KERNEL_INIT, bias_init=DEFAULT_BIAS_INIT, name='proj2', |
| )(x) |
|
|
|
|
| class TimestepEmbedder(nn.Module): |
| """Embeds scalar timesteps into vector representations.""" |
| hidden_size: int |
| frequency_embedding_size: int = 256 |
|
|
| @nn.compact |
| def __call__(self, t): |
| dense = partial( |
| nn.Dense, self.hidden_size, use_bias=True, |
| kernel_init=NORMAL_INIT_002, bias_init=DEFAULT_BIAS_INIT, |
| ) |
| t_emb = dense(name='mlp_0')(self.timestep_embedding(t, self.frequency_embedding_size)) |
| return dense(name='mlp_2')(nn.silu(t_emb)) |
|
|
| @staticmethod |
| def timestep_embedding(t, dim, max_period=10000): |
| """Sinusoidal timestep embeddings: (N,) ints -> (N, dim) floats.""" |
| half = dim // 2 |
| freqs = jnp.exp(-math.log(max_period) * jnp.arange(0, half, dtype=jnp.float32) / half) |
| args = t[:, None].astype(jnp.float32) * freqs[None] |
| embedding = jnp.concatenate([jnp.cos(args), jnp.sin(args)], axis=-1) |
| if dim % 2: |
| embedding = jnp.concatenate([embedding, jnp.zeros_like(embedding[:, :1])], axis=-1) |
| return embedding |
|
|
|
|
| def scaled_dot_product_attention(query, key, value, attn_mask=None): |
| """Scaled dot-product attention. |
| |
| query/key/value: (B, num_heads, L|S, head_dim). |
| attn_mask: optional int mask (B, S) or (B, L, S); 1=valid, 0=masked. |
| Returns: (B, num_heads, L, head_dim). |
| """ |
| scale_factor = 1 / math.sqrt(query.shape[-1]) |
| attn_weight = jnp.einsum( |
| 'bhld,bhsd->bhls', query.astype(jnp.float32), key.astype(jnp.float32), |
| ) * scale_factor |
| if attn_mask is not None: |
| if attn_mask.ndim == 2: |
| mask = attn_mask[:, None, None, :] |
| elif attn_mask.ndim == 3: |
| mask = attn_mask[:, None, :, :] |
| else: |
| mask = attn_mask |
| attn_weight = jnp.where(mask == 0, -1e9, attn_weight) |
| attn_weight = jax.nn.softmax(attn_weight, axis=-1) |
| return jnp.einsum('bhls,bhsd->bhld', attn_weight, value) |
|
|
|
|
| class Attention(nn.Module): |
| """Multi-head self-attention.""" |
| dim: int |
| num_heads: int = 8 |
| qkv_bias: bool = True |
| qk_norm: bool = True |
| attn_drop: float = 0.0 |
| proj_drop: float = 0.0 |
|
|
| @nn.compact |
| def __call__(self, x, rope_fn, attention_mask=None, deterministic=True): |
| """x: (B, N, C). attention_mask: optional int mask (B, N), 1=valid, 0=padded.""" |
| B, N, C = x.shape |
| head_dim = self.dim // self.num_heads |
| bias_init = DEFAULT_BIAS_INIT if self.qkv_bias else None |
| qkv = nn.Dense( |
| self.dim * 3, use_bias=self.qkv_bias, |
| kernel_init=DEFAULT_KERNEL_INIT, bias_init=bias_init, name='qkv', |
| )(x) |
| qkv = qkv.reshape(B, N, 3, self.num_heads, head_dim).transpose(2, 0, 3, 1, 4) |
| q, k, v = qkv[0], qkv[1], qkv[2] |
| if self.qk_norm: |
| q = RMSNorm(head_dim, name='q_norm')(q) |
| k = RMSNorm(head_dim, name='k_norm')(k) |
| if rope_fn is not None: |
| q = rope_fn(q) |
| k = rope_fn(k) |
| x = scaled_dot_product_attention(q, k, v, attn_mask=attention_mask) |
| x = x.transpose(0, 2, 1, 3).reshape(B, N, C) |
| x = nn.Dense(self.dim, kernel_init=DEFAULT_KERNEL_INIT, bias_init=DEFAULT_BIAS_INIT, name='proj')(x) |
| return nn.Dropout(rate=self.proj_drop, deterministic=deterministic)(x) |
|
|
|
|
| class SwiGLUFFN(nn.Module): |
| """SwiGLU Feed-Forward Network.""" |
| dim: int |
| hidden_dim: int |
| drop: float = 0.0 |
| bias: bool = True |
|
|
| @nn.compact |
| def __call__(self, x, deterministic=True): |
| hidden_dim = int(self.hidden_dim * 2 / 3) |
| bias_init = DEFAULT_BIAS_INIT if self.bias else None |
| dense = partial(nn.Dense, use_bias=self.bias, kernel_init=DEFAULT_KERNEL_INIT, bias_init=bias_init) |
| x12 = dense(2 * hidden_dim, name='w12')(x) |
| x1, x2 = jnp.split(x12, 2, axis=-1) |
| hidden = nn.Dropout(rate=self.drop, deterministic=deterministic)(nn.silu(x1) * x2) |
| return dense(self.dim, name='w3')(hidden) |
|
|
|
|
| class FinalLayer(nn.Module): |
| """The final layer of ELF.""" |
| hidden_size: int |
| patch_size: int |
| out_channels: int |
|
|
| @nn.compact |
| def __call__(self, x): |
| x = RMSNorm(self.hidden_size, name='norm_final')(x) |
| return nn.Dense( |
| self.patch_size * self.patch_size * self.out_channels, use_bias=True, |
| kernel_init=ZERO_INIT, bias_init=ZERO_INIT, name='linear', |
| )(x) |
|
|