नोडज (टेंसरफ़्लो.जेएस) में एक मॉडल को कैसे प्रशिक्षित किया जाए?


29

मैं एक छवि वर्गीकृत करना चाहता हूं, लेकिन मैं अजगर को नहीं जानता। Tensorflow.js जावास्क्रिप्ट के साथ काम करता है, जिससे मैं परिचित हूं। क्या मॉडलों को इसके साथ प्रशिक्षित किया जा सकता है और ऐसा करने के लिए क्या कदम उठाए जाएंगे? सच कहूं तो मुझे कोई सुराग नहीं है कि कहां से शुरू करें।

केवल एक चीज मुझे समझ में आई कि "मोबिलनेट" को कैसे लोड किया जाए, जो स्पष्ट रूप से पूर्व-प्रशिक्षित मॉडल का एक सेट है, और इसके साथ छवियों को वर्गीकृत करें:

const tf = require('@tensorflow/tfjs'),
      mobilenet = require('@tensorflow-models/mobilenet'),
      tfnode = require('@tensorflow/tfjs-node'),
      fs = require('fs-extra');

const imageBuffer = await fs.readFile(......),
      tfimage = tfnode.node.decodeImage(imageBuffer),
      mobilenetModel = await mobilenet.load();  

const results = await mobilenetModel.classify(tfimage);

जो काम करता है, लेकिन यह मेरे लिए कोई फायदा नहीं है क्योंकि मैं अपनी छवियों का उपयोग करके अपने स्वयं के मॉडल को प्रशिक्षित करना चाहता हूं जो मैं बनाता हूं।

=======================

कहो कि मेरे पास छवियों और लेबल का एक गुच्छा है। किसी मॉडल को प्रशिक्षित करने के लिए मैं उनका उपयोग कैसे करूँ?

const myData = JSON.parse(await fs.readFile('files.json'));

for(const data of myData){
  const image = await fs.readFile(data.imagePath),
        labels = data.labels;

  // how to train, where to pass image and labels ?

}

आप समस्या का सामना कहाँ कर रहे हैं यदि आपने टेंसोफ़्लो लोड किया है, तो आप अपने स्वयं के मॉडल को प्रशिक्षित कर सकते हैं
अभिषेक आनंद

2
ऐसा लगता है कि आप मॉडल को टेंसोरफ्लो.जेएस टेंसोरफ्लो. org/ js / guide/ train_models के साथ प्रशिक्षित कर सकते हैं । मैंने टेंसोरफ्लो का उपयोग अजगर के साथ किया। यदि TensorFlow.js GPU का उपयोग नहीं कर रहा है, तो प्रशिक्षण में लंबा समय लग सकता है। मेरे लिए, colab.research.google.com एक उपयोगी संसाधन था क्योंकि यह मुफ़्त है और 11 GB का GPU प्रदान करता है।
कैनबक्स

1
यह बहुत व्यापक प्रश्न है ... जैसा कि डॉक्स में बताया गया है , आप किसी मॉडल को प्रशिक्षित करने के लिए ml5 का उपयोग कर सकते हैं या सीधे TF.js का उपयोग कर सकते हैं , जैसे इस Node.js उदाहरण में (प्रशिक्षण उदाहरण देखने के लिए नमूना कोड का विस्तार करें)।
jdehesa

लेकिन मुझे उस कोड में कहीं भी नहीं दिखता है कि छवियों और लेबल को कैसे पारित किया जाए?
एलेक्स

@ एलेक्स वे fitविधि में पारित किए जाते हैं , या डेटासेट में पास किए जाते हैं fitDataset, जैसा कि उदाहरणों में दिखाया गया है।
jdehesa

जवाबों:


22

सबसे पहले, छवियों को दसियों में परिवर्तित करने की आवश्यकता है। पहला दृष्टिकोण एक टेंसर बनाना होगा जिसमें सभी विशेषताएं होंगी (क्रमशः एक टैंसर जिसमें सभी लेबल होंगे)। यह तभी जाना चाहिए जब डेटासेट में कुछ छवियां हों।

  const imageBuffer = await fs.readFile(feature_file);
  tensorFeature = tfnode.node.decodeImage(imageBuffer) // create a tensor for the image

  // create an array of all the features
  // by iterating over all the images
  tensorFeatures = tf.stack([tensorFeature, tensorFeature2, tensorFeature3])

