forgewm-world-model / wan /modules /action_module.py
multimodalart's picture
multimodalart HF Staff
SDPA fallback for flash_attn_func in the action module
3d2e374 verified
Raw History Blame Contribute Delete
29.8 kB
from typing import Any, List, Tuple, Optional, Union, Dict
from einops import rearrange
import torch
import torch.nn as nn
from .posemb_layers import apply_rotary_emb, get_nd_rotary_pos_embed
import math
from torch.nn.attention.flex_attention import flex_attention
try:
import flash_attn_interface
FLASH_ATTN_3_AVAILABLE = torch.cuda.is_available() and (
"h100" in torch.cuda.get_device_name(0).lower()
or "hopper" in torch.cuda.get_device_name(0).lower())
except ModuleNotFoundError:
FLASH_ATTN_3_AVAILABLE = False
try:
from flash_attn import flash_attn_func
except ModuleNotFoundError:
# No FlashAttention wheel on this platform. Every call site below runs
# without a causal flag or a sliding window (causality is enforced by the
# KV-cache layout, not the kernel), so PyTorch SDPA is a numerically
# equivalent substitute.
from .attention import sdpa_flash_attn_func as flash_attn_func
DISABLE_COMPILE = False # get os env
flex_attention = torch.compile(
flex_attention, dynamic=False, mode="max-autotune-no-cudagraphs")
class WanRMSNorm(nn.Module):
def __init__(self, dim, eps=1e-5):
super().__init__()
self.dim = dim
self.eps = eps
self.weight = nn.Parameter(torch.ones(dim))
def forward(self, x):
r"""
Args:
x(Tensor): Shape [B, L, C]
"""
return x * torch.rsqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps)
class ActionModule(nn.Module):
"""
action module from https://arxiv.org/pdf/2501.08325
鼠标控制信号的输入是一个 L*D 的向量
键盘同样
"""
def __init__(
self,
mouse_dim_in: int = 2,
keyboard_dim_in: int = 6,
hidden_size: int = 128,
img_hidden_size: int = 1536,
keyboard_hidden_dim: int = 1024,
mouse_hidden_dim: int = 1024,
vae_time_compression_ratio: int = 4,
windows_size: int = 3,
heads_num: int = 16,
patch_size: list = [1, 2, 2],
qk_norm: bool = True,
qkv_bias: bool = False,
rope_dim_list: list = [8, 28, 28],
rope_theta = 256,
mouse_qk_dim_list = [8, 28, 28],
enable_mouse = True,
enable_keyboard = True,
local_attn_size = 6,
blocks = [],
):
device = None
super().__init__()
self.local_attn_size = local_attn_size
self.enable_mouse = enable_mouse
self.enable_keyboard = enable_keyboard
self.rope_dim_list = rope_dim_list
self.rope_theta = rope_theta
if self.enable_keyboard:
self.keyboard_embed = nn.Sequential(nn.Linear(keyboard_dim_in, hidden_size, bias=True), nn.SiLU(), nn.Linear(hidden_size, hidden_size, bias=True))
self.mouse_qk_dim_list = mouse_qk_dim_list
self.heads_num = heads_num
if self.enable_mouse:
c = mouse_hidden_dim
self.mouse_mlp = torch.nn.Sequential(
torch.nn.Linear(mouse_dim_in * vae_time_compression_ratio * windows_size + img_hidden_size, c, bias=True),
torch.nn.GELU(approximate="tanh"),
torch.nn.Linear(c, c),
torch.nn.LayerNorm(c),
)
head_dim = c // heads_num
self.t_qkv = nn.Linear(c, c*3, bias=qkv_bias)
self.img_attn_q_norm = (
WanRMSNorm(head_dim, eps=1e-6)
if qk_norm
else nn.Identity()
)
self.img_attn_k_norm = (
WanRMSNorm(head_dim, eps=1e-6)
if qk_norm
else nn.Identity()
)
self.proj_mouse = nn.Linear(c, img_hidden_size, bias=qkv_bias)
if self.enable_keyboard:
head_dim_key = keyboard_hidden_dim // heads_num
self.key_attn_q_norm = (
WanRMSNorm(head_dim_key, eps=1e-6)
if qk_norm
else nn.Identity()
)
self.key_attn_k_norm = (
WanRMSNorm(head_dim_key, eps=1e-6)
if qk_norm
else nn.Identity()
)
self.mouse_attn_q = nn.Linear(img_hidden_size, keyboard_hidden_dim, bias=qkv_bias)
self.keyboard_attn_kv = nn.Linear(hidden_size * windows_size * vae_time_compression_ratio, keyboard_hidden_dim * 2, bias=qkv_bias)
self.proj_keyboard = nn.Linear(keyboard_hidden_dim, img_hidden_size, bias=qkv_bias)
self.vae_time_compression_ratio = vae_time_compression_ratio
self.windows_size = windows_size
self.patch_size = patch_size
self.freqs_cos, self.freqs_sin = self.get_rotary_pos_embed(7500, self.patch_size[1], self.patch_size[2], 64, self.mouse_qk_dim_list, start_offset=0)
def patchify(self, x, patch_size):
"""
x : (N C T H W)
"""
pt, ph, pw = self.patch_size
t, h, w = x.shape[2] // pt, x.shape[3] // ph, x.shape[4] // pw
c = x.shape[1]
x = x.reshape(shape=(x.shape[0], c, t , pt, h , ph, w , pw))
x = torch.einsum("nctohpwq->nthwcopq", x)
x = x.reshape(shape=(x.shape[0], t*h*w, c*pt*ph*pw))
return x
def unpatchify(self, x, t, h, w, patch_size):
"""
x: (N, T, patch_size**2 * C)
imgs: (N, H, W, C)
"""
c = x.shape[2] // patch_size #self.unpatchify_channels
pt, ph, pw = self.patch_size
assert t * h * w == x.shape[1]
x = x.reshape(shape=(x.shape[0], t, h, w, c, pt, ph, pw))
x = torch.einsum("nthwcopq->nctohpwq", x)
imgs = x.reshape(shape=(x.shape[0], c, t * pt, h * ph, w * pw))
return imgs
def get_rotary_pos_embed(self, video_length, height, width, head_dim, rope_dim_list = None, start_offset=0):
target_ndim = 3
ndim = 5 - 2
latents_size = [video_length+start_offset, height, width]
if isinstance(self.patch_size, int):
assert all(s % self.patch_size == 0 for s in latents_size), (
f"Latent size(last {ndim} dimensions) should be divisible by patch size({self.patch_size}), "
f"but got {latents_size}."
)
rope_sizes = [s // self.patch_size for s in latents_size]
elif isinstance(self.patch_size, list):
assert all(
s % self.patch_size[idx] == 0
for idx, s in enumerate(latents_size)
), (
f"Latent size(last {ndim} dimensions) should be divisible by patch size({self.patch_size}), "
f"but got {latents_size}."
)
rope_sizes = [
s // self.patch_size[idx] for idx, s in enumerate(latents_size)
]
if len(rope_sizes) != target_ndim:
rope_sizes = [1] * (target_ndim - len(rope_sizes)) + rope_sizes # time axis
if rope_dim_list is None:
rope_dim_list = [head_dim // target_ndim for _ in range(target_ndim)]
assert (
sum(rope_dim_list) == head_dim
), "sum(rope_dim_list) should equal to head_dim of attention layer"
freqs_cos, freqs_sin = get_nd_rotary_pos_embed(
rope_dim_list,
rope_sizes,
theta=self.rope_theta,
use_real=True,
theta_rescale_factor=1,
)
return freqs_cos[-video_length*rope_sizes[1]*rope_sizes[2]//self.patch_size[0]:], freqs_sin[-video_length*rope_sizes[1]*rope_sizes[2]//self.patch_size[0]:]
def forward(self, x, tt, th, tw, mouse_condition=None, keyboard_condition=None, block_mask_mouse=None, block_mask_keyboard=None, is_causal=False, kv_cache_mouse=None, kv_cache_keyboard=None, start_frame=0, use_rope_keyboard=True, num_frame_per_block=3):
'''
hidden_states: B, tt*th*tw, C
mouse_condition: B, N_frames, C1
keyboard_condition: B, N_frames, C2
'''
assert use_rope_keyboard == True
B, N_frames, C = keyboard_condition.shape
assert tt*th*tw == x.shape[1]
assert ((N_frames - 1) + self.vae_time_compression_ratio) % self.vae_time_compression_ratio == 0
N_feats = int((N_frames - 1) / self.vae_time_compression_ratio) + 1
# Defined freqs_cis early so it's available for both mouse and keyboard
freqs_cis = (self.freqs_cos, self.freqs_sin)
if not ((N_feats == tt and ((is_causal and kv_cache_mouse == None) or not is_causal)) or ((N_frames - 1) // self.vae_time_compression_ratio + 1 == start_frame + num_frame_per_block and is_causal)):
import os
if os.environ.get("RANK", "0") == "0":
print(f"[DEBUG action_module assert] N_frames={N_frames} N_feats={N_feats} tt={tt} start_frame={start_frame} num_frame_per_block={num_frame_per_block} is_causal={is_causal} kv_cache_mouse_is_None={kv_cache_mouse is None}", flush=True)
assert (N_feats == tt and ((is_causal and kv_cache_mouse == None) or not is_causal)) or ((N_frames - 1) // self.vae_time_compression_ratio + 1 == start_frame + num_frame_per_block and is_causal)
if self.enable_mouse and mouse_condition is not None:
hidden_states = rearrange(x, "B (T S) C -> (B S) T C", T=tt, S=th*tw) # 65*272*480 -> 17*(272//16)*(480//16) -> 8670
B, N_frames, C = mouse_condition.shape
else:
hidden_states = x
# padding
pad_t = self.vae_time_compression_ratio * self.windows_size
if self.enable_mouse and mouse_condition is not None:
pad = mouse_condition[:, 0:1, :].expand(-1, pad_t, -1)
mouse_condition = torch.cat([pad, mouse_condition], dim=1)
if is_causal and kv_cache_mouse is not None:
mouse_condition = mouse_condition[:, self.vae_time_compression_ratio*(N_feats - num_frame_per_block - self.windows_size) + pad_t:, :]
group_mouse = [mouse_condition[:, self.vae_time_compression_ratio*(i - self.windows_size) + pad_t:i * self.vae_time_compression_ratio + pad_t,:] for i in range(num_frame_per_block)]
else:
group_mouse = [mouse_condition[:, self.vae_time_compression_ratio*(i - self.windows_size) + pad_t:i * self.vae_time_compression_ratio + pad_t,:] for i in range(N_feats)]
group_mouse = torch.stack(group_mouse, dim = 1)
group_frame_count = group_mouse.shape[1]
S = th * tw
group_mouse = group_mouse.unsqueeze(-1).expand(B, group_frame_count, pad_t, C, S)
group_mouse = group_mouse.permute(0, 4, 1, 2, 3).reshape(B * S, group_frame_count, pad_t * C)
group_mouse = torch.cat([hidden_states, group_mouse], dim = -1)
group_mouse = self.mouse_mlp(group_mouse)
# qkv
mouse_qkv = self.t_qkv(group_mouse)
q, k, v = rearrange(mouse_qkv, "B L (K H D) -> K B L H D", K=3, H=self.heads_num) # BHW F H C
q = self.img_attn_q_norm(q).to(v)
k = self.img_attn_k_norm(k).to(v)
# rope embd
# freqs_cis = (self.freqs_cos, self.freqs_sin)
q, k = apply_rotary_emb(q, k, freqs_cis, start_offset = start_frame, head_first=False)
## TODO: adding cache here
if is_causal:
if kv_cache_mouse is None:
assert q.shape[0] == k.shape[0] and q.shape[0] % S == 0
padded_length = math.ceil(q.shape[1] / 32) * 32 - q.shape[1]
padded_q = torch.cat(
[q,
torch.zeros([q.shape[0], padded_length, q.shape[2], q.shape[3]],
device=q.device, dtype=v.dtype)],
dim=1
)
padded_k = torch.cat(
[k, torch.zeros([k.shape[0], padded_length, k.shape[2], k.shape[3]],
device=k.device, dtype=v.dtype)],
dim=1
)
padded_v = torch.cat(
[v, torch.zeros([v.shape[0], padded_length, v.shape[2], v.shape[3]],
device=v.device, dtype=v.dtype)],
dim=1
)
attn = flex_attention(
query=padded_q.transpose(2, 1), # after: B, HW, F, C
key=padded_k.transpose(2, 1),
value=padded_v.transpose(2, 1),
block_mask=block_mask_mouse
)[:, :, :-padded_length].transpose(2, 1)
else:
current_start = start_frame
current_end = current_start + q.shape[1]
assert q.shape[1] == num_frame_per_block
sink_size = 0
max_attention_size = self.local_attn_size if self.local_attn_size != -1 else 15
sink_tokens = sink_size * 1
kv_cache_size = kv_cache_mouse["k"].shape[1]
num_new_tokens = q.shape[1]
# Guard eviction on sliding-window mode only (mirror of main
# kv_cache fix in causal_model.py). In full-causal (-1), the
# cache is sized to fit the whole rollout; rolling it in-place
# during training breaks backward.
if self.local_attn_size != -1 and (current_end > kv_cache_mouse["global_end_index"].item()) and (
num_new_tokens + kv_cache_mouse["local_end_index"].item() > kv_cache_size):
num_evicted_tokens = num_new_tokens + kv_cache_mouse["local_end_index"].item() - kv_cache_size
num_rolled_tokens = kv_cache_mouse["local_end_index"].item() - num_evicted_tokens - sink_tokens
kv_cache_mouse["k"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \
kv_cache_mouse["k"][:, sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone()
kv_cache_mouse["v"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \
kv_cache_mouse["v"][:, sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone()
# Insert the new keys/values at the end
local_end_index = kv_cache_mouse["local_end_index"].item() + current_end - \
kv_cache_mouse["global_end_index"].item() - num_evicted_tokens
local_start_index = local_end_index - num_new_tokens
else:
local_end_index = kv_cache_mouse["local_end_index"].item() + current_end - kv_cache_mouse["global_end_index"].item()
local_start_index = local_end_index - num_new_tokens
kv_cache_mouse["k"][:, local_start_index:local_end_index] = k
kv_cache_mouse["v"][:, local_start_index:local_end_index] = v
# Clone slices under grad to isolate saved_tensors from
# future in-place writes to kv_cache_mouse (see main
# causal_model.py for rationale).
_km = kv_cache_mouse["k"][:, max(0, local_end_index - max_attention_size):local_end_index]
_vm = kv_cache_mouse["v"][:, max(0, local_end_index - max_attention_size):local_end_index]
if torch.is_grad_enabled():
_km = _km.clone()
_vm = _vm.clone()
if FLASH_ATTN_3_AVAILABLE:
attn, attn_prob = flash_attn_interface.flash_attn_func(
q, _km, _vm,
)
else:
attn = flash_attn_func(
q, _km, _vm,
)
kv_cache_mouse["global_end_index"].fill_(current_end)
kv_cache_mouse["local_end_index"].fill_(local_end_index)
else:
attn = flash_attn_func(
q, # 880, f, 16, 64
k, # 880, f, 16, 64
v, # 880, f, 16, 64
)
# Compute cu_squlens and max_seqlen for flash attention
# qk norm
attn = rearrange(attn, '(b S) T h d -> b (T S) (h d)',b=B)
hidden_states = rearrange(x, "(B S) T C -> B (T S) C", B=B)
attn = self.proj_mouse(attn)
hidden_states = hidden_states + attn
if self.enable_keyboard and keyboard_condition is not None:
pad = keyboard_condition[:, 0:1, :].expand(-1, pad_t, -1)
keyboard_condition = torch.cat([pad, keyboard_condition], dim=1)
if is_causal and kv_cache_keyboard is not None:
keyboard_condition = keyboard_condition[:, self.vae_time_compression_ratio*(N_feats - num_frame_per_block - self.windows_size) + pad_t:, :] # keyboard_condition[:, self.vae_time_compression_ratio*(start_frame - self.windows_size) + pad_t:start_frame * self.vae_time_compression_ratio + pad_t,:]
keyboard_condition = self.keyboard_embed(keyboard_condition)
group_keyboard = [keyboard_condition[:, self.vae_time_compression_ratio*(i - self.windows_size) + pad_t:i * self.vae_time_compression_ratio + pad_t,:] for i in range(num_frame_per_block)]
else:
keyboard_condition = self.keyboard_embed(keyboard_condition)
group_keyboard = [keyboard_condition[:, self.vae_time_compression_ratio*(i - self.windows_size) + pad_t:i * self.vae_time_compression_ratio + pad_t,:] for i in range(N_feats)]
group_keyboard = torch.stack(group_keyboard, dim = 1) # B F RW C
group_keyboard = group_keyboard.reshape(shape=(group_keyboard.shape[0],group_keyboard.shape[1],-1))
# apply cross attn
mouse_q = self.mouse_attn_q(hidden_states)
keyboard_kv = self.keyboard_attn_kv(group_keyboard)
B, L, HD = mouse_q.shape
D = HD // self.heads_num
q = mouse_q.view(B, L, self.heads_num, D)
B, L, KHD = keyboard_kv.shape
k, v = keyboard_kv.view(B, L, 2, self.heads_num, D).permute(2, 0, 1, 3, 4)
# Compute cu_squlens and max_seqlen for flash attention
# qk norm
q = self.key_attn_q_norm(q).to(v)
k = self.key_attn_k_norm(k).to(v)
S = th * tw
# position embed
if use_rope_keyboard:
B, TS, H, D = q.shape
T_ = TS // S
q = q.view(B, T_, S, H, D).transpose(1, 2).reshape(B * S, T_, H, D)
q, k = apply_rotary_emb(q, k, freqs_cis, start_offset = start_frame,head_first=False)
k1, k2, k3, k4 = k.shape
k = k.expand(S, k2, k3, k4)
v = v.expand(S, k2, k3, k4)
if is_causal:
if kv_cache_keyboard is None:
assert q.shape[0] == k.shape[0] and q.shape[0] % S == 0
padded_length = math.ceil(q.shape[1] / 32) * 32 - q.shape[1]
padded_q = torch.cat(
[q,
torch.zeros([q.shape[0], padded_length, q.shape[2], q.shape[3]],
device=q.device, dtype=v.dtype)],
dim=1
)
padded_k = torch.cat(
[k, torch.zeros([k.shape[0], padded_length, k.shape[2], k.shape[3]],
device=k.device, dtype=v.dtype)],
dim=1
)
padded_v = torch.cat(
[v, torch.zeros([v.shape[0], padded_length, v.shape[2], v.shape[3]],
device=v.device, dtype=v.dtype)],
dim=1
)
attn = flex_attention(
query=padded_q.transpose(2, 1), # after: B, HW, F, C
key=padded_k.transpose(2, 1),
value=padded_v.transpose(2, 1),
block_mask=block_mask_keyboard
)[:, :, :-padded_length].transpose(2, 1)
else:
current_start = start_frame
current_end = current_start + k.shape[1]
assert k.shape[1] == num_frame_per_block
sink_size = 0
max_attention_size = self.local_attn_size if self.local_attn_size != -1 else 15
sink_tokens = sink_size * 1
kv_cache_size = kv_cache_keyboard["k"].shape[1]
num_new_tokens = k.shape[1]
if self.local_attn_size != -1 and (current_end > kv_cache_keyboard["global_end_index"].item()) and (
num_new_tokens + kv_cache_keyboard["local_end_index"].item() > kv_cache_size):
num_evicted_tokens = num_new_tokens + kv_cache_keyboard["local_end_index"].item() - kv_cache_size
num_rolled_tokens = kv_cache_keyboard["local_end_index"].item() - num_evicted_tokens - sink_tokens
kv_cache_keyboard["k"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \
kv_cache_keyboard["k"][:, sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone()
kv_cache_keyboard["v"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \
kv_cache_keyboard["v"][:, sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone()
# Insert the new keys/values at the end
local_end_index = kv_cache_keyboard["local_end_index"].item() + current_end - \
kv_cache_keyboard["global_end_index"].item() - num_evicted_tokens
local_start_index = local_end_index - num_new_tokens
else:
local_end_index = kv_cache_keyboard["local_end_index"].item() + current_end - kv_cache_keyboard["global_end_index"].item()
local_start_index = local_end_index - num_new_tokens
assert k.shape[0] == S # BS == 1 or the cache should not be saved/ load method should be modified
kv_cache_keyboard["k"][:, local_start_index:local_end_index] = k[:1]
kv_cache_keyboard["v"][:, local_start_index:local_end_index] = v[:1]
if FLASH_ATTN_3_AVAILABLE:
attn, attn_prob = flash_attn_interface.flash_attn_func(
q,
kv_cache_keyboard["k"][:, max(0, local_end_index - max_attention_size):local_end_index].repeat(S, 1, 1, 1),
kv_cache_keyboard["v"][:, max(0, local_end_index - max_attention_size):local_end_index].repeat(S, 1, 1, 1),
)
else:
attn = flash_attn_func(
q,
kv_cache_keyboard["k"][:, max(0, local_end_index - max_attention_size):local_end_index].repeat(S, 1, 1, 1),
kv_cache_keyboard["v"][:, max(0, local_end_index - max_attention_size):local_end_index].repeat(S, 1, 1, 1),
)
kv_cache_keyboard["global_end_index"].fill_(current_end)
kv_cache_keyboard["local_end_index"].fill_(local_end_index)
else:
attn = flash_attn_func(
q, # 1, f*880, 16, 64
k, # 1, f, 16, 64
v, # 1, f, 16, 64
causal=False,
)
attn = rearrange(attn, '(B S) T H D -> B (T S) (H D)', S=S)
else:
if is_causal:
if kv_cache_keyboard is None:
padded_length = math.ceil(q.shape[1] / 32) * 32 - q.shape[1]
padded_q = torch.cat(
[q,
torch.zeros([q.shape[0], padded_length, q.shape[2], q.shape[3]],
device=q.device, dtype=v.dtype)],
dim=1
)
padded_k = torch.cat(
[k, torch.zeros([k.shape[0], padded_length, k.shape[2], k.shape[3]],
device=k.device, dtype=v.dtype)],
dim=1
)
padded_v = torch.cat(
[v, torch.zeros([v.shape[0], padded_length, v.shape[2], v.shape[3]],
device=v.device, dtype=v.dtype)],
dim=1
)
attn = flex_attention(
query=padded_q.transpose(2, 1), # after: B, HW, F, C
key=padded_k.transpose(2, 1),
value=padded_v.transpose(2, 1),
block_mask=block_mask_keyboard
)[:, :, :-padded_length].transpose(2, 1)
else:
current_start = start_frame
current_end = current_start + k.shape[1]
assert k.shape[1] == num_frame_per_block
sink_size = 0
local_attn_size = self.local_attn_size if self.local_attn_size != -1 else 15
max_attention_size = self.local_attn_size if self.local_attn_size != -1 else 15
sink_tokens = sink_size * 1
kv_cache_size = kv_cache_keyboard["k"].shape[1]
num_new_tokens = k.shape[1]
if self.local_attn_size != -1 and (current_end > kv_cache_keyboard["global_end_index"].item()) and (
num_new_tokens + kv_cache_keyboard["local_end_index"].item() > kv_cache_size):
num_evicted_tokens = num_new_tokens + kv_cache_keyboard["local_end_index"].item() - kv_cache_size
num_rolled_tokens = kv_cache_keyboard["local_end_index"].item() - num_evicted_tokens - sink_tokens
kv_cache_keyboard["k"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \
kv_cache_keyboard["k"][:, sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone()
kv_cache_keyboard["v"][:, sink_tokens:sink_tokens + num_rolled_tokens] = \
kv_cache_keyboard["v"][:, sink_tokens + num_evicted_tokens:sink_tokens + num_evicted_tokens + num_rolled_tokens].clone()
# Insert the new keys/values at the end
local_end_index = kv_cache_keyboard["local_end_index"].item() + current_end - \
kv_cache_keyboard["global_end_index"].item() - num_evicted_tokens
local_start_index = local_end_index - num_new_tokens
else:
local_end_index = kv_cache_keyboard["local_end_index"].item() + current_end - kv_cache_keyboard["global_end_index"].item()
local_start_index = local_end_index - num_new_tokens
kv_cache_keyboard["k"][:, local_start_index:local_end_index] = k
kv_cache_keyboard["v"][:, local_start_index:local_end_index] = v
_kk = kv_cache_keyboard["k"][:, max(0, local_end_index - max_attention_size):local_end_index]
_vk = kv_cache_keyboard["v"][:, max(0, local_end_index - max_attention_size):local_end_index]
if torch.is_grad_enabled():
_kk = _kk.clone()
_vk = _vk.clone()
attn = flash_attn_func(
q, _kk, _vk,
# causal=is_causal
)
kv_cache_keyboard["global_end_index"].fill_(current_end)
kv_cache_keyboard["local_end_index"].fill_(local_end_index)
else:
attn = flash_attn_func(
q, # 1, f*880, 16, 64
k, # 1, f, 16, 64
v, # 1, f, 16, 64
# causal=is_causal,
)
attn = rearrange(attn, 'B L H D -> B L (H D)')
attn = self.proj_keyboard(attn)
hidden_states = hidden_states + attn
return hidden_states