深度神经网络——如何为Halide后端调度网络 OpenCV v4.8.0

上一个教程如何启用 Halide 后端以提高效率

下一个教程使用 OpenCV 与 OpenVINO

原作者德米特里-库尔塔耶夫
兼容性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 } 会得到范围为 [0, 5) 的新变量 xo 和范围为 [0, 2) 的新变量 xi。在同一个调度节点中,变量名 x 不再可用。

你可以在 opencv_extra/testdata/dnn 中找到调度示例,并用它来调度你的网络。

层融合

通过层融合,我们可以只调度融合集的顶层。因为对于每个输出值,我们都要使用融合公式。举例来说,如果你有三个层 逐个进行卷积 + 缩放 + 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 的函数需要调度。

调度模式

有时,网络会使用阻塞结构,这意味着某些层是相同或非常相似的。如果想根据平铺或矢量化因素对不同层应用相同的调度,可在调度文件开头的 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。有时它可能比手动调度更有效。但如果特定图层需要手动调度,则可以混合使用手动和自动调度方式。编写调度文件,跳过需要自动调度的图层。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值