DepthwiseConv2D 算子 API 描述

1. 算子简介

二维深度卷积(Depthwise Convolution)运算。

主要应用场景

  • MobileNet、EfficientNet 等轻量级网络中的深度可分离卷积
  • 边缘设备上的高效特征提取
  • 图像处理中的逐通道滤波操作

算子特征

  • 难度等级:L3(Contraction)
  • 三输入(特征图、卷积核、偏置)单输出,支持膨胀卷积
  • 输入 x 为 [N, C, H, W],卷积核 weight 为 [C, K_h, K_w]
  • 是分组卷积的特例:约束 groups = C_in,且 C_out = C_in(channel_multiplier = 1),各通道独立卷积、不做跨通道求和

2. 算子定义

数学公式

对每个 batch n、通道 c、输出空间位置 (h, w):

y[n,c,h,w]=bias[c]+∑kh=0Kh−1∑kw=0Kw−1x[n, c, h⋅sh+kh⋅dh−ph, w⋅sw+kw⋅dw−pw]⋅weight[c,0,kh,kw]y[n,c,h,w] = \text{bias}[c] + \sum_{k_h=0}^{K_h-1}\sum_{k_w=0}^{K_w-1} x[n,\,c,\,h\cdot s_h + k_h\cdot d_h - p_h,\,w\cdot s_w + k_w\cdot d_w - p_w]\cdot \text{weight}[c,0,k_h,k_w]

其中 sh,sws_h, s_w 为 stride、ph,pwp_h, p_w 为 padding、dh,dwd_h, d_w 为 dilation。 与标准 2D 卷积的关键区别:求和号中没有跨输入通道的累加,每个输出通道 c 只由对应的输入通道 c 与该通道独立的核 weight[c] 卷积得到(即 PyTorch / cuDNN 中 groups = C_in = C_out 的分组卷积特例)。

3. 接口规范

算子原型

cann_bench.depthwise_conv_2d(Tensor x, Tensor weight, Tensor bias, int[] kernelSize, int[] stride, int[] padding, int[] dilation, int groups) -> Tensor y

输入参数说明

参数 类型 默认值 描述
x Tensor 必选 输入特征图,shape 为 [N, C, H, W]
weight Tensor 必选 卷积核,shape 为 [C, K_h, K_w](每个通道一个独立的 K_h×K_w 核)
bias Tensor 必选 偏置,shape 为 [C]
kernelSize int[] 必选 卷积核大小 [K_h, K_w],须与 weight.shape[2:] 一致
stride int[] 必选 步长 [s_h, s_w]
padding int[] 必选 填充 [p_h, p_w]
dilation int[] 必选 膨胀率 [d_h, d_w]
groups int 必选 分组数,必须等于 C(depthwise 定义性约束)

输出

参数 Shape dtype 描述
y [N, C, H_out, W_out] 与输入 x 相同 输出特征图

输出空间维度:

Hout=⌊H+2ph−dh(Kh−1)−1sh⌋+1,Wout=⌊W+2pw−dw(Kw−1)−1sw⌋+1H_{out} = \left\lfloor \frac{H + 2 p_h - d_h(K_h - 1) - 1}{s_h} \right\rfloor + 1, \quad W_{out} = \left\lfloor \frac{W + 2 p_w - d_w(K_w - 1) - 1}{s_w} \right\rfloor + 1

数据类型

输入 (x, weight, bias) dtype 输出 dtype
float16 float16
float32 float32
bfloat16 bfloat16

规则与约束

  • x 的 shape 格式为 [N, C, H, W]
  • weight 的 shape 格式为 [C, K_h, K_w](每输入通道一个独立的 K_h×K_w 核,不跨通道累加)
  • bias 的 shape 为 [C]
  • groups 必须等于 C(输入通道数);同时输出通道数 C_out = C_in = C(channel_multiplier = 1),这是 depthwise convolution 的定义性约束,违反则退化为普通分组卷积
  • x、weight、bias 的 dtype 须一致
  • kernelSize 须与 weight.shape[1:] = [K_h, K_w] 一致
  • stride 指定卷积步长 [s_h, s_w]
  • padding 指定对称填充 [p_h, p_w]
  • dilation 指定膨胀率 [d_h, d_w]

