
[InferLLM大模型推理框架项目](17)InferLLM模块kern(src/kern)综合介绍
InferLLM 框架中 kern 模块的代码结构与功能分析
kern
模块是 InferLLM 框架中的核心计算模块,负责提供各种计算内核(kernel)的实现,以支持不同硬件平台上的高效计算。通过分析代码结构,可以看出该模块采用了分层设计,支持多种硬件平台的优化实现。
1. 目录结构
kern
模块的目录结构如下:
kern/
├── gpu/
│ ├── kernel_gpu.cu
│ └── kernel_gpu.h
├── kernel.h
├── kernel_define.h
├── naive/
│ ├── naive.cpp
│ ├── naive.h
│ └── quantize.h
└── optimized/
├── arm/
├── rvv/
└── x86/
这种结构清晰地分离了不同平台的实现:
naive/
: 提供基础的、不依赖特定硬件优化的实现optimized/
: 包含针对不同硬件平台优化的实现arm/
: ARM 平台优化rvv/
: RISC-V 向量扩展优化x86/
: x86 平台优化
gpu/
: GPU 平台优化实现
2. 核心文件分析
2.1 kernel_define.h
kernel_define.h
定义了内核计算所需的基本数据结构和枚举类型:
// 定义内核ID,用于标识不同类型的计算操作
enum class KernelID {
EmbeddingGetInt4Float = 0,
EmbeddingGetInt8Float,
// ... 其他内核ID
MatmulInt4WeightReorder,
};
// 定义内核优化方法
enum class KernelOptMethod {
MatmulInt4Reorder = 0,
};
// 定义元素级操作模式
enum class ElemMode {
Add = 0,
Mul,
Silu,
Gelu,
};
// 定义旋转模式(用于位置编码)
enum class RotMode {
Mode0 = 0,
Mode1,
ModelRotHalf,
};
// 定义内核类型
enum class KernelType { Naive = 0, Arm = 1, X86 = 2, GPU = 3 };
此外,该文件还定义了量化计算所需的数据结构:
// 4位量化块结构
struct BlockQ40 {
float d; // 缩放因子
uint8_t qs[QK40 / 2]; // 量化值(每个字节存储两个4位值)
};
// 8位量化块结构
struct BlockQ80 {
float d; // 缩放因子
int8_t qs[QK80]; // 量化值
};
2.2 kernel.h
kernel.h
定义了 Kernel
类,作为不同平台内核实现的统一接口:
class Kernel {
public:
Kernel(KernelType kernel_type) : m_kernel_type(kernel_type) {}
Kernel(KernelType kernel_type, ThreadPool* thread_pool)
: m_kernel_type(kernel_type), m_thread_pool(thread_pool) {
// 初始化代码
}
// 检查是否支持特定优化方法
bool supported_optimization(KernelOptMethod method) {
// 实现代码
}
// 执行计算操作
template <KernelID Id, typename... Args>
void operator()(Args... args) {
// 根据内核类型选择不同的实现
if (m_kernel_type == KernelType::GPU) {
// GPU实现
} else {
// CPU实现,使用线程池并行执行
TaskSet task_set = opt::Comp<Id, Args...>::get_all_task(std::forward<Args>(args)...);
for (auto& task : task_set) {
m_thread_pool->add_task(task.first, task.second);
}
}
}
// 获取工作空间大小
template <KernelID Id, typename... Args>
size_t get_workspace(Args... args) {
return opt::Space<Id, Args...>::get(std::forward<Args>(args)...);
}
// 成员变量
ThreadPool* m_thread_pool = nullptr;
KernelType m_kernel_type;
// GPU相关成员
};
Kernel
类的设计采用了模板和函数对象模式,通过 operator()
重载实现了统一的计算接口,根据内核类型自动选择相应的实现。
3. 优化实现分析
3.1 x86 平台优化
optimized/x86/
目录下的实现利用了 x86 平台的 SIMD 指令集(如 AVX、AVX2)进行优化:
// 使用AVX2优化的向量点积计算
INFER_ATTRIBUTE_TARGET("avx2")
inline float vec_vec_dot_q4_0(
const int n, const void* __restrict x, const void* __restrict y) {
// 使用AVX2指令集优化实现
__m256 acc = _mm256_setzero_ps();
// ... 实现代码
return sumf;
}
// 默认实现(不使用SIMD)
INFER_ATTRIBUTE_TARGET("default")
inline float vec_vec_dot_q4_0(
const int n, const void* __restrict x, const void* __restrict y) {
// 标量实现
// ... 实现代码
return sumf;
}
通过 INFER_ATTRIBUTE_TARGET
宏,可以根据编译目标自动选择合适的实现。
3.2 ARM 平台优化
optimized/arm/
目录下的实现利用了 ARM 平台的 NEON 指令集进行优化:
// 使用NEON指令集优化的量化操作
inline void quantize_row_q4_0(const float* __restrict x, void* __restrict vy, int k) {
// 使用NEON指令集优化实现
float32x4_t srcv[8];
// ... 实现代码
}
// 使用NEON指令集优化的反量化操作
inline void dequantize_row_q4_0(const void* __restrict vx, float* __restrict y, int k) {
// 使用NEON指令集优化实现
const float32x4_t vd = vdupq_n_f32(x[i].d);
// ... 实现代码
}
3.3 RISC-V 向量扩展优化
optimized/rvv/
目录下的实现针对 RISC-V 向量扩展进行了优化,提供了与其他平台类似的接口。
3.4 GPU 优化
gpu/
目录下的实现使用 CUDA 进行 GPU 加速:
// GPU上的Silu激活函数
struct SiluFunctor {
__device__ float operator()(uint32_t i, const float* input) const {
float src = input[i];
return src / (1.0 + exp(-src));
}
};
// GPU上的元素级操作
template <typename Function, typename... Args>
__global__ void ApplyFunction(Function functor, int64_t n, float* ret, Args... args) {
const int tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < n) {
ret[tid] = functor(tid, args...);
}
}
4. 功能分析
通过分析代码,可以看出 kern
模块提供了以下主要功能:
4.1 基础数学运算
- 元素级操作:加法、乘法、Silu、Gelu 等激活函数
- 矩阵乘法:支持不同精度(float、int4、int8)的矩阵乘法
- 归一化:RMSNorm、LayerNorm 等
4.2 特定于 LLM 的操作
- 嵌入查找:从嵌入表中查找 token 的嵌入向量
- 注意力计算:实现自注意力机制所需的矩阵运算
- 旋转位置编码:实现 RoPE(Rotary Position Embedding)
4.3 量化支持
- 4位量化:支持 4 位整数量化,减少内存占用和计算量
- 8位量化:支持 8 位整数量化
- 量化/反量化:提供在不同精度之间转换的函数
4.4 多线程与并行计算
- 任务分解:将大型计算任务分解为多个子任务
- 线程池集成:利用线程池执行并行计算
- GPU 加速:支持 GPU 上的并行计算
5. 设计模式分析
kern
模块采用了多种设计模式:
5.1 策略模式
通过 KernelType
枚举和不同目录下的实现,可以在运行时选择不同的计算策略(naive、arm、x86、gpu)。
5.2 模板方法模式
使用 C++ 模板和宏定义(如 PartialImplementKernel
)来实现不同内核的统一接口。
5.3 工厂模式
Kernel
类根据 KernelID
和 KernelType
创建并执行相应的计算任务。
5.4 命令模式
通过 TaskSet
和 MultiThreadingTask
将计算任务封装为命令对象,由线程池执行。
6. 优化策略分析
kern
模块采用了多种优化策略:
6.1 SIMD 指令优化
利用 x86 的 AVX/AVX2 和 ARM 的 NEON 指令集进行向量化计算。
6.2 量化计算
通过 4 位和 8 位量化减少内存占用和计算量,同时保持计算精度。
6.3 多线程并行
将计算任务分解为多个子任务,利用线程池并行执行。
6.4 GPU 加速
支持在 GPU 上执行计算,充分利用 GPU 的并行计算能力。
6.5 条件编译
通过条件编译和宏定义,根据目标平台自动选择最优实现。
总结
InferLLM 框架的 kern
模块是一个高度优化的计算内核库,提供了大语言模型推理所需的各种计算操作。它采用分层设计,支持多种硬件平台(x86、ARM、RISC-V、GPU),并通过 SIMD 指令、量化计算、多线程并行和 GPU 加速等技术实现高效计算。这种设计使得 InferLLM 能够在不同硬件平台上高效运行,同时保持代码的可维护性和扩展性。
