是时候准备实习和面试了。

不同以往的是,当前职场已不再是那个双向奔赴时代了。求职者在变多,HC 在变少,岗位要求还更高了。

最近,我们又陆续整理了很多大厂的面试题,帮助一些球友解惑答疑,分享技术面试中的那些弯弯绕绕。

今年上半年给 SGLang 添加了优化版的 CPU 后端,这篇文章记录一下相关的内容细节,也算是对上半年工作的一个总结。

相关工作已经发布在 LMSYS Blogs 里:

https://lmsys.org/blog/2025-07-14-intel-xeon-optimization/

这里对英文版的顺序做了少许调整,英文版是正常的逻辑顺序,中文版是我实际干活的顺序。

01.背景

SGLang 上的工作其实 24 年 Q4 就开始了,不过当时没有特别的需求,就是慢慢悠悠地干。

很多时候做项目也是在赌,PyTorch 的优化工作进入尾声所以要找新方向,我那时候下注的刚好是 SGLang + DeepSeek,那会在对齐 V2。

春节期间幻方发布了 DeepSeek R1,成了爆款,于是我们也紧急提速,春节之后加班两个月把 DeepSeek R1 在 SGLang CPU 后端上的优化解决了。后续逐步把所有代码都开源到了社区,目前开源工作也大致完成。

定位是低成本的 Large MoE serving 场景:单台 CPU 服务器大致是 10w 左右的价格,能满足 DeepSeek R1 671B 满血版 4个 concurrent request 实时性要求。

当然如果并发要求比较高,还是 N 卡集群是最优解,但这个贵了一个数量级,如果并发需求比较低,弄一台 CPU 服务器就够了。

这篇文章侧重 LLM 中(尤其是 DeepSeek)中各种 Kernel 级别的优化策略,我一般不写广文,公司有官方渠道发广。

大多数是对齐 GPU 方案的,我在 CPU 上做了一些相应的改变。一般现在都是先看看 cuda/triton 怎么优化,然后 map 过来。

02.摘要

如下:

  • SGLang 目前支持 native CPU 后端。

  • 支持 BFloat16,INT8 和 FP8:INT8 用 per channel quant,FP8 是 block quant。

  • 支持 DeepSeek R1 671B,Qwen3 235B,Llama3 70B 等主流 MoE/非MoE 模型。

  • 对比 Llama.cpp:TTFT 6-14x 加速,TPOT 2-4x 加速。

  • Multi Numa Support:通过类似于 GPU 多卡的 Tensor Parallel 完成。

[NB] native 指的是纯 C++ 后端,而不是通过 torch.op 的调用。因为 SGLang 这个项目本身很重要,所以从性能角度出发,完全抛弃 torch。

torch 更多的是作为 tensor 的容器来负责 memory 管理,而不参与任何计算。

oneDNN 因为接口问题很难和目前 LLM 需求对齐,另外很多时候性能不尽如人意而且开发进度很慢很慢,所以这次在 SGLang 上面 kernel 部分完全采用 intrinsics + micro kernel 方式,弃用 oneDNN 和 oneMKL。

所以 SGLang CPU 后端没有额外的 denpendency,唯一的 dependency 就是 PyTorch 自己。

另外,目前的 native CPU 后端仅支持 Intel Xeon 第 4 代及以上,需要 AMX 支持,推荐第 6 代。其他平台我们保证 functionality 不保证 performance。

03.CPU 后端的优化策略

这里侧重介绍四个主要的 kernel:Decode Attention,Extend Attention,FusedMoE 还有 FP8 GEMM。

(1)Decode Attention

SGLang 的 KV cache 管理采用了 Radix Attention 的算法,这里不展开,有很多人介绍。

RA 后端后两个接口:Extend Attn 和 Decode Attn,前者处理 prefill 后者处理 decode。

我们添加了一个新的 RA 后端:intel_amx_backend。整个这个活里面最麻烦的就是这个 decode,尤其是 deepseek,因为加了 weight absorption,幸好我从 V2 开始写,V3/R1 和 V2 这部分其实没什么区别。

目前的 CPU 实现是几个 critical optimization 叠加的结果,这里试图从逻辑上将其还原为最初的简单形式(MHA->GQA->MLA),不然直接看到最终版代码会很晕。

首先,flash decoding 适配 MHA。

弄清楚 scaled dot product attention 里面输入的 QKV 的 shape 就会很容易理解,一般我们标注成 [B, H, L, E] 和 [B, H, S, Ev],其中 L 是 query 的 sequence length,S 是 KV 的 sequence length。

一般我们会在 [B, H, MB] 3 个 dimensions 上 parallel,其中 MB 是 L 的 blocking。