支持范围

输入 tensor 各维度与参数的支持范围:

维度 / 参数 范围 备注
N(batch) 1 ~ 256 cases.csv 实测 2 ~ 8
C(通道;=C_in=C_out=groups 1 ~ 2048 cases.csv 实测 7 ~ 2048;depthwise 定义性约束
H, W(空间) 8 ~ 256 cases.csv 实测 13 ~ 128
K_h, K_w(卷积核) 1 ~ 16 cases.csv 实测 1 / 3 / 5
stride[i] 1 ~ 4 cases.csv 实测 (1,1) 和 (2,2)
padding[i] 0 ~ 8 cases.csv 实测 0 ~ 2
dilation[i] 1 ~ 16 cases.csv 实测 1 / 2 / 3
groups 1 ~ 2048 必须等于 C(depthwise 定义性约束)

约束:输出 spatial 维度 (H_out, W_out) 必须 ≥ 1(按 §3 输出公式计算)。

4. 精度要求

采用生态算子精度标准进行验证。

误差指标

  1. 平均相对误差(MERE):采样点中相对误差平均值

    MERE=avg(abs(actual−golden)abs(golden)+1e-7)\text{MERE} = \text{avg}(\frac{\text{abs}(actual - golden)}{\text{abs}(golden)+\text{1e-7}})

  2. 最大相对误差(MARE):采样点中相对误差最大值

    MARE=max⁡(abs(actual−golden)abs(golden)+1e-7)\text{MARE} = \max(\frac{\text{abs}(actual - golden)}{\text{abs}(golden)+\text{1e-7}})

通过标准

数据类型 FLOAT16 BFLOAT16 FLOAT32 HiFLOAT32 FLOAT8 E4M3 FLOAT8 E5M2
通过阈值(Threshold) 2^-10 2^-7 2^-13 2^-11 2^-3 2^-2

当平均相对误差 MERE < Threshold,最大相对误差 MARE < 10 * Threshold 时判定为通过。

5. 标准 Golden 代码

import torch

"""
DepthwiseConv2D算子Torch Golden参考实现

二维深度卷积运算(每个输入通道独立卷积,groups = C_in = C_out)
y[n,c,h,w] = bias[c] + Σ_{kh,kw} x[n,c,h·s+kh·d-p,w·s+kw·d-p] · weight[c,kh,kw]
"""
def depthwise_conv_2d(
    x: torch.Tensor, weight: torch.Tensor, bias: torch.Tensor, kernelSize: list, stride: list, padding: list, dilation: list, groups: int
) -> torch.Tensor:
    """
    二维深度卷积运算
    
    公式: y = bias + weight * x
    
    Args:
        x: 输入特征图
        weight: 卷积核
        bias: 偏置
        kernelSize: 卷积核大小
        stride: 步长
        padding: 填充
        dilation: 膨胀率
        groups: 分组数
    
    Returns:
        输出特征图
    """

    stride_val = (stride[0], stride[1])
    padding_val = (padding[0], padding[1])
    dilation_val = (dilation[0], dilation[1])

    # spec 的 weight shape 是 [C, K_h, K_w];torch.conv2d 要 [C_out, C_in/groups, K_h, K_w],
    # depthwise 下 C_in/groups = 1,unsqueeze 这个冗余维供 PyTorch API 用。
    weight = weight.unsqueeze(1)

    y = torch.nn.functional.conv2d(x, weight, bias, stride=stride_val, padding=padding_val, dilation=dilation_val, groups=groups)
    return y

6. 额外信息

算子调用示例

import torch
import cann_bench

x = torch.randn(1, 64, 56, 56, dtype=torch.float16, device="npu")
weight = torch.randn(64, 3, 3, dtype=torch.float16, device="npu")
bias = torch.randn(64, dtype=torch.float16, device="npu")

y = cann_bench.depthwise_conv_2d(x, weight, bias, kernelSize=[3, 3], stride=[1, 1], padding=[1, 1], dilation=[1, 1], groups=64)