Я пытаюсь использовать «Обучаемую машину» для собственных целей. Я хочу использовать его как шаблон для модели обучения, которая классифицирует изображения из двух классов. Начал играть на примере с github - https://github.com/googlecreativelab/teachable-machine-boilerplate
Изменены некоторые вещи для работы с локальными изображениями на nodeJS. Решены некоторые проблемы и ошибки, которые с ним связаны. И теперь, кажется, работает без ошибок, но ничего не предсказывает.
Пример из git довольно прост для понимания, и я использую его почти как есть (за исключением загрузки изображений не с веб-камеры, а из файлов).
Частично сразу после тренировки каждое изображение выводит это:
Processed image cat.10.jpg
{ classIndex: -1, confidences: { '1': NaN } }
После перехода в другой каталог:
Processed image dog.1.jpg
{ classIndex: -1, confidences: { '1': 0, '2': NaN } }
И когда дело доходит до предсказания, оно выдает следующее:
EXAMPLES:
{ '1': 14, '2': 14 }
PREDICTING
{ classIndex: -1, confidences: { '1': 0, '2': NaN } }
{ classIndex: -1, confidences: { '1': 0, '2': NaN } }
Размеры изображения изменяются как в примере до 227x227
Играется с большим набором данных поезда (до 50 фотографий), но это не имеет смысла, например, работа с 1 фотографией.
Попытка изменения значения TOPK - безуспешно.
getOffsets - это просто функция, которая использует только центральную часть изображения 227x227, если она имеет другой размер. Тоже не проблема.
setTimeout - просто неудачное решение, которое помогло мне делать прогнозы после тренировок. Не знаю, почему его не ждет, но это помогает. И поскольку он говорит, что число примеров является правильным, я предполагаю, что обучение завершено.
Ребята, у вас есть идеи, что я делаю не так?
const tf = require("@tensorflow/tfjs");
require("@tensorflow/tfjs-node");
const mobilenetModule = require("@tensorflow-models/mobilenet");
const knnClassifier = require("@tensorflow-models/knn-classifier");
const fs = require("fs");
const { createCanvas, Image } = require("canvas");
global.fetch = require("node-fetch");
class NN {
constructor() {
this.IMAGE_SIZE = 227;
this.TOPK = 10;
this.loadModel();
}
async loadModel() {
this.knn = await knnClassifier.create();
this.mobilenet = await mobilenetModule.load();
await this.trainData();
await this.predictData();
}
async predictData() {
setTimeout(() => {
const exampleCount = this.knn.getClassExampleCount();
console.log(`EXAMPLES:`);
console.log(exampleCount);
console.log("PREDICTING");
this.predictPath("./dataset/test/a");
}, 0);
}
async trainData() {
await this.trainPath("./dataset/train/a", 1);
console.log("TRAINED A");
await this.trainPath("./dataset/train/b", 2);
console.log("TRAINED B");
}
async trainPath(path, idx) {
await fs.readdir(path, async (err, imageNames) => {
for (let i = 0; i < imageNames.length; i++) {
const img = await this.processImage(`${path}/${imageNames[i]}`);
const imgTf = tf.fromPixels(img);
const inferLocal = img => this.mobilenet.infer(img, "conv_preds");
const logits = inferLocal(imgTf);
this.knn.addExample(logits, idx);
imgTf.dispose();
if (logits != null) {
logits.dispose();
}
console.log(`Processed image ${imageNames[i]}`);
// Try to predict after adding
const numClasses = this.knn.getNumClasses();
if (numClasses > 0) {
const prediction = await this.predictImage(
`${path}/${imageNames[i]}`
);
console.log(prediction);
}
}
});
}
async predictPath(path) {
fs.readdir(path, async (err, imageNames) => {
for (let i = 0; i < imageNames.length; i++) {
const prediction = await this.predictImage(`${path}/${imageNames[i]}`);
console.log(prediction);
}
});
}
async predictImage(imagePath) {
const img = await this.processImage(imagePath);
const imgTf = tf.fromPixels(img);
const inferLocal = () => this.mobilenet.infer(imgTf, "conv_preds");
const logits = inferLocal();
const prediction = await this.knn.predictClass(logits, this.TOPK);
imgTf.dispose();
if (logits != null) {
logits.dispose();
}
return prediction;
}
async processImage(imagePath) {
const canvas = createCanvas(this.IMAGE_SIZE, this.IMAGE_SIZE);
const ctx = canvas.getContext("2d");
const img = new Image();
const promise = new Promise((resolve, reject) => {
img.crossOrigin = "";
img.onload = () => {
const { x, y } = this.getOffsets(img);
ctx.drawImage(img, x, y);
resolve(canvas);
};
});
img.src = `${imagePath}`;
return promise;
}
getOffsets(img) {
let x, y;
if (Number(img.width) > this.IMAGE_SIZE) {
x = -(img.width - this.IMAGE_SIZE) / 2;
} else {
x = (this.IMAGE_SIZE - img.width) / 2;
}
if (Number(img.height) > this.IMAGE_SIZE) {
y = -(img.height - this.IMAGE_SIZE) / 2;
} else {
y = (this.IMAGE_SIZE - img.height) / 2;
}
return { x, y };
}
}
new NN();