Используя экспортированную модель Custom vision с тензорным потоком JS и введите изображение - PullRequest
10 голосов
/ 06 марта 2019

Я новичок в tenorflow.js и tenorflow

Контекст: мы обучили модель, используя нестандартное зрение для распознавания по изображению, длина волос: короткая, средняя, ​​длинная. Эта модель была экспортирована, и мы хотели бы использовать ее локально с tenorflow js. Экспортируемые файлы из пользовательского видения - это файл * .pb и файл label.txt.

Я использовал скрипт python tenorflowjs_converter, вот команда, которую я использовал для преобразования замороженной модели * .pb в модель json:

tensorflowjs_converter --input_format=tf_frozen_model --output_node_names='model_outputs' --output_json OUTPUT_JSON C:\python\tf_models\hairlength\model.pb C:\python\tf_models\exports\

Затем я вставляю этот model.json и осколки в папку активов моего углового клиента. Затем я пытаюсь загрузить модель и даю ему изображение, чтобы получить прогноз, но все, что я получаю, это значения индексов, которые выходят за границы, так как мне нужны только 0: длинная, 1: средняя, ​​2: короткая длина волос. Вот захват консоли prediction list

Это класс, который я использовал в моем клиенте (машинопись) для предсказаний:

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

// import {HAIRLENGTH_LABELS} from './hairlength';
import { FrozenModel } from '@tensorflow/tfjs';

const MODEL = 'assets/models/hairlength/model.json';
const INPUT_NODE_NAME = 'model_outputs';
const OUTPUT_NODE_NAME = 'model_outputs';
const PREPROCESS_DIVISOR = tf.scalar(255 / 2);

export class MobileNetHairLength {

  private model: FrozenModel;
  private labels = ['long', 'mid', 'short'];

  constructor() {}

  async load(){
    this.model = await tf.loadGraphModel(MODEL);
  }

  dispose() {
    if (this.model) {
      this.model.dispose();
    }
  }

  /**
   * Infer through MobileNet. This does standard ImageNet pre-processing before
   * inferring through the model. This method returns named activations as well
   * as softmax logits.
   *
   * @param input un-preprocessed input Array.
   * @return The softmax logits.
   */
  predict(input) {
    const preprocessedInput = tf.div(
        tf.sub(input, PREPROCESS_DIVISOR),
        PREPROCESS_DIVISOR);
    const reshapedInput =
        preprocessedInput.reshape([1, ...preprocessedInput.shape]);
    // tslint:disable-next-line:no-unused-expression
    return this.model.execute({[INPUT_NODE_NAME]: reshapedInput}, OUTPUT_NODE_NAME);
  }

  getTopKClasses(logits, topK: number) {
    const predictions = tf.tidy(() => {
      return tf.softmax(logits);
    });

    const values = predictions.dataSync();
    predictions.dispose();

    let predictionList = [];
    for (let i = 0; i < values.length; i++) {
      predictionList.push({value: values[i], index: i});
    }
    predictionList = predictionList
                         .sort((a, b) => {
                           return b.value - a.value;
                         })
                         .slice(0, topK);

    console.log(predictionList);
    return predictionList.map(x => {
      return {label: this.labels[x.index], value: x.value};
    });
  }
}

И этот класс, который вызывает вышеупомянутый, я просто даю элемент canvas:

import 'babel-polyfill';
import * as tf from '@tensorflow/tfjs';
import { MobileNetHairLength } from './mobilenet-hairlength';

export class PredictionHairLength {

  constructor() {}

  async predict(canvas) {
    const mobileNet = new MobileNetHairLength();
    await mobileNet.load();
    const pixels = tf.browser.fromPixels(canvas);

    console.log('Prediction');
    const result = mobileNet.predict(pixels);
    const topK = mobileNet.getTopKClasses(result, 3);

    topK.forEach(x => {
      console.log( `${x.value.toFixed(3)}: ${x.label}\n` );
    });

    mobileNet.dispose();
  }
}

Мои вопросы:

Правильна ли команда преобразования Python?

Я что-то упустил в своем клиенте, чтобы получить правильные индексы?

Спасибо за ваше время и ответы

Если вам нужна дополнительная информация, я был бы рад предоставить ее вам

Обновления 10/03/2019

Я обновил тензор потока до 1.0.0, используя npm

Я видел, что FrozenModel устарела

Экспорт моей пользовательской модели видения дает мне файлы model.pb и tags.txt, например: custom vision exports