लेबल एक सरणी होगी जो प्रत्येक छवि के प्रकार को दर्शाती है

 labelArray = [0, 1, 2] // maybe 0 for dog, 1 for cat and 2 for birds

लेबल की हॉट एन्कोडिंग बनाने के लिए अभी एक की जरूरत है

 tensorLabels = tf.oneHot(tf.tensor1d(labelArray, 'int32'), 3);

एक बार टेनर्स होने के बाद, किसी को प्रशिक्षण के लिए मॉडल बनाने की आवश्यकता होगी। यहाँ एक सरल मॉडल है।

const model = tf.sequential();
model.add(tf.layers.conv2d({
  inputShape: [height, width, numberOfChannels], // numberOfChannels = 3 for colorful images and one otherwise
  filters: 32,
  kernelSize: 3,
  activation: 'relu',
}));
model.add(tf.layers.flatten()),
model.add(tf.layers.dense({units: 3, activation: 'softmax'}));

तब मॉडल को प्रशिक्षित किया जा सकता है

model.fit(tensorFeatures, tensorLabels)

यदि डेटासेट में बहुत सारी छवियां हैं, तो किसी को इसके बजाय tfDataset बनाने की आवश्यकता होगी। यह उत्तर क्यों चर्चा करता है।

const genFeatureTensor = image => {
      const imageBuffer = await fs.readFile(feature_file);
      return tfnode.node.decodeImage(imageBuffer)
}

const labelArray = indice => Array.from({length: numberOfClasses}, (_, k) => k === indice ? 1 : 0)

function* dataGenerator() {
  const numElements = numberOfImages;
  let index = 0;
  while (index < numFeatures) {
    const feature = genFeatureTensor(imagePath) ;
    const label = tf.tensor1d(labelArray(classImageIndex))
    index++;
    yield {xs: feature, ys: label};
  }
}

const ds = tf.data.generator(dataGenerator);

और model.fitDataset(ds)मॉडल को प्रशिक्षित करने के लिए उपयोग करें


उपरोक्त नोडज में प्रशिक्षण के लिए है। ब्राउज़र में ऐसी प्रक्रिया करने के लिए, genFeatureTensorनिम्नानुसार लिखा जा सकता है:

function load(url){
  return new Promise((resolve, reject) => {
    const im = new Image()
        im.crossOrigin = 'anonymous'
        im.src = 'url'
        im.onload = () => {
          resolve(im)
        }
   })
}

genFeatureTensor = image => {
  const img = await loadImage(image);
  return tf.browser.fromPixels(image);
}

सावधानी का एक शब्द यह है कि भारी प्रसंस्करण करने से ब्राउज़र में मुख्य धागा अवरुद्ध हो सकता है। यह वह जगह है जहाँ वेब कर्मचारी खेल में आते हैं।


इनपुट से चौड़ाई और ऊंचाई छवियों की चौड़ाई और ऊंचाई से मेल खाना चाहिए? इसलिए मैं विभिन्न आयामों के साथ छवियों को पारित नहीं कर सकता हूं?
एलेक्स

हाँ उन्हें मेल खाना चाहिए। यदि आपके पास मॉडल के इनपुटशैप से अलग-अलग चौड़ाई और ऊंचाई की छवियां हैं, तो आपको छवि का आकार बदलने की आवश्यकता होगीtf.image.resizeBilinear
1919 को संपादित करें

खैर, यह वास्तव में काम नहीं करता है। मुझे त्रुटियाँ मिलती हैं
एलेक्स

1
@ एलेक्स क्या आप अपने प्रश्न को मॉडल सारांश और आपके द्वारा लोड की जा रही छवि के आकार के साथ अपडेट कर सकते हैं? सभी छवियों को एक ही आकार की आवश्यकता होती है या प्रशिक्षण के लिए छवि को आकार देने की आवश्यकता होती है
edkeveked

