Различные прогнозы при работе в Node вместо браузера (с использованием той же модели model_web - преобразованной в python модели)

Довольно новичок в ML и tensorflow!

Я сделал модель обнаружения объектов с http://cloud.annotations.ai/, которая позволяет обучать и конвертировать модель в разные форматы, tfjs (model_web) тоже. Этот веб-сайт также предоставляет шаблоны для запуска модели в браузере (приложение для реагирования)... точно так же, как и вы - вероятно, это тот же код, на который не было потрачено достаточно времени.

Итак, у меня есть эта модель, работающая внутри браузера, которая дает предсказание об объектах на фотографии с довольно хорошими результатами, учитывая количество примеров, которые я привел, и оценку предсказания (0,89). данная ограничивающая рамка тоже хороша.

Но, к сожалению, у меня не было "всего одного видео" для покадрового анализа в браузере, их у меня много. Поэтому я решил перейти на node.js, перенеся код как есть. Угадай, что? TF.js полагается на компоненты DOM и браузера, и почти не существует примеров, работающих с Node. Так что ничего страшного, просто потратил утро на выяснение всех недостающих частей. Наконец, я могу запускать свою модель над видео, которые разделены на кадры, с приличной скоростью - хотя у меня есть баннер "Привет, используйте tfjs-node для увеличения скорости", когда я уже использую tfjs-node - но результаты кажется странным. Сравнение того же изображения с той же папкой model_web дало такой же прогноз, но с более низкой оценкой (0,80 вместо 0,89) и другим ограничивающим прямоугольником, при этом объект вообще не центрировался.

(TL;DR)

Есть ли в tfjs разные реализации библиотек (tfjs и tfjs-node), которые по-разному используют одну и ту же модель? Я не думаю, что это может быть проблемой ввода, потому что после долгого поиска и борьбы я выяснил два способа передать изображение tf.browser.getPixel в Node (и мне все еще интересно, почему я должен использовать метод "браузера" внутри 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"); и заменил fetch с участием fs.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
    );
};

1 ответ

Используйте разные реализации библиотек (tfjs и tfjs-node), которые по-разному используют одну и ту же модель.

Если одна и та же модель развернута и в браузере, и в nodejs, прогноз будет таким же.

Если предсказанные значения отличаются, это может быть связано с тензором, используемым для предсказания. Обработка от изображения к тензору может быть разной, что приведет к использованию разных тензоров для предсказания, что приведет к разным результатам.

Я выясняю два способа передать изображение tf.browser.getPixel в Node (и мне все еще интересно, почему я должен использовать метод "браузера" внутри tfjs-node)

Пакет холста использует системную графику для создания браузера, подобного среде холста, которую может использовать nodejs. Это позволяет использовать пространство имен tf.browser, особенно при преобразовании изображений. Однако для создания тензора по-прежнему можно использовать буфер nodejs напрямую.

Другие вопросы по тегам