довольно плохо знакомы с ML и тензорным потоком!
Я создал модель обнаружения объектов с http://cloud.annotations.ai, которая позволяет обучать и конвертировать модель в различных форматах, tf js (model_web ) тоже. Этот веб-сайт также предоставляет шаблоны для запуска модели в браузере (реагирующее приложение) ... точно так же, как вы делаете - возможно, это тот же код, который не потратил достаточно времени.
Так что у меня запущена эта модель внутри браузера, давая прогноз об объектах на фотографии с довольно хорошими результатами, учитывая количество примеров, которые я привел, и оценку прогноза (0,89). данная ограничительная рамка тоже хороша.
Но, к сожалению, у меня не было «только одного видео» для анализа кадр за кадром в браузере, у меня их много. Поэтому я решил переключиться на node.js, портируя код как есть. Угадай, что? TF. js опирается на DOM и компоненты браузера, и практически нет примеров, которые работают с Node. Так что ничего страшного, просто провел утро, выясняя все недостающие части. Наконец, я могу запустить свою модель поверх видео, которые разделены на кадры, с приличной скоростью - хотя при использовании баннера tf * 1041 с надписью «Здравствуйте, используйте tf js -node для увеличения скорости». * -узел - но результаты кажутся странными. Сравнение одного и того же изображения с той же папкой model_web дало тот же прогноз, но с более низким показателем (0,80 вместо 0,89) и другим ограничивающим прямоугольником, причем объект не центрировался вообще.
(TL; DR)
Имеет ли tf js различную реализацию библиотек (узел tf js и tf js), которые по-разному используют одну и ту же модель? Я не думаю, что это может быть проблемой ввода, потому что - после долгого поиска и борьбы - я придумываю два способа передать изображение в tf.browser.getPixel в Node (и я все еще задаюсь вопросом, почему я должен использовать метод «браузер» внутри узла tf js). Кто-нибудь делал сравнения?
Итак ... вот код, который я использовал, для вашей справки:
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 - не работает на узле как есть, я изменил 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
);
};