ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

whisper.cpp Vulkan 后端源码解析:一份构建覆盖四大 GPU 厂商的 8600 行 C++ 实现

whisper.cpp Vulkan 后端源码解析:一份构建覆盖四大 GPU 厂商的 8600 行 C++ 实现 whisper.cpp Vulkan 后端源码解析一份构建覆盖四大 GPU 厂商的 8600 行 C 实现【免费下载链接】whisper.cppPort of OpenAIs Whisper model in C/C项目地址: https://gitcode.com/GitHub_Trending/wh/whisper.cppwhisper.cpp 的 Vulkan 后端把 Whisper 模型推理整体搬上 GPU且只依赖一套跨厂商 API——NVIDIA、AMD、Intel 独显、Apple 与 Intel 核显、Android 平板同一份构建产物全部通吃。如果你需要在一套代码里同时支持 Linux 服务器、Windows 桌面和 Android 端上的实时转写这就是目前 whisper.cpp 里唯一不绑定任何一家厂商的 GPU 路径。本文基于仓库真实源码逐段拆解它如何探测硬件能力、怎么选矩阵乘法内核、内存池怎么运转以及编译和运行时到底有哪些真实可用的配置项。痛点先行CUDA 管得了 NVIDIA管不了其他所有卡whisper.cpp 的推理入口统一走 ggml 计算图。图本身是后端无关的但谁来执行这件事各后端待遇完全不一样CUDA 后端NVIDIA 独占依赖厂商私有 API 和 cuBLAS离开绿色驱动就无能为力Metal 后端Apple 生态独占Linux/Android 上编译都过不了OpenCL 后端历史上覆盖过更多设备但驱动实现普遍残缺精度和性能都不稳定ggml 中已逐步边缘化CPU 后端哪里都能跑但 30 秒音频用 large 级别模型跑一轮离实时差着数量级。Vulkan 是 Khronos 组织维护的开放标准Linux、Windows、Android 的三大 GPU 厂商驱动都实现了它。代价也很直白Vulkan 不提供厂商级优化库对应 cuBLAS 的东西所以 whisper.cpp 必须自己把矩阵乘法、Flash Attention、反量化这些最吃算力的算子写成计算着色器——这是它源码量最大的原因也是后文要展开的重点。源码地图一个 8600 行文件 80 个计算着色器Vulkan 后端的全部实现集中在三个地方位置内容ggml/include/ggml-vulkan.h对外 C API不到 30 行定义了设备枚举、初始化、buffer 类型等接口ggml/src/ggml-vulkan/ggml-vulkan.cpp单文件 8600 行包含实例/设备初始化、队列与同步、内存池、全部算子的调度逻辑ggml/src/ggml-vulkan/vulkan-shaders/80 个.comp计算着色器mul_mm、flash_attn_cm2、dequant_q4_0等与着色器生成脚本头文件里最值得记住的是这组接口——它决定了 Vulkan 后端在 ggml 体系中的身份#define GGML_VK_NAME Vulkan #define GGML_VK_MAX_DEVICES 16 GGML_BACKEND_API ggml_backend_t ggml_backend_vk_init(size_t dev_num); GGML_BACKEND_API int ggml_backend_vk_get_device_count(void); GGML_BACKEND_API ggml_backend_buffer_type_t ggml_backend_vk_buffer_type(size_t dev_num); // pinned host buffer for use with the CPU backend for faster copies between CPU and GPU GGML_BACKEND_API ggml_backend_buffer_type_t ggml_backend_vk_host_buffer_type(void); GGML_BACKEND_API ggml_backend_reg_t ggml_backend_vk_reg(void);ggml_backend_vk_reg()让该后端向 ggml 的后端注册表登记whisper.cpp 主流程src/whisper.cpp 中的whisper_backend_init_gpu在构建上下文时遍历注册表里所有GGML_BACKEND_DEVICE_TYPE_GPU类型的设备初始化第一个成功的作为 GPU 后端CPU 后端则始终兜底加入——也就是说启用 GPU 不需要任何命令行参数只要编译时链接进了 Vulkan 后端运行时就自动接管。着色器侧的关键点在 ggml/src/ggml-vulkan/CMakeLists.txtfind_package(Vulkan COMPONENTS glslc REQUIRED) # Compile a test shader to determine whether GL_NV_cooperative_matrix2 is supported. execute_process(COMMAND ${Vulkan_GLSLC_EXECUTABLE} -o - -fshader-stagecompute --target-envvulkan1.3 .../test_coopmat2_support.comp ...)着色器在构建期由 glslc 编译为 SPIR-V再由vulkan-shaders-gen.cpp生成ggml-vulkan-shaders.hpp内嵌进可执行文件——运行时零外部文件依赖这正是它敢出现在 Android 上的原因。上面那个execute_process还在编译期试探当前 glslc 是否支持 NVIDIA 的GL_NV_cooperative_matrix2扩展不支持就不定义GGML_VULKAN_COOPMAT2_GLSLC_SUPPORT相关着色器直接被排除。运行时解剖先探能力再按能力分派整个后端对硬件的所有认知都装在 ggml-vulkan.cpp 的vk_device_struct结构体里它是理解后续所有分派逻辑的钥匙struct vk_device_struct { vk::PhysicalDevice physical_device; vk::PhysicalDeviceProperties properties; uint64_t max_memory_allocation_size; bool fp16; vk_queue compute_queue; vk_queue transfer_queue; bool single_queue; uint32_t subgroup_size; bool uma; // 集成显卡标记 bool coopmat_support; // 协同矩阵厂商张量核类指令 uint32_t coopmat_m, coopmat_n, coopmat_k; bool coopmat2; bool mul_mat_l, mul_mat_m, mul_mat_s; // 三档矩阵乘法内核是否可用 // ...按 ggml 量化类型逐档预建的反量化矩阵乘法管线 vk_matmul_pipeline2 pipeline_dequant_mul_mat_mat[GGML_TYPE_COUNT]; };设备初始化ggml_vk_init时逐项目探测VK_KHR_16bit_storage扩展决定fp16标志Maintenance3/4属性决定max_memory_allocation_size超过它的单次分配会被拒绝矩阵乘法会据此回退厂商 ID 与驱动类型参与决策——源码里有明确注释Intel 驱动的 coopmat 尚不可靠AMD 上只有 RADV 开源驱动支持 coopmatNVIDIA 闭源驱动不行。这些厂商特例判断就是跨平台方案的真实成本。队列采用计算 传输双队列模型有独立传输队列时分离用传输可与计算重叠靠信号量同步否则single_queue true退化为单队列。集成显卡umaUMA 显存与内存共享带宽会走低带宽敏感的策略。环境变量才是运行时旋钮而不是编译宏排查问题时最常踩的坑网上流传的GGML_VULKAN_DEBUG1、GGML_VULKAN_MEMORY_LIMIT4096、--backend vulkan、--precision mixed这类说法在源码中都不存在。真实配置分两类编译期开关ggml/CMakeLists.txt 第 156–163 行选项作用GGML_VULKAN总开关默认 OFFGGML_VULKAN_DEBUG打开VK_LOG_DEBUG逐调用日志GGML_VULKAN_MEMORY_DEBUG内存分配/释放日志GGML_VULKAN_VALIDATE链接 Vulkan 校验层GGML_VULKAN_PERF按算子输出性能计时GGML_VULKAN_CHECK_RESULTS与 CPU 结果比对用于回归测试运行期环境变量在ggml-vulkan.cpp中以getenv读取变量源码行为GGML_VK_VISIBLE_DEVICES逗号分隔的设备索引白名单非法索引直接抛异常退出GGML_VK_DISABLE_F16强制关闭 FP16 存储/计算路径GGML_VK_DISABLE_COOPMAT/GGML_VK_DISABLE_COOPMAT2关闭对应厂商协同矩阵路径驱动 bug 时救命用GGML_VK_FORCE_MAX_ALLOCATION_SIZE覆盖单次分配上限规避驱动的分配 bug由于 whisper 总是初始化第一个 GPU 后端多 GPU 机器上选卡的正确姿势不是加参数而是用GGML_VK_VISIBLE_DEVICES1 ./build/bin/whisper-cli ...把可见设备收窄到你想要的那块。算子与内存Vulkan 版cuBLAS是怎么自己搓出来的whisper 的解码循环里绝大部分时间花在矩阵乘法和 encoder 的 Flash Attention 上这两块决定了性能上限。矩阵乘法按精度分档建管线。vk_device_struct里预建了pipeline_matmul_f32、pipeline_matmul_f32_f16、pipeline_matmul_f16、pipeline_matmul_f16_f32四组基础管线以及按GGML_TYPE_COUNT全量展开的pipeline_dequant_mul_mat_mat[GGML_TYPE_COUNT]——每种 ggml 量化类型q4_0、q4_k、q8_0……都有专属的反量化 矩阵乘着色器组合对应 vulkan-shaders/ 目录下的mul_mm.comp、dequant_q4_0.comp、mul_mat_vec_q4_k.comp等文件。ggml_vk_mul_mat_q_f16等函数在分派时根据device-fp16和量化类型选择对应管线不存在通用回退慢路径式的运行时分支。Split-K 启发式填满 SM。whisper 解码阶段单次矩阵乘的 M 维度很小batch 为 1 时 M 只有词表投影的宽度量级传统分块方案下着色器核心大量闲置。ggml_vk_guess_split_k的处理是// If k is large and the SMs will fill less than halfway, use split_k. split_k ctx-device-shader_core_count / (m_tiles * n_tiles); split_k std::min(split_k, 4u);把 K 维切成最多 4 份并行归约配套mul_mat_split_k_reduce.comp二阶段并用prealloc_split_k预分配归约缓冲避免热路径上反复分配。内存是池化 pinned 主机内存不是每次 malloc。后端维护 256 格 buffer 池MAX_VK_BUFFERS分配走最小适配策略池满或无适配项时销毁最大的一块复用ggml_vk_host_malloc用eHostVisible | eHostCoherent | eHostCached分配钉住内存供 CPU 后端侧直接读写权重加载走buffer_write_nc_async等异步传输 staging 缓冲。所以启动时加载几 GB 模型权重的开销是真实存在的且池满时会打印WARNING: vk buffer pool full——看到这条日志说明工作集超过了 256 格池子的覆盖能力。Flash Attention 有原生实现。vulkan-shaders/ 里的flash_attn_cm2.comp配合ggml_vk_flash_attn直接加速 encoder 自注意力在支持 coopmat/coopmat2 的硬件上还走张量核变体mul_mm_cm2.comp、flash_attn_cm2.comp。编译配置与落地两条命令启用环境变量救急启用只需要两条命令README.md Vulkan GPU support 一节原文cmake -B build -DGGML_VULKAN1 cmake --build build -j --config Release前置条件是驱动支持 Vulkan 且系统装有 glslcVulkan SDK 自带。CMake 找不到Vulkan组件时该后端静默跳过主库照常构建whisper 回退 CPU 后端——这也是排障第一步跑./build/bin/whisper-cli看启动日志using Vulkan0 backend说明接管成功没有这行说明后端没链进去或设备枚举为空。落地到具体场景的取舍Linux/Windows 多厂商环境Vulkan 后端的收益最大。同一份whisper-cli二进制在 Intel Arc、AMD推荐 RADV 驱动、NVIDIA 卡上都能跑出问题优先试GGML_VK_DISABLE_F16/GGML_VK_DISABLE_COOPMAT多数驱动玄学问题出在厂商私有指令路径上Android着色器内嵌 SPIR-V、无运行时外部依赖的特性让它适合打包但 UMA 带宽是硬瓶颈建议配 small 及以下模型并用GGML_VK_FORCE_MAX_ALLOCATION_SIZE控制单次分配CI/回归GGML_VULKAN_RUN_TESTSGGML_VULKAN_CHECK_RESULTS组合可以在有 GPU 的 CI 节点上对每个算子与 CPU 结果比对是改动着色器前值得开的保险。一句话收束如果你的部署矩阵横跨两个以上 GPU 厂商或者目标包含 Android/无 CUDA 环境的 LinuxVulkan 后端是 whisper.cpp 里值得投入的那条路径——入口是-DGGML_VULKAN1排障旋钮是那几个GGML_VK_*环境变量其余复杂的能力探测和内核分派8600 行的 ggml-vulkan.cpp 已经替你做好了。【免费下载链接】whisper.cppPort of OpenAIs Whisper model in C/C项目地址: https://gitcode.com/GitHub_Trending/wh/whisper.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表