维生素B3叫什么名字| 乙肝核心抗体高是什么意思| 独角戏什么意思| 人乳头瘤病毒39型阳性是什么意思| 王安石号什么| 什么是应届毕业生| 是否是什么意思| 夏天为什么要吃姜| 脾虚湿热吃什么药| hiv是什么| 4月5号是什么星座| 看到刺猬有什么预兆| 闹代表什么生肖| 什么是射频| 4月26日什么星座| 公安局跟派出所有什么区别| 什么是腕管综合征| 重字五行属什么| 李嘉诚是什么国籍| 什么的仪式| 跑男什么时候播出| 女属猪的和什么属相最配| 血红蛋白低吃什么可以补起来| 尿发绿是什么原因| 安徽的特产是什么| 从什么不什么四字词语| 芒种是什么时候| 湿气重喝什么茶好| 鲁迅的原名叫什么| 嘴唇起泡是什么火| 牙髓炎吃什么药最有效| 相招是什么意思| meq是什么单位| 塑料属于什么垃圾| burberry是什么牌子| 经期适合喝什么茶| 吃叶酸有什么好处| 栀子有什么作用与功效| 门前的小树已成年是什么歌| 鱼吃什么| 淀粉酶是什么| 于无声处是什么意思| 为什么一低头就晕| 女性外阴瘙痒用什么药| 真菌阴性是什么意思| 烧心吃什么食物好得快| 手抖是什么症状| 心肌缺血吃什么药管用| 烤麸是什么做的| 公分是什么意思| 血管属于什么组织| 好强的女人是什么性格| 85年属牛是什么命| 香港说什么语言| 眉宇是什么意思| 孕妇适合喝什么牛奶| 呼吸道感染吃什么药| 挑灯夜战是什么意思| 什么样的月亮| 心度高血压是什么意思| 在是什么意思| 995是什么意思| 生姜什么时候种植最合适| 菊花泡水喝有什么功效| 平板撑有什么作用| 卵巢囊肿吃什么药| 为感是什么意思| sharon是什么意思| 什么是前置胎盘| iga肾病是什么病| 茶色是什么颜色| 幽门螺旋杆菌是什么症状| audrey是什么意思| 金字旁土念什么字| 遗精是什么原因| 彩礼什么时候给女方| 中国科协是什么级别| 蛇字五行属什么| 尿毒症有些什么症状| 高血糖主食吃什么好| u是什么元素| 肌层彩色血流星点状是什么意思| 什么是白条| 知柏地黄丸治什么病| 淋巴细胞百分比低是什么意思| 唇炎吃什么药| 肠胃不好吃什么水果好| 什么是佛| 什么是对数| 汗为什么是咸的| 男朋友发烧该说些什么| 巴黎世家是什么| 41年属什么生肖| 讹人是什么意思| suan是什么意思| 烈日灼心什么意思| 黔驴技穷是什么意思| 三下乡是什么意思| 什么的小莲蓬| 势不可挡是什么意思| 曲奇饼干为什么不成形| 胚芽发育成什么| 辅警和协警有什么区别| 舌头有点麻是什么病的前兆| wifi用户名是什么| 守护者是什么意思| 火耗归公是什么意思| 月经血是黑色的是什么原因| 角化异常性疾病是什么| vr间隙是什么意思| 洋桔梗花语是什么| 大便溏泄是什么意思| 白气是什么物态变化| 小儿疝气挂什么科| 津液亏虚吃什么中成药| 钻牛角尖是什么意思| 梦见照相是什么意思| 吃羊肉不能吃什么| 汗蒸和桑拿有什么区别| 白带黄什么原因| 印度是什么人种| 心肺气虚吃什么中成药| 兆是什么意思| 牛油是什么油| 什么发什么颜| 迅雷不及掩耳之势是什么意思| 蛤蟆吃什么| 湿邪是什么意思| 尿不尽挂什么科| 私人订制什么意思| 竹马是什么意思| 武则天是什么生肖| 胸膜牵拉是什么意思| 什么叫三观不合| vip是什么意思| hgb是什么意思| 小径是什么意思| 腋臭和狐臭有什么区别| 感谢老师送什么花| 下面有异味是什么原因| 理数是什么意思| 舌头溃疡吃什么药最好| 吃什么减脂肪| 邓超什么星座的| 黑猫警长叫什么名字| 窦性心律逆钟向转位是什么意思| 什么护肤品最好用| 一什么陆地| 车水马龙的意思是什么| 穿山甲到底说了什么| 身上有白斑块是什么原因造成的| 吃什么可以补充雌激素| 革兰阴性杆菌是什么| seeya是什么意思| 九出十三归是什么意思| 小孩脸上有白斑是什么原因| 尿道炎用什么药| 健忘症是什么意思| 做肝功能检查挂什么科| mice是什么意思| 来大姨妈不能吃什么水果| 胃囊肿是什么病严重吗| 第二磨牙什么时候长| 腊肠和什么菜炒最佳| 虎头蜂泡酒有什么功效| 10.22是什么星座| 狗能吃巧克力吗为什么| 7月16是什么星座| 8月31号是什么星座| 腹泻吃什么好| 摆渡是什么意思| 做梦梦到大蟒蛇是什么意思| 沁什么意思| 为什么脸一边大一边小| 大三阳是什么病| 猜忌是什么意思| 锅包肉是什么肉| 祖马龙是什么档次| 吃什么去湿气最快| 为什么会反复发烧| 疴是什么意思| 猪利是什么| 肝实质回声欠均匀是什么意思| 孩子喉咙痛吃什么药好| 孕期感冒可以吃什么药| 做梦掉牙齿是什么意思| 奥斯卡是什么意思| 八败是什么意思| 舜字五行属什么| 血糖高检查什么项目| 什么是安全期| 孩子咬指甲什么原因| 狗为什么喜欢吃人屎| 信指什么生肖| 钅读什么偏旁| 蝙蝠飞到家里是什么预兆| 阴道炎什么症状| 脂肪肝吃什么药效果好| 酒喝多了喝什么解酒| 早上左眼跳是什么预兆| 小龙虾什么季节| 什么是天葬| 吃相难看是什么意思| crispy是什么意思| 什么样的柳条| 丁火命是什么意思| 12320是什么电话| 长期喝豆浆有什么好处和坏处| 4a广告公司什么意思| 怀孕了有什么征兆| 睡觉为什么会打呼噜| 甲亢查什么| 眼睛红血丝是什么原因| 甲亢不能吃什么东西| 上火喝什么饮料| 血清铁是什么意思| 霉菌感染用什么药最好| 社畜是什么意思| 县教育局局长是什么级别| 中书舍人是什么官职| 乳腺结节有什么症状| 手机为什么会发热| 为什么会胰岛素抵抗| 气管炎吃什么药最有效| 舌头白是什么原因| 手脚经常发麻是什么原因| 败火是什么意思| 资治通鉴讲的是什么| 世界杯什么时候开始| 排酸是什么意思| 大暑是什么时间| 水泻拉肚子是什么原因| 学生早餐吃什么方便又营养| 月黑见渔灯的见读什么| 辰砂和朱砂有什么区别| 白内障有什么症状表现| 小孩睡觉磨牙是什么原因引起的| 孕晚期吃什么长胎不长肉| 8月29是什么星座| 血尿挂什么科| 素鸡是什么做的| 紫绀是什么症状| 红润润的什么| 甲亢甲减有什么症状| 肝昏迷是什么意思| feel什么意思| 开什么玩笑| 脑梗吃什么食物好| 体外受精是什么意思| 颈椎脑供血不足吃什么药| 睡着了放屁是什么原因| 可遇不可求是什么意思| 鸡精吃多了有什么危害| 舌头胖大是什么原因| mom什么意思| 梦见自己生了个女孩是什么意思| 风热火眼是什么意思| 尿蛋白弱阳性是什么意思| 94属什么生肖| 虞是什么意思| 什么是肺大泡| 眼睛视力模糊用什么眼药水| 50元人民币什么时候发行的| 铁扇公主是什么生肖| 百度

