首页 > 解决方案 > 如何在 tensorflow.js 中通过 model.executeAsync(x) 执行 tf.grad

问题描述

我试图传递model.executeAsync(x).reshape([-1]).gather(2))tf.grad它会返回一个错误:

Uncaught (in promise) TypeError: model.executeAsync(...).reshape is not a function

当我删除.reshape([-1])它返回此错误:

Uncaught (in promise) TypeError: model.executeAsync(...).gather is not a function

当我删除.gather它返回此错误:

Uncaught (in promise) 错误:f() 返回的结果 y 必须是张量。

    <html>
 <head>
 <!-- Load TensorFlow.js -->
 <!-- Get latest version at https://github.com/tensorflow/tfjs -->
 <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.2.9/dist/tf.min.js"></script> 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 </script>
 </head>
 <body>
   <div id="output_field"></div>
   <img id="img_predicted" src="test_img.jpg" style="width: 320px; height: 320px;"/>
   <script>

        function preprocessImage(image) {
            return tf.tidy(() => {
                let tensor = tf.browser.fromPixels(image, numChannels=3).toFloat();
                let resized = tf.image.resizeBilinear(tensor, [320, 320], alignCorners=true);

                let meanImageNetRGB = {red: 0.485, green: 0.456, blue: 0.406};
                let stdImageNetRGB = {red: 0.229, green: 0.224, blue: 0.225};
                let indices = [tf.tensor1d([0], "int32"),tf.tensor1d([1], "int32"),tf.tensor1d([2], "int32")];

                cropImage = (img) => {
                    const size = 320;
                    const beginHeight = parseInt((img.shape[1]-size+1)*0.5);
                    const beginWidth = parseInt((img.shape[0]-size+1)*0.5);
                    return img.slice([beginWidth , beginHeight, 0], [size, size, 3]);
                }

                let crop = cropImage(resized);
                let toTensor = crop.div(tf.scalar(255.0));

                let centeredRGB = {
                    red: tf.gather(toTensor, indices[0], 2)
                        .sub(tf.scalar(meanImageNetRGB.red))
                                .reshape([102400]),
                    green: tf.gather(toTensor, indices[1], 2)
                        .sub(tf.scalar(meanImageNetRGB.green))
                                .reshape([102400]),
                    blue: tf.gather(toTensor, indices[2], 2)
                        .sub(tf.scalar(meanImageNetRGB.blue))
                                .reshape([102400])
                };

                let norm = tf.stack([centeredRGB.red.div(tf.scalar(stdImageNetRGB.red)).reshape([1,320,320]), 
                centeredRGB.green.div(tf.scalar(stdImageNetRGB.green)).reshape([1,320,320]), 
                centeredRGB.blue.div(tf.scalar(stdImageNetRGB.blue)).reshape([1,320,320])], 1);

                let proc_image = tf.tensor4d(Array.from(norm.dataSync()),[1,3,320,320]);

                // Return final pre-processed image tensor
                return proc_image;
            })
        }

        let im;
        window.onload = function() {
            im = $('#img_predicted')[0];
            console.log(im)
            test_grad(im);
        };

        async function test_grad(image) {

            model = await tf.loadGraphModel("models/tfjsFromSaved/model.json");

            // *Lines to confirm model works

            // const warmupResult = await model.executeAsync(tf.zeros([1,3,320,320]), );
            // warmupResult.dataSync();
            // warmupResult.print(); 
            // tf.dispose(warmupResult);

            layer = tf.tidy(() => {
    
                chestgrad = tf.grad(x =>model.executeAsync(x).reshape([-1]).gather(2))
                const batched = preprocessImage(image);
                const grad = chestgrad(batched);
                grad.print();
                const layer = grad.mean(0).abs().max(0)
                return layer.div(layer.max())
            });
            
            layer.print(); // *IMPORTANT: Need this line working *
            console.log(layer);  // *IMPORTANT: Need this line working *


            //////// display grad image
            var myCanvas = document.getElementById("img_predicted");
            await tf.browser.toPixels(layer, myCanvas); 
            console.log(myCanvas)
            var myCanvasContext = myCanvas.getContext("2d");
            d = myCanvasContext.getImageData(0, 0, myCanvas.width, myCanvas.height);
            makeColor(d.data);
            makeTransparent(d.data)
            myCanvasContext.putImageData(d,0,0);

            // *IMPORTANT: Display on browser canvas *
        }

    </script>
  </body>
<html>

标签: javascriptkerastensorflow.js

解决方案


正如方法名所指出的executeAsync,它是一个异步方法,它返回一个需要等待的承诺。

chestgrad = tf.grad(async x => await model.executeAsync(x)).reshape([-1].gather(2))

tf.grad 似乎不接受异步函数。所以上面的行不通。一种选择是model.execute(x)改用。

如果您更愿意使用 model.executeAsync,则需要限制tf.grad仅计算梯度并将异步部分移到tf.tidy.

        const batched = preprocessImage(image);
        const prediction = await model.executeAsync(batched);

        layer = tf.tidy(() => {

            chestgrad = tf.grad(x => x.reshape([-1]).gather(2));
            const grad = chestgrad(prediction);
            grad.print();
            const layer = grad.mean(0).abs().max(0)
            return layer.div(layer.max())
        });

推荐阅读