mirror of
https://github.com/deepseek-ai/DeepGEMM.git
synced 2026-11-05 00:47:26 +00:00
[GH-ISSUE #37] only uses the highest 14 bits #24
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#24
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 @sisiwuxi on GitHub (Mar 4, 2025).
Original GitHub issue: https://github.com/deepseek-ai/DeepGEMM/issues/37
3.5.2. Compute Hardware
Higher FP8 GEMM Accumulation Precision in Tensor Cores. In the current Tensor Core implementation of the NVIDIA Hopper architecture, FP8 GEMM (General Matrix Multiply) employs fixed-point accumulation, aligning the mantissa products by right-shifting based on the maximum exponent before addition. Our experiments reveal that it only uses the highest 14 bits of each mantissa product after sign-fill right shifting, and truncates bits exceeding this range. However, for example, to achieve precise FP32 results from the accumulation of 32 FP8×FP8 multiplications, at least 34-bit precision is required. Thus, we recommend that future chip designs increase accumulation precision in Tensor Cores to support full-precision accumulation, or select an appropriate accumulation bit-width according to the accuracy requirements of training and inference algorithms. This approach ensures that errors remain within acceptable bounds while maintaining computational efficiency.
请教 14bits 是怎样得到的?
实验步骤:
1、基于 tests/test_core.py 做修改得到 tests/test_core_simple.py,如附件
test_core_simple.py.txt
在 DeepGEMM目录执行 python3 tests/test_core_simple.py
修改部分:
m, k, n = 16, 256, 64
左支x,右支y 初始化为全 0,再分别赋值 x_[0,0] = 448, x_[0,1] = 7.5,y_[0,0] = 1, y_[0,1] = 1;
per_token_cast_to_fp8(x) 和 per_block_cast_to_fp8(y) 返回不做量化,scale全1的Tuple[torch.Tensor, torch.Tensor];
实现调用 wgmma 指令的计算满足 a1 * b1 + a2 * b2 + 0 * 0 + ... + 0 * 0
2、实验结果发现 调用 deep_gemm.gemm_fp8_fp8_bf16_nt(x_fp8, y_fp8, out) 后计算结果不满足预期,wgmma 指令 trunc 后保留的位数从5bit到8bit不等。
比如 448 * 1 + 7.5 * 1 + 0 + ... + 0 = 456 != 455.5
448 = (1.11)b * pow(2,8)
7.5 = (1.111)b * pow(2,2)
448 + 7.5 = (1.11)b * pow(2,8) + (0.00000 1111)b * pow(2,8) = (1.11000 1111)b * pow(2,8)
而
455.5 = (1.11000 1111)b * pow(2,8)
456 = (1.11001 0000)b * pow(2,8)
个人理解,仅保留了5bit的尾数
3、在 deep_gemm/include/deep_gemm/fp8_gemm.cuh/fp8_gemm_kernel末尾添加打印 printf("%f, ", (final_accum[0])); 得到 0.000000, 455.500000, 0.000000, 0.000000,观察到 448 + 7.5 此时的值为 455.5,满足预期。
printf("%f, ", (final_accum[0]));
修改为
printf("%.23f, ", (final_accum[0]));
@jason-huang03 commented on GitHub (Mar 4, 2025):
@sisiwuxi Hi, you can refer to our work SageAttention2, which is the first paper (even earlier than DeepSeek V3) revealing the accumulator issue of Hopper/Ada fp8 tensor core. Actually we find that fp8 has 22 bits accumulator, rather than 14 bits as mentioned by deepseek. We conduct the experiment as follows:
In this way, we conclude that the fp8 accumulator has 22 effective bits. In other word, the last 10 bits of accumulator are always truncated by fp8 tensor core operation.
@soundOfDestiny commented on GitHub (Mar 4, 2025):
这里y的amax不是448,因此per_block_cast_to_fp8(y)返回的y的scale不会是1吧?
@sisiwuxi commented on GitHub (Mar 5, 2025):
ok 16 * 1 + 0.029296875 * 1 + 0 + ... + 0, (16.029296875)d = (1. 0000 00000 1111)b * 2**(4)
err 32 * 1 + 0.029296875 * 1 + 0 + ... + 0, (32.029296875)d = (1. 00000 00000 1111)b * 2**(5),但是final_accum[0]打印结果32.02734375
32.029296875 = (1. 00000 00000 1111)b * 2**(5)
32.02734375 = (1. 00000 00000 1110)b * 2**(5)
2. printf("\n [tid_0]: %.23f, %.23f \n", accum[0], final_accum[0]); print打印保留23bit精度
@soundOfDestiny commented on GitHub (Mar 5, 2025):
'14 bits' in DeepSeekV3 paper includes a sign bit and mantissa bits. 14bits + 8 exponent bits == 22 bits in total
@soundOfDestiny commented on GitHub (Mar 5, 2025):
这里y的amax不是448,因此per_block_cast_to_fp8(y)返回的y的scale不会是1吧?
@sisiwuxi commented on GitHub (Mar 5, 2025):
附件test_core_simple.py第26和第50行,左支右支的scale都手动修改为全1,避免wgmma之后cuda core乘scale的影响
@sisiwuxi commented on GitHub (Mar 5, 2025):
感谢回复,和实验结果相同,多谢
@sisiwuxi commented on GitHub (Mar 5, 2025):
感谢回复,和实验结果相同,多谢
@soundOfDestiny commented on GitHub (Mar 5, 2025):
455.5到456是结果转换成bf16的时候四舍五入了
@seanxcwang commented on GitHub (Jun 9, 2025):
I followed this and wrote an MMA example running on a Hopper architecture GPU, but I didn't observe the result where C != D. Did I misunderstand something?
mma_example_fp8.cu.txt
@jason-huang03 commented on GitHub (Jun 9, 2025):
@sisiwuxi on hopper, the mma fp8 instruction will fall back to fp16 (hence super slow). Instead, you should use wgmma on hopper to reproduce the problem.
@seanxcwang commented on GitHub (Jun 10, 2025):
thx for the reply, wgmma produce the result where C != D