Различные прогнозы при работе в 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 напрямую.