# 小程序AI使用指南

# 开始

小程序AI通用接口是一套小程序官方提供的通用AI模型推理解决方案,内部使用充分优化的自研推理引擎,支持 CPU、GPU、NPU 推理。小程序开发者无需关注内部实现和模型转换,只需提供训练好的 ONNX 模型,小程序内部会将用户的 ONNX 模型自动转换为自研推理引擎可以识别的模型格式并完成推理。

本指南将展示如何从头开始使用小程序AI推理能力完成一个分类任务。我们将摄像头实时采集到的数据经过简单的前处理转换为AI推理的输入,完成推理后,再对模型运行输出进行简单的后处理,获取最终分类结果并展示在页面上。

示例使用 ONNX 官方 modelzoo 所提供的 mobileNetV2 模型。相关模型可以从官方github 获取;示例中使用的前后处理方式也与 ONNX 官方给出的imagenet_validation一致。

# 1 创建session

首先我们需要创建一个 session 用于推理。 这里我们使用从官方github下载的浮点模型,选择 precisionLevel 为0,这样 session 运行时,将会自动选择 fp16 存储中间 tensor 的结果,也会用 fp16 进行计算,并且会开启 fp16 计算的 Winograd,同时开启近似 math 计算。我们选择不使用量化推理,不使用 NPU。 创建 session 时除了必须提供参数 model 来指定 ONNX 模型路径外,其他设置都不是必须的。

