在Node.js或浏览器中为Tensorflow.js使用自定义图像

Tensorflow.js的CNN示例非常不错,我决定用我的自定义字符图像进行训练(如这样的本地图像 imgur,也可以作为浏览器中的img元素使用)。然而,我无法复制测试,因为示例代码使用了预处理的数据图像。

我复制了这里的示例(https://github.com/tensorflow/tfjs-examples/blob/master/mnist-node/README.md)并添加了所需的Node.js包。示例成功运行了。但我意识到我无法更改示例使用的数据,因为它加载了如下预处理的数据。

const BASE_URL = 'https://storage.googleapis.com/cvdf-datasets/mnist/';const TRAIN_IMAGES_FILE = 'train-images-idx3-ubyte';const TRAIN_LABELS_FILE = 'train-labels-idx1-ubyte';const TEST_IMAGES_FILE = 't10k-images-idx3-ubyte';const TEST_LABELS_FILE = 't10k-labels-idx1-ubyte';

我制作了与MNIST相同格式的图像(28*28),所以我以为我可以只更改训练和测试数据,但失败了,因为我不知道idx3-ubyte格式是什么。data.js文件的URL在这里这里

如何生成相同的ubyte文件?或者如何直接使用本地图像或img元素?

更新我检查了data.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;}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;}  getData_(isTrainingData) {    let imagesIndex;    let labelsIndex;    if (isTrainingData) {      imagesIndex = 0;      labelsIndex = 1;    } else {      imagesIndex = 2;      labelsIndex = 3;    }    const size = this.dataset[imagesIndex].length;    tf.util.assert(        this.dataset[labelsIndex].length === size,        `Mismatch in the number of images (${size}) and ` +            `the number of labels (${this.dataset[labelsIndex].length})`);    // Only create one big array to hold batch of images.    const imagesShape = [size, IMAGE_HEIGHT, IMAGE_WIDTH, 1];    const images = new Float32Array(tf.util.sizeFromShape(imagesShape));    const labels = new Int32Array(tf.util.sizeFromShape([size, 1]));    let imageOffset = 0;    let labelOffset = 0;    for (let i = 0; i < size; ++i) {      images.set(this.dataset[imagesIndex][i], imageOffset);      labels.set(this.dataset[labelsIndex][i], labelOffset);      imageOffset += IMAGE_FLAT_SIZE;      labelOffset += 1;    }    return {      images: tf.tensor4d(images, imagesShape),      labels: tf.oneHot(tf.tensor1d(labels, 'int32'), LABEL_FLAT_SIZE).toFloat()    };  }}

以下是生成器代码。

const {createCanvas, loadImage} = require('canvas');const tf = require('@tensorflow/tfjs');require('@tensorflow/tfjs-node');const fs = require('fs');const util = require('util');// const writeFile = util.promisify(fs.writeFile);// const readFile = util.promisify(fs.readFile);(async()=>{      const canvas = createCanvas(28,28);      const ctx = canvas.getContext('2d');      const ch1 = await loadImage('./u.png');      const ch2 = await loadImage('./q.png');      const ch3 = await loadImage('./r.png');      const ch4 = await loadImage('./c.png');      const ch5 = await loadImage('./z.png');      console.log(ch1);            ctx.drawImage(ch1, 0, 0);      const ch1Data = tf.fromPixels(canvas, 1);      ctx.drawImage(ch2, 0, 0);      const ch2Data = tf.fromPixels(canvas, 1);      ctx.drawImage(ch3, 0, 0);      const ch3Data = tf.fromPixels(canvas, 1);      ctx.drawImage(ch4, 0, 0);      const ch4Data = tf.fromPixels(canvas, 1);      ctx.drawImage(ch5, 0, 0);      const ch5Data = tf.fromPixels(canvas, 1);      // console.log(await ch1Data.data());      const b1 = Buffer.from(await ch1Data.data());      const b2 = Buffer.from(await ch2Data.data());      const b3 = Buffer.from(await ch3Data.data());      const b4 = Buffer.from(await ch4Data.data());      const b5 = Buffer.from(await ch5Data.data());      const buffers = [b1,b2,b3,b4,b5];      const labels = [0,1,3,2,4,0,1,2,1,0,3,0,2,3,4,0,];      const Images = [];      const size = labels.length;      for(var i = 0; i < size;i++){            Images.push(buffers[labels[i]]);      }      const imageHeaderBytes = 16;      const imageRecordBytes = 28 * 28;      const labelHeaderBytes = 8;      const labelRecordBytes = 1;      let imageBuffer = Buffer.alloc(imageHeaderBytes + size * imageRecordBytes);      let labelBuffer = Buffer.alloc(labelHeaderBytes + size * labelRecordBytes);            const imageHeaderValues = [2051, size, 28, 28];      const labelHeaderValues = [2049, size];      for (let i = 0; i < 4; i++) {            // Header data is stored in-order (aka big-endian)            imageBuffer.writeUInt32BE(imageHeaderValues[i], i * 4);      }      for (let i = 0; i < 2; i++) {            // Header data is stored in-order (aka big-endian)            labelBuffer.writeUInt32BE(labelHeaderValues[i], i * 4);      }      let imageindex = imageHeaderBytes;      let labelindex = labelHeaderBytes;      for(let i = 0; i < size; i++){            // imageBuffer = Buffer.concat([imageBuffer, Images[i]]);            // labelBuffer= Buffer.concat([labelBuffer, Buffer.from([labels[i]])]);            // labelBuffer= Buffer.concat([labelBuffer, Buffer.from([labels[i]])]);            const image = Images[i];            let index = 0;            while(index < image.byteLength){                  imageBuffer.writeUInt8(image[index], imageindex);                  index++;                  imageindex++;            }            labelBuffer.writeUInt8(labels[i], labelindex++);      }      fs.writeFileSync('./testGeneratedImageBuffer', imageBuffer);      fs.writeFileSync('./testGeneratedLabelBuffer', labelBuffer);})();


回答:

“ubyte”代表”无符号字节”。它指的是一个无符号的8位整数。每个images-ubyte文件包含一系列无符号8位整数。每个整数都是MNIST图像中的一个像素,其值在0到255之间。

这就是图像在像素级别上的表示方式。现在让我们看看整个图像的级别,由28行和28列组成。需要28 * 28 = 784个这样的整数来表示一张图像。在文件中,它们的组织方式是:前28个整数对应第一行,接下来的28个整数对应第二行,依此类推。

数据集中所有的图像都是以这种方式表示的,它们的整数被连接起来形成一个image-ubyte文件的内容。为什么有两个这样的文件?这是因为train-images-idx3-ubyte是训练数据集,而t10k-images-idx3-ubyte是测试数据集。

另外两个文件(labels-ubyte)是MNIST图像的标签。像image-ubyte文件一样,它们包含uint8(即无符号8位整数)。但与其保存0到255的值不同,标签文件的值在0到9之间,因为MNIST数据集中只有10个图像类别。

希望这些解释清楚了。

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注