Распознавание / маркировка изображений с использованием TensorFlow.js - PullRequest
0 голосов
/ 25 февраля 2019

Мы используем TensorFlow.js для создания и обучения пользовательской модели.Мы используем функцию tf.browser.fromPixels () для преобразования изображения в тензор.Мы хотим создать кастом и обучить кастомной модели.Для достижения этой цели мы создали две разные веб-страницы (то есть: 1-я страница предназначена для создания пользовательского режима и обучения его с изображениями и связанными с ними метками, 2-я страница используется для загрузки обученной модели и с использованием предварительно обученной модели, которую мы пытаемсячтобы предсказать изображение, чтобы получить ассоциированную метку с этим изображением) для достижения этой функциональности мы рассмотрим следующие свойства:

  • AddImage (HTML_Image_Element, 'Label'): -Добавьте элемент image с меткой.Допустим, у нас есть три изображения для предсказания, а именно: img1, img2, img3 с тремя метками «A», «B» и «C» соответственно.
  • Train () / fit (): - Тренируйте эту пользовательскую модель со связанными метками.Поэтому мы хотим создать и обучить нашу модель с этими изображениями и соответствующими метками.

  • Сохранить / загрузить модель: - Чтобы сделать предварительно обученную модель пригодной для повторного использования,мы хотим сохранить обученную модель и загрузить эту модель всякий раз, когда мы хотим сделать прогноз с одним и тем же набором данных.С помощью функции save () мы получаем два файла, а именно: «model.json» и «model.weights.bin».

  • Predict (): - После успешного обученияПосле загрузки модели мы можем загрузить эту модель на другой странице, чтобы пользователь мог прогнозировать изображения с помощью соответствующей метки, и он будет возвращать предсказанный ответ с прикрепленной меткой каждого изображения.Скажем, всякий раз, когда пользователь хочет предсказать 'img1', он отображает прогноз как имя класса 'A', аналогично, для прогнозов 'img2' с именем класса 'B' и для прогнозов 'img3' с именем класса 'C' со значением достоверности какхорошо.

Шаги, которые достигнуты: В вышеупомянутом требовании мы успешно выполнили следующие пункты:

  • В самомНа первой веб-странице мы создаем последовательную модель и добавляем изображения (путем преобразования в тензор) в модель.и после этого мы обучаем / подгоняем эту модель с этими изображениями и связываем метки.

  • После обучения мы можем легко сохранить () эту пользовательскую предварительно обученную модель для дальнейших предсказаний.с этим временем пользователь может предсказать любое конкретное изображение из набора данных, с которым он был использован во время обучения, модель дает ответ с соответствующей меткой, т. е. если пользователь хочет прогноз для «img1», ответ модели прогноз с меткой как «A '.

  • После сохранения модели мы можем теперь открыть вторую веб-страницу, где пользователь может делать прогноз с изображениями, не проводя никаких тренировок, используя предварительно обученную модель.на этом этапе мы можем загрузить нашу сохраненную модель и получить прогноз следующим образом:

prediction:::0.9590839743614197,0.0006004410679452121,0.002040663966909051,0.001962134148925543,0.008351234719157219,0.004203603137284517,0.010159854777157307,0.007813011296093464,0.0013025108492001891,0.004482310265302658
В этом ответе (предсказание :: :) мы не получаем никакого имени класса / метки изображения.он просто возвращает значение достоверности на основе тензора / изображения.

Все еще необходимо достичь: При обучении пользовательской модели, мы одновременно добавляем изображения и метки в нашу пользовательскую модель.Но когда мы сохраняем файл model.json, то в этом файле .json мы не можем найти метки, которые ассоциируем с изображениями («A», «B» и «C») при добавлении и обучении модели.Поэтому, когда мы добавляем этот model.json на вторую страницу и пытаемся предсказать, тогда модель не показывает метку ассоциированного объекта.Мы не смогли добавить метки в модель (model.json) во время тренировки / подгонки.Пожалуйста, найдите код и прикрепленный скриншот веб-страницы для лучшего понимания.

Ниже приведены некоторые вложения / sample_code, которые помогают понять требование: Страница прогноза (2-я страница): Страница прогнозаС предварительно обученной моделью

Найдите здесь оба файла модели (.json и .bin): Пользовательские файлы модели

Ниже приведен код обеих страниц:

