1.cache line 的大小
CPU cache line 64B
GPU cache line :
L1 128B ,恰好支持一个 一个warp 32 * 4B = 128B;
128B 分为4个 32B的扇区,作用是可以区分,当发生线程束发散的时候,可以避免整个cache line同时访问,降低总线带宽。
L2 缓存就是32B
2.roofline模型
横轴: 计算强度 = 浮点数运算次数/总内存数据移动量
纵轴: 计算次数
FLOP/Byte
斜线部分斜率:内存带宽
计算密集型: 右侧,运算强度>拐点值
内存密集型:左侧,运算强度< 拐点值
下图中: A1和A2是内存密集型;A3是计算密集型
A2可以通过提高内存利用率来提高程序的性能。
3.BF16和FP16的区别
FP16: 1+5+10
BF16: 1+8+7
FP32: 1+8+23
参数权重:BF16
优化器状态:FP32
激活值:FP16+BF6
4.算子融合
收益:减少内存访问延迟,提高缓存利用率,并减少执行过程中的内存移动
分类:水平融合、垂直融合
融合规则:
TVM中对算子类型进行了区分:
- Injective: 一对一映射,逐点操作。
- Reduction:
5.MHA/GQA/MQA/MLA等注意力原理与显存计算
符号定义
- b:batch size
- L:当前已生成序列长度(cache 长度)
- $n_{layer}$ :层数
- $d_{model}$:模型维度
- h: query head 数(attention heads)
- $h_{kv}$:key/value head 数(MHA: $h_{kv}=h$,GQA: $h_{kv}<h$,MQA: $h_{kv}=1$)
- d_k:每个 head 的维度(通常 $d_k=d_{model}/h$)
- dtype 大小:
- fp16 / bf16:2 bytes
- fp32:4 bytes
单层 KV-cache
$$
KV_{per-layer} = 2 \cdot b \cdot h_{kv} \cdot L \cdot d_k \cdot \text{bytes}
$$
全模型 KV-cache
$$
{total} = 2 \cdot b \cdot n_{layer} \cdot h_{kv} \cdot L \cdot d_k \cdot \text{bytes}
$$
带入 $d_k = d_{model}/h$:
$$
{total} = 2 \cdot b \cdot n_{layer} \cdot h_{kv} \cdot L \cdot \frac{d_{model}}{h} \cdot \text{bytes}
$$
MLA:
6.flashAttention
优质参考文章:
https://zhuanlan.zhihu.com/p/676655352
https://www.cnblogs.com/rossiXYZ/p/18791822#12-transformer%E7%9A%84%E5%86%85%E5%AD%98%E5%92%8C%E8%AE%A1%E7%AE%97
7.动态图和静态图的区别
动态图(eager):运行时即刻执行,控制流灵活,便于调试;但优化空间有限,跨算子融合和全局内存规划较难。
静态图(graph):先构图再执行,可做全局优化(算子融合、常量折叠、内存复用、调度重排);但控制流表达复杂,调试成本更高。
工程实践:训练/研发阶段更偏动态图,部署/推理阶段更偏静态图或半静态(如 TorchScript、XLA、TensorRT)。
8.pybind 绑定方法:
常用方式:
PYBIND11_MODULE定义模块,m.def绑定函数。py::class_绑定类、构造函数、方法与属性。py::enum_绑定枚举。
常见要点:
- 生命周期:
py::return_value_policy控制返回对象所有权。 - 性能:启用
py::gil_scoped_release释放 GIL 执行耗时计算。 - Numpy:
py::array/buffer_info支持零拷贝视图。
9.libtorch
libtorch 是 PyTorch 的 C++ 前端,提供:
- 模型加载与推理(
torch::jit::load/torch::jit::Module)。 - 张量算子 API(
torch::Tensor)与自动求导(torch::autograd)。 - 与 CUDA/cuDNN 集成,用于高性能部署。
典型场景:C++ 端高性能推理服务、与现有 C++ 系统深度集成、需精细控制线程/内存。
10.对于具体的量化操作,如果采用朴素的方法,W4A32模型,反量化操作是什么时候,反量化计算时是行主序还是列主序?为什么?
朴素做法:在 GEMM 前将 W4 反量化成 FP16/FP32,再执行常规矩阵乘;即“先反量化、后计算”。
反量化次序与布局:
- 推理时权重常按列分组量化(如 per-channel/ per-group),因此反量化通常按列(K 维)取缩放;
- 但实际内核更关注读取连续性,会把反量化融合进 GEMM 的 K 维循环,按当前实现的 pack 布局做“块级反量化”。
本质:不是行主序或列主序的问题,而是内核的打包布局与访存连续性决定反量化在 K 维块上进行,以减少带宽与访存不连续。
11.MoE的原理和好处是什么?
原理:对每个 token 通过门控网络选择少量专家(Top-k),仅激活部分专家参与计算;其余专家不参与。
好处:
- 计算稀疏化:参数规模增大但每步 FLOPs 近似不变。
- 提升模型容量与表达能力。
- 训练/推理可用更小的批次代价获得更大的参数量。
挑战:负载不均衡、通信开销(All-to-All)、路由不稳定,需要平衡损失或负载约束。
12.Pagedattention解决了什么问题
解决 KV-cache 的显存碎片与动态序列管理问题:
- 将 KV-cache 按页(block)管理,实现动态序列长度的弹性分配。
- 避免为最大长度预留连续大块显存,显著提升利用率。
- 便于批次中不同序列的插入/删除与并行调度。
13.Vllm除了Pagedattention还有其他什么优化
主要优化:
- 连续批处理(continuous batching):动态加入请求,减少空泡。
- 高效调度器:优先级/公平性调度,提升吞吐与延迟平衡。
- KV-cache 共享与复用策略(如 prefix caching)。
- CUDA kernel 融合与高效内存拷贝路径。
14.FlashAttention主要解决了什么问题,V1到V4的改进
核心问题:标准注意力需要 $O(L^2)$ 显存存储注意力矩阵,带宽与显存压力极大。
FlashAttention 思路:分块计算并在寄存器/共享内存中完成 softmax 归一化,避免显式存储全量注意力矩阵。
版本演进(概览):
- V1:提出分块在线 softmax,显存从 $O(L^2)$ 降为 $O(L)$。
- V2:更强的 kernel 融合与更优的块调度,吞吐提升。
- V3/V4:针对新架构与 FP8/张量核心优化,支持更多布局与更高带宽利用率。
15.安培架构和候陪架构的主要区别,FP8 一般用于什么计算?
安培(Ampere)到 Hopper 的关键差异:
- Hopper 引入更强的 Tensor Core(如 FP8 支持)与异步加载、调度优化。
- 更高带宽 HBM 与更大的共享内存/寄存器配置。
- 对 Transformer 友好的特性(如更高效的矩阵/注意力计算路径)。
FP8 主要用于:
- 大模型训练/推理中的矩阵乘(GEMM)与注意力计算,尤其在精度可接受的场景下提升吞吐。
16.常见的量化算法有哪些? AWQ量化算法的原理是什么?
常见量化:
- PTQ:GPTQ、AWQ、SmoothQuant。
- QAT:训练中量化感知。
- 低比特:INT8/INT4、NF4、FP8。
AWQ(Activation-aware Weight Quantization):
- 用少量校准数据估计激活分布。
- 按通道/分组选择缩放,保留对激活敏感的权重范围。
- 通过“感知激活的权重缩放”减少量化误差,兼顾精度与低比特。
17.llama.cpp中有哪些量化算法?有哪些图优化手段?
量化:
- 常见有 Q8_0、Q6_K、Q5_K、Q4_K、Q2_K 等分组/块量化格式。
- 支持对称/非对称缩放与分组缩放。
图优化与执行优化:
- 算子融合与内核特化(如 GEMM/attention 内核)。
- KV-cache 复用与内存复用。
- 线程并行与向量化(AVX/NEON)。
- 预打包权重,减少运行期开销。
18.多线程、双缓冲、向量化分别会在什么场景下能够提升效果?分别适应哪些内核?
多线程:
- 适合计算密集或可分块并行的内核(GEMM、卷积、embedding 聚合)。
- 前提是任务足够大,避免线程调度开销占比过高。
双缓冲:
- 适合计算与数据搬运可重叠的场景(内存带宽受限、IO/PCIe 传输)。
- 常用于流水化的注意力或 GEMM 分块。
向量化:
- 适合连续内存、规则计算(逐点算子、softmax、layernorm、GEMM 内核)。
- 依赖数据对齐与 SIMD 指令集(AVX/NEON)。