Why do I receive the Error: Tensor is disposed, when using tf.grad() to implement FGSM?

Why do I receive the Error: Tensor is disposed, when using tf.grad() to implement FGSM?

我正在尝试使用 tensorflow.js 在 MobileNet 上实现快速梯度符号法 (FGSM),但是在使用 [= 计算梯度时我在最新版本 (1.0.1) 上遇到了问题38=]().

代码在 tfjs 0.13.0 及以下版本中运行良好,但是更新到任何更高版本都会导致以下错误:

core.js:15723 ERROR Error: Uncaught (in promise): Error: Tensor is disposed. Error: Tensor is disposed.
at e.throwIfDisposed (tf-core.esm.js:17)
at e.greaterEqual (tf-core.esm.js:17)
at Object.$x (tf-core.esm.js:17)
at n (tf-core.esm.js:17)
at backpropagateGradients (tf-core.esm.js:17)
at tf-core.esm.js:17
at tf-core.esm.js:17
at e.scopedRun (tf-core.esm.js:17)
at e.tidy (tf-core.esm.js:17)
at e.gradients (tf-core.esm.js:17)
at resolvePromise (zone.js:831)
at zone.js:896
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
at Object.onInvokeTask (core.js:17289)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
at drainMicroTaskQueue (zone.js:601)
at push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask (zone.js:502)
at ZoneTask.invoke (zone.js:487)
at timer (zone.js:2281)

调用tf.grad(lossFunction)时出现错误:

任何 help/insight 不胜感激!

完整代码:

let canvas = <HTMLCanvasElement> document.getElementById('canvas')

let img = tf.browser.fromPixels(canvas, 3) //let img = tf.fromPixels(canvas, 3)
let img4 = tf.browser.fromPixels(canvas, 4) //let img4 = tf.fromPixels(canvas, 4)

let model = mobilenet.load().then(model =>
{
    var output = model.classify(img, 3).then(predictions =>
    {
        let tbuffer = tf.buffer([1000])
        var labelClasses = IMAGENET_CLASSES 

        let targetClass = predictions[0].className
        Object.keys(labelClasses).forEach(function(key) 
        {
            if (labelClasses[key].valueOf() == targetClass.valueOf()) 
            {
                tbuffer.set(1, parseInt(key));
            }
        })          

        const oneHotLabels = tbuffer.toTensor()

        const getModelLogits = x => model.infer(x)
        const lossFunction = x => tf.losses.softmaxCrossEntropy(oneHotLabels, getModelLogits(x).as1D())
        const gradientFunction = tf.grad(lossFunction)
        var gradient = gradientFunction(img)


        // scale the gradient and apply to original image
        var perturbation = this.scaleGradient(gradient, 50)
        const zeroes = new Uint8Array(224*224).fill(0)
        let alphaChannel = tf.tensor3d(zeroes, [224, 224, 1]) 
        let perturbationWithAlpha = tf.concat([perturbation, alphaChannel], 2)  
        var adversarialImage = tf.add(tf.cast(img4,'float32'), perturbationWithAlpha)

        // Draw adversarial image to canvas
        var context = canvas.getContext("2d")
        let imgArray = Uint8ClampedArray.from(adversarialImage.dataSync());
        let imgData = context.createImageData(this.imgHeight, this.imgWidth);
        imgData.data.set(imgArray);
        context.putImageData(imgData, 0, 0);            

    }) 
})  

此处提供完整的回购协议:https://github.com/BenMcFadyen/tfjsFGSM https://github.com/BenMcFadyen/tfjsFGSM/blob/master/src/app/app.component.ts

FGSM 代码最初来自:https://github.com/jaxball/advis.js

full trace

successful execution on tensorflow/tfjs@0.13.0, tensorflow-models/mobilenet@0.2.2

tensorflow-models/mobilenet@0.2.2 是一个 tf.LayersModel,它提供梯度,因此可以重新训练。然而 tensorflow-models/mobilenet@1.0.0 在 https://github.com/tensorflow/tfjs-models/pull/161 中被更改为 tf.GraphModel,以便从 TF-Hub 提供 MobileNet V2。 GraphModels 不提供渐变,因此您的代码不再有效。

我认为你有几条可能的前进道路:

  1. 如果它们满足您的需要,请坚持使用工作版本(tensorflow-models/mobilenet@0.2.2 应该可以与 tfjs 一起工作到 0.15.3,尽管这会产生弃用警告)。
  2. 在 PR #156 分支 tensorflow/tfjs-models 并在那里构建 mobilenet 包。 那和0.2.2是一样的,只是它可以和tfjs一起使用>1.0.0.
  3. 从 head 中分叉 tensorflow/tfjs-models,并将模型加载部分还原为使用 tf.loadLayersModel() 和在 #161 中删除的 BASE_PATH。 (这只会让你获得 V1)。
  4. 获取 Keras .h5 格式的 MobileNet V2(例如,从 here) and use the TF.js converter 获取 tf.LayersModel.

我重现了错误并手动验证 https://github.com/tensorflow/tfjs-core/pull/1604 修复了它。修复将在下一个 TF.js 版本 (1.0.2) 中发布,我们计划在本周末发布。

即使 MobileNet 现在是 tf.GraphModel 而不是 tf.LayersModel,梯度仍然有效,因为该库很急切并且可以即时计算梯度。