TPU编程竞赛

《第二届TPU编程竞赛》赛题分析-RGB2BGR

sophgo logo
算能SOPHGO
智算赋能数字世界

功能描述

输入格式:大小为 1 X 1 的RGB通道图片张量

输出格式:大小为 1 X 1 的BGR通道图片向量

HOST端

API协议

该算子host端和device端API通信结构体为

typedef struct {
    unsigned int size; 
    unsigned long long output_addr;
    unsigned long long input_addr;
} __attribute__((packed)) param_t;

从host端的代码分析,size为图片数量,每张图片的原始通道顺序为RGB,in/output_addr为Global Memory的数据存放地址,图片数据连续存放,同一个图片的RGB三个通道也是连续存放的。

主要流程

可以参考host/rgb2bgr.cpp中的rgb2bgr_reference函数实现:

static inline void rgb2bgr_reference(float *output, const float *input, const param_t &param) {
    for(unsigned int i = 0; i < param.size; i++) { // 分别对每张图片处理
        output[i*3+2] = input[i*3];  // 源图像的R通道保存到目标图像的第三个通道
        output[i*3+1] = input[i*3+1];// 源图像的G通道保存到目标图像的第二个通道
        output[i*3] = input[i*3+2];  // 源图像的B通道保存到目标图像的第一个通道
    }
}

DEVICE端

思路1

这里视输入数据大小为 [1, 1, 3, 1]

以1张图片为例:

不考虑一切特殊情况,使用一个NPU,配合GDMA操作就可以完成该算子的实现,参赛选手只需要将R/G/B三个通道的数据、从input_addr搬运到Local Memory中,再从Local Memory搬运到output_addr即可。

思路2

这里视输入数据大小为 [2, 1, 3, 1]

扩展到2张图片,可以有以下思路

参赛选手当然可以按照一张图片的处理逻辑进行处理,但是这样效率较低,如果一次性处理两张图片,那么效率可能就会更高一点。如图所示,若参赛选手精心地设计了GDMA的strideshape参数,那么就可以做到将两张图片 [2, 1, 3, 1] 视为按一定规则排放的一张图片 [1, 1, 3, 2],通过自定义strideshape就可以一次完成两张图片的搬运。但该方法也使得GDMA数据读取效率变低,具体的性能如何参赛选手可以进行尝试和探索。

以上两种方法都可以用于任意图片数量的数据处理。

思路3

不难发现前两种思路都基于数据为 [N, 1, 3, 1]的数据格式,而根据文档可以发现BM1684的数据搬运,会按照维度 C 切分并搬运到不同NPU上,如此设计shape浪费了大量NPU空间和性能,那么基于 [1, N, 3, 1]的数据格式,就可以充分利用64个NPU进行数据搬运,在此就不做更详细的描述,若参赛选手完成了思路1的代码,则应该很容易修改为思路3的代码。

提升

在完成基础的算子实现后,参赛选手可以从以下几点考虑改进RGB2BGR算子的实现:

  • 思路2也可以和思路3相结合,充分利用每个NPU的Local Memory
  • 虽然GDMA可以直接完成搬运,但是如果引入BDC操作会不会使得搬出时可以连续搬运,一次搬完?这样会不会带来性能提升,又会引入什么缺点?
  • 如果引入BDC操作,则一定可以引入Parallel和PingPong来减少运算时间