Я пытался использовать эти файлы с Python, все работает нормально ... Теперь я хотел бы преобразовать этот файл model.pb в файл model.json, чтобы использовать его с tennorflowjs, для этого мне нужно использовать tennsflowjs_converter, проблема в том, что структура файла для преобразования этой сохраненной модели недопустима, см. https://www.tensorflow.org/guide/saved_model#structure_of_a_savedmodel_directory

Единственное, что работает, если я использую формат frozen_model в конвертере и даю имя узла вывода: потеря ... как это tensorflowjs_converter --input_format=tf_frozen_model --output_node_names='loss' --output_json OUTPUT_JSON C:\python\tf_models\hairlength\model.pb C:\python\tf_models\exports\

Это выходные данные, которые я получаю при выполнении вышеуказанной команды: output files затем я загружаю модель, вот мой код для загрузки и прогнозирования с использованием экспортированной модели json (я использую предикат () и удаляю узлы ввода и вывода, как вы мне посоветовали):

import * as tf from '@tensorflow/tfjs';
import { GraphModel } from '@tensorflow/tfjs';

const MODEL = 'assets/models/hairlength/model.json';
// const INPUT_NODE_NAME = 'Placeholder';
// const OUTPUT_NODE_NAME = 'loss';
const PREPROCESS_DIVISOR = tf.scalar(255 / 2);

export class MobileNetHairLength {

  private model: GraphModel;
  private labels = ['long', 'mid', 'short'];

  constructor() {}

  async load() {
    this.model = await tf.loadGraphModel(MODEL);
  }

  dispose() {
    if (this.model) {
      this.model.dispose();
    }
  }

  /**
   * Infer through MobileNet. This does standard ImageNet pre-processing before
   * inferring through the model. This method returns named activations as well
   * as softmax logits.
   *
   * @param input un-preprocessed input Array.
   * @return The softmax logits.
   */
  predict(input: tf.Tensor<tf.Rank>) {
    const preprocessedInput = tf.div(
      tf.sub(input.asType('float32'), PREPROCESS_DIVISOR),
      PREPROCESS_DIVISOR);
    const reshapedInput =
      preprocessedInput.reshape([...preprocessedInput.shape]);
    return this.model.predict(reshapedInput);
  }

  getTopKClasses(logits, topK: number) {
    const predictions = tf.tidy(() => {
      return tf.softmax(logits);
    });

    const values = predictions.dataSync();
    predictions.dispose();

    let predictionList = [];
    for (let i = 0; i < values.length; i++) {
      predictionList.push({value: values[i], index: i});
    }
    predictionList = predictionList
                         .sort((a, b) => {
                           return b.value - a.value;
                         })
                         .slice(0, topK);

    console.log(predictionList);
    return predictionList.map(x => {
      return {label: this.labels[x.index], value: x.value};
    });
  }
}

И вызывающий класс вот этот:

import 'babel-polyfill';
import * as tf from '@tensorflow/tfjs';
import { MobileNetHairLength } from './mobilenet-hairlength';

export class PredictionHairLength {

  constructor() {}

  async predict(canvas) {
    // Convert to tensor
      const mobileNet = new MobileNetHairLength();
      await mobileNet.load();
      const imgTensor = tf.browser.fromPixels(canvas);
      console.log(imgTensor);
      // Init input with correct shape
      const input = tf.zeros([1, 224, 224, 3]);
      // Add img to input
      input[0] = imgTensor;

      console.log('Prediction');
      const result = mobileNet.predict(input);
      console.log(result);

      const topK = mobileNet.getTopKClasses(result, 3);

      topK.forEach(x => {
        console.log( `${x.value.toFixed(3)}: ${x.label}\n` );
      });

      mobileNet.dispose();
  }
}

Тогда отправка элемента canvas, взятого из потока веб-камеры, выдает мне эту ошибку: js error

Как можно запустить команду конвертера в формате «сохраненная модель», поскольку структура файла неверна?

Почему я получаю 'Ошибка компиляции фрагмента шейдера, бесконечность: необъявленный идентификатор в tf-core.esm'?

Спасибо за ваше время и ответы

Ответы [ 2 ]

1 голос
/ 06 марта 2019

Я думаю, это простая ошибка в вашем коде: const INPUT_NODE_NAME = 'model_outputs';, вероятно, должно быть 'model_inputs' или чем-то еще. Здесь вы устанавливаете выходное изображение как входное изображение, а затем читаете его обратно, ничего не прогнозируя.

0 голосов
/ 27 марта 2019

Также наткнулся на сбойный шейдер.Запустите его на другом, более мощном компьютере, проблема исчезнет.

Мне кажется, что в Chrome недостаточно ресурсов для успеха

...