//2nd Page which is for prediction -
<apex:page sidebar="false" >
<head>
    <title>Predict with tensorflowJS</title> 
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.15.1"> </script>
</head>
<div class="container mt-5">
    <div class="row">
        <div class="col-12">
            <div class="progress progress-bar progress-bar-striped progress-bar-animated mb-2">Loading Model</div>
        </div>
    </div>
    <div class="row">
        <div class="col-3">
            <select id="model-selector" class="custom-select" >
                <option>mobilenet</option>
            </select>
        </div>
    </div>
    <input type="file" id="load" multiple="multiple" /><br/>
    <label for="avatar">Load Model:</label>

    <div class="row">
        <input id ="image-selector" class="form-control border-0" type="file"/>
    </div>

    <div class="col-6">
        <button id="predict-button" class="btn btn-dark float-right">Predict</button>
    </div>
</div>
<div class="row">
    <div class="col">
        <h2>Prediction</h2>
        <ol id="prediction-list"></ol>
    </div>
</div>
<div class="row">
    <div class="col-12">
        <h2 class="ml-3">Image</h2>
        <img id="selected-image" class="ml-3" src="" crossorigin="anonymous" width="400" height="300"/>
    </div>
</div>
<script>
$(document).ready()
{
    $('.progress-bar').hide();
}
$("#image-selector").change(function(){
    let reader = new FileReader();

    reader.onload = function(){
        let dataURL = reader.result;
        $("#selected-image").attr("src",dataURL);
        $("#prediction-list").empty();
    }
    let file = $("#image-selector").prop('files')[0];
    reader.readAsDataURL(file);
});

$("#model-selector").ready(function(){
    loadModel($("#model-selector").val());
    $('.progress-bar').show();
})

let model;
let cutomModelJson;
let cutomModelbin;
async function loadModel(name){
    $("#load").change(async function(){
        for (var i = 0; i < $(this).get(0).files.length; ++i) {
            console.log('AllFiles:::'+JSON.stringify($(this).get(0).files[i]));
            if($(this).get(0).files[i].name == 'my-model-1.json'){
                cutomModelJson = $(this).get(0).files[i];
            }else{
                cutomModelbin = $(this).get(0).files[i];
            }
        }
        console.log('cutomModelJson::'+cutomModelJson.name+'cutomModelbin::'+cutomModelbin.name);
        model = await tf.loadModel(tf.io.browserFiles([cutomModelJson, cutomModelbin]));

        console.log('model'+JSON.stringify(model));
    });
}

$("#predict-button").click(async function(){
    let image= $('#selected-image').get(0);
    console.log('image',image);
    let tensor = preprocessImage(image,$("#model-selector").val());
    const resize_image = tf.reshape(tensor, [1, 224, 224, 3],'resize');
    console.log('tensor',tensor);
    console.log('resize_image',resize_image);
    console.log('model1',model);
    let prediction = await model.predict(tensor).data();
    console.log('prediction:::'+ prediction);

    let top5 = Array.from(prediction)
    .map(function(p,i){
        return {
            probability: p,
            className: prediction[i]
        };
    }).sort(function(a,b){
        return b.probability-a.probability;
    }).slice(0,1);

    $("#prediction-list").empty();
    top5.forEach(function(p){
        $("#prediction-list").append(`<li>${p.className}:${p.probability.toFixed(6)}</li>`);
    });
});

function preprocessImage(image,modelName)
{
    let tensor=tf.browser.fromPixels(image)
    .resizeNearestNeighbor([224,224])
    .toFloat();
    console.log('tensor pro', tensor);
    if(modelName==undefined)
    {
        return tensor.expandDims();
    }
    if(modelName=="mobilenet")
    {
        let offset=tf.scalar(127.5);
        console.log('offset',offset);
        return tensor.sub(offset)
        .div(offset)
        .expandDims();
    }
    else
    {
        throw new Error("UnKnown Model error");
    }
}
</script>

//1st Page which is for Create and train model -
<apex:page sidebar="false">
<head>
    <title>Add image and train model with tensorflowJS</title> 
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.15.1"> </script>
    <script src="https://unpkg.com/@tensorflow-models/mobilenet"></script>
</head>
<div class="container mt-5">
    <div class="row">
        <div class="col-12">
            <div class="progress progress-bar progress-bar-striped progress-bar-animated mb-2">Loading Model</div>
        </div>
    </div>
    <div class="row">
        <div class="col-3">
            <select id="model-selector" class="custom-select" >
                <option>mobilenet</option>                    
            </select>
        </div>
    </div>

    <div class="row">
        <input id ="image-selector" class="form-control border-0" type="file"/>
    </div>

    <div class="col-6">
        <button id="predict-button" class="btn btn-dark float-right">Predict</button>
    </div>
</div>
<div class="row">
    <div class="col">
        <h2>Prediction></h2>
        <ol id="prediction-list"></ol>
    </div>
