Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ def infer_audio_cross_attn(self, phase, x, pre_infer_out, x_ref_attn_map):
encoder_k, encoder_v = kv.unbind(dim=2)

if human_num > 1:
q, encoder_k = self._apply_multi_human_audio_rope(q, encoder_k, x_ref_attn_map, grid_t)
q, encoder_k = self._apply_multi_human_audio_rope(q, encoder_k, x_ref_attn_map, grid_t, human_num)

if self.audio_attn_cu_seqlens_q is None:
self.audio_attn_cu_seqlens_q = torch.arange(0, (grid_t + 1) * spatial_tokens, spatial_tokens, dtype=torch.int32)
Expand All @@ -233,21 +233,46 @@ def infer_audio_cross_attn(self, phase, x, pre_infer_out, x_ref_attn_map):
)
return phase.proj.apply(attn_out).view_as(x)

def _apply_multi_human_audio_rope(self, q, encoder_k, x_ref_attn_map, grid_t):
def _multi_human_rope_ranges(self, human_num, dtype, device):
h1 = torch.tensor(self.rope_h1, dtype=dtype, device=device)
h2 = torch.tensor(self.rope_h2, dtype=dtype, device=device)
if human_num == 2:
return torch.stack([h1, h2], dim=0)
starts = torch.linspace(h1[0], h2[0], human_num, dtype=dtype, device=device)
ends = torch.linspace(h1[1], h2[1], human_num, dtype=dtype, device=device)
return torch.stack([starts, ends], dim=1)
Comment on lines +237 to +243

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The _multi_human_rope_ranges method can be simplified by directly using the scalar values from self.rope_h1 and self.rope_h2 in torch.linspace. This avoids creating temporary tensors h1 and h2 on the device and eliminates the redundant if human_num == 2 branch, as torch.linspace with steps=2 naturally produces the same output.

        starts = torch.linspace(self.rope_h1[0], self.rope_h2[0], human_num, dtype=dtype, device=device)
        ends = torch.linspace(self.rope_h1[1], self.rope_h2[1], human_num, dtype=dtype, device=device)
        return torch.stack([starts, ends], dim=1)


def _apply_multi_human_audio_rope(self, q, encoder_k, x_ref_attn_map, grid_t, human_num):
if x_ref_attn_map is None:
return q, encoder_k

max_values = x_ref_attn_map.max(1).values[:, None, None]
min_values = x_ref_attn_map.min(1).values[:, None, None]
max_min_values = torch.cat([max_values, min_values], dim=2)
human1_max_value, human1_min_value = max_min_values[0, :, 0].max(), max_min_values[0, :, 1].min()
human2_max_value, human2_min_value = max_min_values[1, :, 0].max(), max_min_values[1, :, 1].min()
human_map_count = min(int(human_num), max(0, x_ref_attn_map.shape[0] - 1))
if human_map_count <= 0:
return q, encoder_k

human1 = normalize_and_scale(x_ref_attn_map[0], (human1_min_value, human1_max_value), (self.rope_h1[0], self.rope_h1[1]))
human2 = normalize_and_scale(x_ref_attn_map[1], (human2_min_value, human2_max_value), (self.rope_h2[0], self.rope_h2[1]))
back = torch.full((x_ref_attn_map.size(1),), self.rope_bak, dtype=human1.dtype, device=human1.device)
rope_ranges = self._multi_human_rope_ranges(human_map_count, x_ref_attn_map.dtype, x_ref_attn_map.device)
human_positions = []
for idx in range(human_map_count):
human_map = x_ref_attn_map[idx]
human_min_value = human_map.min()
human_max_value = human_map.max()
human_positions.append(
normalize_and_scale(
human_map,
(human_min_value, human_max_value),
(rope_ranges[idx, 0], rope_ranges[idx, 1]),
)
)

back = torch.full(
(x_ref_attn_map.size(1),),
self.rope_bak,
dtype=x_ref_attn_map.dtype,
device=x_ref_attn_map.device,
)
max_indices = x_ref_attn_map.argmax(dim=0)
normalized_map = torch.stack([human1, human2, back], dim=1)
max_indices = torch.clamp(max_indices, max=human_map_count)
normalized_map = torch.stack([*human_positions, back], dim=1)
normalized_pos = normalized_map[range(x_ref_attn_map.size(1)), max_indices]

q_rope = rearrange(q, "t s h d -> 1 h (t s) d")
Expand All @@ -256,8 +281,12 @@ def _apply_multi_human_audio_rope(self, q, encoder_k, x_ref_attn_map, grid_t):

audio_tokens = encoder_k.shape[1]
per_frame = torch.zeros(audio_tokens, dtype=encoder_k.dtype, device=encoder_k.device)
per_frame[: audio_tokens // 2] = (self.rope_h1[0] + self.rope_h1[1]) / 2
per_frame[audio_tokens // 2 :] = (self.rope_h2[0] + self.rope_h2[1]) / 2
token_edges = torch.linspace(0, audio_tokens, human_map_count + 1, dtype=torch.int64, device=encoder_k.device)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using torch.linspace with an integer dtype can lead to inconsistent rounding or truncation behaviors across different PyTorch versions. It is safer and more robust to generate the linspace as float, round it, and then cast to int64.

Suggested change
token_edges = torch.linspace(0, audio_tokens, human_map_count + 1, dtype=torch.int64, device=encoder_k.device)
token_edges = torch.linspace(0, audio_tokens, human_map_count + 1, device=encoder_k.device).round().to(torch.int64)

rope_centers = rope_ranges.mean(dim=1).to(dtype=encoder_k.dtype, device=encoder_k.device)
for idx in range(human_map_count):
start = int(token_edges[idx].item())
end = int(token_edges[idx + 1].item())
per_frame[start:end] = rope_centers[idx]
encoder_pos = torch.concat([per_frame] * grid_t, dim=0)
k_rope = rearrange(encoder_k, "t s h d -> 1 h (t s) d")
k_rope = self.rope_1d(k_rope, encoder_pos)
Expand Down
Loading
Loading