一、Yolov8输出结果
首先查看开源代码转出来的yolov8 图,只有一个输出output0 size为1*84*8400
根据这个布局NPU推理后,获取到NPU的输出就结果内存布局如下,总共长度为1*84*8400*sizeof(float)
内存数据布局主要点,
1.每个分类都会有8400个框,有8400个打分阈值
2.所有的框的信息在最前面,第一个连续8400个数据是中心X的坐标,第二个是连续8400个Y坐标,然后是8400个box 宽度坐标,在加上8400个box高度坐标
3.后面会跟着80个分类的置信度,每个分类有8400个置信度,都是连续的;
二、C语言解析代码如下
/*
src为output数据
len = 84*8400 ,因为前面已经除以sizeof(float)
pout 为用户输出数据
*/
int result_yolov8(float *src, unsigned int len, stYolov5Objs *pOut)
{
pOut->count = 0;
//判断长度,保证数据长度争取
if (len != 84 * 8400)
{
return 0;
}
proposals.clear();
float *pScore = NULL;
const float prob_threshold = 0.45f;
int cx, cy, cw, ch;
//遍历80个分类的置信度
for (size_t j = 0; j < 80; j++)
{
//每个分类有8400个置信度
for (size_t i = 0; i < 8400; i++)
{
//置信度数据的起点 4*8400 + j
pScore = src + ((j + 4) * 8400 + i);
//取符合置信度数据的对应坐标
if (*pScore > prob_threshold)
{
Object obj;
cx = src[i]; //第一行8400个数据x
cy = src[1 * 8400 + i]; //第二行8400个数据有
cw = src[2 * 8400 + i]; //第三行8400个数据我
ch = src[3 * 8400 + i]; //第四行8400个数据h
//下面把中心点和长宽转化为左上角坐标
obj.rect.x = cx - cw / 2;
obj.rect.y = cy - ch / 2;
obj.rect.width = cw;
obj.rect.height = ch;
obj.label = j;
obj.prob = *pScore;
proposals.push_back(obj);
}
}
}
//做NMS
//把结果填充到pout
}
以上主要核心代码
三、详细内容如下
2.海思SS928(3403)YOLOV8移植-后处理的代码实现
四、其他
因为Yolov8 开源输出的数据结构问题,会导致C语言有非常多的指针位移,会导致后处理的时间非常长,我实际测试,在还是SS928上,NPU部分处理大约25ms,后处理大约需要130ms;详细的log如下.
nnn_execute execution time: 158 ms
57 = 0.76660 at 345.00 183.00 256.00 x 175.00 couch 76.7%
nnn_execute execution time: 158 ms
57 = 0.75586 at 345.00 183.00 255.00 x 174.00 couch 75.6%
nnn_execute execution time: 158 ms
57 = 0.75391 at 345.00 182.00 256.00 x 176.00 couch 75.4%
nnn_execute execution time: 158 ms
57 = 0.72900 at 346.00 182.00 255.00 x 174.00 couch 72.9%