对于 prefill,这个尺寸够大足够多个核分;对于 decode,因为 L=1 (MB=1),当 request 小的时候,退化为 [1, H, 1] 就只剩一个 H 可以用来并行。

DS-R1 H 是 22,但我们一个 socket 上有 128 cores,所以需要创造另一个 dimension 来增大 parallel 的尺寸。

我们会去把 S(KV sequence length)切分成多个 splits,这样 parallel 尺寸变成了 [B, H, kvSplits],而每个 split 上面还是常规的 online softmax 算法 - 这就是 flash decoding 的思想。

这个操作本身是由一定 overhead 的,因为多了一个对于 kvSplits 的 reduce 操作。

图片

Fig-1:Flash Decoding Implementation

 这份完整版的大模型 AI 学习和面试资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

其次,Head dimension 的 folding 适配 GQA。

对于 MHA 来说,我们算的是 H 个 GEMV;而对于 GQA/MLA 的 Hv = 1, 我们可以把 head fold 到 GEMM 里面,增加计算密度。

Head 对应 GEMM 里面的 M,在 DS R1 上面是 22,这一步对于 AMX 来说非常重要,一般 GEMM 的 M 越大那么 AMX 优势越大。

图片

在代码中,对 Head 做 blocking 的大小做了取舍,因为如果不对 Head 做 blocking,那么 parallel 的大小又不够。

实验下来选取的方案是:B=1, BlockH = 6;1<B<16, BlockH=11;B>16, BlockH=22。

最后,借用 FlashMLA 的思想。

因为 MLA 里面 key 和 value 是 share 一块内存,所以 FlashMLA 里面用 shared memory 只从 global memory 里面 load 一次 KV cache。

CPU 的实现采用了类似的策略 (Fig-2.) SGLang 里面拿 KV cache 是个 两次 查表得过程,我们每 32 行 (BLOCK_N 的大小),然后对数据进行 pack。

这个地方写起来非常麻烦,AMX 要求 B 矩阵是 VNNI format [K/2, N, 2],但是 SDPA 里面的两个 GEMM 是不一样的,第一个是 NT,第二个是 NN;所以需要 pack 成两块不同的 buffer。

图片

Fig-2:MLA Decoding Implementation

最终版的代码会比单纯使用 MHA 代码快 4-5 倍,这里是 AMX 发力的地方。时间几乎都是在拿 KV cache 上,GEMM 本身非常快 <10% 的占比。

另外,我们也把 KV cache 的存储操作 fuse 到了 decode attn 里面。这个操作本身没什么计算量,但如果不 fuse 会占差不多 12% 的时间。

原因是 torch 的 index (用[])会重创建一个对于 tensor 的描述结构,叫 TensorImpl,然后 copy 的时候会有一个结构叫 TensorIterator,都很费时间。torch 里面的坑还是不少的。

(2)Extend Attention

这部分比较简单一些,就是 Flash Attention V2,没什么花头。

值得一提的就是 SGLang 里面对 Prefill Attention 做了切分:prefix 对应的是历史信息,这部分 attention 是个矩形;

extend 是当前对话的 prompt,对用的 attention 是个下三角。有很多文章详细介绍这部分内容,不再赘述。

图片

Fig-1:Flash Attention in Prefilling Phase

只需要常规地对 Query sequence 和 KV sequence 做 blocking 即可。

之前我也写过文章,Flash Attention V2 其实和 xFormer 的 Efficient Attention 数学上是等价的。

Scaled Dot Product Attention(SDPA)在 CPU 上的性能优化,只不过 Efficient Attention 没做 blocking。

在 CPU 上面,因为 AMX 的计算使用 FP32 做 accumulation(A: BF16 x B: BF16 = C: FP32),所以要对中间变量做一些 fusion。

把 softmax momentum 的更新和 data type conversion fuse 到一起,然后按照 L2 的尺寸做 blocking。

这里介绍一个小技巧,对于经常写 flash attention 的小伙伴一定有一个困扰:这玩意中间过程这么长,怎么确定我写对了呢...

有时候可能是某个 block 算错了,那么怎么快速定位?可以把 KV 手动设置成 head index,例如 trick,然后打印 attn 和 output,有惊喜哦。一眼就能看出来哪里算错了!

(3)FusedMoE

MoE 这个模块对性能非常重要,对于 CPU 来说 concurrent requests 不可能太高,大部分时间都是花在 MoE 上面。

原版的 MoE 的实现对等于在 experts 之间串行执行,gather 选出每个 expert 的 activation 的部分,然后算 GEMM-SiLU-GEMM。

llama.cpp 和 原版的 IPEX 对应的都是这个逻辑,慢的原因是没有在 experts 之间做并行,只对 GEMM 的 M 和 N 并行。当然 torch 实现还有别的坑,就不细说了。

