TensorFlowJS 移植微信小程序再次尝试

动机

之前写了篇 tfjs 移植到微信小程序,本来以为没什么人会感兴趣,就只是大概写了个思路。

前几天,突然有读者通过公众号联系我,咨询实现细节。我心血来潮,想把之前的代码再折腾下,搞个 Demo 再开源出去,没准还能火一把?

坎坷的尝试

从头开始

把大象装进冰箱需要三步,但是首先得有冰箱和大象。距离上篇文章已经快半年时间了,原来的 Demo 代码早就不知道扔哪里去了,只剩下之前改造的 wx-tfjs-core

因为需要 tfjs-core 和 tfjs-converter 配合使用,才能实现模型的加载和预测功能。两者版本要一致,而我已经不太记得当时的 tfjs-core 和 tfjs-converter 是从哪个时间点拉的代码,真的是雪上加霜。

克隆了 wx-tfjs-core 到本地,再把 tfjs-core 的官方代码合进去重新编译后,下载官方编译好的 tfjs-converter,一起引入小程序中。

正要开始实现的时候,我发现一个比较严重的问题:加载模型的 API 变了。emoji-scavenger-hunt 中使用的 loadFrozenModel 已经废弃,改用 loadGraphModel

两者最主要的区别在于,loadFrozenModel 分别加载 tensorflowjs_model.pb 和 weights_manifest.json,而新接口则是把两者统一到一个 json 文件中。这个倒是还可以解决的,毕竟有相应的解决方案:

1
2
3
4
git clone [email protected]:tensorflow/tfjs-converter.git
cd tfjs-converter
yarn
yarn ts-node tools/pb2json_converter.ts pb_model_directory/ json_model_directory/

麻烦的地方在于,需要对之前改造 tfjs-core 时写的一些方法做改造,比较费时费力。而且使用模型预测的代码也不适用了,真叫人头大。

发现新大陆

某天晚上,洗完澡躺床上思考人生的时候,我突然想到之前有把代码通过微信传给别人。于是我马上搜索微信聊天记录,把代码转存到了本地,真是天助我也!

打开微信开发工具,导入代码运行,一气呵成!看着控制台输出的模型加载的相关日志,我仿佛看到了曙光。当然事情也不是那么顺利,由于微信可能又做了什么升级,原来改造的一些代码,不得不「重构」一番。

比如,原来写的 fetch 方法中,用于将 BufferArray 转成字符串的 String.fromCharCode.apply(null, xxx),现在在手机端已经无法正常运行,总是报类似「调用栈溢出」的错误。

实现思路

解决一些基本的 BUG 之后,算是能够在手机端正常加载模型,对打开的图片进行识别了。但这还不够,我要做的是利用摄像头成像,然后识别所拍摄的物体。

多番尝试之后,我找到了可行的办法:摄像头成像之后,将图片显示在 canvas 中,通过小程序的 API 可以获取到 canvas 的「类 ImageData」数据,再调用 tfjs 的 API 实现预测。

至于刚刚提到的「类 ImageData」,是因为获取到的数据格式和 ImageData 是基本一致的,不过小程序中并没有提供 ImageData 这个类。

Demo 效果

代码开源在 wx-tfjs-demo,可以改进的地方很多,感兴趣的同学可以优化然后提交 PR。具体的功能代码实现和 UI 调整,我就不啰嗦了,看下 Demo 的实现效果吧。

demo

因为大小限制,GIF 图仅展示部分预测效果(使用 该工具 在线压缩),可以在 我的知乎专栏 —— 猎人杂货铺 看到完整视频。

结语

熬了几次夜,匆匆搞出来的 Demo,模型的预测效果还行,不过代码写得比较随意。因为是纯 CPU 运算,预测的速度不快,如果能深度定制化 tfjs-core,速度应该还可以再次提高。

如果只是纯兴趣爱,本人是不打算继续深挖了,小程序的坑怎么都填不完,表示再也不想开发微信小程序!另外,如果该项目对你有帮助,欢迎通过各种途径赞赏!

参考资料

  • 小程序开发文档
  • 微信小程序 canvas 实现图片拉伸、压缩与裁剪