0

ML 和 tensorflow 的新手!

我使用http://cloud.annotations.ai制作了一个对象检测模型,它允许训练和转换不同格式的模型,tfjs (model_web) 也是如此。该网站还提供了在浏览器(反应应用程序)中运行模型的样板......就像你一样 - 可能是相同的代码,没有花费足够的时间。

所以我让这个模型在浏览器中运行,考虑到我给出的示例数量和预测分数(0.89),对照片中的对象进行预测,结果非常好。给定的边界框也很好。

但是,不幸的是,我没有“只有一个视频”可以在浏览器中逐帧分析,我有很多。所以我决定切换到 node.js,按原样移植代码。你猜怎么着?TF.js 依赖于 DOM 和浏览器组件,几乎没有适用于 Node 的示例。所以没什么大不了的,只是花了一个上午找出所有缺失的部分。最后,我能够以相当快的速度在帧分割的视频上运行我的模型——尽管当我已经在使用 tfjs-node 时出现“Hello there, use tfjs-node to gain speed”横幅——但结果看起来很奇怪。将相同的图片与相同的 model_web 文件夹进行比较给出了相同的预测,但得分较低(0.80 而不是 0.89)和不同的边界框,对象根本不居中。

(TL;DR)

tfjs 是否有不同的库(tfjs 和 tfjs-node)实现,它们对同一模型的使用不同?我不认为这可能是输入问题,因为 - 经过长时间的搜索和斗争 - 我想出了两种方法将图像提供给节点中的 tf.browser.getPixel (我仍然想知道为什么我必须使用tfjs-node 中的“浏览器”方法)。有人做过比较吗?

所以...这是我使用的代码,供您参考:

model_web 正在加载tf.loadGraphModel("file://path/to/model_web/model.json");

转换 JPG 并使其与 tf.browser.getPixel() 一起使用的两种不同方法

const inkjet = require('inkjet');
const {createCanvas, loadImage} = require('canvas');

const decodeJPGInkjet = (file) => {
    return new Promise((rs, rj) => {
        fs.readFile(file).then((buffer) => {
            inkjet.decode(buffer, (err, decoded) => {
                if (err) {
                    rj(err);
                } else {
                    rs(decoded);
                }
            });
        });
    });
};

const decodeJPGCanvas = (file) => {
    return loadImage(file).then((image) => {
        const canvas = createCanvas(image.width, image.height);
        const ctx = canvas.getContext('2d');
        ctx.drawImage(image, 0, 0, image.width, image.height);
        const data = ctx.getImageData(0, 0, image.width, image.height);
        return {data: new Uint8Array(data.data), width: data.width, height: data.height};
    });
};

这就是使用加载的模型进行预测的代码 - 节点和浏览器的相同代码,位于https://github.com/cloud-annotations/javascript-sdk/blob/master/src/index.js - 没有t 按原样在节点上工作,我更改require("@tensorflow/tfjs");require("@tensorflow/tfjs-node");并替换fetchfs.read

const runObjectDetectionPrediction = async (graph, labels, input) => {
    const batched = tf.tidy(() => {
        const img = tf.browser.fromPixels(input);
        // Reshape to a single-element batch so we can pass it to executeAsync.
        return img.expandDims(0);
    });

    const height = batched.shape[1];
    const width = batched.shape[2];

    const result = await graph.executeAsync(batched);

    const scores = result[0].dataSync();
    const boxes = result[1].dataSync();

    // clean the webgl tensors
    batched.dispose();
    tf.dispose(result);

    const [maxScores, classes] = calculateMaxScores(
        scores,
        result[0].shape[1],
        result[0].shape[2]
    );

    const prevBackend = tf.getBackend();
    // run post process in cpu
    tf.setBackend("cpu");
    const indexTensor = tf.tidy(() => {
        const boxes2 = tf.tensor2d(boxes, [result[1].shape[1], result[1].shape[3]]);
        return tf.image.nonMaxSuppression(
            boxes2,
            maxScores,
            20, // maxNumBoxes
            0.5, // iou_threshold
            0.5 // score_threshold
        );
    });
    const indexes = indexTensor.dataSync();
    indexTensor.dispose();
    // restore previous backend
    tf.setBackend(prevBackend);

    return buildDetectedObjects(
        width,
        height,
        boxes,
        maxScores,
        indexes,
        classes,
        labels
    );
};
4

1 回答 1

0

对使用相同模型的库(tfjs 和 tfjs-node)进行不同的实现

如果在浏览器和 nodejs 中都部署了相同的模型,则预测将是同一件事。

如果预测值不同,则可能与用于预测的张量有关。从图像到张量的处理可能不同,导致用于预测的张量不同,从而导致输出不同。

我想出了两种将图像提供给节点中的 tf.browser.getPixel 的方法(我仍然想知道为什么我必须在 tfjs-node 中使用“浏览器”方法)

canvas包使用系统图形来创建nodejs可以使用的类似浏览器的canvas环境。这使得使用 tf.browser 命名空间成为可能,尤其是在处理图像转换时。但是,仍然可以直接使用 nodejs 缓冲区来创建张量。

于 2020-02-19T13:01:57.927 回答