提高性能的关键是 parallel experts。这个地方我完全复刻了 GPU kernel 的算法,首先通过 moe_align_index 的操作重拍 activation 的 indices,然后对 sorted_ids 进行 blocking,记录好对等的 expert id。

图片

Fig-4:MoE Implementation

我在此基础上做了几个小幅改进:

SiLU and MUL fusion:这部分操作 fuse 进 GEMM1,把 W13 切分,左边做 SiLU 右边做 MUL。

需要改造 GEMM 基本操作,变成 A * [B1, B2] = [C1, C2],然后算 SiLU(C1) * C2。

Dynamic Quant Fusion:INT8 目前是 DA8W8 的格式,我把 quant 过程和 fetch 过程都 fuse 到了一起。

这里面写了 AVX512 和 AMX 两套 kernel,功能完全对等,会跟进输入的大小自动选择走哪个。

为了对齐 AVX512 和 AMX,需要对 B 做 compensation:原因是 AVX512 是没有 S8S8 的,这个 AMX 是有的。

这里面是按照 U8S8 算的,就要对 B 做一个 -128B 的补偿项:A x B = (A + 128) x B - 128 x B。

把 S8S8 转化成 U8S8 算。这个地方性能和直接算 S8S8 是一样的,因为补偿项是在 prepack weight 时做掉的,A+128 和 quantize 是 fuse 到一起的,不花额外的时间。

Thread Offset:排序过程并不是全排,因为我们只需要知道每个 expert 对应的 activation index 的集合,不需要其是有序的。

这里我在排序过程中透传 thread offsets 到计算 kernel 中,记录每个 M block 的起始位置。

这些优化都加上之后,memory efficiency 实测值能到 85%,在 MRDIMMs 能到 1.45 TB/s,这差不多就是 CPU 目前的物理极限了。

(4)FP8 GEMM

DS R1 的另一大难点就是 FP8,因为 CPU 是不支持 FP8 计算的,而且 data type conversion 奇慢无比。

起初我也不想做,但无奈有客户就要 FP8,后来花了很大力气把 FP8 做到 INT8 80%-90% 性能。

我会在另外的文章里面写一下怎么用 micro kernel 快速地实现一个 AMX GEMM 和怎么把 dtype conversion 和 cache blocking 藏起来,这里篇幅原因只是简单写一下。

Weight Only FP8:这个很好理解,因为硬件不支持,只能搞 WOQ,用 BF16 算。

Vectorized Conversion:FP8 GEMM 难点是 dtype 转换。我们试了两种方式:a)查表;b) intrinsics。

无奈的是两种方式都奇慢无比,大概六七十个 cycle,对比 x86 是每个 0.5 cycle 一条计算,这个实在是慢的不行。

后来剔除了 b) 方案里面的 NaN checks 和 DENORM 处理,能缩到三十 cycles。

我们有团队查过 DS R1 里面大概 0.07% 是 DENORM,目前我们这个方案在测 accuracy 时都能和 NV GPU 对齐,所以还好。

开发过程中有个小插曲,是有同事搞错了把 0.07% 抄成 7% 了,我心想 7% 肯定要处理,但死活快不了 - 后来说搞错了,当时气得我想砸键盘啊... 但后来想想只能说大家都是牛马,都不易。

WOQ Aware Cache Blocking:我们都知道对于 B 矩阵是由多次访问的,访问次数就是 A 矩阵的分块数量。

这里我把 dtype conversion 和 cache blocking 联合考虑,保证每个 thread 上的 B blocks 只 convert 一次,就是把 FP8->BF16 过程尽量藏起来。

还有一个地方我自己也不是很明白,加 software prefetch 对 FP8 GEMM 有奇效,能加速差不多 30%;

搞优化很多时候靠猜的,software prefetch 很多时候都是负优化,但这个地方很有用。

04.多 NUMA 的设计

现代的 CPU server 一般都是 NUMA(Non-uniform memory access)的设计,比如 Xeon6 顶配机器是 6 个 NUMA Node。

cross numa 的内存访问比较慢,所以要充分利用 CPU server 的一个前提就是 设计 multi numa parallelism。

llama.cpp 比较慢的另一个原因是没有这个东西。

我们采用了类似 multi-GPU Tensor Parallel 的设计,每个 CPU NUMA node 对应 TP 中的一个 rank。

然后采用了 shared memory 的方式实现了高效的 all-reduce,all-gather 通信源语。这部分借鉴了 deepseed 项目的代码。

我们的实测数据在但 CPU 上 DS R1 671B 通信开销在 3% 左右。

05.性能数据

我们一共跑了 4 个 LLM model,大小都有:DeepSeek-R1-671B, Qwen3-235B, DeepSeek-R1-Distilled-70B 和 Llama3.2-3B。