1
hi @edkeveked, मैं ऑब्जेक्ट डिटेक्शन के बारे में बात कर रहा हूं, मैंने एक नया सवाल यहां जोड़ा है कृपया एक नज़र stackoverflow.com/questions/59322382/…
प्रणॉय सरकार

10

उदाहरण पर विचार करें https://codelabs.developers.google.com/codelabs/tfjs-training-classfication/#0

वे क्या करते हैं:

  • बड़ी छवि (चित्र का एक लंबवत अवतरण) लें
  • कुछ लेबल ले लो
  • डेटासेट बनाना (data.js)

फिर ट्रेन

डेटासेट की इमारत इस प्रकार है:

  1. इमेजिस

बड़ी छवि को एन ऊर्ध्वाधर चंक्स में विभाजित किया गया है। (n chunkSize)

आकार 2 के एक चंक्साइज़ पर विचार करें।

छवि 1 के पिक्सेल मैट्रिक्स को देखते हुए:

  1 2 3
  4 5 6

छवि 2 के पिक्सेल मैट्रिक्स को देखते हुए है

  7 8 9
  1 2 3

परिणामी सरणी होगी 1 2 3 4 5 6 7 8 9 1 2 3(किसी भी तरह 1 डी का संघटन)

तो मूल रूप से प्रसंस्करण के अंत में, आपके पास एक बड़ा बफर का प्रतिनिधित्व है

[...Buffer(image1), ...Buffer(image2), ...Buffer(image3)]

  1. लेबल

वर्गीकरण समस्याओं के लिए इस तरह का प्रारूपण बहुत कुछ किया जाता है। एक संख्या के साथ वर्गीकृत करने के बजाय, वे बूलियन सरणी लेते हैं। 10 में से 7 कक्षाओं की भविष्यवाणी करने के लिए हम विचार करेंगे [0,0,0,0,0,0,0,1,0,0] // 1 in 7e position, array 0-indexed

आरंभ करने के लिए आप क्या कर सकते हैं

  • अपनी छवि (और इसके संबंधित लेबल) लें
  • अपनी छवि को कैनवास पर लोड करें
  • इसका संबद्ध बफर निकालें
  • अपनी सभी छवि के बफर को एक बड़े बफर के रूप में सम्‍मिलित करें। यह एक्स के लिए है।
  • अपने सभी संबद्ध लेबल लें, उन्हें बूलियन सरणी के रूप में मैप करें, और उन्हें संक्षिप्त करें।

नीचे, मैं उपवर्ग MNistData::load(बाकी को स्क्रिप्ट के अलावा छोड़ सकता हूं। जहां आपको अपनी कक्षा को इसके बजाय तत्काल करने की आवश्यकता है)

मैं अभी भी 28x28 चित्र बनाता हूं, इस पर एक अंक लिखता हूं, और एक सटीक सटीकता प्राप्त करता हूं क्योंकि मैं शोर या स्वैच्छिक रूप से गलत लेबलिंग शामिल नहीं करता हूं।


import {MnistData} from './data.js'

const IMAGE_SIZE = 784;// actually 28*28...
const NUM_CLASSES = 10;
const NUM_DATASET_ELEMENTS = 5000;
const NUM_TRAIN_ELEMENTS = 4000;
const NUM_TEST_ELEMENTS = NUM_DATASET_ELEMENTS - NUM_TRAIN_ELEMENTS;


function makeImage (label, ctx) {
  ctx.fillStyle = 'black'
  ctx.fillRect(0, 0, 28, 28) // hardcoded, brrr
  ctx.fillStyle = 'white'
  ctx.fillText(label, 10, 20) // print a digit on the canvas
}

