查看: 3623|回复: 1

编译模型的编译器—glow推理引擎初探

[复制链接]
  • TA的每日心情
    开心
    2025-7-11 08:53
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3874

    主题

    7478

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39283
    最后登录
    2025-7-22
    发表于 2021-3-4 14:16:47 | 显示全部楼层 |阅读模式
    编译模型的编译器—glow推理引擎初探


    看到本文标题,相信不少观众都会有点迷茫,发出这样的灵魂拷问,什么,模型还可以编译?你在骗人吧?小编摸着良心告诉大家,小编真的没有说谎,本期,就为大家介绍一下这个伴随着NXP eIQ工具打包推出的推理引擎。

    看过小编前几期文章的朋友们,肯定对推理引擎这一名词不那么陌生了,所谓推理引擎就是能够在设备端运行AI模型的一个小东西,只有有了Ta,模型才可以在设备端享受那夕阳下的奔跑。
    而小编已经介绍过了两款推理引擎,分别是NNCU,以及Tflite Micro。今天这个小家伙叫做GLOW,glow的英文意思是光辉,但是在这里,此GLOW可非彼glow,这里的GLOW是graph + lowering的简写,意思是说,通过这个工具,在针对大量不同的上层model中的ops,到下层不同硬件设备的实现上,尽可能通过一些精简的指令进行表达。
    来个比较官方的解释,Glow是用于神经网络图的机器学习编译器(https://github.com/pytorch/glow)。它旨在优化神经网络图并为各种硬件设备生成代码。
    Glow有两种形式:即时(JIT)编译,即在执行模型之前在运行时执行编译;和Ahead of Time(AOT)编译,其中编译是脱机执行的,并生成一个目标文件(捆绑包),该文件随后与应用程序代码链接。
    本文将主要介绍如何创建集成使用GlowAOT编译器,即采用脱机的方式进行模型的编译,随后将生成的包集成到工程中的所需步骤。GLOW下载网址https://www.nxp.com.cn/downloads ... /eIQ_Glow_Win64.exe
    本文代码基于EVK-MIMXRT1060SDK中的eiq_examples\glow_lenet_mnist,版本为2.9.1中,下载地址https://mcuxpresso.nxp.com/en/builder?hw=EVK-MIMXRT1060,请注意勾选eIQ选项然后下载SDK。

    生成Bundle
    Bundle代表了模型编译后生成的二进制目标文件。model-compiler工具用来生成Bundle,其流程为:
    21.png
    当然,无论是浮点还是量化模型,工具本身都是支持的。但是,考虑到所生成代码的尺寸,以及运行时间,量化模型当然是首选。强烈建议生成量化模型。


    Glow还有一个秘密武器,由于Glow采用LLVM作为后端,这使得他具有了跨平台的模型编译能力。通过编译选项可以进行目标平台的设置:
    适用Cortext-M7的指令
      -target=arm  -mcpu=cortex-m7 -float-abi=hard
    适用Cortext-M33的指令
      -target=arm  -mcpu=cortex-m33 -float-abi=hard


    编译量化模型的完整指令,请注意这里所标红的地方,是为了使用CMSIS-NN库中的函数进行加速所必需的:
    1. model-compiler.exe    -model=models\lenet_mnist -model-input=data,float,[1,1,28,28] -emit-bundle=bundle
    2.     -backend=CPU -target=arm -mcpu=cortex-m7 -float-abi=hard
    3.     -load-profile=profile.yml
    4.     -quantization-schema=symmetric_with_power2 scale
    5.     -quantization-precision-bias=Int8 -use-cmsis
    复制代码
    其他参数说明:
    22.png
    这样,运行结束后,会在bundle路径中生成如下文件:
    23.png
    获取量化参数

    上一节说到,进行模型量化时候需要传入一个profile.yml,用于指导编译器进行模型量化,而image-classifier工具就是为了生成这一文件。
    24.png
    使用方法,将测试图片放到目录下,并当作参数传入命令行,如果想要使用CMSIS-NN库进行加速,请注意标红部分:
    1. image-classifier.exe
    2.     images\*.png
    3.     -image-mode=0to1
    4.     -image-layout=NCHW
    5.     -image-channel-order=BGR
    6.     -model=models\lenet_mnist
    7.     -model-input-name=data
    8.     -dump-profile=profile.yml
    9.     -quantization-schema=symmetric_with_power2 scale
    10.     -quantization-precision-bias=Int8
    复制代码
    参数说明:
    25.png
    模型集成

    下面介绍如何以静态方式,将上述通过Glow编译成功的代码集成到工程中。所谓静态方式,是将所有文件,包括权重文件添加到工程中,编译下载到板子上运行。


    第一步 导入glow_bundle_utils.h头文件到main.c,并假设模型编译出的文件为lenet_mnist.h一并导入到main.c。
    1. // Bundle include
    2. #include "lenet_mnist.h"
    3. #include "glow_bundle_utils.h"
    复制代码
    第二步 为权重,输入输出tensor,以及中间层激活变量声明buffer,注意权重是以include的方式导入:
    1. // Statically allocate memory for constant weights (model weights) and initialize.
    2. GLOW_MEM_ALIGN(LENET_MNIST_MEM_ALIGN)
    3. uint8_t constantWeight[LENET_MNIST_CONSTANT_MEM_SIZE] = {
    4. #include "lenet_mnist.weights.txt"
    5. };

    6. // Statically allocate memory for mutable weights (model input/output data).
    7. GLOW_MEM_ALIGN(LENET_MNIST_MEM_ALIGN)
    8. uint8_t mutableWeight[LENET_MNIST_MUTABLE_MEM_SIZE];

    9. // Statically allocate memory for activations (model intermediate results).
    10. GLOW_MEM_ALIGN(LENET_MNIST_MEM_ALIGN)
    11. uint8_t activations[LENET_MNIST_ACTIVATIONS_MEM_SIZE];
    复制代码
    第三步 通过宏GLOW_GET_ADDR获取模型的输入与输出指针:
    1. // Bundle input data absolute address.
    2. uint8_t *inputAddr = GLOW_GET_ADDR(mutableWeight, LENET_MNIST_data);

    3. // Bundle output data absolute address.
    4. uint8_t *outputAddr = GLOW_GET_ADDR(mutableWeight, LENET_MNIST_softmax);
    复制代码
    第四步 初始化出入数据,即用户需要在运行模型之前对inputAddr进行赋值,需要自行准备imageData,这里需要说明,glow默认输入数据为float类型:
    1. // Produce input data for bundle.
    2. // Copy the pre-processed image data into the bundle input buffer.
    3. memcpy(inputAddr, imageData, sizeof(imageData));
    复制代码
    第五步 现在万事俱备了,让模型跑起来,你没有看错,就是如此简单的一句话:
    1. lenet_mnist(constantWeight, mutableWeight, activations);
    复制代码
    第六步 运行完之后,结果会被保存在outputAddr所指向的内存区域,但是要注意,结果是以float型数据保存的,处理时要以float*型指针访问数据:
    1. // Get classification top1 result and confidence.
    2. float *out_data = (float*)(outputAddr);
    3. float max_val = 0.0;
    4. uint32_t max_idx = 0;
    5. for(int i = 0; i < LENET_MNIST_OUTPUT_CLASS; i++) {
    6.    if (out_data[i] > max_val) {
    7.       max_val = out_data[i];
    8.       max_idx = i;
    9.    }
    10. }
    复制代码
    第七步 运行结果:
    26.png
    Having Fun ....


    至此,利用Glow进行模型的编译,然后集成到工程中的流程就介绍完毕了。相信大家已经对Glow这个奇妙的模型编译器产生了浓厚的兴趣。祝大家玩的开心哟!

    qiandao qiandao
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 16:53
  • 签到天数: 1439 天

    连续签到: 8 天

    [LV.10]以坛为家III

    2

    主题

    3444

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    6904
    最后登录
    2025-7-21
    发表于 2021-3-8 11:29:55 | 显示全部楼层
    感谢楼主整理分享!
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-22 10:55 , Processed in 0.083099 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表