Skip to content
Open
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
21c3eeb
support 31B
WANDY666 Apr 30, 2026
99b790c
fix
WANDY666 May 6, 2026
4c30c73
Merge branch 'main' of https://github.com/ModelTC/LightLLM into suppo…
WANDY666 May 6, 2026
15a5379
support moe
WANDY666 May 7, 2026
83f4983
support e4b (PLE and shared_kv)
WANDY666 May 9, 2026
d969a5f
support visual module
WANDY666 May 11, 2026
08f066d
optimize sliding window
WANDY666 May 12, 2026
7678de8
fix
WANDY666 May 12, 2026
63c658a
simplify
WANDY666 May 13, 2026
300e577
minor improvements
WANDY666 May 13, 2026
50822f0
fix
WANDY666 May 13, 2026
b4b13cc
fix attention cuda graph
WANDY666 May 13, 2026
f19074b
fused gelu gate up
WANDY666 May 14, 2026
5b61450
add out_dtype
WANDY666 May 14, 2026
c0ca212
minor improvements
WANDY666 May 14, 2026
9499a00
fix eos_token_ids
WANDY666 May 14, 2026
de7e220
for HF format
WANDY666 May 14, 2026
bfc59ff
Merge branch 'main' of https://github.com/ModelTC/LightLLM into suppo…
WANDY666 May 14, 2026
109d27c
fix window_size
WANDY666 May 14, 2026
2ea258e
fix window_size
WANDY666 May 14, 2026
b297af5
fix
WANDY666 May 14, 2026
7a81e85
add reasoning_parser for gemma4
WANDY666 May 15, 2026
d619534
[fix]ple support cudagraph
WANDY666 May 16, 2026
c2578c0
fix PLE illegal memory access
WANDY666 May 18, 2026
d744cbc
support sliding_window_right
WANDY666 May 18, 2026
05a0db8
fix notes
WANDY666 May 18, 2026
6f1bd2e
tune in H200
WANDY666 May 19, 2026
90643db
fix
hiworldwzj May 19, 2026
a2b74ab
fix
hiworldwzj May 19, 2026
e606e05
fix
hiworldwzj May 19, 2026
7354da2
fix
hiworldwzj May 20, 2026
afa0194
fix
hiworldwzj May 20, 2026
46ce6af
fix
hiworldwzj May 20, 2026
0188c10
fix
hiworldwzj May 20, 2026
393ec69
fix
hiworldwzj May 20, 2026
e96c2b7
fix
WANDY666 May 20, 2026
f806326
fix
hiworldwzj May 20, 2026
c5b2b81
fix
hiworldwzj May 20, 2026
3bd46d7
fix
hiworldwzj May 20, 2026
91051f0
Merge branch 'support_gemma4' of https://github.com/ModelTC/LightLLM …
WANDY666 May 20, 2026
fb75045
fix
WANDY666 May 20, 2026
7c664c3
fix
hiworldwzj May 20, 2026
0d35e8b
fix
hiworldwzj May 20, 2026
74a4b1f
fix
hiworldwzj May 20, 2026
d2df0a0
fix
hiworldwzj May 20, 2026
3491641
fix
hiworldwzj May 20, 2026
c8812f2
fix
hiworldwzj May 20, 2026
8f160b5
fix
hiworldwzj May 20, 2026
ee92fee
fix
hiworldwzj May 21, 2026
131a163
fix
hiworldwzj May 21, 2026
6d7729f
fix
hiworldwzj May 21, 2026
87da477
fix
WANDY666 May 21, 2026
819497c
Merge branch 'main' of https://github.com/ModelTC/LightLLM into suppo…
WANDY666 May 21, 2026
c57e062
format
WANDY666 May 21, 2026
6ebf9db
finish
WANDY666 May 21, 2026
e682f9b
fix
WANDY666 May 21, 2026
c28f085
Merge https://github.com/ModelTC/LightLLM into gemma4_mtp
WANDY666 May 22, 2026
6099413
format
WANDY666 May 22, 2026
ba47045
format
WANDY666 May 22, 2026
33d7ceb
format
WANDY666 May 22, 2026
bca6990
refactor: unify gemma4_mtp post forward with ModelOutput
zhangts20 Jul 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions lightllm/common/basemodel/attention/triton/fp.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ def prefill_att(
att_control: AttControl = AttControl(),
alloc_func=torch.empty,
) -> torch.Tensor:
assert att_control.use_sliding_window is False and att_control.use_att_sink is False
if att_control.use_alibi:
assert att_control.use_sliding_window is False, "alibi + sliding_window not supported"
assert att_control.tp_alibi is not None
return self._alibi_prefill_att(q=q, k=k, v=v, att_control=att_control, alloc_func=alloc_func)
else:
return self._nomarl_prefill_att(q=q, k=k, v=v, alloc_func=alloc_func)
return self._nomarl_prefill_att(q=q, k=k, v=v, att_control=att_control, alloc_func=alloc_func)