export class MyMnistData extends MnistData{
  async load() { 
    const canvas = document.createElement('canvas')
    canvas.width = 28
    canvas.height = 28
    let ctx = canvas.getContext('2d')
    ctx.font = ctx.font.replace(/\d+px/, '18px')
    let labels = new Uint8Array(NUM_DATASET_ELEMENTS*NUM_CLASSES)

    // in data.js, they use a batch of images (aka chunksize)
    // let's even remove it for simplification purpose
    const datasetBytesBuffer = new ArrayBuffer(NUM_DATASET_ELEMENTS * IMAGE_SIZE * 4);
    for (let i = 0; i < NUM_DATASET_ELEMENTS; i++) {

      const datasetBytesView = new Float32Array(
          datasetBytesBuffer, i * IMAGE_SIZE * 4, 
          IMAGE_SIZE);

      // BEGIN our handmade label + its associated image
      // notice that you could loadImage( images[i], datasetBytesView )
      // so you do them by bulk and synchronize after your promises after "forloop"
      const label = Math.floor(Math.random()*10)
      labels[i*NUM_CLASSES + label] = 1
      makeImage(label, ctx)
      const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      // END you should be able to load an image to canvas :)

      for (let j = 0; j < imageData.data.length / 4; j++) {
        // NOTE: you are storing a FLOAT of 4 bytes, in [0;1] even though you don't need it
        // We could make it with a uint8Array (assuming gray scale like we are) without scaling to 1/255
        // they probably did it so you can copy paste like me for color image afterwards...
        datasetBytesView[j] = imageData.data[j * 4] / 255;
      }
    }
    this.datasetImages = new Float32Array(datasetBytesBuffer);
    this.datasetLabels = labels

    //below is copy pasted
    this.trainIndices = tf.util.createShuffledIndices(NUM_TRAIN_ELEMENTS);
    this.testIndices = tf.util.createShuffledIndices(NUM_TEST_ELEMENTS);
    this.trainImages = this.datasetImages.slice(0, IMAGE_SIZE * NUM_TRAIN_ELEMENTS);
    this.testImages = this.datasetImages.slice(IMAGE_SIZE * NUM_TRAIN_ELEMENTS);
    this.trainLabels =
        this.datasetLabels.slice(0, NUM_CLASSES * NUM_TRAIN_ELEMENTS);// notice, each element is an array of size NUM_CLASSES
    this.testLabels =
        this.datasetLabels.slice(NUM_CLASSES * NUM_TRAIN_ELEMENTS);
  }

}

8

मुझे एक ट्यूटोरियल मिला [1] नई कक्षाओं को प्रशिक्षित करने के लिए मौजूदा मॉडल का उपयोग कैसे करें। यहाँ मुख्य कोड भागों:

index.html सिर:

   <script src="https://unpkg.com/@tensorflow-models/knn-classifier"></script>

index.html बॉडी:

    <button id="class-a">Add A</button>
    <button id="class-b">Add B</button>
    <button id="class-c">Add C</button>

index.js:

    const classifier = knnClassifier.create();

    ....

    // Reads an image from the webcam and associates it with a specific class
    // index.
    const addExample = async classId => {
           // Capture an image from the web camera.
           const img = await webcam.capture();

           // Get the intermediate activation of MobileNet 'conv_preds' and pass that
           // to the KNN classifier.
           const activation = net.infer(img, 'conv_preds');

           // Pass the intermediate activation to the classifier.
           classifier.addExample(activation, classId);

           // Dispose the tensor to release the memory.
          img.dispose();
     };

     // When clicking a button, add an example for that class.
    document.getElementById('class-a').addEventListener('click', () => addExample(0));
    document.getElementById('class-b').addEventListener('click', () => addExample(1));
    document.getElementById('class-c').addEventListener('click', () => addExample(2));

    ....

मुख्य विचार मौजूदा नेटवर्क का उपयोग अपनी भविष्यवाणी करने के लिए किया जाता है और फिर अपने स्वयं के साथ पाए गए लेबल को प्रतिस्थापित करता है।

पूरा कोड ट्यूटोरियल में है। एक और आशाजनक, [2] में अधिक उन्नत। इसे सख्त पूर्व प्रसंस्करण की आवश्यकता है, इसलिए मैं इसे केवल यहां छोड़ देता हूं, मेरा मतलब है कि यह बहुत अधिक उन्नत है।

सूत्रों का कहना है:

