metal: support non-zero left padding for PAD - #25827
Conversation
The Metal PAD kernel only handled right padding (all left paddings lp0/lp1/lp2/lp3 == 0). For any PAD node with non-zero left padding, ggml_metal_device_supports_op returned false, silently skipping the op and breaking any model whose graph depends on it. Hit in the wild by CosyVoice's flow-matching decoder, which emits PAD(lp0=2, rp0=0); the model could not run on Metal and fell back to CPU (~6x slower on Apple silicon). Fix: compute source coords as i0x = i_x - lp_x, writing zero outside [0, ne0x). Mirrors the CPU reference implementation (ggml_compute_forward_pad_f32). Circular padding (op_params[8] != 0) remains unsupported and still returns false; tracked separately by ggml-org#16985. Backward compatible: with all lp == 0 the kernel is identical to the previous version. Verified with test-backend-ops test -o PAD on Apple M2 Ultra (Metal vs CPU reference), including new left-padding regression cases.
|
Hi @flyingtimes, thanks for your contribution! Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:
Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below. |
|
Closing in favor of the upstream-track fix at the consumer level (cosyvoice.cpp maintains a local patch for this in After looking closer I realized this overlaps with work already done in the cosyvoice.cpp tree (originally PR Lourdle/cosyvoice.cpp#2 by @jasagiri), and the Metal PAD left-padding behavior is already tracked by the existing Thanks for the consideration. Happy to reopen if a maintainer feels the upstream change is still wanted. |
Overview
The Metal
PADkernel only handled right padding (all left paddingslp0/lp1/lp2/lp3 == 0). For any PAD node with non-zero left padding,ggml_metal_device_supports_opreturnedfalse, silently skipping the op and breaking any model whose graph depends on it.This was hit in the wild by CosyVoice's flow-matching decoder, which emits
PAD(lp0=2, rp0=0); the model could not run on Metal and fell back to CPU (~6x slower on Apple silicon).Root cause
kernel_pad_implassumed source and destination were aligned at the origin of every dim (i0x = i_x), so it only produced correct results when there was no left padding.Fix
Compute source coords as
i0x = i_x - lp_x, writing zero outside[0, ne0x). This mirrors the CPU reference implementation (ggml_compute_forward_pad_f32).ggml-metal-impl.h: addlp0..lp3toggml_metal_kargs_padggml-metal.metal:kernel_pad_implapplies the per-dim left offsetggml-metal-ops.cpp: populatelp0..lp3from op_paramsggml-metal-device.m: drop thelp == 0requirementCircular padding (
op_params[8] != 0) is still not supported and keeps returningfalse; that is tracked separately by #16985.Compatibility
With all
lp == 0the kernel is identical to the previous version (all pre-existing right-padding tests continue to pass).Verification
test-backend-ops test -o PADon Apple M2 Ultra (Metal vs CPU reference), with new regression cases for left padding:End-to-end, CosyVoice3-0.5B now runs on Metal:
tts_generatefor a 50-char prompt drops from ~14.5s (CPU) to ~2.4s (Metal).