vulkan 的顯存管理
-
一個 VkBuffer 對象,多個 offset
- 使用同一塊 VkBuffer 存儲中間層的特征數據,不同的 blob 使用不同的offset進行區(qū)分 。

VkDeviceMemory結構
-
可以在內存架構方面做到零拷貝
- 集成顯卡和手機上采用
unified內存架構(統(tǒng)一內存架構),這種架構下,GPU可以直接訪問CPU上的主存。利用這種架構上的特性,在GPU計算的時候就不用把 內存上的數據 拷貝到 顯存 上,計算完成后也不需要將 顯存上的數據 拷貝到 內存。
- 集成顯卡和手機上采用

不同內存架構的對比
對GPU存儲布局的優(yōu)化
1.[c,h,w] 這種布局不太適合在GPU上做IO:[c, h, w] ---> [c/4, h, w, 4]
- 因為GPU訪問和讀寫顯存用的時候更多的是使用 vec4 的類型,ncnn 通過將布局改為[c/4,h,w,4],使得GPU的IO效率得到大幅度提升
-
減少內存帶寬的需求
- ncnn 中的 Tensor float數據可以使用半精度
- 在一些不直接支持 fp16 存儲的情況下,ncnn 使用 packHalf2x16 和unpackHalf2x16 來模擬 fp16 和 fp32 的轉換(這兩個函數是 GLSL 內置的函數)
-
更加方便的維護代碼
-
ncnn 中創(chuàng)建了一個 GLSL 的宏。
所以寫代碼的時候可以不用管類型上的事,運行時會自動轉換為設備支持的 fp32和 fp16 的對應代碼
-
cpu-gpu 混合推理
- 模型中有些層,在沒有GPU實現(xiàn)的時候,我們需要自動切換到CPU上去做推理。這就涉及到存儲布局相互轉換

CPU和GPU轉換
- ncnn 提供了一套pipline,使用一套pipline實現(xiàn)端到端的完成 最佳的布局轉換。在獨顯上也傾向使用 fp16 做上傳和下載,能用半精度,也會優(yōu)先使用。
并行推理
-
ncnn 在GPU上實現(xiàn)并行推理的方式。
-
Vulkan的api中同一塊gpu會暴露多個隊列。
例如:nvidia的gpu中有8個隊列,那么就可以使用多線程的方式同時在8個隊列上提交8個任務。
好處:可以增加GPU的使用率 ,從而提高效率。
-

11個任務同時在三塊gpu上做推理
GLSL->SPIR-V 運行編譯
- 原因:有些驅動需要對 GLSL 或者 SPIR-V 的源代碼進行特殊的處理,所以只能采用運行時編譯
- 好處:不需要在離線時編譯多個 SPIR-V 的二進制文件,減少二進制文件的體積。
Swiftshader
- swiftshader項目地址:google在cpu上實現(xiàn) vulkan驅動 的項目,可以實現(xiàn)在cpu上執(zhí)行vulkan的代碼,可以保證每次代碼運行結果都是一致的。
復用 VkPipeline 和相關的 vulkan object
- 模型加載的時候, 特別是第一次加載模型的時候,由于沒有離線的cache和優(yōu)化的手段, pipeline的編譯是一個十分耗時的操作。
- 有些模型層的參數(kernal size, stride)是一樣的。ncnn 在運行時就將 層的參數 和 vulkan對象 的關系記錄下來,當遇到具有相同參數層的時候,就可以直接復用之前創(chuàng)建好的 vulkan對象,這樣可以顯著降低第一次加載模型的耗時。

降低第一次加載模型的耗時