Skip to content

Commit 9983a27

Browse files
author
niushengxiao
committed
fix: reduce memory occupation
1 parent de908fa commit 9983a27

8 files changed

Lines changed: 455 additions & 176 deletions

File tree

lightllm/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@
22

33
if is_musa():
44
import torchada # noqa: F401
5+
else:
6+
import torch
7+
8+
torch._C._accelerator_setAllocatorSettings("expandable_segments:True")

lightllm/common/basemodel/layer_weights/meta_weights/fused_moe/fused_moe_weight.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,20 +222,28 @@ def masked_group_gemm(
222222
def prefilled_group_gemm(
223223
self,
224224
num_recv_tokens_per_expert_list,
225+
num_unaligned_recv_tokens_per_expert: torch.Tensor,
226+
recv_src_metadata: torch.Tensor,
225227
recv_x: Tuple[torch.Tensor],
226228
recv_topk_idx: torch.Tensor,
227229
recv_topk_weights: torch.Tensor,
228230
hidden_dtype=torch.bfloat16,
231+
workspace_index: int = 0,
232+
workspace_count: int = 1,
229233
):
230234
assert self.enable_ep_moe, "prefilled_group_gemm is only supported when enable_ep_moe is True"
231235
return self.fuse_moe_impl.prefilled_group_gemm(
232236
num_recv_tokens_per_expert_list=num_recv_tokens_per_expert_list,
237+
num_unaligned_recv_tokens_per_expert=num_unaligned_recv_tokens_per_expert,
238+
recv_src_metadata=recv_src_metadata,
233239
recv_x=recv_x,
234240
recv_topk_idx=recv_topk_idx,
235241
recv_topk_weights=recv_topk_weights,
236242
w13=self.w13,
237243
w2=self.w2,
238244
hidden_dtype=hidden_dtype,
245+
workspace_index=workspace_index,
246+
workspace_count=workspace_count,
239247
)
240248

241249
def low_latency_combine(

lightllm/common/basemodel/layer_weights/meta_weights/fused_moe/impl/deepgemm_impl.py

Lines changed: 26 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from typing import Optional, Tuple, Any
33
from .triton_impl import FuseMoeTriton
44
from lightllm.distributed import dist_group_manager
5-
from lightllm.common.triton_utils.autotuner import Autotuner
65
from lightllm.common.quantization.quantize_method import WeightPack
76
from lightllm.utils.envs_utils import (
87
get_deepep_num_max_dispatch_tokens_per_rank_prefill,
@@ -12,15 +11,10 @@
1211
fused_experts,
1312
get_ep_num_sms,
1413
masked_group_gemm,
15-
deepgemm_grouped_fp8_nt_contiguous,
14+
get_prefill_moe_workspace,
15+
expanded_moe_chunked_reduce,
1616
quantize_fused_experts_input,
1717
)
18-
from lightllm.common.basemodel.triton_kernel.quantization.fp8act_quant_kernel import (
19-
per_token_group_quant_fp8,
20-
tma_align_input_scale,
21-
)
22-
from lightllm.common.basemodel.triton_kernel.fused_moe.deepep_scatter_gather import ep_scatter, ep_gather
23-
from lightllm.common.basemodel.triton_kernel.fused_moe.moe_silu_and_mul import silu_and_mul_fwd
2418
from lightllm.common.basemodel.triton_kernel.redundancy_topk_ids_repair import redundancy_topk_ids_repair
2519
from lightllm.utils.device_utils import is_sm100_gpu
2620

@@ -182,6 +176,8 @@ def dispatch(
182176
allocate_on_comm_stream=True,
183177
do_cpu_sync=True,
184178
do_handle_copy=False,
179+
do_expand=True,
180+
use_tma_aligned_col_major_sf=True,
185181
)
186182

187183
def hook():
@@ -214,92 +210,35 @@ def masked_group_gemm(
214210
def prefilled_group_gemm(
215211
self,
216212
num_recv_tokens_per_expert_list,
213+
num_unaligned_recv_tokens_per_expert: torch.Tensor,
214+
recv_src_metadata: torch.Tensor,
217215
recv_x: Tuple[torch.Tensor],
218216
recv_topk_idx: torch.Tensor,
219217
recv_topk_weights: torch.Tensor,
220218
w13: WeightPack,
221219
w2: WeightPack,
222220
hidden_dtype=torch.bfloat16,
221+
workspace_index: int = 0,
222+
workspace_count: int = 1,
223223
):
224-
device = recv_x[0].device
225224
w13_weight, w13_scale = w13.weight, w13.weight_scale
226225
w2_weight, w2_scale = w2.weight, w2.weight_scale
227-
_, K = recv_x[0].shape
228-
_, N, _ = w13_weight.shape
229-
block_size = self.quant_method.block_size
230-
# scatter
231-
all_tokens = sum(num_recv_tokens_per_expert_list) # calcu padding all nums.
232-
# gather_out shape [recive_num_tokens, hidden]
233-
gather_out = torch.empty_like(recv_x[0], device=device, dtype=hidden_dtype)
234-
if all_tokens > 0:
235-
input_tensor = [
236-
torch.empty((all_tokens, K), device=device, dtype=recv_x[0].dtype),
237-
torch.empty((all_tokens, K // 128), device=device, dtype=torch.float32),
238-
]
239-
# when m_indices is filled ok.
240-
# m_indices show token use which expert, example, [0, 0, 0, 0, .... 1, 1, 1, 1,...., cur_expert_num - 1, ..]
241-
# the count of 0 is num_recv_tokens_per_expert_list[0], the count of 1 is num_recv_tokens_per_expert_list[1]
242-
# ...
243-
m_indices = torch.empty(all_tokens, device=device, dtype=torch.int32)
244-
# output_index shape [recive_num_tokens, topk_num]
245-
# output_index use to show the token index in input_tensor
246-
output_index = torch.empty_like(recv_topk_idx)
247-
248-
num_recv_tokens_per_expert = torch.tensor(
249-
num_recv_tokens_per_expert_list, dtype=torch.int32, pin_memory=True, device="cpu"
250-
).cuda(non_blocking=True)
251-
252-
expert_start_loc = torch.empty_like(num_recv_tokens_per_expert)
253-
254-
ep_scatter(
255-
recv_x[0],
256-
recv_x[1],
257-
recv_topk_idx,
258-
num_recv_tokens_per_expert,
259-
expert_start_loc,
260-
input_tensor[0],
261-
input_tensor[1],
262-
m_indices,
263-
output_index,
264-
)
265-
input_tensor[1] = tma_align_input_scale(input_tensor[1])
266-
# groupgemm (contiguous layout)
267-
gemm_out_a = torch.empty((all_tokens, N), device=device, dtype=hidden_dtype)
268-
269-
deepgemm_grouped_fp8_nt_contiguous(input_tensor, (w13_weight, w13_scale), gemm_out_a, m_indices)
270-
271-
# silu_and_mul_fwd + qaunt
272-
# TODO fused kernel
273-
silu_out = torch.empty((all_tokens, N // 2), device=device, dtype=hidden_dtype)
274-
275-
silu_and_mul_fwd(gemm_out_a.view(-1, N), silu_out)
276-
qsilu_out, qsilu_out_scale = per_token_group_quant_fp8(
277-
silu_out,
278-
block_size,
279-
dtype=w13_weight.dtype,
280-
column_major_scales=True,
281-
scale_tma_aligned=True,
282-
use_ue8m0_scales=is_sm100_gpu(),
283-
)
284-
285-
# groupgemm (contiguous layout)
286-
gemm_out_b = torch.empty((all_tokens, K), device=device, dtype=hidden_dtype)
287-
288-
deepgemm_grouped_fp8_nt_contiguous(
289-
(qsilu_out, qsilu_out_scale), (w2_weight, w2_scale), gemm_out_b, m_indices
290-
)
291-
# gather and local reduce
292-
ep_gather(gemm_out_b, recv_topk_idx, recv_topk_weights, output_index, gather_out)
293-
else:
294-
######################################## warning ##################################################
295-
# here is used to match autotune feature, make moe model run same triton kernel in different rank.
296-
# in some special case, one rank will recv 0 token, so add a token to make it run triton kernel.
297-
if Autotuner.is_autotune_warmup():
298-
_gemm_out_a = torch.zeros((1, N), device=device, dtype=hidden_dtype)
299-
_silu_out = torch.zeros((1, N // 2), device=device, dtype=hidden_dtype)
300-
silu_and_mul_fwd(_gemm_out_a.view(-1, N), _silu_out)
301-
_gemm_out_a, _silu_out = None, None
302-
226+
assert recv_topk_idx is None
227+
gather_out = expanded_moe_chunked_reduce(
228+
num_recv_tokens_per_expert_list,
229+
num_unaligned_recv_tokens_per_expert,
230+
recv_x,
231+
recv_topk_weights,
232+
recv_src_metadata,
233+
w13_weight,
234+
w13_scale,
235+
w2_weight,
236+
w2_scale,
237+
self.quant_method.block_size,
238+
get_prefill_moe_workspace(workspace_index, workspace_count),
239+
hidden_dtype,
240+
)
241+
del recv_x
303242
return gather_out
304243

305244
def low_latency_combine(
@@ -320,6 +259,8 @@ def combine(
320259
handle: Any,
321260
overlap_event: Optional[Any] = None,
322261
):
262+
# Chunked W2 has already reduced expanded expert slots to dense rows.
263+
handle.do_expand = False
323264
# normal combine
324265
combined_x, _, event = dist_group_manager.ep_buffer.combine(
325266
gemm_out_b,

lightllm/common/basemodel/triton_kernel/fused_moe/deepep_scatter_gather.py

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,181 @@ def ep_scatter(
152152
return
153153

154154

155+
@torch.no_grad()
156+
def ep_fill_m_indices(
157+
num_recv_tokens_per_expert: torch.Tensor,
158+
m_indices: torch.Tensor,
159+
):
160+
"""Build DeepGEMM's contiguous expert index vector without scattering data."""
161+
block_e = 128
162+
num_experts = num_recv_tokens_per_expert.shape[0]
163+
assert m_indices.shape[0] % block_e == 0
164+
165+
expert_start_loc = torch.empty_like(num_recv_tokens_per_expert)
166+
_fwd_kernel_ep_scatter_1[(num_experts,)](
167+
num_recv_tokens_per_expert,
168+
expert_start_loc,
169+
m_indices,
170+
num_experts=num_experts,
171+
num_warps=8,
172+
BLOCK_E=block_e,
173+
BLOCK_EXPERT_NUM=triton.next_power_of_2(num_experts),
174+
)
175+
return expert_start_loc
176+
177+
178+
@triton.jit
179+
def _zero_expanded_padding_kernel(
180+
recv_x,
181+
recv_x_stride_m,
182+
recv_x_stride_k,
183+
recv_x_scale,
184+
recv_x_scale_stride_m,
185+
recv_x_scale_stride_k,
186+
recv_topk_weights,
187+
num_recv_tokens_per_expert,
188+
num_unaligned_recv_tokens_per_expert,
189+
expert_start_loc,
190+
hidden_size: tl.constexpr,
191+
scale_hidden_size: tl.constexpr,
192+
BLOCK_M: tl.constexpr,
193+
BLOCK_K: tl.constexpr,
194+
BLOCK_SCALE_K: tl.constexpr,
195+
):
196+
expert_id = tl.program_id(0)
197+
pad_block_id = tl.program_id(1)
198+
hidden_block_id = tl.program_id(2)
199+
expert_start = tl.load(expert_start_loc + expert_id)
200+
aligned_count = tl.load(num_recv_tokens_per_expert + expert_id)
201+
actual_count = tl.load(num_unaligned_recv_tokens_per_expert + expert_id)
202+
pad_offsets = pad_block_id * BLOCK_M + tl.arange(0, BLOCK_M)
203+
row_offsets = (expert_start + actual_count + pad_offsets).to(tl.int64)
204+
row_mask = pad_offsets < aligned_count - actual_count
205+
206+
hidden_offsets = hidden_block_id * BLOCK_K + tl.arange(0, BLOCK_K)
207+
x_ptrs = recv_x + row_offsets[:, None] * recv_x_stride_m + hidden_offsets[None, :] * recv_x_stride_k
208+
tl.store(x_ptrs, 0.0, mask=row_mask[:, None] & (hidden_offsets[None, :] < hidden_size))
209+
if hidden_block_id == 0:
210+
scale_offsets = tl.arange(0, BLOCK_SCALE_K)
211+
scale_ptrs = (
212+
recv_x_scale
213+
+ row_offsets[:, None] * recv_x_scale_stride_m
214+
+ scale_offsets[None, :] * recv_x_scale_stride_k
215+
)
216+
tl.store(scale_ptrs, 0.0, mask=row_mask[:, None] & (scale_offsets[None, :] < scale_hidden_size))
217+
tl.store(recv_topk_weights + row_offsets, 0.0, mask=row_mask)
218+
219+
220+
@torch.no_grad()
221+
def ep_zero_expanded_padding(
222+
recv_x: torch.Tensor,
223+
recv_x_scale: torch.Tensor,
224+
recv_topk_weights: torch.Tensor,
225+
num_recv_tokens_per_expert: torch.Tensor,
226+
num_unaligned_recv_tokens_per_expert: torch.Tensor,
227+
expert_start_loc: torch.Tensor,
228+
):
229+
block_m = 8
230+
block_k = 256
231+
scale_hidden_size = recv_x_scale.shape[1]
232+
grid = (
233+
num_recv_tokens_per_expert.shape[0],
234+
triton.cdiv(127, block_m),
235+
triton.cdiv(recv_x.shape[1], block_k),
236+
)
237+
_zero_expanded_padding_kernel[grid](
238+
recv_x,
239+
recv_x.stride(0),
240+
recv_x.stride(1),
241+
recv_x_scale,
242+
recv_x_scale.stride(0),
243+
recv_x_scale.stride(1),
244+
recv_topk_weights,
245+
num_recv_tokens_per_expert,
246+
num_unaligned_recv_tokens_per_expert,
247+
expert_start_loc,
248+
hidden_size=recv_x.shape[1],
249+
scale_hidden_size=scale_hidden_size,
250+
BLOCK_M=block_m,
251+
BLOCK_K=block_k,
252+
BLOCK_SCALE_K=triton.next_power_of_2(scale_hidden_size),
253+
num_warps=4,
254+
)
255+
256+
257+
@triton.jit
258+
def _accumulate_expanded_chunk_kernel(
259+
total_recv_tokens,
260+
chunk,
261+
chunk_stride_m,
262+
chunk_stride_k,
263+
chunk_start,
264+
chunk_end,
265+
weights,
266+
recv_src_metadata,
267+
metadata_stride_m,
268+
metadata_stride_k,
269+
output,
270+
output_stride_m,
271+
output_stride_k,
272+
TOPK: tl.constexpr,
273+
BLOCK_D: tl.constexpr,
274+
):
275+
hidden_block_id = tl.program_id(0)
276+
start_recv_token_id = tl.program_id(1)
277+
recv_token_grid_size = tl.num_programs(1)
278+
hidden_offsets = hidden_block_id * BLOCK_D + tl.arange(0, BLOCK_D)
279+
280+
for recv_token_id in range(start_recv_token_id, total_recv_tokens, recv_token_grid_size):
281+
output_ptrs = output + recv_token_id * output_stride_m + hidden_offsets * output_stride_k
282+
accumulator = tl.load(output_ptrs).to(tl.float32)
283+
for topk_id in range(TOPK):
284+
slot = tl.load(
285+
recv_src_metadata
286+
+ recv_token_id * metadata_stride_m
287+
+ (topk_id + 2) * metadata_stride_k
288+
)
289+
if slot >= chunk_start and slot < chunk_end:
290+
local_row = (slot - chunk_start).to(tl.int64)
291+
value = tl.load(chunk + local_row * chunk_stride_m + hidden_offsets * chunk_stride_k)
292+
weight = tl.load(weights + slot)
293+
accumulator += value.to(tl.float32) * weight
294+
tl.store(output_ptrs, accumulator)
295+
296+
297+
@torch.no_grad()
298+
def ep_accumulate_expanded_chunk(
299+
chunk: torch.Tensor,
300+
chunk_start: int,
301+
weights: torch.Tensor,
302+
recv_src_metadata: torch.Tensor,
303+
output: torch.Tensor,
304+
):
305+
"""Accumulate one contiguous expanded W2 chunk into dense receive-token rows."""
306+
topk = recv_src_metadata.shape[1] - 2
307+
block_d = 1024
308+
assert chunk.shape[1] == output.shape[1] and output.shape[1] % block_d == 0
309+
grid = (triton.cdiv(output.shape[1], block_d), min(output.shape[0], 1024))
310+
_accumulate_expanded_chunk_kernel[grid](
311+
output.shape[0],
312+
chunk,
313+
chunk.stride(0),
314+
chunk.stride(1),
315+
chunk_start,
316+
chunk_start + chunk.shape[0],
317+
weights,
318+
recv_src_metadata,
319+
recv_src_metadata.stride(0),
320+
recv_src_metadata.stride(1),
321+
output,
322+
output.stride(0),
323+
output.stride(1),
324+
TOPK=topk,
325+
BLOCK_D=block_d,
326+
num_warps=2,
327+
)
328+
329+
155330
@triton.jit
156331
def _fwd_kernel_ep_gather(
157332
total_token_num,

0 commit comments

Comments
 (0)