一般来说,使用的 precisionLevel 等级越低,推理速度越快,但可能带来精度损失。因此推荐开发者在使用时,在效果满足需求时优先使用更低精度以提高推理速度,节约能耗。

除了使用wx.createInferenceSession()接口创建 session 外,此处我们还为 session 添加了2个事件,以监听 error 或者创建完成。onLoad()函数中我们通过设置一个 isReady 变量,记录 session 完成了初始化,可以用来进行推理。

// 这里 modelPath 为需要的 ONNX 模型,注意 model 目前只能识别后缀为.onnx 的文件作为参数。
const modelPath = `${wx.env.USER_DATA_PATH}/mobilenetv2-12.onnx`;

this.session = wx.createInferenceSession({
    model: modelPath,
    /* 0: 最低精度  使用 fp16 存储浮点,fp16 计算,Winograd 算法也采取 fp16 计算,开启近似 math 计算
       1: 较低精度  使用 fp16 存储浮点,fp16 计算,禁用 Winograd 算法,开启近似 math 计算
       2: 中等精度  使用 fp16 存储浮点,fp32 计算,开启 Winograd,开启近似 math 计算
       3: 较高精度  使用 fp32 存储浮点,fp32 计算,开启 Winograd,开启近似 math 计算
       4: 最高精度  使用 fp32 存储浮点,fp32 计算,开启 Winograd,关闭近似 math 计算

       通常更高的精度需要更长的时间完成推理
    */
    precisionLevel : 0,
    allowNPU : false,     // 是否使用 NPU 推理,仅针对 IOS 有效
    allowQuantize: false, // 是否产生量化模型
    });

// 监听error事件
session.onError((error) => {
  console.error(error);
});

// 监听模型加载完成事件
session.onLoad(() => {
  console.log('session load')
}); 

# 2 session推理

# 2.1 处理摄像头采集数据

首先我们创建一个 camera context, 并调用 onCameraFrame 采集帧。此处的 classifier 封装了推理 session 相关的调用,具体完整代码可以参考 demo 示例。onCameraFrame 会持续采集摄像头图像,如果我们的 session 初始化成功的并且完成了上一帧的推理任务,就会传递摄像头采集的数据,执行新一次的推理任务。

    const context = wx.createCameraContext(this); 
     
    const listener = context.onCameraFrame(frame => {

        const fps = this.fpsHelper.getAverageFps();
        console.log(`fps=${fps}`);

        if (this.classifier && this.classifier.isReady() && !this.predicting) {
           this.executeClassify(frame);
        }
    });

# 2.2 对摄像头的采集数据进行前处理

OnCameraFrame 返回的 frame 包含属性 width、height 和 data,分别表示二维图像数据的宽度,高度,以及图像像素点数据。其中 data 为一个 ArrayBuffer,存储数据类型为 Uint8,存储的数据 format 为 rgba,即每连续的4个值表示一个像素点的 rgba。 详细关于 onCameraFrame 的内容可以参考CameraContext.onCameraFrame.

对于 frame 内容,我们首先进行前处理操作以转化为模型输入。

用 Netron 打开 ONNX 文件,我们可以看到 mobileNet 输入输出的描述信息。 可以看到,本模型的输入大小为[1, 3, 224, 224],数据类型为 float32。


为了将摄像头采集到的frame转换为模型需要的数据,我们需要丢弃 alpha 通道信息,将数据由 nhwc 变换成 nchw, 将 frame 的 width 和 height resize 成 224 x 224, 并且完成 normallize 操作。

以下代码通过 js 完成了所有前处理过程,将摄像头采集到 frame 转化为模型输入 dstInput。 其中 frame 为摄像头采集的数据, var dstInput = new Float32Array(3 * 224 * 224);

  /* 原始输入为 rgba uint8 数据, 目标为 nchw float32 数据

     将camera 采集数据缩放到模型的 input 大小, 将 uint8 数据转换成 float32,
     并且从 NHWC 转换到 NCHW
  */
  preProcess(frame, dstInput) {

    return new Promise((resolve, reject) =>
    {
      const origData = new Uint8Array(frame.data);

      const hRatio = frame.height / modelHeight;

      const wRatio = frame.width / modelWidth;


      const origHStride = frame.width * 4;
      const origWStride = 4;
    
      const mean = [0.485, 0.456, 0.406]

      // Reverse of std = [0.229, 0.224, 0.225]
      const reverse_div = [4.367, 4.464, 4.444]
      const ratio = 1 / 255.0

      const normalized_div = [ratio / reverse_div[0], ratio * reverse_div[1], ratio * reverse_div[2]];

      const normalized_mean = [mean[0] * reverse_div[0], mean[1] * reverse_div[1], mean[2] * reverse_div[2]];

      var idx = 0;
      for (var c = 0; c < modelChannel; ++c)
      {
        for (var h = 0; h < modelHeight; ++h)
        {
          const origH = Math.round(h * hRatio);

          const origHOffset = origH * origHStride;

          for (var w = 0; w < modelWidth; ++w)
          {
            const origW = Math.round(w * wRatio);

            const origIndex = origHOffset + origW * origWStride + c;

            const val = origData[origIndex] * (normalized_div[c]) - normalized_mean[c];

            dstInput[idx] = val;

            idx++;
          }
        }
      } 

      resolve();
    });
  }