[1] https://codelabs.developers.google.com/codelabs/tensorflowjs-teachablemachine-codelab/index.html#6

[२] https://towardsdatascience.com/training-custom-image-classification-model-on-the-browser-with-tensorflow-js-and-angular-fun96ed24934


कृपया, मेरे दूसरे उत्तर पर एक नज़र डालें, यह वास्तविकता के बहुत करीब है, जहां से शुरू करना है।
mico

क्यों नहीं दोनों जवाब एक में डाल दिया?
edkeveked

एक ही चीज के लिए उनका अलग दृष्टिकोण होता है। यह एक से ऊपर, जहां मैं अब टिप्पणी करता हूं, वास्तव में एक वर्कअराउंड है, दूसरा एक मूल से शुरू हो रहा है, जो मुझे लगता है कि अब बाद में प्रश्न सेटिंग के लिए अधिक उपयुक्त है।
mico

3

टी एल; डॉ

MNIST छवि पहचान हैलो वर्ल्ड है। इसे दिल से सीखने के बाद, आपके दिमाग में इन सवालों को हल करना आसान है।


प्रश्न सेटिंग:

आपका मुख्य प्रश्न लिखित है

 // how to train, where to pass image and labels ?

आपके कोड ब्लॉक के अंदर। उन लोगों के लिए मुझे Tensorflow.js उदाहरण अनुभाग के उदाहरणों से परिपूर्ण उत्तर मिला: MNIST उदाहरण। मेरे नीचे दिए गए लिंक में शुद्ध जावास्क्रिप्ट और नोड हैं। इसके और विकिपीडिया स्पष्टीकरण के संस्करण। मैं आपके दिमाग में मुख्य प्रश्न का उत्तर देने के लिए आवश्यक स्तर पर उनके माध्यम से जाऊंगा और मैं यह भी जोड़ूंगा कि आपकी खुद की छवियों और लेबल का MNIST छवि सेट और इसका उपयोग करने वाले उदाहरणों के साथ क्या करना है।

पहली चीजें पहले:

कोड के टुकड़े।

छवियों को कहाँ पास करें (Node.js नमूना)

async function loadImages(filename) {
  const buffer = await fetchOnceAndSaveToDiskWithBuffer(filename);

  const headerBytes = IMAGE_HEADER_BYTES;
  const recordBytes = IMAGE_HEIGHT * IMAGE_WIDTH;

  const headerValues = loadHeaderValues(buffer, headerBytes);
  assert.equal(headerValues[0], IMAGE_HEADER_MAGIC_NUM);
  assert.equal(headerValues[2], IMAGE_HEIGHT);
  assert.equal(headerValues[3], IMAGE_WIDTH);

  const images = [];
  let index = headerBytes;
  while (index < buffer.byteLength) {
    const array = new Float32Array(recordBytes);
    for (let i = 0; i < recordBytes; i++) {
      // Normalize the pixel values into the 0-1 interval, from
      // the original 0-255 interval.
      array[i] = buffer.readUInt8(index++) / 255;
    }
    images.push(array);
  }

  assert.equal(images.length, headerValues[1]);
  return images;
}

टिप्पणियाँ:

एमएनआईएसटी डेटासेट एक बहुत बड़ी छवि है, जहां एक फाइल में पहेली में टाइल्स जैसी कई छवियां होती हैं, प्रत्येक और समान आकार के साथ, साइड में, एक्स और वाई समन्वय तालिका में बक्से की तरह। प्रत्येक बॉक्स में एक नमूना होता है और लेबल सरणी में x और y का लेबल होता है। इस उदाहरण से, इसे कई फ़ाइलों के प्रारूप में बदलना कोई बड़ी बात नहीं है, ताकि वास्तव में एक समय में केवल एक ही तस्वीर को हैंडल करने के लिए समय दिया जाए।

लेबल:

