由于数据只能线性存储,因此这四个维度有对应的顺序。不同深度学习框架会按照不同的顺序存储特征图数据,比如Caffe,排列顺序为[Batch, Channels, Height, Width],即NCHW。TensorFlow中,排列顺序为[Batch, Height, Width, Channels],即NHWC。
如图1所示,以一张格式为RGB的图片为例,NCHW中,C排列在外层,实际存储的是“RRRRRRGGGGGGBBBBBB”,即同一通道的所有像素值顺序存储在一起;而NHWC中C排列在最内层,实际存储的则是“RGBRGBRGBRGBRGBRGB”,即多个通道的同一位置的像素值顺序存储在一起。
尽管存储的数据相同,但不同的存储顺序会导致数据的访问特性不一致,因此即便进行同样的运算,相应的计算性能也会不同。
NPU在NCHW基础格式上,定义了众多与硬件强相关的私有格式,用于加速硬件计算,NPU主要计算单元AI Core包括了三种基础计算资源:矩阵计算单元(Cube Unit)、向量计算单元(Vector Unit)和标量计算单元(Scalar Unit)。Cube的特殊计算方式导致了更加严格的对齐方式,因此通常在计算之前就按照Cube的对齐要求先把数据组织好;Vector相对没有那么严格,因此可以在计算逻辑中做一些对齐操作。Cube算子对于format的要求,典型有两种:卷积类算子要求的NC1HWC0,Matmul类算子要求的FRACTAL_NZ,Vector算子对入参tensor无特殊对齐要求,一般使用ND格式
NPU私有格式全量列举如下。
typedef enum { ACL_FORMAT_UNDEFINED = -1, ACL_FORMAT_NCHW = 0, ACL_FORMAT_NHWC = 1, ACL_FORMAT_ND = 2, ACL_FORMAT_NC1HWC0 = 3, ACL_FORMAT_FRACTAL_Z = 4, ACL_FORMAT_NC1HWC0_C04 = 12, ACL_FORMAT_HWCN = 16, ACL_FORMAT_NDHWC = 27, ACL_FORMAT_FRACTAL_NZ = 29, ACL_FORMAT_NCDHW = 30, ACL_FORMAT_NDC1HWC0 = 32, ACL_FRACTAL_Z_3D = 33 } aclFormat;
NPU对于不同的计算单元(cube、vector)所使用的默认私有格式不一致,导致在数据在不同的计算单元下流通时需要进行格式转化,另外基础格式到NPU私有格式也需要进行格式转换,NPU侧执行格式转换的算子为TransData。举例如下(图中闪电图标所在位置即为添加转换算子的位置):
TransData算子通常耗时比Conv、MatMul等算子的耗时大。有一些TransData存在冗余的情况,举例如下:
典型场景如下:
使能npu_format_cast(format_type)。
def forward(x): x = x.npu_format_cast(3) # 3代表format_type的数字映射,完整映射关系请参见▪NPU私有格式 ....# 前向计算过程
示例2:
hidden_states = self.embeddings(pixel_values) # 模型计算 hidden_states = hidden_states.npu_format_cast(29) # 手动添加格式转换 hidden_states = self.pre_layrnorm(hidden_states) # 模型计算
option = {} option['MM_BMM_ND_ENABLE'] = 'disable' torch.npu.set_option(option)