Search code examples
deep-learningtensorflow.jspre-trained-model

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


I'm trying to implement the Fast Gradient Sign Method (FGSM) on MobileNet with tensorflow.js, however I'm having problems on the latest version (1.0.1) when computing the gradient using tf.grad().

The code is working fine with tfjs version 0.13.0 and below, however updating to any of the later versions results in the following error:

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)

The error occurs when calling tf.grad(lossFunction):

Any help/insight is appreciated!

Full code:

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);            

    }) 
})  

Full repo available here: https://github.com/BenMcFadyen/tfjsFGSM https://github.com/BenMcFadyen/tfjsFGSM/blob/master/src/app/app.component.ts

FGSM code originally from: https://github.com/jaxball/advis.js

full trace

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


Solution

  • I reproduced the error and verified manually that https://github.com/tensorflow/tfjs-core/pull/1604 fixes it. The fix will be out in the next TF.js release (1.0.2), which we plan to get out by end of this week.

    The gradients are working even though MobileNet is now a tf.GraphModel instead of tf.LayersModel, because the library is eager and can compute gradients on-the-fly.