Files
smthemex-ComfyUI_FlashVSR/FlashVSR/diffsynth/models/test_mask_draft.py
T
2025-10-16 09:08:27 +08:00

207 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
import random
from typing import Tuple, Optional, List
from einops import rearrange
from block_sparse_attn import block_sparse_attn_func
out_path = '/cpfs01/shared/xpixel/zhuangjunhao/swin_base/DiffSynth-Studio/diffsynth/models/out_mask/'
class WindowPartition3D:
"""Partition / reverse‑partition helpers for 5‑D tensors (B,F,H,W,C)."""
@staticmethod
def partition(x: torch.Tensor, win: Tuple[int, int, int]):
B, F, H, W, C = x.shape
wf, wh, ww = win
assert F % wf == 0 and H % wh == 0 and W % ww == 0, "Dims must divide by window size."
x = x.view(B,
F // wf, wf,
H // wh, wh,
W // ww, ww,
C)
# (B, nf, nh, nw, wf, wh, ww, C) -> (B*nf*nh*nw, wf*wh*ww, C)
x = x.permute(0, 1, 3, 5, 2, 4, 6, 7).contiguous()
return x.view(-1, wf * wh * ww, C)
@staticmethod
def reverse(windows: torch.Tensor,
win: Tuple[int, int, int],
orig: Tuple[int, int, int]):
F, H, W = orig
wf, wh, ww = win
nf, nh, nw = F // wf, H // wh, W // ww
B = windows.size(0) // (nf * nh * nw)
x = windows.view(B, nf, nh, nw, wf, wh, ww, -1)
x = x.permute(0, 1, 4, 2, 5, 3, 6, 7).contiguous()
return x.view(B, F, H, W, -1)
def generate_causal_draft_block_mask(batch_size, nheads, seqlen, local_num, window_size, q_w, k_w, topk=10, device='cuda'):
assert batch_size == 1, "batch_size must be 1"
# 生成 causal_mask
causal_mask = generate_causal_block_mask(batch_size, nheads, seqlen, local_num, window_size, device).squeeze(0)
# q_w 和 k_w 的形状为 (nf*nh*nw, wf*wh*ww, D)
# avgpool_q 和 avgpool_k 的形状为 (nf*nh*nw, D) avgpool wf*wh*ww
avgpool_q = torch.mean(q_w, dim=1)
avgpool_k = torch.mean(k_w, dim=1)
# avgpool_q = torch.randn(avgpool_q.shape, device=avgpool_q.device, dtype=avgpool_q.dtype)
# avgpool_k = torch.randn(avgpool_k.shape, device=avgpool_k.device, dtype=avgpool_k.dtype)
# print(avgpool_q.shape, avgpool_k.shape)
avgpool_q = rearrange(avgpool_q, 's (h d) -> s h d', h=nheads) # (nf*nh*nw, h, D)
avgpool_k = rearrange(avgpool_k, 's (h d) -> s h d', h=nheads) # (nf*nh*nw, h, D)
q_heads = avgpool_q.permute(1, 0, 2) # (h, nf*nh*nw, D)
k_heads = avgpool_k.permute(1, 0, 2) # (h, nf*nh*nw, D)
D = avgpool_q.shape[-1]
scores = torch.einsum("hld,hmd->hlm", q_heads, k_heads) / math.sqrt(D) # (h, nf*nh*nw, nf*nh*nw)
# causal_mask 中为 False 的区域设置为 -inf True 的区域设置为 0
causal_mask = causal_mask.to(torch.float32)
causal_mask = causal_mask.masked_fill(causal_mask == False, -float('inf'))
causal_mask = causal_mask.masked_fill(causal_mask == True, 0)
scores = scores + causal_mask
attn_map = torch.softmax(scores, dim=-1)
# print(attn_map)
assert attn_map.shape == causal_mask.shape, "attn_map.shape must be equal to causal_mask.shape"
attn_map = rearrange(attn_map, 'h (it s1) s2 -> (h it) s1 s2', it=seqlen)
loop_num = attn_map.shape[0]
mask = torch.zeros_like(attn_map, dtype=torch.bool)
# process each head independently
for h in range(loop_num):
head_scores = attn_map[h] # [S1, S2]
# print(head_scores)
flat = head_scores.flatten() # [S1*S2]
n = flat.numel()
k = topk # number of smallest to exclude
if k == 0:
mask[h] = True
continue
if k >= n:
# nothing to keep
continue
# threshold = max of the k smallest scores
# print(flat, k)
# 计算非0元素个数
# non_zero_num = (flat > 0).sum()
# print('non_zero_num', non_zero_num, k)
# threshold = torch.topk(flat, k, largest=False).values.max()
# print(torch.sort(flat, descending=True)[0])
threshold = torch.sort(flat, descending=True)[0][k]
# build head mask
# print(threshold)
mask[h] = head_scores > threshold
# print(mask[h])
mask = rearrange(mask, '(h it) s1 s2 -> h (it s1) s2', it=seqlen)
# save mask 为图像
import matplotlib.pyplot as plt
for i in range(mask.shape[0]):
plt.imshow(mask[i].float().int().cpu().numpy())
plt.savefig(out_path + f'mask_{i}.png')
mask = mask.unsqueeze(0).repeat(batch_size, 1, 1, 1)
return mask
def generate_causal_block_mask(batch_size, nheads, seqlen, local_num, window_size, device='cuda'):
# i: 当前 query 的位置,j: key 的位置
i = torch.arange(seqlen, device=device).view(-1, 1) # [seqlen, 1]
j = torch.arange(seqlen, device=device).view(1, -1) # [1, seqlen]
# 条件:j <= i 且 j >= i - local_num + 1
causal_mask = (j <= i) & (j >= i - local_num + 1) # [seqlen, seqlen]
# print(causal_mask.float().int())
causal_mask = causal_mask.unsqueeze(1).unsqueeze(-1).repeat(1, window_size, 1, window_size)
causal_mask = rearrange(causal_mask, 'a n1 b n2 -> (a n1) (b n2)')
# save causal_mask 为图像
# import matplotlib.pyplot as plt
# plt.imshow(causal_mask.float().int())
# plt.savefig('causal_mask.png')
# 扩展 batch 维度
causal_mask = causal_mask.unsqueeze(0).unsqueeze(0).repeat(batch_size, nheads, 1, 1)
# causal_mask[:] = True
return causal_mask
win = (2, 8, 8)
B = 1
nheads = 12
f = 16
h = 32
w = 56
dim = 128
device = 'cuda'
dtype = torch.bfloat16
seqlen = f//win[0]
token_num = f*h*w
local_num = random.randint(2, seqlen)
# local_num = 4
print(local_num)
# print(seqlen)
window_size = win[0]*h*w//128
q = torch.randn(B, token_num, nheads*dim, device=device, dtype=dtype)
k = torch.randn(B, token_num, nheads*dim, device=device, dtype=dtype)
k = q+torch.randn(B, token_num, nheads*dim, device=device, dtype=dtype)
v = torch.randn(B, token_num, nheads*dim, device=device, dtype=dtype)
q = q.view(B, f, h, w, nheads*dim)
k = k.view(B, f, h, w, nheads*dim)
v = v.view(B, f, h, w, nheads*dim)
q_w = WindowPartition3D.partition(q, win) # (B*nf*nh*nw, wf*wh*ww, D)
k_w = WindowPartition3D.partition(k, win) # (B*nf*nh*nw, wf*wh*ww, D)
v_w = WindowPartition3D.partition(v, win) # (B*nf*nh*nw, wf*wh*ww, D)
square_num = window_size*window_size
topk_ratio = (random.uniform(0., 1.0)**2)*(local_num-1.2)+1.2
topk = int(square_num*topk_ratio)
print(topk/square_num)
# topk = int(window_size*window_size*1.5)
attention_mask = generate_causal_draft_block_mask(B, nheads, seqlen, local_num, window_size, q_w, k_w, topk=topk, device=q.device)
print(attention_mask.shape)
print(attention_mask.float().mean())