|
|
|
|
| import torch |
| from einops import rearrange |
|
|
|
|
| def naive_recurrent_kda( |
| q: torch.Tensor, |
| k: torch.Tensor, |
| v: torch.Tensor, |
| g: torch.Tensor, |
| beta: torch.Tensor, |
| scale: float | None = None, |
| initial_state: torch.Tensor | None = None, |
| output_final_state: bool = False, |
| ): |
| dtype = v.dtype |
| B, T, H, K, V = *q.shape, v.shape[-1] |
| if scale is None: |
| scale = K ** -0.5 |
|
|
| q, k, v, g, beta = map(lambda x: x.to(torch.float), [q, k, v, g, beta]) |
| q = q * scale |
|
|
| S = k.new_zeros(B, H, K, V).to(q) |
| if initial_state is not None: |
| S += initial_state |
| o = torch.zeros_like(v) |
| for i in range(0, T): |
| q_i, k_i, v_i, g_i, b_i = q[:, i], k[:, i], v[:, i], g[:, i], beta[:, i] |
| S = S * g_i[..., None].exp() |
| S = S + torch.einsum('b h k, b h v -> b h k v', b_i[..., None] * k_i, v_i - (k_i[..., None] * S).sum(-2)) |
| o[:, i] = torch.einsum('b h k, b h k v -> b h v', q_i, S) |
| if not output_final_state: |
| S = None |
| return o.to(dtype), S |
|
|
|
|
| def naive_chunk_kda( |
| q: torch.Tensor, |
| k: torch.Tensor, |
| v: torch.Tensor, |
| g: torch.Tensor, |
| beta: torch.Tensor, |
| scale: float | None = None, |
| initial_state: torch.Tensor | None = None, |
| output_final_state: bool = False, |
| chunk_size: int = 64, |
| ): |
| dtype = v.dtype |
| B, T, H, K, V = *q.shape, v.shape[-1] |
| BT = chunk_size |
| NT = T // BT |
| if scale is None: |
| scale = K ** -0.5 |
| assert T % BT == 0 |
|
|
| q, k, v, g, beta = map(lambda x: rearrange(x, 'b (n c) h ... -> b h n c ...', c=BT).to(torch.float), [q, k, v, g, beta]) |
| q = q * scale |
| g = g.cumsum(-2) |
|
|
| |
| mask = torch.triu(torch.ones(BT, BT, dtype=torch.bool, device=q.device), diagonal=0) |
|
|
| A = torch.zeros(*q.shape[:-1], BT, dtype=torch.float, device=q.device) |
| for i in range(BT): |
| k_i = k[..., i, :] |
| g_i = g[..., i:i+1, :] |
| A[..., i] = torch.einsum('... c d, ... d -> ... c', k * (g - g_i).exp(), k_i) |
| A = A * beta[..., None] |
|
|
| A = -A.masked_fill(mask, 0) |
| for i in range(1, BT): |
| A[..., i, :i] = A[..., i, :i].clone() + (A[..., i, :, None].clone() * A[..., :, :i].clone()).sum(-2) |
| A = (A + torch.eye(BT, dtype=torch.float, device=q.device)) * beta[..., None, :] |
|
|
| w = A @ (g.exp() * k) |
| u = A @ v |
|
|
| S = k.new_zeros(B, H, K, V).to(q) |
| if initial_state is not None: |
| S += initial_state |
| o = torch.zeros_like(v) |
| mask = torch.triu(torch.ones(BT, BT, dtype=torch.bool, device=q.device), diagonal=1) |
| for i in range(0, NT): |
| |
| q_i, k_i, u_i, g_i, w_i = q[:, :, i], k[:, :, i], u[:, :, i], g[:, :, i], w[:, :, i] |
| A = torch.zeros(B, H, BT, BT, dtype=torch.float, device=q.device) |
| for j in range(BT): |
| k_j = k[:, :, i, j] |
| g_j = g[:, :, i, j:j+1, :] |
| A[..., j] = torch.einsum('... c d, ... d -> ... c', q_i * (g_i - g_j).exp(), k_j) |
| A = A.masked_fill(mask, 0) |
| v_i = u_i - w_i @ S |
| o[:, :, i] = (q_i * g_i.exp()) @ S + A @ v_i |
| S = S * rearrange(g_i[:, :, -1].exp(), 'b h k -> b h k 1') |
| S += rearrange((g_i[:, :, -1:] - g_i).exp() * k_i, 'b h c k -> b h k c') @ v_i |
| if not output_final_state: |
| S = None |
| return rearrange(o, 'b h n c d -> b (n c) h d').to(dtype), S |
|
|