</div>
<div class="row">
    <div class="col-12">
        <h2 class="ml-3">Image</h2>
        <img id="selected-image" src="{!$Resource.cat}" crossorigin="anonymous" width="400" height="300" />
    </div>
</div>
<script>

$("#model-selector").ready(function(){
    loadModel($("#model-selector").val());
})

let model;
async function loadModel(name){
    model = tf.sequential();
    console.log('model::'+JSON.stringify(model));
}

$("#predict-button").click(async function(){
    let image= $('#selected-image').get(0);
    console.log('image:::',image);
    let tensor = preprocessImage(image,$("#model-selector").val());
    const resize_image = tf.reshape(tensor, [1, 224, 224, 3],'resize');
    console.log('tensorFromImage:::',resize_image);
    // Labels
    const label = ['cat'];
    const setLabel = Array.from(new Set(label));
    const ys = tf.oneHot(tf.tensor1d(label.map((a) => setLabel.findIndex(e => e === a)), 'int32'), 10)
    console.log('ys:::'+ys);

    model.add(tf.layers.conv2d({
        inputShape: [224, 224 , 3],
        kernelSize: 5,
        filters: 8,
        strides: 1,
        activation: 'relu',
        kernelInitializer: 'VarianceScaling'
    }));

    model.add(tf.layers.maxPooling2d({poolSize: 2, strides: 2}));
    model.add(tf.layers.maxPooling2d({poolSize: 2, strides: 2}));
    model.add(tf.layers.flatten({}));
    model.add(tf.layers.dense({units: 64, activation: 'relu'}));
    model.add(tf.layers.dense({units: 10, activation: 'softmax'}));
    model.compile({
        loss: 'meanSquaredError',
        optimizer : 'sgd'
    })

    // Train the model using the data.
    model.fit(resize_image, ys, {epochs: 100}).then((loss) => {
        const t = model.predict(resize_image);
        console.log('Prediction:::'+t);
        pred = t.argMax(1).dataSync(); // get the class of highest probability
        const labelsPred = Array.from(pred).map(e => setLabel[e])
        console.log('labelsPred:::'+labelsPred);
        const saveResults = model.save('downloads://my-model-1');
        console.log(saveResults);
    }).catch((e) => {
        console.log(e.message);
    })


});


function preprocessImage(image,modelName)
{
    let tensor = tf.browser.fromPixels(image)
    .resizeNearestNeighbor([224,224])
    .toFloat();
    console.log('tensor pro:::', tensor);
    if(modelName==undefined)
    {
        return tensor.expandDims();
    }
    if(modelName=="mobilenet")
    {
        let offset=tf.scalar(127.5);
        console.log('offset:::',offset);
        return tensor.sub(offset)
        .div(offset)
        .expandDims();
    }
    else
    {
        throw new Error("UnKnown Model error");
    }
}
</script>

Пожалуйста, дайте нам знать, если мы идем не так, как нужно, или нам нужно предпринять какие-либо дополнительные шаги для достижения этой задачи.

1 Ответ

0 голосов
/ 26 февраля 2019

Сохраненная модель не содержит названия метки.Сохраненная модель содержит топологию модели и веса архитектуры.

После загрузки сохраненной модели можно прогнозировать достоверность для каждого заданного класса последнего слоя.Из этого предсказания можно только определить, является ли 1-й класс наиболее вероятным или вторым или третьим ... Но нельзя сказать, является ли этот класс "A", "B" или "C", ... Например.На самом деле даже первоначальная модель не может этого сделать.Это еще одна обработка.

Как правило, при выполнении классификации используется однократное кодирование до подгонки модели.Таким образом, модель не имеет семантики того, что такое метка «A», «B» или «C».Он имеет семантику «100», «010», «001», например, для трех классов.При заданном тензоре одно предсказание может быть [0,1, 0,3, 0,6], что указывает на то, что вход, скорее всего, относится к третьему классу.

После вывода модели, чтобы получить имя метки, необходимо выполнить обратный процесс кодирования, такой как следующий

// take the index i of the highest probability
// indexing the element i of the array of labels

. Никогда во время этого процесса модель не имеетзнание названия ярлыка.Таким образом, эта информация нигде не сохраняется.Поэтому, если загруженная модель используется для прогнозирования на разных этапах, необходимо иметь способ передать массив имен меток на всех этих этапах.Эта информация о фрагментах может поступать с сервера или также может быть сохранена в localStorage - можно думать о многом, кроме как ожидать, что загруженная модель сама выдаст ее.

...