Skip to content

Commit d68d16e

Browse files
authored
Update PR 713 stride fix for packed sequence (#834)
* Ensure strides are correct for causal_conv1d * Add comment
1 parent 620cd98 commit d68d16e

1 file changed

Lines changed: 26 additions & 13 deletions

File tree

mamba_ssm/ops/triton/ssd_combined.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,23 @@ def init_to_zero(names):
5656
return lambda nargs: [nargs[name].zero_() for name in names if nargs[name] is not None]
5757

5858

59-
def rearrange_and_update_stride(tensor, pattern=None, dim=2):
60-
# ensure tensor.stride(dim) is a multiple of eight after rearranging according to pattern,
61-
# if not call contiguous(), rearrange only if pattern is not None
62-
tensor_rearranged = rearrange(tensor, pattern) if pattern is not None else tensor
63-
return tensor_rearranged.contiguous() if tensor_rearranged.stride(dim) % 8 != 0 else tensor_rearranged
59+
def ensure_stride(inp):
60+
"""
61+
Return inp, while ensuring that stride(1) of the returned tensor is a multiple of 8.
62+
63+
The inp tensor is of shape [batch, length, channels], where channels is assumed, and tested, to be
64+
a multiple of 8. If it is contiguous, inp will have strides [length*channels, channels, 1]. The
65+
output of this function will be rearranged to shape [batch, channels, length] before being passed to
66+
causal_conv1d. That rearranged tensor will have strides [length*channels, 1, channels].
67+
causal_conv1d handles this stride configuration (which it calls channels_last) directly and
68+
efficiently, after first recognizing it (when stride[1]==1 and stride[2]>1). causal_conv1d cannot
69+
operate on a channels_last tensor for which stride[2] is not a multiple of 8, and in that case will
70+
raise an exception. This function prevents the aforementioned exception by returning a tensor with
71+
stride(1) equal to channels, by making the returned tensor contiguous, if inp.stride(1) is not
72+
already a multiple of 8.
73+
"""
74+
assert inp.shape[2] % 8 == 0, "Number of convolution channels is required to be a multiple of 8."
75+
return inp if inp.stride(1) % 8 == 0 else inp.contiguous()
6476

6577

6678
@triton.autotune(
@@ -826,8 +838,8 @@ def forward(ctx, zxbcdt, conv1d_weight, conv1d_bias, dt_bias, A, D, chunk_size,
826838
zx0, z, xBC, dt = torch.split(zxbcdt, [2 * d_nonssm, dim, dim + ngroups * dstate * 2, nheads], dim=-1)
827839
seq_idx = seq_idx.contiguous() if seq_idx is not None else None
828840
xBC_conv = rearrange(
829-
causal_conv1d_fwd_function(rearrange_and_update_stride(xBC, "b s d -> b d s"),
830-
conv1d_weight, conv1d_bias, seq_idx, None, None, activation in ["silu", "swish"]),
841+
causal_conv1d_fwd_function(rearrange(ensure_stride(xBC), "b s d -> b d s"),
842+
conv1d_weight, conv1d_bias, seq_idx, None, None, activation in ["silu", "swish"]),
831843
"b d s -> b s d"
832844
)
833845
x, B, C = torch.split(xBC_conv, [dim, ngroups * dstate, ngroups * dstate], dim=-1)
@@ -900,8 +912,8 @@ def backward(ctx, dout, *args):
900912
zx0, z, xBC, dt = torch.split(zxbcdt, [2 * d_nonssm, dim, dim + 2 * ctx.ngroups * dstate, nheads], dim=-1)
901913
# Recompute x, B, C
902914
xBC_conv = rearrange(
903-
causal_conv1d_fwd_function(rearrange_and_update_stride(xBC, "b s d -> b d s"),
904-
conv1d_weight, conv1d_bias, seq_idx, None, None, ctx.activation in ["silu", "swish"]),
915+
causal_conv1d_fwd_function(rearrange(ensure_stride(xBC), "b s d -> b d s"),
916+
conv1d_weight, conv1d_bias, seq_idx, None, None, ctx.activation in ["silu", "swish"]),
905917
"b d s -> b s d"
906918
)
907919
x, B, C = torch.split(xBC_conv, [dim, ctx.ngroups * dstate, ctx.ngroups * dstate], dim=-1)
@@ -949,16 +961,17 @@ def backward(ctx, dout, *args):
949961
doutproj_bias = dout_og.sum(dim=(0, 1)) if outproj_bias is not None else None
950962
else:
951963
doutproj_weight, doutproj_bias = None, None
952-
dxBC_given = rearrange(dxBC_given, "b s d -> b d s")
953964
dxBC_given_update, dweight, dbias, *_ = causal_conv1d_bwd_function(
954-
rearrange_and_update_stride(xBC, "b s d -> b d s"), conv1d_weight, conv1d_bias,
955-
rearrange(dxBC, "b s d -> b d s"), seq_idx, None, None, rearrange_and_update_stride(dxBC_given), False, ctx.activation in ["silu", "swish"]
965+
rearrange(ensure_stride(xBC), "b s d -> b d s"), conv1d_weight, conv1d_bias,
966+
# It might be okay to not run ensure_stride on dxBC, but we're not sure. So playing safe here.
967+
rearrange(ensure_stride(dxBC), "b s d -> b d s"), seq_idx, None, None,
968+
rearrange(ensure_stride(dxBC_given), "b s d -> b d s"), False, ctx.activation in ["silu", "swish"]
956969
)
970+
dxBC_given_update = rearrange(dxBC_given_update, "b d s -> b s d")
957971
if dxBC_given.stride() != dxBC_given_update.stride():
958972
dxBC_given.copy_(dxBC_given_update)
959973
else:
960974
dxBC_given = dxBC_given_update
961-
dxBC_given = rearrange(dxBC_given, "b d s -> b s d")
962975
return dzxbcdt, dweight, dbias, ddt_bias, dA, dD, None, dinitial_states, None, None, None, None, drmsnorm_weight, None, doutproj_weight, doutproj_bias, None, None, None
963976

964977

0 commit comments

Comments
 (0)