开发者问题收集

带有 tensorflowjs 的 Vue3 应用程序抛出 TypeError:无法读取未定义的属性“backend”

2021-06-03
2888

我用普通的 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. Github:TypeError:无法读取未定义的属性“backend”

  2. TypeError:无法读取未定义的属性“backend” - 调用 moveData 时已释放张量

因此,我创建数据集的过程可能会引起疑问, 在我的另一篇文章中 描述了这一点。

请有人帮帮我。自从我遇到这个问题以来已经过去了将近一周的时间。

编辑 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)
3个回答

就我而言,错误似乎是由于 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)
    }
  }
}
Pierre Caillaud
2021-07-05

当我尝试在 Vue3 中使用我的模型时,我遇到了同样的情况。我设法通过执行以下操作在模型上运行预测:

import { toRaw } from 'vue'

...

let raw_model = toRaw(this.model)
let result = raw_model.predict(img)

...
JinAquo123
2021-08-19

我在 CLI 中遇到了同样的错误,但与 Vue 无关。

就我而言,我尝试使用 tf.tidy(() => {}) 范围之外的张量。

Csabi
2021-08-04