对比 reference 选的 llama.cpp,sglang INT8 对比 GGUF Q8;因为 llama.cpp 没有高效的 FP8 实现,所以 sglang FP8 也是拿 GGUF Q8 对比。

另外 llama.cpp 跑 multi instance,因为开两个 socket 比一个 socket 还要慢。

图片

我们内部版本 TPOT 额外能快 10%,TTFT 能快 50%-80%,后续会对齐 upstream 版本。

06.后续工作

后续会加入 graph mode 的支持,这个主要是为了剔除 python overhead,torch.compile 搞这个还是挺有用的。

另外还会提供 INT4 的支持,还有别的团队在做类似于 KTransformer 的 GPU/CPU offload 的模式。另外,章老师建议我试试异构的 PD 分离,接下来会实现出来。

07.写在最后

SGLang 上的优化工作是我过去两年中难得的干得比较开心的项目。公司和部门背景的原因几乎就没什么正面因素,此处省略一万字 :(。

另外,这个项目难度真的很大,有好几次我也没把握能搞定,如果我不能在短时间内弄出比 oneDNN 好的性能,那这口大锅就是我的。

而且写 kernel 的工作一旦开始就不能停,停了就会断思路,所以大部分工作都是晚上做的,很辛苦。

我比较高兴的地方有两点:一是能认识很多青年才俊,sglang 的 Yineng Zhang,Jiexin Liang 还有 Mick。还有清华的章老师。

sglang 开发者主要都是国人,所以 slack channel 里面大家都用中文,效率非常高,沟通很顺畅。

另一点是能看到我们团队(intel pytorch team)的成长。这个项目其实时间非常紧张,我上班之后的习惯是周五晚上不加班,其他时间都可以加班。这种难度的项目加班也不一定能搞定,不加肯定搞不定。

我其实从来没要求过别的同事加班,我也不是 manager 我没权利这么做,但可以说全员晚上 10 点都在线(一叫马上回复,不是那种挂机的),大家可能就是单纯地作为一名工程师,想把事情做成。

08.大模型风口已至:月薪30K+的AI岗正在批量诞生

2025年大模型应用呈现爆发式增长,根据工信部最新数据:

国内大模型相关岗位缺口达47万

初级工程师平均薪资28K

70%企业存在"能用模型不会调优"的痛点

真实案例:某二本机械专业学员,通过4个月系统学习,成功拿到某AI医疗公司大模型优化岗offer,薪资直接翻3倍!

 这份完整版的大模型 AI 学习和面试资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

09.如何学习大模型 AI ?


🔥AI取代的不是人类,而是不会用AI的人!麦肯锡最新报告显示:掌握AI工具的从业者生产效率提升47%,薪资溢价达34%!🚀

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

1️⃣ 提示词工程:把ChatGPT从玩具变成生产工具
2️⃣ RAG系统:让大模型精准输出行业知识
3️⃣ 智能体开发:用AutoGPT打造24小时数字员工

📦熬了三个大夜整理的《AI进化工具包》送你:
✔️ 大厂内部LLM落地手册(含58个真实案例)
✔️ 提示词设计模板库(覆盖12大应用场景)
✔️ 私藏学习路径图(0基础到项目实战仅需90天)

 

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

*   大模型 AI 能干什么?
*   大模型是怎样获得「智能」的?
*   用好 AI 的核心心法
*   大模型应用业务架构
*   大模型应用技术架构
*   代码示例:向 GPT-3.5 灌入新知识
*   提示工程的意义和核心思想
*   Prompt 典型构成
*   指令调优方法论
*   思维链和思维树
*   Prompt 攻击和防范
*   …

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

*   为什么要做 RAG
*   搭建一个简单的 ChatPDF
*   检索的基础概念
*   什么是向量表示(Embeddings)
*   向量数据库与向量检索
*   基于向量检索的 RAG
*   搭建 RAG 系统的扩展知识
*   混合检索与 RAG-Fusion 简介
*   向量模型本地部署
*   …

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

*   为什么要做 RAG
*   什么是模型
*   什么是模型训练
*   求解器 & 损失函数简介
*   小实验2:手写一个简单的神经网络并训练它
*   什么是训练/预训练/微调/轻量化微调
*   Transformer结构简介
*   轻量化微调
*   实验数据集的构建
*   …

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

*   硬件选型
*   带你了解全球大模型
*   使用国产大模型服务
*   搭建 OpenAI 代理
*   热身:基于阿里云 PAI 部署 Stable Diffusion
*   在本地计算机运行大模型
*   大模型的私有化部署
*   基于 vLLM 部署大模型
*   案例:如何优雅地在阿里云私有部署开源大模型
*   部署一套开源 LLM 项目
*   内容安全
*   互联网信息服务算法备案
*   …

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