# 2.3 模型推理

对摄像头采集到的数据进行简单前处理后,我们就可以用来设置 input,进行模型推理了。 我们用前处理得到的 dstInput 来构造一个 xInput,将这个 xInput 作为模型推理的输入,传递给 session.run 即可。

const xinput = {
    shape: [1, 3, 224, 224],  // 输入形状 NCHW 值
    data: dstInput.buffer,    // 为一个 ArrayBuffer
    type: 'float32',          // 输入数据类型
};

this.session.run({
    // 这里 "input" 必须与 ONNX 模型文件中的模型输入名保持严格一致
    "input": xinput,
})
.then((res) => {

    // 这里使用 res.outputname.data
    // 其中 outputname 需要严格与 ONNX 模型文件中的模型输出名保持一致
    let num = new Float32Array(res.output.data)

运行之后的结果我们通过 res.output 获取。 需要注意的是, 这里的 input/output 不是所有模型固定的,需要严格与具体 ONNX 文件中的输入,输出名字对应。 回到之前 Netron 看到的 mobilenet 模型描述信息:我们可以看到本模型有一个输入,名字叫做 “input”,有一个输出,名字就叫做 “output”。 因此我们设置输入时, session.run({"input": xinput}), "input" 即为 ONNX 模型中的 input name. 当有多个输入时,我们通过session.run({"input1": xxx, "input2": xxx}) 来分别对模型中名字为 “input1” 和 “input2” 的输入设置数据。 同样的,我们获取模型的输出时,res.output 指获取名字为 “output” 的输出。

不管是模型的输入还是输出 Tensor, 都是一个 Object,包含了 shape,type 和 data 三个属性。其中 data 是一块ArrayBuffer。

# 2.4 后处理

本示例对后处理过程比较简单,获取到模型输出后,我们通过一个 argMax 操作,计算出分数最高的分类 Index, 并将这个 Index 转换为所表示的类别即可。

let num = new Float32Array(res.output.data)

var maxVar = num[0];

var index = 0;

for (var i = 1; i < num.length; ++i)
{
if (maxVar < num[i])
{
    maxVar = num[i]   
    index = i     
}
}

this.getClass(index);

# 3 运行效果

扫描下方二维码,点击接口-通用AI推理能力-mobileNet, 可以查看运行效果。



运行 demo,可以看到摄像头在采集同时,将会实时地将分类结果写回到页面下方。



完整 demo 请参考官方github小程序示例

# 算子支持列表

详细算子支持情况请参考算子支持列表

肝内低密度影是什么意思 河童是什么意思 腮腺炎是什么 明年是什么生肖年 什么争什么斗
s倾向是什么意思 属虎的五行属什么 减肥吃什么 5.29是什么星座 碳13是检查什么的
舌头上火吃什么药 温度计里面红色液体是什么 落花流水什么意思 阴湿是什么意思 大便发黑是什么情况
老感冒是什么原因 高兴的反义词是什么 口干是什么病的前兆 甘耳朵旁什么字 乾隆是什么生肖
什么是事业hcv9jop6ns8r.cn 什么是心脑血管疾病hcv8jop4ns3r.cn 蝙蝠飞到家里是什么预兆bjhyzcsm.com 宁波有什么特产hcv9jop2ns2r.cn 甲状腺4a是什么意思hcv8jop7ns5r.cn
旭五行属性是什么hcv8jop3ns6r.cn hi是什么酸hcv7jop9ns6r.cn 皮蛋不能和什么一起吃hcv9jop4ns6r.cn 昆山有什么好玩的地方hcv8jop0ns8r.cn 人出现幻觉是什么原因hcv8jop3ns3r.cn
越五行属性是什么dayuxmw.com 两个圈的皮带是什么牌子beikeqingting.com 千秋无绝色悦目是佳人什么意思hcv9jop5ns6r.cn 果是什么结构的字gangsutong.com 荷花的寓意是什么hcv8jop3ns5r.cn
斗是什么样子hcv7jop5ns6r.cn 死库水是什么意思hcv7jop6ns4r.cn 复方对乙酰氨基酚片是什么药hcv8jop8ns3r.cn 白带有腥味是什么原因hcv9jop1ns9r.cn 决裂是什么意思hcv8jop7ns2r.cn
百度