def _alibi_prefill_att(
self,
Expand Down Expand Up @@ -59,9 +59,21 @@ def _alibi_prefill_att(
)
return out

def _nomarl_prefill_att(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, alloc_func=torch.empty):
def _nomarl_prefill_att(
self,
q: torch.Tensor,
k: torch.Tensor,
v: torch.Tensor,
att_control: AttControl = AttControl(),
alloc_func=torch.empty,
):
from ...triton_kernel.att.prefill_att.context_flashattention_nopad import context_attention_fwd

if att_control.use_sliding_window:
sliding_window = att_control.sliding_window
else:
sliding_window = (-1, -1)

out = alloc_func(q.shape, q.dtype)
context_attention_fwd(
q,
Expand All @@ -74,6 +86,7 @@ def _nomarl_prefill_att(self, q: torch.Tensor, k: torch.Tensor, v: torch.Tensor,
self.infer_state.b_ready_cache_len,
self.infer_state.max_q_seq_len,
self.infer_state.req_manager.req_to_token_indexs,
sliding_window=sliding_window,
)
return out

Expand All @@ -94,17 +107,20 @@ def decode_att(
att_control: AttControl = AttControl(),
alloc_func=torch.empty,
):
assert att_control.use_sliding_window is False and att_control.use_att_sink is False
if att_control.use_alibi:
assert att_control.use_sliding_window is False, "alibi + sliding_window not supported"
assert att_control.tp_alibi is not None
return self._alibi_decode_att(q=q, k=k, v=v, att_control=att_control, alloc_func=alloc_func)
else:
q_head_num = q.shape[1]
k_head_num = k.shape[1]
if q_head_num == k_head_num:
assert att_control.use_sliding_window is False, "sliding_window not supported in non-gqa attention yet"
return self._normal_decode_flash_decoding_att(q=q, k=k, v=v, alloc_func=alloc_func)
elif q_head_num > k_head_num:
return self._normal_decode_gqa_flash_decoding_att(q=q, k=k, v=v, alloc_func=alloc_func)
return self._normal_decode_gqa_flash_decoding_att(
q=q, k=k, v=v, att_control=att_control, alloc_func=alloc_func
)
else:
raise NotImplementedError("error")

Expand Down Expand Up @@ -163,12 +179,18 @@ def _normal_decode_gqa_flash_decoding_att(
q: torch.Tensor,
k: torch.Tensor,
v: torch.Tensor,
att_control: AttControl = AttControl(),
alloc_func=torch.empty,
):
from ...triton_kernel.att.decode_att.gqa.flash_decoding.gqa_flash_decoding import (
gqa_token_decode_attention_flash_decoding,
)

if att_control.use_sliding_window:
sliding_window = att_control.sliding_window
else:
sliding_window = (-1, -1)

out = alloc_func(q.shape, q.dtype)

gqa_token_decode_attention_flash_decoding(
Expand All @@ -178,6 +200,7 @@ def _normal_decode_gqa_flash_decoding_att(
cache_v=v,
out=out,
alloc_tensor_func=alloc_func,
sliding_window=sliding_window,
)

return out
Expand Down
89 changes: 67 additions & 22 deletions lightllm/common/basemodel/basemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def __init__(self, kvargs):
"eagle_with_att",
"vanilla_no_att",
"eagle_no_att",
"eagle_frozen_kv",
]
self.prefill_graph: PrefillCudaGraph = None

Expand Down Expand Up @@ -649,14 +650,19 @@ def prefill_func(input_tensors, infer_state):
last_input_embs = infer_state._all_to_all_unbalance_get(data=last_input_embs)

predict_logits = self.post_infer.token_forward(last_input_embs, infer_state, self.pre_post_weight)
if isinstance(predict_logits, tuple):
predict_logits, mtp_main_output_hiddens = predict_logits
else:
mtp_main_output_hiddens = None
model_output = ModelOutput(logits=predict_logits)

# 特殊模型特殊模式的额外输出
if self.is_mtp_mode:
input_embs = self.pre_infer._tpsp_allgather(input=input_embs, infer_state=infer_state)
if infer_state.need_dp_prefill_balance:
input_embs = infer_state._all_to_all_unbalance_get(data=input_embs)
model_output.mtp_main_output_hiddens = input_embs.contiguous()
if mtp_main_output_hiddens is None:
mtp_main_output_hiddens = self.pre_infer._tpsp_allgather(input=input_embs, infer_state=infer_state)
if infer_state.need_dp_prefill_balance:
mtp_main_output_hiddens = infer_state._all_to_all_unbalance_get(data=mtp_main_output_hiddens)
model_output.mtp_main_output_hiddens = mtp_main_output_hiddens.contiguous()

# 在开启使用deepep的时候,需要调用clear_deepep_buffer做资源清理,没有启用的时候
# 该调用没有实际意义
Expand All @@ -679,12 +685,20 @@ def _token_forward(self, infer_state: InferStateInfo):
last_input_embs, infer_state=infer_state, layer_weight=self.pre_post_weight
)

if isinstance(predict_logits, tuple):
predict_logits, mtp_main_output_hiddens = predict_logits
else:
mtp_main_output_hiddens = None

model_output = ModelOutput(logits=predict_logits.contiguous())

# 特殊模型特殊模式的额外输出
if self.is_mtp_mode:
input_embs = self.pre_infer._tpsp_allgather(input=input_embs, infer_state=infer_state)
model_output.mtp_main_output_hiddens = input_embs.contiguous()
if mtp_main_output_hiddens is None:
mtp_main_output_hiddens = self.pre_infer._tpsp_allgather(input=input_embs, infer_state=infer_state)
if infer_state.need_dp_prefill_balance:
mtp_main_output_hiddens = infer_state._all_to_all_unbalance_get(data=mtp_main_output_hiddens)
model_output.mtp_main_output_hiddens = mtp_main_output_hiddens.contiguous()

# 在 cuda graph 模式下,输出需要转为 no ref tensor, 加强mem pool 的复用,降低显存的使用。
if infer_state.is_cuda_graph:
Expand Down Expand Up @@ -900,19 +914,30 @@ def _overlap_tpsp_context_forward(self, infer_state: InferStateInfo, infer_state
predict_logits, predict_logits1 = self.post_infer.overlap_tpsp_token_forward(
last_input_embs, last_input_embs1, infer_state, infer_state1, self.pre_post_weight
)
if isinstance(predict_logits, tuple):
predict_logits, mtp_main_output_hiddens = predict_logits
else:
mtp_main_output_hiddens = None
if isinstance(predict_logits1, tuple):
predict_logits1, mtp_main_output_hiddens1 = predict_logits1
else:
mtp_main_output_hiddens1 = None
g_cache_manager.cache_env_out()

model_output = ModelOutput(logits=predict_logits.contiguous())
model_output1 = ModelOutput(logits=predict_logits1.contiguous())

if self.is_mtp_mode:
input_embs = self.pre_infer._tpsp_allgather(input=input_embs, infer_state=infer_state)
input_embs1 = self.pre_infer._tpsp_allgather(input=input_embs1, infer_state=infer_state1)
if infer_state.need_dp_prefill_balance:
input_embs = infer_state._all_to_all_unbalance_get(data=input_embs)
input_embs1 = infer_state1._all_to_all_unbalance_get(data=input_embs1)
model_output.mtp_main_output_hiddens = input_embs.contiguous()
model_output1.mtp_main_output_hiddens = input_embs1.contiguous()
if mtp_main_output_hiddens is None:
mtp_main_output_hiddens = self.pre_infer._tpsp_allgather(input=input_embs, infer_state=infer_state)
if infer_state.need_dp_prefill_balance:
mtp_main_output_hiddens = infer_state._all_to_all_unbalance_get(data=mtp_main_output_hiddens)
model_output.mtp_main_output_hiddens = mtp_main_output_hiddens.contiguous()
if mtp_main_output_hiddens1 is None:
mtp_main_output_hiddens1 = self.pre_infer._tpsp_allgather(input=input_embs1, infer_state=infer_state1)
if infer_state1.need_dp_prefill_balance:
mtp_main_output_hiddens1 = infer_state1._all_to_all_unbalance_get(data=mtp_main_output_hiddens1)
model_output1.mtp_main_output_hiddens = mtp_main_output_hiddens1.contiguous()

return model_output, model_output1

Expand All @@ -939,15 +964,29 @@ def _overlap_tpsp_token_forward(self, infer_state: InferStateInfo, infer_state1:
predict_logits, predict_logits1 = self.post_infer.overlap_tpsp_token_forward(
last_input_embs, last_input_embs1, infer_state, infer_state1, self.pre_post_weight
)
if isinstance(predict_logits, tuple):
predict_logits, mtp_main_output_hiddens = predict_logits
else:
mtp_main_output_hiddens = None
if isinstance(predict_logits1, tuple):
predict_logits1, mtp_main_output_hiddens1 = predict_logits1
else:
mtp_main_output_hiddens1 = None

model_output = ModelOutput(logits=predict_logits.contiguous())
model_output1 = ModelOutput(logits=predict_logits1.contiguous())

if self.is_mtp_mode:
input_embs = self.pre_infer._tpsp_allgather(input=input_embs, infer_state=infer_state)
input_embs1 = self.pre_infer._tpsp_allgather(input=input_embs1, infer_state=infer_state1)
model_output.mtp_main_output_hiddens = input_embs.contiguous()
model_output1.mtp_main_output_hiddens = input_embs1.contiguous()
if mtp_main_output_hiddens is None:
mtp_main_output_hiddens = self.pre_infer._tpsp_allgather(input=input_embs, infer_state=infer_state)
if infer_state.need_dp_prefill_balance:
mtp_main_output_hiddens = infer_state._all_to_all_unbalance_get(data=mtp_main_output_hiddens)
model_output.mtp_main_output_hiddens = mtp_main_output_hiddens.contiguous()
if mtp_main_output_hiddens1 is None:
mtp_main_output_hiddens1 = self.pre_infer._tpsp_allgather(input=input_embs1, infer_state=infer_state1)
if infer_state1.need_dp_prefill_balance:
mtp_main_output_hiddens1 = infer_state1._all_to_all_unbalance_get(data=mtp_main_output_hiddens1)
model_output1.mtp_main_output_hiddens = mtp_main_output_hiddens1.contiguous()

if infer_state.is_cuda_graph:
model_output.to_no_ref_tensor()
Expand Down Expand Up @@ -1155,15 +1194,21 @@ def _init_padded_req(self):
def _gen_special_model_input(self, token_num: int):
special_model_input = {}

cls_name = str(self.__class__)
is_mtp_draft_model = (
"Deepseek3MTPModel" in str(self.__class__)
or "Qwen3MOEMTPModel" in str(self.__class__)
or "MistralMTPModel" in str(self.__class__)
or "Glm4MoeLiteMTPModel" in str(self.__class__)
"Deepseek3MTPModel" in cls_name
or "Qwen3MOEMTPModel" in cls_name
or "MistralMTPModel" in cls_name
or "Glm4MoeLiteMTPModel" in cls_name
or "Gemma4MTPModel" in cls_name
)
if is_mtp_draft_model:
# Gemma-4's drafter consumes the recurrent hidden state in backbone
# width (the target's hidden size), not its own draft width; the other
# MTP drafters have draft width == backbone width so hidden_size fits.
hidden_size = self.config.get("backbone_hidden_size", self.config["hidden_size"])
special_model_input["mtp_draft_input_hiddens"] = torch.randn(
token_num, self.config["hidden_size"], dtype=self.data_type, device="cuda"
token_num, hidden_size, dtype=self.data_type, device="cuda"
)
else:
special_model_input["mtp_draft_input_hiddens"] = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,13 @@ def _context_attention_wrapper_run(
) -> torch.Tensor:
if torch.cuda.is_current_stream_capturing():
q = q.contiguous()
cache_kv = cache_kv.contiguous()
_q, _cache_kv = (
tensor_to_no_ref_tensor(q),
tensor_to_no_ref_tensor(cache_kv),
)
# cache_kv is None for layers that own no K/V slot (e.g. gemma4
# KV-shared layers, which read K/V from a prior layer's cache and
# ignore this arg in _context_attention_kernel). Skip the
# graph-input plumbing for it instead of crashing on None.
cache_kv = cache_kv.contiguous() if cache_kv is not None else None
_q = tensor_to_no_ref_tensor(q)
_cache_kv = tensor_to_no_ref_tensor(cache_kv) if cache_kv is not None else None
pre_capture_graph = infer_state.prefill_cuda_graph_get_current_capture_graph()
pre_capture_graph.__exit__(None, None, None)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ def __init__(
num_fused_shared_experts: int = 0,
layer_num: int = 0,
network_config: Dict[str, Any] = None,
per_expert_scale_name: str = "",
) -> None:
super().__init__(data_type=data_type)
self.w1_weight_name = gate_proj_name
self.w2_weight_name = down_proj_name
self.w3_weight_name = up_proj_name
self.e_score_correction_bias_name = e_score_correction_bias_name
# gemma4 的专家计算出的值都需要一个 scale 值,每个专家有自己独立的scale参数
# per_expert_scale_name 是专家的scale参数权重的名称, 为 "" 表示没有专家独立的scale参数
self.per_expert_scale_name = per_expert_scale_name
self.weight_prefix = weight_prefix
self.layer_num_ = layer_num
self.global_rank_ = get_global_rank()
Expand Down Expand Up @@ -145,6 +149,7 @@ def experts(
topk_group=topk_group,
num_expert_group=num_expert_group,
is_prefill=is_prefill,
per_expert_scale=self.per_expert_scale,
)

def low_latency_dispatch(
Expand Down Expand Up @@ -261,25 +266,42 @@ def combine(

def load_hf_weights(self, weights):
# Load bias
if self.e_score_correction_bias_name in weights:
self.e_score_correction_bias.copy_(weights[self.e_score_correction_bias_name])
self._load_e_score_correction_bias(weights)
self._load_per_expert_scale(weights)
self._load_weight(self.expert_idx_to_local_idx, weights)
if self.redundancy_expert_num > 0:
self._load_weight(self.redundancy_expert_idx_to_local_idx, weights)

def verify_load(self):
return all(all(_weight_pack.load_ok) for _weight_pack in self.w1_list + self.w2_list + self.w3_list)
weight_load_ok = all(all(_weight_pack.load_ok) for _weight_pack in self.w1_list + self.w2_list + self.w3_list)
per_expert_scale_load_ok = (
True if self.per_expert_scale is None else getattr(self.per_expert_scale, "load_ok", False)
)
e_score_correction_bias_load_ok = (
True if self.e_score_correction_bias is None else getattr(self.e_score_correction_bias, "load_ok", False)
)
return weight_load_ok and per_expert_scale_load_ok and e_score_correction_bias_load_ok

def _create_weight(self):
intermediate_size = self.split_inter_size
self.e_score_correction_bias = None
self.per_expert_scale = None
# Create e_score_correction_bias
if self.e_score_correction_bias_name:
self.e_score_correction_bias = torch.empty(
(self.n_routed_experts,),
dtype=self.data_type_,
device=f"cuda:{self.device_id_}",
)
self.e_score_correction_bias.load_ok = False

if self.per_expert_scale_name:
self.per_expert_scale = torch.empty(
(self.n_routed_experts,),
dtype=torch.float32,
device=f"cuda:{self.device_id_}",
)
self.per_expert_scale.load_ok = False

self.w13, w13_param_list = self.quant_method.create_moe_weight(
out_dims=[intermediate_size, intermediate_size],
Expand All @@ -299,6 +321,16 @@ def _create_weight(self):
self.w3_list: List[WeightPack] = self._get_expert_weight_list(w13_param_list[1])
self.w2_list: List[WeightPack] = self._get_expert_weight_list(self.w2)

def _load_e_score_correction_bias(self, weights: Dict[str, torch.Tensor]):
if self.e_score_correction_bias_name and self.e_score_correction_bias_name in weights:
self.e_score_correction_bias.copy_(weights[self.e_score_correction_bias_name])
self.e_score_correction_bias.load_ok = True

def _load_per_expert_scale(self, weights: Dict[str, torch.Tensor]):
if self.per_expert_scale_name and self.per_expert_scale_name in weights:
self.per_expert_scale.copy_(weights[self.per_expert_scale_name].to(self.per_expert_scale.dtype))
self.per_expert_scale.load_ok = True

def _get_expert_weight_list(self, weight_pack: WeightPack):
weight_list = []
for idx in range(self.local_n_routed_experts):
Expand All @@ -307,7 +339,6 @@ def _get_expert_weight_list(self, weight_pack: WeightPack):
return weight_list

def _load_weight(self, expert_idx_to_local_idx: Dict[int, int], weights: Dict[str, torch.Tensor]):

# Load each expert with TP slicing
for expert_idx, local_expert_idx in expert_idx_to_local_idx.items():
with self.lock:
Expand Down
Loading