async function loadLabels(filename) {
  const buffer = await fetchOnceAndSaveToDiskWithBuffer(filename);

  const headerBytes = LABEL_HEADER_BYTES;
  const recordBytes = LABEL_RECORD_BYTE;

  const headerValues = loadHeaderValues(buffer, headerBytes);
  assert.equal(headerValues[0], LABEL_HEADER_MAGIC_NUM);

  const labels = [];
  let index = headerBytes;
  while (index < buffer.byteLength) {
    const array = new Int32Array(recordBytes);
    for (let i = 0; i < recordBytes; i++) {
      array[i] = buffer.readUInt8(index++);
    }
    labels.push(array);
  }

  assert.equal(labels.length, headerValues[1]);
  return labels;
}

टिप्पणियाँ:

यहां, लेबल एक फ़ाइल में बाइट डेटा भी हैं। जावास्क्रिप्ट दुनिया में, और आपके शुरुआती बिंदु में आपके पास दृष्टिकोण के साथ, लेबल भी एक json सरणी हो सकते हैं।

मॉडल को प्रशिक्षित करें:

await data.loadData();

  const {images: trainImages, labels: trainLabels} = data.getTrainData();
  model.summary();

  let epochBeginTime;
  let millisPerStep;
  const validationSplit = 0.15;
  const numTrainExamplesPerEpoch =
      trainImages.shape[0] * (1 - validationSplit);
  const numTrainBatchesPerEpoch =
      Math.ceil(numTrainExamplesPerEpoch / batchSize);
  await model.fit(trainImages, trainLabels, {
    epochs,
    batchSize,
    validationSplit
  });

टिप्पणियाँ:

यहाँ model.fitकोड की वास्तविक लाइन है जो इस चीज़ को करती है: मॉडल को प्रशिक्षित करती है।

पूरी बात के परिणाम:

  const {images: testImages, labels: testLabels} = data.getTestData();
  const evalOutput = model.evaluate(testImages, testLabels);

  console.log(
      `\nEvaluation result:\n` +
      `  Loss = ${evalOutput[0].dataSync()[0].toFixed(3)}; `+
      `Accuracy = ${evalOutput[1].dataSync()[0].toFixed(3)}`);

ध्यान दें:

डेटा साइंस में, इस बार भी यहाँ, सबसे अधिक भाग लेने वाला हिस्सा यह जानना है कि मॉडल नए डेटा और किसी भी लेबल के परीक्षण में कितनी अच्छी तरह बचता है, क्या यह उन्हें लेबल कर सकता है या नहीं? इसके लिए मूल्यांकन हिस्सा है जो अब हमें कुछ नंबरों को प्रिंट करता है।

नुकसान और सटीकता: [४]

कम नुकसान, बेहतर मॉडल (जब तक मॉडल ने प्रशिक्षण डेटा से अधिक फिट नहीं किया है)। नुकसान की गणना प्रशिक्षण और सत्यापन पर की जाती है और इसका अंतर यह है कि इन दो सेटों के लिए मॉडल कितना अच्छा काम कर रहा है। सटीकता के विपरीत, नुकसान प्रतिशत नहीं है। यह प्रशिक्षण या सत्यापन सेट में प्रत्येक उदाहरण के लिए की गई त्रुटियों का एक योग है।

..

एक मॉडल की सटीकता आमतौर पर मॉडल के मापदंडों को जानने और तय करने के बाद निर्धारित की जाती है और कोई सीखने की जगह नहीं होती है। फिर परीक्षण के नमूने मॉडल को खिलाए जाते हैं और सही लक्ष्यों की तुलना के बाद मॉडल की गलतियों (शून्य-एक नुकसान) को रिकॉर्ड किया जाता है।


अधिक जानकारी:

Github पृष्ठों में, README.md फ़ाइल में, ट्यूटोरियल का एक लिंक होता है, जहाँ github के सभी उदाहरणों को अधिक विस्तार से समझाया जाता है।


[१] https://github.com/tensorflow/tfjs-examples/tree/master/mnist

[२] https://github.com/tensorflow/tfjs-examples/tree/master/mnx-ode

[३] https://en.wikipedia.org/wiki/MNIST_database

[४] मशीन लर्निंग मॉडल के लिए "नुकसान" और "सटीकता" की व्याख्या कैसे करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.