echo / code /flash-linear-attention /tests /ops /test_titans.py
amonshano's picture
Add Echo-Memory codebase used for this run (CC BY 4.0, JD Echo Team) (part 4)
c335050 verified
Raw
History Blame Contribute Delete
3.69 kB
import pytest
import torch
import torch.nn.functional as F
from fla.ops.titans.naive import chunk_titans_linear_ref
from fla.utils import assert_close, device
def initialize_chunked_param(B, H, T, BT, dtype=torch.float32):
# Calculate number of complete chunks and remaining elements
num_complete_chunks = T // BT
remainder = T % BT
# Initialize for complete chunks
if num_complete_chunks > 0:
theta_chunks = torch.rand(B, H, num_complete_chunks, 1, dtype=dtype)
theta_main = theta_chunks.repeat_interleave(
BT, dim=2,
) # Shape: (B, H, num_complete_chunks*BT, 1)
else:
theta_main = torch.empty(B, H, 0, 1, dtype=dtype)
# Handle remaining elements if any
if remainder > 0:
theta_remainder = torch.rand(B, H, 1, 1, dtype=dtype)
theta_remainder = theta_remainder.repeat_interleave(
remainder, dim=2,
) # Shape: (B, H, remainder, 1)
# Concatenate main chunks with remainder
theta = torch.cat([theta_main, theta_remainder], dim=2)
else:
theta = theta_main
return theta
@pytest.mark.parametrize(
('B', 'T', 'H', 'D', 'dtype'),
[
pytest.param(*test, id="B{}-T{}-H{}-D{}-{}".format(*test))
for test in [
(1, 63, 1, 64, torch.float16),
(2, 100, 4, 60, torch.float16),
(2, 1024, 3, 128, torch.float16),
(3, 2000, 4, 128, torch.float16),
(4, 2048, 8, 64, torch.float16),
]
],
)
@pytest.mark.skipif(
True, reason='FIXME',
)
def test_naive_chunk(
B: int,
T: int,
H: int,
D: int,
dtype: torch.dtype,
):
BT = 64
# set seed
torch.manual_seed(1)
# we don't use such initialization in the original code
# theta = initialize_chunked_param(B, H, T, BT, dtype)
# alpha = initialize_chunked_param(B, H, T, BT, dtype)
# eta = initialize_chunked_param(B, H, T, BT, dtype)
theta = torch.rand(B, H, T, 1, dtype=dtype)
alpha = torch.rand(B, H, T, 1, dtype=dtype)
eta = torch.rand(B, H, T, 1, dtype=dtype)
# titans normalize queries and keys using ℓ2-normalization
q = F.normalize(torch.randn(B, H, T, D, dtype=torch.float32), p=2, dim=-1).to(dtype)
k = F.normalize(torch.randn(B, H, T, D, dtype=torch.float32), p=2, dim=-1).to(dtype)
v = torch.randn(B, H, T, D, dtype=dtype)
w = torch.randn(H, D, dtype=dtype)
b = torch.randn(H, D, dtype=dtype)
h0 = torch.randn(B, H, D, D, dtype=torch.float32)
q = q.permute(0, 2, 1, 3)
k = k.permute(0, 2, 1, 3)
v = v.permute(0, 2, 1, 3)
theta = theta.permute(0, 2, 1, 3)
alpha = alpha.permute(0, 2, 1, 3)
eta = eta.permute(0, 2, 1, 3)
q, k, v, w, b, theta, alpha, eta = map(
lambda x: x.to(device).requires_grad_(False), (q, k, v, w, b, theta, alpha, eta),
)
# in titans paper, h0 is not learnable
h0 = h0.to(device)
ref_naive, ref_ht_naive = chunk_titans_linear_ref(
q.clone(),
k.clone(),
v.clone(),
w.clone(),
b.clone(),
theta.clone(),
alpha.clone(),
eta.clone(),
output_final_state=True,
chunk_size=BT,
initial_state=h0.clone(),
use_chunk=False,
)
ref, ref_ht = chunk_titans_linear_ref(
q.clone(),
k.clone(),
v.clone(),
w.clone(),
b.clone(),
theta.clone(),
alpha.clone(),
eta.clone(),
output_final_state=True,
chunk_size=BT,
initial_state=h0.clone(),
use_chunk=True,
)
assert_close(" o", ref, ref_naive, 0.006)
assert_close("ht", ref_ht, ref_ht_naive, 0.005)