Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/41.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在nodejs(tensorflow.js)中训练模型?_Javascript_Node.js_Tensorflow_Training Data_Tensorflow.js - Fatal编程技术网

Javascript 如何在nodejs(tensorflow.js)中训练模型?

Javascript 如何在nodejs(tensorflow.js)中训练模型?,javascript,node.js,tensorflow,training-data,tensorflow.js,Javascript,Node.js,Tensorflow,Training Data,Tensorflow.js,我想做一个图像分类器,但我不懂python。 js使用javascript,我对此很熟悉。模型可以用它来训练吗?训练的步骤是什么? 坦白说,我不知道从哪里开始 我唯一知道的是如何加载“mobilenet”,这显然是一组预先训练好的模型,并用它对图像进行分类: const tf = require('@tensorflow/tfjs'), mobilenet = require('@tensorflow-models/mobilenet'), tfnode = requir

我想做一个图像分类器,但我不懂python。 js使用javascript,我对此很熟悉。模型可以用它来训练吗?训练的步骤是什么? 坦白说,我不知道从哪里开始

我唯一知道的是如何加载“mobilenet”,这显然是一组预先训练好的模型,并用它对图像进行分类:

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 ?

}

我找到了一个教程[1],介绍了如何使用现有模型来训练新类。此处的主要代码部分:

index.html标题:

   <script src="https://unpkg.com/@tensorflow-models/knn-classifier"></script>
其主要思想是利用现有网络进行预测,然后用自己的标签替换找到的标签

完整的代码在教程中。[2]中的另一个有希望的、更高级的。它需要严格的预处理,所以我只把它放在这里,我的意思是它是如此的先进

来源:

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;
}
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
  });
  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)}`);
[1]


[2] 首先,图像需要转换为张量。第一种方法是创建包含所有特征的张量(分别是包含所有标签的张量)。只有当数据集包含很少的图像时,才应该这样做

  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);
需要注意的是,执行繁重的处理可能会阻塞浏览器中的主线程。这就是网络工作者发挥作用的地方。

考虑一下这个例子

他们所做的是:

  • 拍摄一个大的png图像(图像的垂直拼接)
  • 带上一些标签
  • 构建数据集(data.js)
然后训练

数据集的构建如下所示:

  • 图像
  • 大图像被分成n个垂直块。 (n为块大小)

    考虑大小为2的chunkSize

    给定图像1的像素矩阵:

      1 2 3
      4 5 6
    
    给定图像2的像素矩阵为

      7 8 9
      1 2 3
    
    生成的数组将是
    123456789123
    (1D连接)

    因此,基本上在处理结束时,有一个大的缓冲区表示

    […缓冲区(图像1),…缓冲区(图像2),…缓冲区(图像3)]

  • 标签
  • 对于分类问题,这种格式设置做了很多工作。它们不使用数字进行分类,而是采用布尔数组。 要预测10个班中的7个,我们会考虑
    [0,0,0,0,0,0,0,1,0,0]//1在7e位置,数组0索引

    你能做些什么来开始

    • 拍摄您的图像(及其相关标签)
    • 将图像加载到画布
    • 提取其关联的缓冲区
    • 将图像的所有缓冲区连接为一个大缓冲区。xs就是这样
    • 获取所有关联的标签,将它们映射为布尔数组,并将它们连接起来
    下面是我的子类
    MNistData::load
    (其余部分可以按原样使用(除了在script.js中,您需要实例化自己的类)

    我仍然会生成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);
      }
    
    }
    
    
    从“./data.js”导入{MnistData}
    const IMAGE_SIZE=784;//实际上是28*28。。。
    const NUM_CLASSES=10;
    常量NUM_数据集元素=5000;
    列车元素数量=4000;
    const NUM_TEST_ELEMENTS=NUM_DATASET_ELEMENTS-NUM_TRAIN_ELEMENTS;
    函数makeImage(标签,ctx){
    ctx.fillStyle='黑色'
    ctx.fillRect(0,0,28,28)//硬编码,brrr
    ctx.fillStyle='white'
    fillText(标签,10,20)//在画布上打印一个数字
    }
    导出类MyMnistData扩展了MnistData{
    异步加载(){
    const canvas=document.createElement('canvas')
    画布宽度=28
    画布高度=28
    设ctx=canvas.getContext('2d')
    ctx.font=ctx.font.replace(/\d+px/,'18px')
    let labels=new Uint8Array(NUM\u数据集\u元素*NUM\u类)
    //在data.js中,他们使用一批图像(也称为chunksize)
    //为了简化起见,我们甚至可以删除它
    const datasetBytesBuffer=new ArrayBuffer(NUM_DATASET_ELEMENTS*IMAGE_SIZE*4);
    for(设i=0;i // how to train, where to pass image and labels ?
    
    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;
    }
    
    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;
    }
    
    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
      });
    
      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)}`);