在线时间4070 小时
UID3441752
注册时间2017-11-21
NXP金币752404
TA的每日心情 | 开心 2024-3-26 15:16 |
---|
签到天数: 266 天 [LV.8]以坛为家I
管理员
- 积分
- 32045
- 最后登录
- 2024-4-29
|
eIQ Toolkit上手指南(四) 在上期文章的最后,我们又留下了一个悬念,即模型的部署,现在就让我们填上上期小编留下的坑,我们来看看怎么让我们的模型运行到目标板上。
首先,需要下载我们最新的SDK2.10.0,注意选择组件时,勾选eIQ选项。
下载完成后,找到并打开SDK_2_10_0_MIMXRT1170-EVK\boards\evkmimxrt1170\eiq_examples下的deepviewrt_labelimage例程。由于例程默认使用的是mobilenetv1模型,接下来我们需要将我们的模型添加到工程中,这里要注意,我们所导出的模型格式需要是*.rtm格式, 并将其放到SDK_2_10_0_MIMXRT1170-EVK\boards\evkmimxrt1170\eiq_examples\deepviewrt_labelimage\source\models文件夹下,当然也可以是其他位置。
添加模型的方式,是借助于汇编指令.incbin将模型文件直接导入到工程中并导出对应的符号,具体而言,我们打开model.S,这个就是我们添加模型文件的地方,加入下面几段话:
- /* 导出符号,以在C函数中使用 */
- .global model_cifar10
- .global model_cifar10_end
- /* 导入模型文件 */
- model_cifar10:
- .incbin “models/cifar10.rtm” /* 需要修改为模型具体路径 */
- model_cifar10_end:
复制代码 这样一来,我们就完成了模型的定义,需要在main.c中添加引用:
- extern const unsigned char model_cifar10;
- extern const unsigned char model_cifar10_end;
复制代码 随后,将我们的模型首地址,以及模型尺寸传入下面的API,进行context的初始化以完成模型的正式导入:
- const uint8_t *model_end = &model_cifar10_end;
- const uint8_t *model = &model_cifar10;
- int model_size = model_end - model;
- NNError err = nn_context_model_load(context, (size_t) model_size, model);
复制代码 当然,只有模型当然还是不行的,我们还需要提供测试图片,添加方法类似于添加模型文件,将图片放到SDK_2_10_0_MIMXRT1170-EVK\boards\evkmimxrt1170\eiq_examples\deepviewrt_labelimage\source\data文件夹下,这里我们选用一张可爱的小猫图片:
之后依旧是依靠我们的.incbin指令:
- /* 导出符号 */
- .global sample_img_start
- .global sample_img_end
- /* 导入图片 */
- sample_img_start:
- .incbin "data/sample.jpg"
- sample_img_end:
复制代码 在main.c中添加引用:
- extern const unsigned char sample_img_start;
- extern const unsigned char sample_img_end;
复制代码 将图像数据加载到模型输入tensor中:
- const uint8_t *image_end = &sample_img_end;
- const uint8_t *sample_image = &sample_img_start;
- int sample_image_size = image_end - sample_image;
- nn_tensor_load_image_ex(input, sample_image, (size_t) sample_image_size, proc);
复制代码 这里的input指代的就是我们的模型输入tensor,稍后小编会给大家介绍这个变量是怎么获取的。还有一个比较特殊的参数,叫做proc,这个参数代表了是否需要对图像进行预处理操作:
0:不进行图像的预处理
1:输入图像直接除以255
2:将对图形进行白化操作
有了模型以及模型的输入,我们来分析一下其他所用到的比较重要的API函数,有了他们才能完整的实现模型的推理操作:
函数 | 作用 | NNContext* | 初始化NNContext,可以理解是模型运行的上下文信息 | nn_context_init(NNEngine* engine, | 结构体,如果memory指针需要用户传入,存储模型运行 | size_t memory_size, | 期间的中间结果,如果memory=NULL的话,底层会自动 | void* memory, | 调用malloc函数进行分配;cache指针被用于DeepView | size_t cache_size, | 内部优化,需要指向一块快速内存,如果需要的话。 | void* cache); | | const uint32_t* nn_model_inputs( | 获取模型输入tensor编号列表,同时还有可选参数 | const NNModel* model, | n_inputs,可以存储输入tensor个数,即模型共有多少 | size_t* n_inputs); | 维输入; | NNTensor *nn_context_tensor_index( | 根据tensor编号获取tensor | NNContext* context, | size_t index); | const uint32_t* nn_model_inputs( | 获取模型输出tensor编号列表,同时还有可选参数 | const NNModel* model, | n_outputs,可以存储输出tensor个数,即模型共有 | size_t* n_outputs); | 多少维; | NNError nn_context_run(NNContext* context); | 运行模型 | NNError nn_argmax( | 获取模型运行结果最大值及其所在编号, | NNTensor* input, | value_size指定数指所占字节数 | int* index, | | void* value, | | size_t value_size); | | const char* nn_model_label( | 获取index对应的label值,这里要特殊说明的是, | const NNModel* model, | NNModel中集成了模型的标签,用户无需再手动声明 | int index); | | 这样一来,结合着上面我们的模型导入以及测试图片的导入函数,所有我们运行模型所需要的函数就全部凑齐了,亟待召唤神龙!那么详细的代码,还请大家自行翻阅我们的main.c。
到了最振奋人心的时刻了,分析完代码,终于来到了最终的模型部署部分。当然,具体流程就是熟悉的编译,下载过程,此处略去万字操作攻略,连好板子后,复位运行即可看到我们的程序运行结果打印到了控制台上。
那么,我们最后一期的eIQ Toolkit系列文章就到此结束了,小编终于填上了之前埋下的模型部署的坑,希望大家都能够构建自己的神经网络模型,跑出心仪的结果!
相关阅读:
eIQ Toolkit上手指南(一)
eIQ Toolkit上手指南(二)
eIQ Toolkit上手指南(三)
恩智浦小课堂第二十九期—30分钟在MCU上跑通机器学习
恩智浦相关的【软件大全】
|
|