OpenCV 4.12.0
開源計算機視覺
載入中...
搜尋中...
無匹配項
如何為 Halide 後端排程你的網路

上一個教程: 如何啟用 Halide 後端以提高效率
下一個教程: OpenCV 與 OpenVINO 的用法

原始作者Dmitry Kurtaev
相容性OpenCV >= 3.3

介紹

Halide 程式碼對於我們使用的每個裝置都是相同的。但是為了獲得令人滿意的效率,我們應該正確地排程計算。在本教程中,我們將介紹如何使用 OpenCV 深度學習模組中的 Halide 後端來排程你的網路。

為了更好地理解 Halide 排程,你可能需要閱讀教程 @ http://halide-lang.org/tutorials

如果這是你第一次在 OpenCV 中接觸 Halide,我們建議從 如何啟用 Halide 後端以提高效率 開始。

配置檔案

你可以透過編寫文字配置檔案來排程 Halide 管道的計算。這意味著你可以輕鬆地向量化、並行化和管理層計算的迴圈順序。在第一次呼叫 cv::dnn::Net::forward 之前,將包含特定裝置的排程指令的檔案路徑傳遞給 cv::dnn::Net::setHalideScheduler

排程配置檔案表示為 YAML 檔案,其中每個節點都是一個排程的函式或排程指令。

relu1
reorder: [x, c, y]
split: { y: 2, c: 8 }
parallel: [yo, co]
unroll: yi
vectorize: { x: 4 }
conv1_constant_exterior
compute_at: { relu1: yi }

考慮使用變數 n 表示批處理維度,c 表示通道,y 表示行,x 表示列。對於分割後的變數,使用帶有相同字首但帶有 oi 字尾的名稱分別表示外部和內部變數。例如,對於範圍為 [0, 10) 的變數 x,指令 split: { x: 2 } 會給出新的變數 xo(範圍為 [0, 5))和 xi(範圍為 [0, 2))。變數名 x 在同一排程節點中不再可用。

你可以在 opencv_extra/testdata/dnn 中找到排程示例,並使用它來排程你的網路。

層融合

由於層融合,我們只能排程融合集的最頂層。因為對於每個輸出值,我們都使用融合的公式。例如,如果你有三個層:Convolution + Scale + ReLU 依次排列,

conv(x, y, c, n) = sum(...) + bias(c);
scale(x, y, c, n) = conv(x, y, c, n) * weights(c);
relu(x, y, c, n) = max(scale(x, y, c, n), 0);

融合的函式類似於

relu(x, y, c, n) = max((sum(...) + bias(c)) * weights(c), 0);

所以只有名為 relu 的函式需要排程。

排程模式

有時,網路使用阻塞結構構建,這意味著某些層是相同的或非常相似的。如果你想將相同的排程應用於不同的層,並精確到 tiling 或 vectorization 因子,請在排程檔案開頭的 patterns 部分中定義排程模式。此外,你的模式可以使用一些引數變數。

# 在檔案開頭
patterns
fully_connected
split: { c: c_split }
fuse: { src: [x, y, co], dst: block }
parallel: block
vectorize: { ci: c_split }
# 在下面的某個地方
fc8
pattern: fully_connected
params: { c_split: 8 }

自動排程

你可以讓 DNN 自動排程層。只需跳過呼叫 cv::dnn::Net::setHalideScheduler。有時,它可能比手動排程更有效。但是,如果特定層需要手動排程,你可以混合使用手動和自動排程方式。編寫排程檔案並跳過你希望自動排程的層。