Почему model.predict () из tenorflowjs всегда возвращает одно и то же предсказание? - PullRequest
0 голосов
/ 10 января 2019

Я делаю приложение в платформе ionic 3 для распознавания рукописных символов, и для этого я использую tenorflowjs. Проблема в том, что когда все решено, прогноз всегда возвращает одно и то же значение.

Модель (преобразованная из керас с tenorflowjs-конвертером) хранится локально в assets/models/model.json.

Изображения, которые я пытаюсь предсказать, извлекаются из HTMLCanvasElement, в котором вы можете нарисовать символ, а затем функция getCanvas() извлекает из него ImageData:

getCanvas() {
    let photo = document.getElementById('MyCanvas') as HTMLCanvasElement;
    let ctx = photo.getContext('2d');
    const data: ImageData = ctx.createImageData(300,300);
    return data;
}

Затем вычисляется входной тензор [1, 32, 32, 3] модели из data, а затем я передаю его модели * evaluateModel(). В этой функции я загружаю model.json с tf.loadModel() и пытаюсь предсказать класс изображения:

import * as tf from '@tensorflow/tfjs';

async evaluateModel() {
    imageData: ImageData = this.getCanvas();
    const modelURL: string = './../../assets/models/model.json';

    let img: tf.Tensor<tf.Rank.R3> = tf.fromPixels(imageData);
    img = tf.image.resizeBilinear(img, [32, 32]);
    img = img.expandDims(0);

    await tf.loadModel(modelURL).then(model => {
        const output: any = model.predict(img);
        const results: number = output.argMax(1).dataSync()[0];
        console.log(results);
    }

Все работает нормально, без ошибок, но при записи прогноза вывода на консоль всегда возвращается одно и то же значение. Кроме того, массив предсказаний очень плоский, указывая на то, что модель в Python достигает 99,01% точности в тесте :

console.log(Array.from(output.dataSync())); 

17  /* Result of the argMax function on output */
[0.011652837507426739, 0.03457817807793617, 0.029257778078317642, 0.008851004764437675, 0.01691449247300625, 0.026485547423362732, 0.04974032938480377, 0.016473202034831047, 0.021701140329241753, 0.020724112167954445, 0.03173287212848663, 0.024661116302013397, 0.007072054781019688, 0.022814681753516197, 0.011404283344745636, 0.015105938538908958, 0.024694452062249184, 0.07453715801239014, 0.011547397822141647, 0.03946337103843689, 0.018134022131562233, 0.027423541992902756, 0.014102200977504253, 0.016702469438314438, 0.05513478443026543, 0.030478181317448616, 0.012863627634942532, 0.011269242502748966, 0.022525735199451447, 0.022545555606484413, 0.02840271405875683, 0.011758353561162949, 0.006561313755810261, 0.020660076290369034, 0.009705542586743832, 0.024312887340784073, 0.011940978467464447, 0.020643217489123344, 0.009319263510406017, 0.00957920216023922, 0.01844164915382862, 0.015434195287525654, 0.02170679345726967, 0.017867043614387512, 0.013763428665697575, 0.029312126338481903]

Единственные две вещи, которые приходят мне в голову при попытке решить эту проблему:

  1. ImageData неправильно извлекает чертеж холста, и поэтому прогноз всегда возвращает одно и то же значение.
  2. Весам на model.json нет доступа или загрузки, поэтому модель возвращает одно и то же значение.

Есть идеи?

Любая помощь приветствуется.

1 Ответ

0 голосов
/ 11 января 2019

createImageData создает новый ImageDate с прозрачным черным пикселем. Поэтому при каждом вызове метода будут возвращаться одни и те же ImageData.

Вы скорее хотите перерисовать исходное изображение на другом холсте, размеры которого (высота и ширина) соответствуют форме тензора, заданного в качестве параметра модели.

// create a new canvas on which the initial canvas will be redrawn 
const canvas = document.createElement('canvas');
// draws on the first 32 * 32 pixels
canvas.drawImage(photos, 0, 0, 32, 32);
// returns the imageData corresponding to the part of the canvas we drew
return canvas.getImageData(0, 0, 32, 32);

С этим новым imageData больше не нужно использовать tf.bilinear, достаточно tf.reshape, чтобы придать тензору требуемую форму.

img = tf.image.reshape(img, [1, 32, 32, 3]);
...