微信官方说可以加载本地的onnx模型,结果我放在程序目录下的onnx文件,用相对路径传入,“真机调试”时死活报错,说路径不对。后来发现,“以下文件未上传”中赫然有我的onnx模型。我的天,除了代码的文件、常见媒体的格式,其他都不会上传,甚至不能自己选哪些格式要上传。查看官方的代码,发现是从网络中下载到wx.env.USER_DATA_PATH路径下,但我没有服务器,也懒得找个地方存。于是有了以下的尝试:
1. 把onnx改成jpg格式,然后转存并重命名回onnx。首先要读取文件为二进制,然后得到暂存地址,然后保存到本地。结果第一步读取就permission denied,挂了。
2. 转为base64,转回二进制,然后保存。结果解码base64的API停止维护了。
3. 【最终绝招】将文件先解码为ArrayBuffer,然后转为Uint8Array,然后转为Array,然后JSON字符串化,然后将它写到js文件中。下载到本地时,先读取这个Uint8Array,然后提取其ArrayBuffer保存到本地。代码如下:
首先是获取文件数据,用html实现:
<body>
<input type="file">
</body>
<script>
const fileInput = document.querySelector('input[type="file"]');
var out;
fileInput.addEventListener('change', function (event) {
const file = event.target.files[0]; // 获取选择的文件
// 创建FileReader对象
const reader = new FileReader();
// 将文件读取为ArrayBuffer
reader.readAsArrayBuffer(file);
// 读取完成后的回调
reader.onload = function (e) {
// e.target.result 就是文件内容的ArrayBuffer
const arrayBuffer = e.target.result;
out = arrayBuffer;
// 转字符串
let u = new Uint8Array(out);
console.log(JSON.stringIfy([...u])); // 输出的结果复制出来
};
reader.onerror = function (e) {
console.error('读取文件时发生错误:', e);
};
});
</script>
把控制台的数据复制到微信小程序中的onnx.js中:
export default new Uint8Array([8,7,18,.....省略
保存(转存)模型:
import jpnet from './onnx.js';
const modelPath = `${wx.env.USER_DATA_PATH}/mymodel.onnx`;
async function saveModel() {
try {
if(await checkExist(modelPath)) return;
await write(jpnet.buffer, modelPath);
} catch (e) {
throw new Error(e);
}
}
function checkExist(path) {
return new Promise((resolve) => {
const fs = wx.getFileSystemManager()
// 判断文件/目录是否存在
fs.access({
path: path,
success(res) {
resolve(true);
},
fail(res) {
resolve(false);
}
});
});
}
// 写入文件
function write(arraybuffer, targetPath) {
return new Promise((resolve, reject) => {
wx.getFileSystemManager().writeFile({
filePath: targetPath,
data: arraybuffer,
encoding: 'binary',
success: function () {
console.log('模型保存成功');
resolve();
},
fail: function (err) {
console.error('模型保存失败', err);
reject(err);
}
});
});
}
然后就可以从modelPath访问onnx模型了。但是原来一个小小98KB的模型,硬是变成了344KB的js文件,悲。(吐槽一下微信小程序的函数,又臭又长)
再吐槽一件事,我的onnx在html上运行一切正常,但是到了微信上,对结果用argmax结果总是0。我注意到了输入的接口是ArrayBuffer,结果没想到输出也是ArrayBuffer……需要先转为Float32Array,再用argmax。