基于TensorFlow.js的JavaScript机器学习-Hello World

简介: 我们有一些基于TensorFlow.js的JavaScript机器学习尝试,可以分享一点心得。

image.png

前言

2017年的双十一为了解决运营图片审核任务繁重的问题,我们发起了素材智能审核项目。在这个项目中,我们基于深度学习拿到了很好的项目结果,至今已经审核数千万张图片。

后续我们也尝试做一个 JavaScript 版本 TensorFlow - Tens.js(github.com/tensjs/tens),不过发现很多问题比较难解决。好在后续 TensorFlow 官方发布了 JavaScript 版本,并在近期发布 2.0 版本。

最近几年深度学习在人工智能领域取得了非凡进展,在很多任务中远远超过人类的表现,我相信深度学习后续会在更多的工作场景中被广泛使用。随着 TensorFlow.js 的发布,我们的学习成本进一步降低,我认为深度学习的工程化、大众化是接下来的必然趋势。

介绍

本系列不需要深度学习基础,会避免使用数学符号,会通过代码示例来介绍概念。 代码示例使用 JavaScript,使用 TensorFlow.js(浏览器/Node.js)框架。

Hello World

几乎所有深度学习相关的教程都会以 Minist 项目为例,Mnist 是机器学习一个经典的数据集,包含 60000 张训练图片和 10000 张测试图片,在本项目中我们会基于这些图片数据通过深度学习训练出一个图像识别的模型。 图像目前也是深度学习最有优势的场景,通过该项目,我们也可以理解TensorFlow.js 的基础用法和深度学习的一些核心概念。 简单来看,通过深度学习解决一个问题一般抽象为下面的流程

3.1. 数据预处理

对于浏览器环境来说,数据处理与其他环境相比还是比较麻烦。这次 Mnist 我们使用单张雪碧图来存储,对应 label 使用二进制进行存储。我们可以直接从 Google 的 url 中获取。

3.1.1. 图片数据预处理

图片数据的处理在浏览器场景非常有用,无论是图片数据集处理、模型预测时的上传图片处理都经常用到

const MNIST_IMAGES_SPRITE_PATH =
    'https://storage.googleapis.com/learnjs-data/model-builder/mnist_images.png';
const MNIST_LABELS_PATH =
    'https://storage.googleapis.com/learnjs-data/model-builder/mnist_labels_uint8';

在浏览器将图片转换成二进制数据,需要

const img = new Image();
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
img.crossOrigin = '';
// 图片加载后,使用 canvas drawImage,然后 getImageData 获取二进制数据
img.onload = () => {
  img.width = img.naturalWidth;
  img.height = img.naturalHeight;
  ctx.drawImage(img, 0, i * chunkSize, img.width, chunkSize, 0, 0, img.width,chunkSize);
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
}
img.src = MNIST_IMAGES_SPRITE_PATH;

3.1.2. ArrayBuffer & DataView

在 Tensorflow.js 的使用中,会经常使用 ArrayBuffer 类型,比如Canvas、Fetch API、File API。

// Canvas Uint8ClampedArray
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const uint8ClampedArray = imageData.data; 
// Fetch ArrayBuffer
fetch(url)
.then(function(response){
  return response.arrayBuffer()
})
.then(function(arrayBuffer){
  // ...
});
// File ArrayBuffer
const fileInput = document.getElementById('fileInput');
const file = fileInput.files<a href="https://storage.googleapis.com/tfjs-examples/mnist/dist/index.html">0];
const reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function () {
  const arrayBuffer = reader.result;
  // ···
};

3.1.3. 测试数据与验证数据

如果用全量数据来训练模型,模型很容易和数据集过度拟合,并不一定能很好的应对未来产生的新数据。为了解决这个问题,一般我们会将数据分为多份,分别用来做训练和验证使用。

image.png

this.datasetLabels = new Uint8Array(await labelsResponse.arrayBuffer());
  // Slice the the images and labels into train and test sets.
  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);
  this.testLabels =
      this.datasetLabels.slice(NUM_CLASSES * NUM_TRAIN_ELEMENTS);

3.2. 构建模型

深度学习本质上是构建了一个多层网络模型,不能层会来实现 特征提取、关联学习的工作,通过 TensorFlow 我们可以很简单的构建一个自己的深度网络

function createDenseModel() {
  const model = tf.sequential();
  model.add(tf.layers.flatten({inputShape: [IMAGE_H, IMAGE_W, 1]}));
  model.add(tf.layers.dense({units: 42, activation: 'relu'}));
  model.add(tf.layers.dense({units: 10, activation: 'softmax'}));
  return model;
}
// 下一章会来介绍更多细节

3.3. 训练模型

模型编译后,便可进行训练,目前 TensorFlow.js 也提供 tfjs-vis 方便将训练过程可视化

model.compile({
  optimizer,
  loss: 'categoricalCrossentropy',
  metrics: ['accuracy'],
});
await model.fit(trainData.xs, trainData.labels, {
  batchSize,
  validationSplit,
  epochs: trainEpochs
});

线上示例

后续

下一周会来介绍 TensorFlow.js 中的核心概念

参考

相关文章
|
9月前
|
资源调度 JavaScript 前端开发
Day.js极简轻易快速2kB的JavaScript库-替代Moment.js
dayjs是一个极简快速2kB的JavaScript库,可以为浏览器处理解析、验证、操作和显示日期和时间,它的设计目标是提供一个简单、快速且功能强大的日期处理工具,同时保持极小的体积(仅 2KB 左右)。
548 24
|
JavaScript 前端开发
JavaWeb JavaScript ③ JS的流程控制和函数
通过本文的详细介绍,您可以深入理解JavaScript的流程控制和函数的使用,进而编写出高效、可维护的代码。
269 32
|
11月前
|
JavaScript 前端开发 算法
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
11月前
|
数据采集 JavaScript 前端开发
JavaScript中通过array.filter()实现数组的数据筛选、数据清洗和链式调用,JS中数组过滤器的使用详解(附实际应用代码)
用array.filter()来实现数据筛选、数据清洗和链式调用,相对于for循环更加清晰,语义化强,能显著提升代码的可读性和可维护性。博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
JavaScript 前端开发 Java
springboot解决js前端跨域问题,javascript跨域问题解决
本文介绍了如何在Spring Boot项目中编写Filter过滤器以处理跨域问题,并通过一个示例展示了使用JavaScript进行跨域请求的方法。首先,在Spring Boot应用中添加一个实现了`Filter`接口的类,设置响应头允许所有来源的跨域请求。接着,通过一个简单的HTML页面和jQuery发送AJAX请求到指定URL,验证跨域请求是否成功。文中还提供了请求成功的响应数据样例及请求效果截图。
244 3
springboot解决js前端跨域问题,javascript跨域问题解决
|
JavaScript 前端开发
【JavaScript】——JS基础入门常见操作(大量举例)
JS引入方式,JS基础语法,JS增删查改,JS函数,JS对象
|
JavaScript 前端开发
Moment.js与其他处理时间戳格式差异的JavaScript库相比有什么优势?
Moment.js与其他处理时间戳格式差异的JavaScript库相比有什么优势?
|
机器学习/深度学习 人工智能 TensorFlow
基于TensorFlow的深度学习模型训练与优化实战
基于TensorFlow的深度学习模型训练与优化实战
630 3
|
JSON JavaScript 前端开发
使用JavaScript和Node.js构建简单的RESTful API
使用JavaScript和Node.js构建简单的RESTful API