|
32 | 32 | Sm100FmhaStaticTileSchedulerParams as FmhaStaticTileSchedulerParams, |
33 | 33 | ) |
34 | 34 |
|
| 35 | +import flash_attn.cute.copy_utils as fa_copy_utils |
35 | 36 |
|
36 | 37 | LAYOUT_RANK_CONSTANT = 3 |
37 | 38 |
|
@@ -2811,38 +2812,53 @@ def epilogue_clear( |
2811 | 2812 | dK.iterator + mdK_offset, |
2812 | 2813 | cute.make_layout((K, self.tile_shape_dQ_K, HB), stride=dK.stride), |
2813 | 2814 | ) |
2814 | | - gdK = cute.local_tile( |
2815 | | - mdK, (self.dSQ_mma_tiler[0], self.dSQ_mma_tiler[1]), (None, None, None) |
2816 | | - ) |
| 2815 | + gdK = cute.local_tile(mdK, (self.cta_tiler[1], self.cta_tiler[2]), (None, None, None)) |
2817 | 2816 | gdK = gdK[None, None, blk_coord_k, 0, blk_coord_batch] |
2818 | 2817 | cdK = cute.domain_offset( |
2819 | 2818 | (blk_coord_k * self.tile_shape_K, 0), |
2820 | | - cute.make_identity_tensor((self.dSQ_mma_tiler[0], self.dSQ_mma_tiler[1])), |
| 2819 | + cute.make_identity_tensor((self.cta_tiler[1], self.cta_tiler[2])), |
2821 | 2820 | ) |
2822 | 2821 |
|
2823 | 2822 | mdV_offset = cute.assume(blk_offset[1] * dV.stride[0], divby=64) |
2824 | 2823 | mdV = cute.make_tensor( |
2825 | 2824 | dV.iterator + mdV_offset, |
2826 | 2825 | cute.make_layout((K, self.tile_shape_dV_dO, HB), stride=dV.stride), |
2827 | 2826 | ) |
2828 | | - gdV = cute.local_tile( |
2829 | | - mdV, (self.PdO_mma_tiler[0], self.PdO_mma_tiler[1]), (None, None, None) |
2830 | | - ) |
| 2827 | + gdV = cute.local_tile(mdV, (self.cta_tiler[1], self.cta_tiler[2]), (None, None, None)) |
2831 | 2828 | gdV = gdV[None, None, blk_coord_k, 0, blk_coord_batch] |
2832 | 2829 | cdV = cute.domain_offset( |
2833 | 2830 | (blk_coord_k * self.tile_shape_K, 0), |
2834 | | - cute.make_identity_tensor((self.PdO_mma_tiler[0], self.PdO_mma_tiler[1])), |
| 2831 | + cute.make_identity_tensor((self.cta_tiler[1], self.cta_tiler[2])), |
2835 | 2832 | ) |
2836 | 2833 |
|
2837 | | - for i in cutlass.range(tidx * 8, cute.size(gdK), block_dim_x * 8): |
2838 | | - if cute.elem_less(cdK[i], cute.select(problem_shape, mode=[1, 2])): |
2839 | | - gdK_i = cute.make_tensor(gdK.iterator + cute.assume(i, divby=8), (8)) |
2840 | | - gdK_i.fill(0) |
| 2834 | + num_zero_epi_threads = 256 |
| 2835 | + |
| 2836 | + tiled_copy_r2g = fa_copy_utils.tiled_copy_2d( |
| 2837 | + dK.element_type, self.cta_tiler[2], num_zero_epi_threads |
| 2838 | + ) |
| 2839 | + |
| 2840 | + thr_copy_r2g = tiled_copy_r2g.get_slice(tidx) |
| 2841 | + |
| 2842 | + tRG_gdK = thr_copy_r2g.partition_D(gdK) |
| 2843 | + tRG_cdK = thr_copy_r2g.partition_D(cdK) |
| 2844 | + tRG_gdV = thr_copy_r2g.partition_D(gdV) |
| 2845 | + tRG_cdV = thr_copy_r2g.partition_D(cdV) |
| 2846 | + |
| 2847 | + zero_frg = cute.make_rmem_tensor_like(tRG_gdK[None, 0, None]) |
| 2848 | + zero_frg.fill(dK.element_type(0.0)) |
| 2849 | + |
| 2850 | + # check we don't need zero fragment duplication |
| 2851 | + V_frg_size = cute.size(tRG_gdV[None, 0, None]) |
| 2852 | + assert cute.size(zero_frg) == V_frg_size |
| 2853 | + |
| 2854 | + if tidx < num_zero_epi_threads: |
| 2855 | + for n in cutlass.range(cute.size(tRG_gdK.shape[1]), unroll_full=True): |
| 2856 | + if cute.elem_less(tRG_cdK[0, n, 0][0], problem_shape[1]): |
| 2857 | + cute.copy(tiled_copy_r2g, zero_frg, tRG_gdK[None, n, None]) |
2841 | 2858 |
|
2842 | | - for i in cutlass.range(tidx * 8, cute.size(gdV), block_dim_x * 8): |
2843 | | - if cute.elem_less(cdV[i], cute.select(problem_shape, mode=[1, 2])): |
2844 | | - gdV_i = cute.make_tensor(gdV.iterator + cute.assume(i, divby=8), (8)) |
2845 | | - gdV_i.fill(0) |
| 2859 | + for n in cutlass.range(cute.size(tRG_gdV.shape[1]), unroll_full=True): |
| 2860 | + if cute.elem_less(tRG_cdV[0, n, 0][0], problem_shape[1]): |
| 2861 | + cute.copy(tiled_copy_r2g, zero_frg, tRG_gdV[None, n, None]) |
2846 | 2862 |
|
2847 | 2863 | @cute.jit |
2848 | 2864 | def epilogue( |
|
0 commit comments