[CPU] Fix MoE layer support for DeepSeek-OCR models (#12555)

This commit is contained in:
jianan-gu
2026-03-19 13:57:55 +08:00
committed by GitHub
parent 85fe8c6793
commit 8d4fcf2f7b
2 changed files with 65 additions and 10 deletions

View File

@@ -48,7 +48,12 @@ from sglang.srt.layers.vocab_parallel_embedding import (
)
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
from sglang.srt.model_loader.weight_utils import default_weight_loader
from sglang.srt.utils import add_prefix
from sglang.srt.utils import add_prefix, cpu_has_amx_support, is_cpu
_is_cpu_amx_available = cpu_has_amx_support()
_is_cpu = is_cpu()
if _is_cpu and _is_cpu_amx_available:
import sgl_kernel # noqa: F401
class DeepseekMLP(nn.Module):
@@ -176,14 +181,31 @@ class DeepseekMoE(nn.Module):
# router_logits: (num_tokens, n_experts)
router_logits, _ = self.gate(hidden_states)
topk_output = self.topk(hidden_states, router_logits)
final_hidden_states = fused_moe.fused_moe(
hidden_states,
w1=self.w1,
w2=self.w2,
topk_output=topk_output,
moe_runner_config=MoeRunnerConfig(inplace=True),
)
if _is_cpu and _is_cpu_amx_available:
topk_weights, topk_ids, _ = topk_output
final_hidden_states = torch.ops.sgl_kernel.fused_experts_cpu(
hidden_states,
self.w1,
self.w2,
topk_weights,
topk_ids,
False, # inplace # See [Note] inplace should be False in fused_experts.
0, # CPUQuantMethod.UNQUANT,
None, # w1_scale
None, # w2_scale
None, # w1_zp
None, # w2_zp
None, # block_size
True, # is_vnni
)
else:
final_hidden_states = fused_moe.fused_moe(
hidden_states,
w1=self.w1,
w2=self.w2,
topk_output=topk_output,
moe_runner_config=MoeRunnerConfig(inplace=True),
)
if self.config.n_shared_experts is not None:
final_hidden_states = final_hidden_states + shared_output
final_hidden_states = tensor_model_parallel_all_reduce(final_hidden_states)

View File

@@ -41,6 +41,10 @@ from sglang.srt.model_loader.weight_utils import default_weight_loader
from sglang.srt.models.deepseek import DeepseekForCausalLM
from sglang.srt.models.deepseek_v2 import DeepseekV2ForCausalLM, DeepseekV3ForCausalLM
from sglang.srt.models.transformers import maybe_prefix
from sglang.srt.utils import cpu_has_amx_support, is_cpu
_is_cpu_amx_available = cpu_has_amx_support()
_is_cpu = is_cpu()
NestedTensors: TypeAlias = Union[
list["NestedTensors"],
@@ -1772,7 +1776,6 @@ class DeepseekOCRForCausalLM(nn.Module):
params_dict = dict(self.named_parameters())
loaded_params: Set[str] = set()
for name, loaded_weight in weights:
if "rotary_emb.inv_freq" in name:
continue
@@ -1852,6 +1855,36 @@ class DeepseekOCRForCausalLM(nn.Module):
raise RuntimeError(
f"Some weights are not initialized from checkpoints: {unloaded_params}"
)
self.post_load_weights()
def post_load_weights(self):
if _is_cpu and _is_cpu_amx_available:
from sglang.srt.layers.amx_utils import _amx_process_weight_after_loading
layer_ids = int(self.config.num_hidden_layers)
first_k_dense_replace_id = (
self.config.first_k_dense_replace
if hasattr(self.config, "first_k_dense_replace")
else -1
)
moe_layer_freq_id = (
self.config.moe_layer_freq
if hasattr(self.config, "moe_layer_freq")
else 1
)
for layer_id in range(0, layer_ids):
if (
layer_id >= first_k_dense_replace_id
and layer_id % moe_layer_freq_id == 0
):
if (
hasattr(self.model, "model")
and hasattr(self.model.model, "layers")
and hasattr(self.model.model.layers[layer_id], "mlp")
):
self_moe = self.model.model.layers[layer_id].mlp
if hasattr(self_moe, "w1") and hasattr(self_moe, "w2"):
_amx_process_weight_after_loading(self_moe, ["w1", "w2"])
EntryClass = [DeepseekOCRForCausalLM]