hpcaitech/Open-Sora · error · ValueError

The last dimension D must be even.

Error message

The last dimension D must be even.

What it means

rearrange_tensor interleaves a 4D [B, H, L, D] tensor's head dimension by splitting D into two halves and shuffling even/odd indices (Rearrange '... (s d) -> ... d s' style used before interleaved QKV projection packing). This permutation only exists when D is even, so an odd last dimension raises immediately.

Source

Thrown at opensora/models/mmdit/math.py:81

    xq_out = freqs_cis[..., 0] * xq_[..., 0] + freqs_cis[..., 1] * xq_[..., 1]
    xk_out = freqs_cis[..., 0] * xk_[..., 0] + freqs_cis[..., 1] * xk_[..., 1]
    return xq_out.reshape(*xq.shape).type_as(xq), xk_out.reshape(*xk.shape).type_as(xk)


def rearrange_tensor(tensor):
    """
    Rearranges the last dimension (D) of the input tensor based on the specified mapping:
    2d -> d, 2d+1 -> D/2 + d.

    Args:
        tensor (torch.Tensor): Input tensor of shape [B, H, L, D], where D is even.

    Returns:
        torch.Tensor: Tensor with rearranged last dimension, same shape as input.
    """
    B, H, L, D = tensor.shape
    if D % 2 != 0:
        raise ValueError("The last dimension D must be even.")

    half_D = D // 2
    indices = torch.empty(D, dtype=torch.long, device=tensor.device)

    # Fill the indices based on the mapping rule
    indices[:half_D] = torch.arange(0, D, 2, device=tensor.device)
    indices[half_D:] = torch.arange(1, D, 2, device=tensor.device)

    # Rearrange the tensor based on the computed indices
    return tensor.index_select(dim=-1, index=indices)


def reverse_rearrange_tensor(tensor):
    """
    Restores the original order of the last dimension (D) of the input tensor based on the reverse mapping:
    d -> 2d, D/2 + d -> 2d + 1.

    Args:

View on GitHub (pinned to 7ad6a96a13)

Solutions

  1. Check tensor.shape[-1] % 2 == 0 before calling; if odd, your upstream projection or reshape is wrong
  2. Verify num_heads divides hidden_size and the per-head dimension layout matches what rearrange_tensor expects
  3. Use the matching reverse_rearrange_tensor after the operation to round-trip correctly

Example fix

# before
y = rearrange_tensor(x)  # x.shape[-1] == 375
# after
assert x.shape[-1] % 2 == 0, f"odd head dim {x.shape[-1]}"
y = rearrange_tensor(x)
Defensive patterns

Strategy: validation

Validate before calling

assert tensor.dim() == 4 and tensor.shape[-1] % 2 == 0, f"need even last dim, got {tensor.shape}"

Type guard

def has_even_head_dim(t: torch.Tensor) -> bool:
    return t.dim() == 4 and t.shape[-1] % 2 == 0

Prevention

When it happens

Trigger: Calling rearrange_tensor(tensor) where tensor.shape[-1] is odd — e.g. a projection output of size 3*head_dim per-head being fed with an incompatible head packing, or a custom attention head_dim producing an odd D.

Common situations: Changing num_heads/hidden_size so that per-head dim becomes odd; feeding attention weights that were packed for interleaved layouts into a tensor whose last dim is not 2-divisible.

Related errors


AI-assisted analysis of hpcaitech/Open-Sora@7ad6a96a13 (2026-08-28). Data as JSON: /api/errors/763858a357bf825e. Report an issue: GitHub.