ColabWan / models /kandinsky5 /kandinsky /magcache_utils.py
1ripon1's picture
Upload folder using huggingface_hub
7344bef verified
Raw
History Blame Contribute Delete
13.7 kB
# This is an adaptation of Magcache from https://github.com/Zehong-Ma/MagCache/
import numpy as np
import torch
from types import MethodType
def nearest_interp(src_array, target_length):
src_length = len(src_array)
if target_length == 1:
return np.array([src_array[-1]])
scale = (src_length - 1) / (target_length - 1)
mapped_indices = np.round(np.arange(target_length) * scale).astype(int)
return src_array[mapped_indices]
def _prepare_mag_ratios(mag_ratios, num_steps):
if mag_ratios is None:
return None
mag_ratios = np.array([1.0] * 2 + list(mag_ratios))
if len(mag_ratios) != num_steps * 2:
mag_ratio_con = nearest_interp(mag_ratios[0::2], num_steps)
mag_ratio_ucon = nearest_interp(mag_ratios[1::2], num_steps)
mag_ratios = np.concatenate(
[mag_ratio_con.reshape(-1, 1), mag_ratio_ucon.reshape(-1, 1)], axis=1
).reshape(-1)
return mag_ratios
def compute_magcache_threshold(
mag_ratios,
num_steps,
speed_factor,
start_step=0,
no_cfg=False,
magcache_K=2,
retention_ratio=0.2,
):
if mag_ratios is None or num_steps <= 0 or speed_factor is None or speed_factor <= 0:
return None
mag_ratios = _prepare_mag_ratios(mag_ratios, num_steps)
if mag_ratios is None:
return None
total_calls = num_steps if no_cfg else num_steps * 2
target_calls = max(1, int(total_calls / max(speed_factor, 1e-6)))
retention_cnt = int(num_steps * 2 * retention_ratio)
best_threshold = 0.01
best_diff = float("inf")
best_signed_diff = 0
threshold = 0.01
while threshold <= 0.6:
nb_calls = 0
accumulated_err = [0.0, 0.0]
accumulated_steps = [0, 0]
accumulated_ratio = [1.0, 1.0]
for i in range(total_calls):
cnt = i * 2 if no_cfg else i
step_no = cnt // 2
skip_forward = False
if cnt >= retention_cnt and (start_step is None or step_no > start_step):
stream = cnt % 2
cur_mag_ratio = mag_ratios[cnt]
accumulated_ratio[stream] *= cur_mag_ratio
accumulated_steps[stream] += 1
cur_skip_err = np.abs(1 - accumulated_ratio[stream])
accumulated_err[stream] += cur_skip_err
if accumulated_err[stream] < threshold and accumulated_steps[stream] <= magcache_K:
skip_forward = True
else:
accumulated_err[stream] = 0.0
accumulated_steps[stream] = 0
accumulated_ratio[stream] = 1.0
if not skip_forward:
nb_calls += 1
signed_diff = target_calls - nb_calls
diff = abs(signed_diff)
if diff < best_diff:
best_threshold = threshold
best_diff = diff
best_signed_diff = signed_diff
elif diff > best_diff:
break
threshold += 0.01
nb_calls = target_calls - best_signed_diff
achieved_speed = total_calls / max(1, nb_calls)
print(
f"Mag Cache, best threshold found:{best_threshold:0.2f} "
f"with gain x{achieved_speed:0.2f} for a target of x{speed_factor}"
)
return best_threshold
def set_magcache_params(
dit,
mag_ratios,
num_steps,
no_cfg,
start_step=None,
magcache_thresh=None,
magcache_K=None,
retention_ratio=None,
):
print('using Magcache')
dit.forward = MethodType(magcache_forward, dit)
dit.cnt = 0
dit.num_steps = num_steps * 2
dit.magcache_thresh = 0.12 if magcache_thresh is None else magcache_thresh
dit.K = 2 if magcache_K is None else magcache_K
dit.accumulated_err = [0.0, 0.0]
dit.accumulated_steps = [0, 0]
dit.accumulated_ratio = [1.0, 1.0]
dit.consecutive_skips = [0, 0]
dit.magcache_start_step = 0 if start_step is None else int(start_step)
dit.retention_ratio = 0.2 if retention_ratio is None else retention_ratio
dit.magcache_retention_cnt = int(dit.num_steps * dit.retention_ratio)
dit.residual_cache = [None, None]
dit.mag_ratios = _prepare_mag_ratios(mag_ratios, num_steps)
dit.no_cfg = no_cfg
def _magcache_should_skip(dit, cnt):
stream = cnt % 2
skip_forward = False
residual_visual_embed = None
step_no = cnt // 2
if cnt >= dit.magcache_retention_cnt and step_no > dit.magcache_start_step:
cur_mag_ratio = dit.mag_ratios[cnt]
dit.accumulated_ratio[stream] *= cur_mag_ratio
dit.accumulated_steps[stream] += 1
cur_skip_err = np.abs(1 - dit.accumulated_ratio[stream])
dit.accumulated_err[stream] += cur_skip_err
if dit.accumulated_err[stream] < dit.magcache_thresh and dit.accumulated_steps[stream] <= dit.K:
if getattr(dit, "consecutive_skips", [0, 0])[stream] < dit.K:
skip_forward = True
residual_visual_embed = dit.residual_cache[stream]
else:
dit.accumulated_err[stream] = 0.0
dit.accumulated_steps[stream] = 0
dit.accumulated_ratio[stream] = 1.0
else:
dit.accumulated_err[stream] = 0.0
dit.accumulated_steps[stream] = 0
dit.accumulated_ratio[stream] = 1.0
return skip_forward, residual_visual_embed, stream
def _magcache_forward_single(
self,
x,
text_embed,
pooled_text_embed,
time,
visual_rope_pos,
text_rope_pos,
scale_factor=(1.0, 1.0, 1.0),
sparse_params=None,
attention_mask=None
):
text_embed, time_embed, text_rope, visual_embed = self.before_text_transformer_blocks(
text_embed, time, pooled_text_embed, x, text_rope_pos)
x = None
pooled_text_embed = None
for text_transformer_block in self.text_transformer_blocks:
text_embed = text_transformer_block(text_embed, time_embed, text_rope, attention_mask)
if self._check_interrupt():
return None
text_rope = None
visual_embed, visual_shape, to_fractal, visual_rope = self.before_visual_transformer_blocks(
visual_embed, visual_rope_pos, scale_factor, sparse_params)
visual_rope_pos = None
skip_forward, residual_visual_embed, stream = _magcache_should_skip(self, self.cnt)
if skip_forward and residual_visual_embed is None:
skip_forward = False
if skip_forward:
cache = getattr(self, "cache", None)
if cache is not None and hasattr(cache, "skipped_steps") and stream == 0:
cache.skipped_steps += 1
visual_embed = visual_embed + residual_visual_embed
if hasattr(self, "consecutive_skips"):
self.consecutive_skips[stream] += 1
else:
if hasattr(self, "consecutive_skips"):
self.consecutive_skips[stream] = 0
ori_visual_embed = visual_embed.clone()
for visual_transformer_block in self.visual_transformer_blocks:
visual_embed = visual_transformer_block(visual_embed, text_embed, time_embed,
visual_rope, sparse_params, attention_mask)
if self._check_interrupt():
return None
torch.sub(visual_embed, ori_visual_embed, out=ori_visual_embed)
residual_visual_embed = ori_visual_embed
self.residual_cache[stream] = residual_visual_embed
visual_rope = None
x = self.after_blocks(visual_embed, visual_shape, to_fractal, text_embed, time_embed)
if self.no_cfg:
self.cnt += 2
else:
self.cnt += 1
if self.cnt >= self.num_steps:
self.cnt = 0
self.accumulated_ratio = [1.0, 1.0]
self.accumulated_err = [0.0, 0.0]
self.accumulated_steps = [0, 0]
if hasattr(self, "consecutive_skips"):
self.consecutive_skips = [0, 0]
return x
def _magcache_forward_joint(
self,
x_list,
text_embed_list,
pooled_text_embed_list,
time_list,
visual_rope_pos_list,
text_rope_pos_list,
scale_factor_list,
sparse_params_list,
attention_mask_list,
):
count = len(x_list)
text_embed_list = self._normalize_list(text_embed_list, count)
pooled_text_embed_list = self._normalize_list(pooled_text_embed_list, count)
time_list = self._normalize_list(time_list, count)
visual_rope_pos_list = self._normalize_list(visual_rope_pos_list, count)
text_rope_pos_list = self._normalize_list(text_rope_pos_list, count)
scale_factor_list = self._normalize_list(scale_factor_list, count)
sparse_params_list = self._normalize_list(sparse_params_list, count)
attention_mask_list = self._normalize_list(attention_mask_list, count)
text_embed_out = [None] * count
time_embed_out = [None] * count
text_rope_out = [None] * count
visual_embed_out = [None] * count
for idx in range(count):
text_embed_out[idx], time_embed_out[idx], text_rope_out[idx], visual_embed_out[idx] = (
self.before_text_transformer_blocks(
text_embed_list[idx],
time_list[idx],
pooled_text_embed_list[idx],
x_list[idx],
text_rope_pos_list[idx],
)
)
x_list[idx] = None
pooled_text_embed_list[idx] = None
for text_transformer_block in self.text_transformer_blocks:
for idx in range(count):
text_embed_out[idx] = text_transformer_block(
text_embed_out[idx], time_embed_out[idx], text_rope_out[idx], attention_mask_list[idx]
)
if self._check_interrupt():
return None
for idx in range(count):
text_rope_out[idx] = None
visual_shape_list = [None] * count
to_fractal_list = [None] * count
visual_rope_out = [None] * count
for idx in range(count):
visual_embed_out[idx], visual_shape_list[idx], to_fractal_list[idx], visual_rope_out[idx] = (
self.before_visual_transformer_blocks(
visual_embed_out[idx],
visual_rope_pos_list[idx],
scale_factor_list[idx],
sparse_params_list[idx],
)
)
visual_rope_pos_list[idx] = None
stream_ids = [0] * count
skip_forward = [False] * count
residual_visual_embed = [None] * count
ori_visual_embed = [None] * count
cnt = self.cnt
for idx in range(count):
stream_ids[idx] = cnt % 2
skip_forward[idx], residual_visual_embed[idx], _ = _magcache_should_skip(self, cnt)
if skip_forward[idx] and residual_visual_embed[idx] is None:
skip_forward[idx] = False
if not skip_forward[idx] and hasattr(self, "consecutive_skips"):
self.consecutive_skips[stream_ids[idx]] = 0
if skip_forward[idx]:
if idx == 0:
cache = getattr(self, "cache", None)
if cache is not None and hasattr(cache, "skipped_steps"):
cache.skipped_steps += 1
visual_embed_out[idx] = visual_embed_out[idx] + residual_visual_embed[idx]
if hasattr(self, "consecutive_skips"):
self.consecutive_skips[stream_ids[idx]] += 1
else:
ori_visual_embed[idx] = visual_embed_out[idx].clone()
cnt += 2 if self.no_cfg else 1
for visual_transformer_block in self.visual_transformer_blocks:
for idx in range(count):
if skip_forward[idx]:
continue
visual_embed_out[idx] = visual_transformer_block(
visual_embed_out[idx],
text_embed_out[idx],
time_embed_out[idx],
visual_rope_out[idx],
sparse_params_list[idx],
attention_mask_list[idx],
)
if self._check_interrupt():
return None
for idx in range(count):
visual_rope_out[idx] = None
for idx in range(count):
if skip_forward[idx]:
residual = residual_visual_embed[idx]
else:
torch.sub(visual_embed_out[idx], ori_visual_embed[idx], out=ori_visual_embed[idx])
residual = ori_visual_embed[idx]
self.residual_cache[stream_ids[idx]] = residual
outputs = []
for idx in range(count):
outputs.append(
self.after_blocks(
visual_embed_out[idx],
visual_shape_list[idx],
to_fractal_list[idx],
text_embed_out[idx],
time_embed_out[idx],
)
)
self.cnt = cnt
if self.cnt >= self.num_steps:
self.cnt = 0
self.accumulated_ratio = [1.0, 1.0]
self.accumulated_err = [0.0, 0.0]
self.accumulated_steps = [0, 0]
if hasattr(self, "consecutive_skips"):
self.consecutive_skips = [0, 0]
return outputs
def magcache_forward(
self,
x,
text_embed,
pooled_text_embed,
time,
visual_rope_pos,
text_rope_pos,
scale_factor=(1.0, 1.0, 1.0),
sparse_params=None,
attention_mask=None,
):
if isinstance(x, (list, tuple)):
return _magcache_forward_joint(
self,
list(x),
text_embed,
pooled_text_embed,
time,
visual_rope_pos,
text_rope_pos,
scale_factor,
sparse_params,
attention_mask,
)
return _magcache_forward_single(
self,
x,
text_embed,
pooled_text_embed,
time,
visual_rope_pos,
text_rope_pos,
scale_factor=scale_factor,
sparse_params=sparse_params,
attention_mask=attention_mask,
)