带有 tensorflowjs 的 Vue3 应用程序抛出 TypeError:无法读取未定义的属性“backend”
我用普通的 Jquery 构建了一个简单的 tensorflowjs 应用程序,它运行良好,尽管预测不是很好,但它确实有效。
现在,我开始使用 Vue3 为应用程序构建 GUI,它是使用 @vue/cli 创建的。我已经通过 npm 安装了其他几个插件,例如 tailwindcss、clmtrackr,它们运行良好。
现在我已经使用 npm 安装了 tensorflowjs -
npm install @tensorflow/tfjs
一切都安装好了,没有任何错误,但是当我在设置模型创建和训练的代码后运行应用程序时,我开始收到错误 -
Uncaught (in promise) TypeError: Cannot read property 'backend' of undefined
at Engine.moveData (engine.js?6ae2:288)
at DataStorage.get (backend.js?8b87:29)
at eval (backend_webgl.js?5edb:497)
at Array.every (<anonymous>)
at MathBackendWebGL.shouldExecuteOnCPU (backend_webgl.js?5edb:497)
at concatImpl (Concat_impl.js?2cbf:39)
at Object.concat [as kernelFunc] (Concat.js?b4c2:35)
at kernelFunc (engine.js?6ae2:463)
at eval (engine.js?6ae2:524)
at Engine.scopedRun (engine.js?6ae2:337)
首先我想我可能需要安装 - @tensorflow/tfjs-node,它是为 NodeJs 制作的,但我还是继续安装了它。当然它不起作用,因为我有 node v.14,所以我开始收到 node-gyp 错误。我读到我需要使用旧版本的 node v12 来安装它,因此我安装了 nvm 并安装了另一个版本的 nodejs,然后运行 ​​@tensorflow/tfjs-node 并且它起作用了。之后我开始收到一堆我已经预料到的错误,因为这个包是为 NodeJS 制作的。
接下来,我删除了 node_modules 文件夹并修改了 package.json 以删除 tensorflow 的 node 版本,然后运行
npm install
安装所有新包及其最新版本。所有安装都没有任何错误,但无法读取属性“backend”的问题没有得到解决。
令人惊讶的是,当我在 Firefox 中运行代码时,我得到了未定义错误的信息,而在 chrome 中得到了未定义错误的信息,我不明白。
导致错误的代码是这样的 -
async trainModel(imageArray, labelArray) {
// tf.getBackend()
let imageSet = tf.tidy(() => {
return tf.concat(imageArray); <--------------- Error
});
let labelSet = tf.tidy(() => {
return tf.oneHot(tf.tensor1d(labelArray, 'int32'), 3);
})
this.model.fit(.............
}
我怎么知道的?好吧,我在 tf.tidy() 中返回了 null,并且确实传递到了下一个代码块。我经历了很多 github 问题,它们都有不同的问题,但错误相同。
因此,我创建数据集的过程可能会引起疑问, 在我的另一篇文章中 描述了这一点。
请有人帮帮我。自从我遇到这个问题以来已经过去了将近一周的时间。
编辑 1:
因此,对 imageArray 的任何操作都会导致后端错误,这实际上可能与我如何创建数据集并将其传递给类方法有关。
我怎么知道的?我试过了
console.log(imageArray.toString()) <--- this causes backend error
console.log(imageArray) < -- this doesn't
|
---> console output <--------------------------------
Tensor {kept: false, isDisposedInternal: false, shape: Array(4), dtype: "float32", size: 135000, …} (4) [1, 150, 300, 3]
Models.vue?2820:139 Tensor {kept: false, isDisposedInternal: false, shape: Array(4), dtype: "float32", size: 135000, …} (4) [1, 150, 300, 3]
Models.vue?2820:139 Tensor {kept: false, isDisposedInternal: false, shape: Array(4), dtype: "float32", size: 135000, …} (4) [1, 150, 300, 3]
Models.vue?2820:139 Tensor {kept: false, isDisposedInternal: false, shape: Array(4), dtype: "float32", size: 135000, …} (4) [1, 150, 300, 3]
Models.vue?2820:139 Tensor {kept: false, isDisposedInternal: false, shape: Array(4), dtype: "float32", size: 135000, …} (4) [1, 150, 300, 3]
TFModel.js?4fc1:71 Proxy {0: Tensor, 1: Tensor, 2: Tensor, 3: Tensor, 4: Tensor}
我在 vue3 应用程序中添加了我的数据集创建方法 -
initCanvas() {
this.mycan.canvas = this.$refs.mycan;
this.mycan.context = this.mycan.canvas.getContext('2d')
this.mycan.w = this.mycan.canvas.width
this.mycan.h = this.mycan.canvas.height
},
collectData() {
const img = tf.tidy(() => {
const captureImg = this.getImage();
console.log(captureImg, captureImg.shape)
return captureImg;
})
this.imageArray.push(img)
this.label = parseInt(Math.random() * 3)
this.labelArray.push(this.label) //--- labels are 0,1,2
},
getImage() {
return tf.tidy(() => {
const image = tf.browser.fromPixels(this.mycan.canvas);
const batchedImage = image.expandDims(0);
const norm = batchedImage.toFloat().div(tf.scalar(255)).sub(tf.scalar(1));
return norm;
});
}
编辑 2:
所以我对 getImage() 方法进行了另一项测试并记录了返回的值。它正确返回了下面提到的所有值,但同时抛出了相同的 未定义后端 错误
let imgData = this.getImage()
console.log(imgData)
console.log(imgData.shape)
console.log(imgData.toString())
<--- console output-->
Tensor {kept: false, isDisposedInternal: false, shape: Array(4), dtype: "float32", size: 135000, …}
Models.vue?2820:119 (4) [1, 150, 300, 3]
Models.vue?2820:120 Tensor
[[[[-0.6117647, -0.5411765, -0.3450981],
[-0.6117647, -0.5411765, -0.3450981],
[-0.6117647, -0.5411765, -0.3450981],
...,
[-0.5333334, -0.5019608, -0.3176471],
[-0.5333334, -0.5019608, -0.3176471],
[-0.5333334, -0.5019608, -0.3176471]],
[[-0.6039216, -0.5333334, -0.3372549],
[-0.6078432, -0.5372549, -0.3411765],
[-0.6078432, -0.5372549, -0.3411765],
...,
[-0.5372549, -0.5019608, -0.3176471],
[-0.5372549, -0.5019608, -0.3176471],
[-0.5372549, -0.5019608, -0.3176471]],
[[-0.6 , -0.5294118, -0.3333334],
[-0.6 , -0.5294118, -0.3333334],
[-0.6 , -0.5294118, -0.3333334],
...,
[-0.5372549, -0.4980392, -0.3176471],
[-0.5372549, -0.4980392, -0.3176471],
[-0.5333334, -0.4941177, -0.3137255]],
...
[[-0.4039216, -0.454902 , -0.3529412],
[-0.4078432, -0.4588236, -0.3568628],
[-0.4078432, -0.4588236, -0.3568628],
...,
[-0.309804 , -0.3254902, -0.2352942],
[-0.309804 , -0.3254902, -0.2352942],
[-0.309804 , -0.3254902, -0.2352942]],
[[-0.4039216, -0.454902 , -0.3529412],
[-0.4039216, -0.454902 , -0.3529412],
[-0.4039216, -0.454902 , -0.3529412],
...,
[-0.3058824, -0.3215687, -0.2313726],
[-0.309804 , -0.3254902, -0.2352942],
[-0.309804 , -0.3254902, -0.2352942]],
[[-0.4039216, -0.454902 , -0.3529412],
[-0.4039216, -0.454902 , -0.3529412],
[-0.4039216, -0.454902 , -0.3529412],
...,
[-0.3058824, -0.3215687, -0.2313726],
[-0.309804 , -0.3254902, -0.2352942],
[-0.309804 , -0.3254902, -0.2352942]]]]
Uncaught TypeError: Cannot read property 'backend' of undefined
at Engine.moveData (engine.js?6ae2:288)
at DataStorage.get (backend.js?8b87:29)
at reshape (Reshape.js?ad24:31)
at conv2dWithIm2Row (Conv2D_impl.js?7600:157)
at Object.fusedConv2d [as kernelFunc] (FusedConv2D.js?2d19:46)
at kernelFunc (engine.js?6ae2:463)
at eval (engine.js?6ae2:524)
at Engine.scopedRun (engine.js?6ae2:337)
at Engine.runKernelFunc (engine.js?6ae2:520)
at Engine.runKernel (engine.js?6ae2:393)
就我而言,错误似乎是由于 Vue3 将我的模型属性包装在 代理对象 中造成的。您可以使用 Object.freeze() 来阻止 Vue 框架修改您的对象。
之前:
export default {
data: ()=>({
prediction: null,
model: null
}),
methods:{
async initModel(){
this.model = await tmImage.load(modelURL, metadataURL)
// model is wrapped in a Proxy object
},
async predict(){
this.prediction = await this.model.predict(canvas) // this line throwed error
}
}
}
之后:
export default {
data: ()=>({
prediction: null,
model: null
}),
methods:{
async initModel(){
this.model = Object.freeze(await tmImage.load(modelURL, metadataURL))
},
async predict(){
this.prediction = await this.model.predict(canvas)
}
}
}
当我尝试在 Vue3 中使用我的模型时,我遇到了同样的情况。我设法通过执行以下操作在模型上运行预测:
import { toRaw } from 'vue'
...
let raw_model = toRaw(this.model)
let result = raw_model.predict(img)
...
我在 CLI 中遇到了同样的错误,但与 Vue 无关。
就我而言,我尝试使用
tf.tidy(() => {})
范围之外的张量。