mirror of
https://github.com/deepseek-ai/DeepGEMM.git
synced 2026-11-05 00:47:26 +00:00
[GH-ISSUE #10] Is DeepGEMM directly applicable to backward in training? #7
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
deepseek-ai/DeepGEMM#7
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @YouJiacheng on GitHub (Feb 26, 2025).
Original GitHub issue: https://github.com/deepseek-ai/DeepGEMM/issues/10
bwd of GEMM is two GEMMs, but I wonder if I need to take some special care of the range of gradients?
@YouJiacheng commented on GitHub (Feb 26, 2025):
Oh, so we must write a quantization kernel that produces the correct
lhs_scalesandrhs_scales.@zhipeng93 commented on GitHub (Feb 26, 2025):
We need a fp8 gemm with 128x1 LHS scaling and 1x128 RHS scaling?
@LyricZhao commented on GitHub (Feb 26, 2025):
We provide this library mainly for inference. So this library only supports DGRAD, not WGRAD.
In my understanding, WGRAD support needs more than a GEMM kernel, but also some utility fused kernels (e.g. transposing, fused with casting, fused with SwiGLU, fused with MoE layout). We want this library to be clean, so we didn't open-source them.
We may later release the WGRAD kernel, we will discuss about it internally :)
@YouJiacheng commented on GitHub (Feb 26, 2025):
Thank you Chenggang!
Yup I forgot that WGRAD needs to transpose matrices.
@thefacetakt commented on GitHub (Feb 27, 2025):
@LyricZhao, Could you hint at the approach you are taking for now?
Since it seems infeasible to perform (128, 1) x (1, 128) block-quantized gemm (because hopper tensor cores do not support scales), I am guessing you are using requantization of some kind. Do you use (1, 128) x (128,128) blocks for wgrad or (1, 128) x (128, 1)?
@soundOfDestiny commented on GitHub (Feb 28, 2025):
(128, 128) block scale is only used in weight matrix and won't be used in activation.
@TheTinyTeddy commented on GitHub (Mar 12, 2025):
So if not using the block scale for activation matrix then what should I use to calculate wgrad=x^T * dy since per token per tile quantizations are used on both A and B matrices (both are activations), which result in very inefficient GEMM (since the accumulation dimension K have different scales for every element), i.e. the GEMM is decomposed to many vector outer products
@soundOfDestiny commented on GitHub (Mar 12, 2025):
Requantization is inevitable in your case.
@TheTinyTeddy commented on GitHub (Mar 12, 2025):
So do you mean rather than per token per 128 tile quantization for x during inference, I should be using per channel per 128 tile quantization for x^T and the same per channel per 128 tile for dy?
However, this means I need to quantize input x twice (1 for per token 1 for per channel) or save x in bf16 format during inference? both approaches increase memory for training (deepseek v3 paper explicitly says "the FP8 Wgrad GEMM allows activations to be stored in FP8 for use in the backward pass")
@soundOfDestiny commented on GitHub (Mar 12, 2025):
P.S. Usually we don't call the forward pass in training 'inference'.
@TheTinyTeddy commented on GitHub (Mar 12, 2025):
My mistake, the terminology should indeed be the forward pass for training. So would you be able to let me know if my previous message is correct regarding the per channel quantization for activations in the Wgrad computation?
@soundOfDestiny commented on GitHub (Mar 12, 2025):
As you mentioned, we don't save x in bf16 format. (deepseek v3 paper explicitly says "the FP8 Wgrad GEMM allows activations to be stored in FP8 for use in the backward pass")
@NiuMa-1234 commented on GitHub (Mar 18, 2025):
I found the fp8 gemm for Wgrad in BWD requires the shape of input activation to be the multiple of 128. But in moe layer it couldn't always be this way. Is there any necessity to restrain the number of tokens dispatched to each expert?
@qijiaxing commented on GitHub (Mar 20, 2025):
I have implemented a variant that supports 1d1d scaling, can be used for WGRAD computation.
https://github.com/qijiaxing/DeepGEMM/tree/1d1d
any feedback or suggestions are welcomed!
@thefacetakt commented on GitHub (Mar 20, 2025):
Hi @qijiaxing, thanks for publishing 1d1d kernel!
I tried to run test_1d1d.py from your branch, but got an error.
When compiled with
-lineinfoand run with cuda-gdb, I am getting the followind error:Any idea what went wrong?
@qijiaxing commented on GitHub (Mar 20, 2025):
HI @thefacetakt , thanks for your message, I also got a CUDA error when block_n is set to 112. I need to check further how to fix it.
As a temporary workaround, can you try change this line in file
gemm_1d1d.pythese two values works for me.
@thefacetakt commented on GitHub (Mar 20, 2025):
@qijiaxing thanks, that did the trick.
TWIMC, right now I am getting the followind 1d1d perf:
@qijiaxing commented on GitHub (Mar 24, 2025):
Hi @thefacetakt , I fixed the bug you mentioned in this commit. It is due to a TMA 128 bytes alignment required for scale B shared memory storage. Now it should have no limitation on the block_n value any more. You may pull my branch and test again.
@RuiWang1998 commented on GitHub (Mar 24, 2025):
Hi @qijiaxing,
Does it work with grouped gemm?
@young-mu commented on GitHub (Mar 25, 2025):
@qijiaxing
Perhaps this can NOT be used in WGRAD directly, since WGRAD needs 128x1 LHS scales and 128x1 RHS scales, not 1x128 LHS scales and 1x128 RHS scales.
WGRAD formula:
grad_weight = grad_output ^ T * input, in whichThe scaling should be applied along with N/K axis (hidden_states), not M axis
@RuiWang1998 commented on GitHub (Mar 25, 2025):
I don't think that's possible under Hopper. P.S., I think input should be (M, K)?
@young-mu commented on GitHub (Mar 25, 2025):
it's a typo, corrected.
@qijiaxing commented on GitHub (Mar 26, 2025):
HI @RuiWang1998 , I didn't check if it works for grouped gemm yet, will let you later on.
@RuiWang1998 @young-mu , concerning WGRAD, my understanding is like this
@RuiWang1998 commented on GitHub (Mar 26, 2025):
Hi @qijiaxing ,
Got it! Thanks for the great work!
@young-mu commented on GitHub (Mar 26, 2025):
@qijiaxing
Got it, the process itself seems fine.
The key question is that if scaling can be applied along with M-axis (tokens in your case). From my understanding, it should be applied along with the N/K axis (hidden states), not the M axis (tokens). However, I don’t have solid proof for this yet.
BTW, the technical report mentions 128x1 tiles in the backward pass, but I couldn't find it in your 1d1d test case. Did I miss something? What's your take on this?
I have integrated FP8 DeepGEMM into FPROP, DGRAD and WGRAD processes (with WGRAD using your 1d1d implementation) and tested it on a GPT-2 model (about 410M). After hundreds of iterations, the final loss shows almost no difference compared with the baseline (BF16 + torch.matmul).
It seems that my initial understand was incorrect.
Thanks for your great work.
@MayDomine commented on GitHub (Apr 2, 2025):
@RuiWang1998 In this way, it seems that we still need to do transpose on x and y since we only have a
gemm_nt_1d1dkernel. Is there any chance that we can have agemm_tn_1d1dkernel?@qijiaxing commented on GitHub (Apr 3, 2025):
the reason for NT is about perf. Because each C value is computed from a row of A and a column of B, both are a list of K values, thus make K dim the continuous dim would make memory loading most efficient. This leads to NT for A and B. otherwise perf would not be optimal.
@hxdtest commented on GitHub (May 4, 2025):
DeepSeek v3 report: In our workflow, activations during the forward pass are quantized into 1x128 FP8 tiles and stored. During the backward pass, the matrix needs to be read out, dequantized, transposed, re-quantized into 128x1 tiles, and stored in HBM.
https://github.com/qijiaxing/DeepGEMM/blob/1d1d/deep_gemm/jit_kernels/gemm_1d1d.py#L134 Do a normal GEMM with FP8 inputs and BF16 output, with 1x128 LHS scaling and 1x128 RHS scaling. The method mentioned in DeepSeek V3 technical report and in
1d1dare not the same?@qijiaxing commented on GitHub (May 7, 2025):
@hxdtest the method is the same as DS v3 report.
in BWD, in math,
dw = dy^t @ x, x is the RHS tensor, thus its scaling is 128x1. But the actual GEMM kernel, it requires RHS tensor to be transposed, thus we needx^t, whose scaling become 1x128.@hxdtest commented on GitHub (May 8, 2025):
Many thanks for your reply.
@hxdtest commented on GitHub (May 9, 2025):
@qijiaxing
in BWD, in math, dw = dy^t @ x, x is the RHS tensor, thus its scaling is 128x1.I am still confused about rule of tiling and scaling. When x is the activation, in forward y = x @ w^t , x is the LHS tensor, x's scaling is 1x128, it's tiled in hidden_dim . If the tiling rule is scaling at hidden_dim, it's stilled need 1x128 in RHS.--- update ---
Oh the rule of tiling and scaling is
k is the dim for accumulation, thus every 128 elements in k dim need to share the same scale factor, which is applied after accumulation.Is that right ?@qijiaxing commented on GitHub (May 12, 2025):
@hxdtest yes, the scaling tile is determined by the GEMM algorithm. Even though x is used in both the FWD GEMM and WGRAD GEMM, these two GEMMs are independent. It's not necessary for x to have the same scaling.
@LyricZhao commented on GitHub (May 14, 2025):
Official weight gradient GEMM support is in #95, will merge today.