[npu] Skip unnecessary gradients in NPU fused MoE backward (#10918)

This commit is contained in:
xvxuopop
2026-11-04 21:32:27 +08:00
committed by GitHub
parent 84024cefa6
commit d13f1632e6

View File

@@ -60,7 +60,11 @@ class GmmFunction(torch.autograd.Function):
Returns: Returns:
Tensor: The result of the grouped matrix multiplication. Tensor: The result of the grouped matrix multiplication.
""" """
ctx.save_for_backward(x, weight) # Input gradients need weights; weight gradients need inputs.
ctx.save_for_backward(
x if ctx.needs_input_grad[1] else None,
weight if ctx.needs_input_grad[0] else None,
)
ctx.group_list = group_list ctx.group_list = group_list
fwd_output = torch_npu.npu_grouped_matmul( fwd_output = torch_npu.npu_grouped_matmul(
@@ -82,10 +86,19 @@ class GmmFunction(torch.autograd.Function):
input_tensor, weight = ctx.saved_tensors input_tensor, weight = ctx.saved_tensors
group_list = ctx.group_list group_list = ctx.group_list
weight = torch.transpose(weight, 1, 2) grad_input = grad_weight = None
# Frozen experts still propagate input gradients to upstream LoRA layers.
if ctx.needs_input_grad[0]:
grad_input = torch_npu.npu_grouped_matmul( grad_input = torch_npu.npu_grouped_matmul(
[grad_output], [weight], bias=None, group_list=group_list, split_item=2, group_type=0, group_list_type=1 [grad_output],
[weight.transpose(1, 2)],
bias=None,
group_list=group_list,
split_item=2,
group_type=0,
group_list_type=1,
)[0] )[0]
if ctx.needs_input_grad[1]:
grad_weight = torch_npu.npu_grouped_matmul( grad_weight = torch_npu.npu_grouped_matmul(
[input_tensor.T], [input_tensor.T],
[grad_output], [grad_output],
@@ -120,7 +133,10 @@ class HybridGmmFunction(torch.autograd.Function):
ctx.split_sizes = split_sizes ctx.split_sizes = split_sizes
ctx.num_experts = num_experts ctx.num_experts = num_experts
ctx.save_for_backward(*args) ctx.save_for_backward(
*(x if ctx.needs_input_grad[1 + num_experts + i] else None for i, x in enumerate(x_list)),
*(w if ctx.needs_input_grad[1 + i] else None for i, w in enumerate(weight_list)),
)
outputs = torch_npu.npu_grouped_matmul( outputs = torch_npu.npu_grouped_matmul(
x_list, weight_list, bias=None, group_list=None, split_item=0, group_type=-1 x_list, weight_list, bias=None, group_list=None, split_item=0, group_type=-1
@@ -147,21 +163,28 @@ class HybridGmmFunction(torch.autograd.Function):
grad_outputs_contiguous = [g.contiguous() for g in grad_outputs] grad_outputs_contiguous = [g.contiguous() for g in grad_outputs]
w_t_list = [w.t() for w in weight_list] grad_x_list = [None] * num_experts
grad_x_list = torch_npu.npu_grouped_matmul( input_indices = [i for i in range(num_experts) if ctx.needs_input_grad[1 + i]]
grad_outputs_contiguous, # List[Tensor], 每个 [M_i, N] if input_indices:
w_t_list, # List[Tensor], 每个 [N, K] (view) grad_inputs = torch_npu.npu_grouped_matmul(
[grad_outputs_contiguous[i] for i in input_indices],
[weight_list[i].t() for i in input_indices],
bias=None, bias=None,
group_list=None, group_list=None,
split_item=0, split_item=0,
group_type=-1, group_type=-1,
) )
for i, grad in zip(input_indices, grad_inputs, strict=True):
grad_x_list[i] = grad
x_concat = torch.cat(x_list, dim=0) grad_w_list = [None] * num_experts
dy_concat = torch.cat(grad_outputs_contiguous, dim=0) # [Total_M, N] weight_indices = [i for i in range(num_experts) if ctx.needs_input_grad[1 + num_experts + i]]
if weight_indices:
group_list = torch.tensor(split_sizes, device=x_concat.device, dtype=torch.int64) x_concat = torch.cat([x_list[i] for i in weight_indices], dim=0)
dy_concat = torch.cat([grad_outputs_contiguous[i] for i in weight_indices], dim=0)
group_list = torch.tensor(
[split_sizes[i] for i in weight_indices], device=x_concat.device, dtype=torch.int64
)
grad_w_stack = torch_npu.npu_grouped_matmul( grad_w_stack = torch_npu.npu_grouped_matmul(
[x_concat.t()], [x_concat.t()],
[dy_concat], [dy_concat],
@@ -172,10 +195,10 @@ class HybridGmmFunction(torch.autograd.Function):
group_list_type=1, group_list_type=1,
)[0] )[0]
if grad_w_stack.dim() == 3: if grad_w_stack.dim() != 3:
grad_w_list = list(torch.unbind(grad_w_stack, dim=0))
else:
raise RuntimeError(f"Unexpected grad_w_stack shape: {grad_w_stack.shape}") raise RuntimeError(f"Unexpected grad_w_stack shape: {grad_w_stack.shape}")
for i, grad in zip(weight_indices, grad_w_stack.unbind(0), strict=True):
grad_w_list[i] = grad
return (None, *grad_x_list, *grad_w_list) return (None, *grad_x_list, *grad_w_list)