想要把内核测量部分一块测量完成发布,但是暂时有点问题,得推迟一点发布那部分了,就先把之前集成ML的部分完善一下吧。
eIQ模型转换
之前我使用随便一个模型文件,经过eIQ转化之后没有发生变化,我之前怀疑是优化了卷积等地方的运算,不过我使用了一个新的模型,里边有最常见的一些模块,却并没有看到这一个现象。
这个是我所使用的模型的完整的样子,但是经过转换之后并没有变化,模型是完全一样的,没有出现示例那样的变化,因此我现在并不清楚具体这个转换会将什么模块优化。我查看了TensorFlow Lite的算子文档,里边也能 找到常见的模块名称,这个算子文档与转换后的模型理应是一一对应的,也就是常见模块的名称在转换后的模型中也是存在的。具体优化了什么,只能在后续的实践中看了,不过这个也不是什么急需解决的问题,有则更好,没有也不会对项目有特别大的影响。
操作算子文件
我之前说有两个文件可以使用,一个是示例工程中的micro_mutable_op_resolver.h,另一个是micro/all_ops_resolver.h
我后续到TensorFlow Lite的官方网站看了一下,确实是都可以使用,但是他们有一个区别,这个区别在嵌入式开发中影响还是比较大的。
具体来说,all_ops_resolver.h 会拉取每一个可用的运算,因此它会占用大量内存但是micro_mutable_op_resolver.h并不是这样的,他会将每个运算分开,仅拉取我们所指定的运算。因此在生产应用中,应该仅使用 micro_mutable_op_resolver.h 拉取模型所需的运算。
模型运行
之前因为我没有仔细看过算子文件,因此之前的模型并没有完整运行过。这次我在修改过模型之后,重新运行了下项目。根据我在上文所提到的模型结构,我将model_cifarnet_ops_npu.cpp中的算子进行了修改
红框中的部分就是针对我的模型所添加的算子
注意
除了这个以外,一定要将这段代码中的容器容量改为我们所需要的大小,默认工程是5,因为我增加了4个,改为了9
玄学问题
本来我以为这些地方修改完以后,按照示例文档来说,就可以直接运行成功了,但是我得到的却是这样的结果
但是我们可以看示例结果应该是这样的
可以发现,在进行文件的推理时候项目卡住不动了。这不是时间的问题,我忙别的,放在那没有管他几个小时,他依然没有打印出正确的信息,可以看出并不是推理时间太长的问题。打印出的最后一句话是调用image_load.c文件中IMAGE_GetImage时候的结果。经过多次调试,最终发现,问题就出现在这行代码中,不是后续的问题。这行代码关系着图像数据的获取,这里出现了问题,后续自热无法进行模型推理。
可以看到是memcpy这个函数发生了问题。这个函数声明这样的,功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。
void *memcpy(void *destin, void *source, unsigned n);
我当时觉得问题就是因为这个,这个是拷贝字节,而不是某个数据类型。我当时立即想改为这样的形式。
memcpy(dstData, srcData, dstWidth * dstHeight * dstChannels * sizeof(uint8_t));
但是示例工程中最开始包含的是image_data .h文件,与给出的Python代码不同,Python代码要进行十六进制转换,image_data中是RGB数值(对于数据类型转换这个不是什么问题)这个又并非与我所考虑的数据类型字节数有关,也就不存在拷贝错误的问题。多次运行模型结果都是和上边一样,卡在了推理的那一步。
由于memcpy问题可能是空指针/内存重叠/无效内存/内存超出等导致的, 我就根据这个进行排查。
对于空指针,我在memcpy函数前加入了一段代码,来检验是否是空,这部分并没有被运行,也就是指针是正常的
if (srcData == NULL || dstData == NULL) {
PRINTF("ERROR: Null pointer detected.\n");
return kStatus_Fail;
}
我继续进行调试,在image_load.c文件中加入这行代码想查看一下数据内存读取时候大小,但是这时候奇怪的事发生了,输出竟然正常了,而我两次下载中间唯一的区别仅仅是加入了这一个PRINTF
。
if (s_staticCount == 1)
{
PRINTF("Size of string array: %d bytes\n", sizeof(bird));
PRINTF(EOL "Static data processing:" EOL);
return IMAGE_Decode(bird, dstData, dstWidth, dstHeight, dstChannels);
}
我感觉很奇怪,把我所有添加的代码都注释掉后,也就是恢复到最开始的状态,重新编译下载,结果是正常显示的,之前卡在推理前的那种现象完全不见了,我怎么弄都没有找到是发生了什么改变了之前重复编译下载几十次都一样的现象,这个问题实在是太玄学了,我实在没有办法,如果有人后续也碰到了一样的情况,希望可以告诉我一下