前端人工智能:经过机器学习推导函数方程式--铂金Ⅲ

图片描述

什么是tensorflow.js

tensorflow.js是一个能运行在浏览器和nodejs的一个机器学习、机器训练的javascript库,众所周知在浏览器上用javascript进行计算是很慢的,而tensorflow.js会基于WebGL经过gpu进行运算加速来对高性能的机器学习模块进行加速运算,从而能让咱们前端开发人员能在浏览器中进行机器学习和训练神经网络。本文要讲解的项目代码,就是要根据一些规则模拟数据,而后经过机器学习和训练,根据这些数据去反向推测出生成这些数据的公式函数。javascript

基本概念

接下来咱们用五分钟过一下tensorflow的基本概念,这一部分主要介绍一些概念,笔者会用一些类比方式简单的讲述一些概念,旨在帮助你们快速理解,可是限于精力和篇幅,概念的具体详细定义读者们仍是多去参照官方文档。前端

张量(tensors)

张量其实就是一个数组,能够一维或多维数组。张量在tensorflow.js里就是一个数据单元。java

const tensors = tf.tensor([[1.0, 2.0, 3.0], [10.0, 20.0, 30.0]]);
tensors.print();

在浏览器里将会输出:node

图片描述

tensorflow还提供了语义化的张量建立函数:tf.scalar(建立零维度的张量), tf.tensor1d(建立一维度的张量), tf.tensor2d(建立二维度的张量), tf.tensor3d(建立三维度的张量)、tf.tensor4d(建立四维度的张量)以及 tf.ones(张量里的值全是1)或者tf.zeros(张量里的值全是0)。git

变量(variable)

张量tensor是不可变的,而变量variable是可变的,变量是经过张量初始化而来,代码以下:github

const initialValues = tf.zeros([5]);//[0, 0, 0, 0, 0]
const biases = tf.variable(initialValues); //经过张量初始化变量
biases.print(); //输出[0, 0, 0, 0, 0]

操做(operations)

张量能够经过操做符进行运算,好比add(加法)、sub(减法)、mul(乘法)、square(求平方)、mean(求平均值) 。web

const e = tf.tensor2d([[1.0, 2.0], [3.0, 4.0]]);
const f = tf.tensor2d([[5.0, 6.0], [7.0, 8.0]]);

const e_plus_f = e.add(f);
e_plus_f.print();

上面的例子输出:
图片描述算法

内存管理(dispose和tf.tidy)

dispose和tf.tidy都是用来清空GPU缓存的,就至关于我们在编写js代码的时候,经过给这个变量赋值null来清空缓存的意思。小程序

var a = {num: 1};
a = null;//清除缓存

dispose

张量和变量均可以经过dispose来清空GPU缓存:数组

const x = tf.tensor2d([[0.0, 2.0], [4.0, 6.0]]);
const x_squared = x.square();

x.dispose();
x_squared.dispose();
tf.tidy

当有多个张量和变量的时候,若是挨个调用dispose就太麻烦了,因此有了tf.tidy,将张量或者变量操做放在tf.tidy函数中,就会自动给咱们优化和清除缓存。

const average = tf.tidy(() => {
  const y = tf.tensor1d([4.0, 3.0, 2.0, 1.0]);
  const z = tf.ones([1]);
  return y.sub(z);
});

average.print()

以上例子输出:
图片描述

模拟数据

首先,咱们要模拟一组数据,根据 这个三次方程,以参数a=-0.8, b=-0.2, c=0.9, d=0.5生成[-1, 1]这个区间内一些有偏差的数据,数据可视化后以下:
图片描述

假设咱们并不知道a、b、c、d这四个参数的值,咱们要经过这一堆数据,用机器学习和机器训练去反向推导出这个多项式函数方程的和它的a、b、c、d这四个参数值。

设置变量(Set up variables)

由于咱们要反向推导出多项式方程的a、b、c、d这四个参数值,因此首先咱们要先定义这四个变量,并给他们赋上一些随机数当作初始值。

const a = tf.variable(tf.scalar(Math.random()));
const b = tf.variable(tf.scalar(Math.random()));
const c = tf.variable(tf.scalar(Math.random()));
const d = tf.variable(tf.scalar(Math.random()));

上面这四行代码,tf.scalar就是建立了一个零维度的张量,tf.variable就是将咱们的张量转化并初始化成一个变量variable,若是通俗的用咱们平时编写javascript去理解,上面四行代码就至关于:

let a = Math.random();
let b = Math.random();
let c = Math.random();
let d = Math.random();

当咱们给a、b、c、d这四个参数值赋上了初始随机值之后,a=0.513, b=0.261, c=0.259, d=0.504,咱们将这些参数放入方程式后获得的曲线图以下:
图片描述

咱们能够看到,根据随机生成的a、b、c、d这四个参数并入到多项式后生成的数据跟真正的数据模拟的曲线差异很大,这就是咱们接下来要作的,经过机器学习和训练,不断的调整a、b、c、d这四个参数来将这根曲线尽量的无限接近实际的数据曲线。

建立优化器(Create an optimizer)

const learningRate = 0.5;
const optimizer = tf.train.sgd(learningRate);

learningRate这个变量是定义学习率,在进行每一次机器训练的时候,会根据学习率的大小去进行计算的偏移量调整幅度,学习率越低,最后预测到的值就会越精准,可是响应的会增长程序的运行时间和计算量。高学习率会加快学习过程,可是因为偏移量幅度太大,容易形成在正确值的周边上下摆动致使运算出的结果没有那么准确。

tf.train.sgd是咱们选用了tensorflow.js里帮咱们封装好的SGD优化器,即随机梯度降低法。在机器学习算法的时候,一般采用梯度降低法来对咱们的算法进行机器训练,梯度降低法经常使用有三种形式BGD、SGD以及MBGD。

咱们使用的是SGD这个批梯度降低法,由于每当梯度降低而要更新一个训练参数的时候,机器训练的速度会随着样本的数量增长而变得很是缓慢。随机梯度降低正是为了解决这个办法而提出的。假设通常线性回归函数的函数为:
图片描述

SGD它是利用每一个样本的损失函数对θ求偏导获得对应的梯度,来更新θ:
图片描述

随机梯度降低是经过每一个样原本迭代更新一次,对比上面的批量梯度降低,迭代一次须要用到全部训练样本,SGD迭代的次数较多,在解空间的搜索过程看起来很盲目。可是大致上是往着最优值方向移动。随机梯度降低收敛图以下:
图片描述

预期函数模型(training process functions)
编写预期函数模型,其实就是用一些列的operations操做去描述咱们的函数模型

function predict(x) {
  // y = a * x ^ 3 + b * x ^ 2 + c * x + d
  return tf.tidy(() => {
    return a.mul(x.pow(tf.scalar(3, 'int32')))
      .add(b.mul(x.square()))
      .add(c.mul(x))
      .add(d);
  });
}

a.mul(x.pow(tf.scalar(3, 'int32')))就是描述了ax^3(a乘以x的三次方),b.mul(x.square()))描述了b x ^ 2(b乘以x的平方),c.mul(x)这些同理。注意,在predict函数return的时候,用tf.tidy包了起来,这是为了方便内存管理和优化机器训练过程的内存。

定义损失函数(loss)

接下来咱们要定义一个损失函数,使用的是MSE(均方偏差,mean squared error)。数理统计中均方偏差是指参数估计值与参数真值之差平方的指望值,记为MSE。MSE是衡量“平均偏差”的一种较方便的方法,MSE能够评价数据的变化程度,MSE的值越小,说明预测模型描述实验数据具备更好的精确度。MSE的计算很是简单,就是先根据给定的x获得实际的y值与预测获得的y值之差 的平方,而后在对这些差的平方求平均数便可。 
图片描述

根据如上所述,咱们的损失函数代码以下:

function loss(prediction, labels) {
  const error = prediction.sub(labels).square().mean();
  return error;
}

预期值prediction减去实际值labels,而后平方后求平均数便可。

机器训练(training)

好了,上面说了这么多,作了这么多的铺垫和准备,终于到了最关键的步骤,下面这段代码和函数就是真正的根据数据而后经过机器学习和训练计算出咱们想要的结果最重要的步骤。咱们已经定义好了基于SGD随机梯度降低的优化器optimizer,而后也定义了基于MSE均方偏差的损失函数,咱们应该怎么结合他们两个装备去进行机器训练和机器学习呢,看下面的代码。

const numIterations = 75;

async function train(xs, ys, numIterations) {
  for (let iter = 0; iter < numIterations; iter++) {
    //优化器:SGD随机梯度降低
    optimizer.minimize(() => {
      const pred = predict(xs);
      //损失函数:MSE均方偏差
      return loss(pred, ys);
    });
    //防止阻塞浏览器
    await tf.nextFrame();
  }
}

咱们在外层定义了一个numIterations = 75,意思是咱们要进行75次机器训练。在每一次循环中咱们都调用了optimizer.minimize这个函数,它会不断地调用SGD随机梯度降低法来不断地更新和修正咱们的a、b、c、d这四个参数,而且每一次return的时候都会调用咱们的基于MSE均方偏差loss损失函数来减少损失。通过这75次的机器训练和机器学习,加上SGD随机梯度降低优化器和loss损失函数进行校准,最后就会获得很是接近正确数值的a、b、c、d四个参数。

咱们注意到这个函数最后有一行tf.nextFrame(),这个函数是为了解决在机器训练和机器学习的过程当中会进行大量的机器运算,会阻塞浏览器,致使ui无法更新的问题。

咱们调用这个机器训练的函数train:

import {generateData} from './data';//这个文件在git仓库里
  const trainingData = generateData(100, {a: -.8, b: -.2, c: .9, d: .5});
  await train(trainingData.xs, trainingData.ys, 75);

调用了train函数后,咱们就能够拿到a、b、c、d四个参数了。

console.log('a', a.dataSync()[0]);
  console.log('b', b.dataSync()[0]);
  console.log('c', c.dataSync()[0]);
  console.log('d', d.dataSync()[0]);

最后获得的值是a=-0.564, b=-0.207, c=0.824, d=0.590,和原先咱们定义的实际值a=-0.8, b=-0.2, c=0.9, d=0.5很是的接近了,对比图以下:
图片描述

项目运行和安装

本文涉及到的代码安装和运行步骤以下:

git clone https://github.com/tensorflow/tfjs-examples
cd tfjs-examples/polynomial-regression-core
yarn
yarn watch

tensorflow.js的官方example里有不少个项目,其中polynomial-regression-core(多项式方程回归复原)这个例子就是咱们本文重点讲解的代码,我在安装的过程当中并不太顺利,每一次运行都会报缺乏模块的error,读者只须要根据报错,把缺乏的模块挨个安装上,而后根据error提示信息上google去搜索相应的解决方法,最后都能运行起来。

结语

bb了这么多,原本不想写结语的,可是想一想,仍是想表达一下本人心里的一个搞笑荒谬的想法。我为何会对这我的工智能的例子感兴趣呢,是由于,在我广西老家(一个偏远的山村),那边比较封建迷信,常常拿一我的的生辰八字就去计算并说出这我的一辈子的命运,balabala说一堆,本人对这些风气一向都是嗤之以鼻。可是,可是,可是。。。。荒谬的东西来了,我老丈人十早年前由于车祸而断了一条腿,几年前带媳妇和老丈人回老家见亲戚,老丈人以为南方人这些封建迷信很好玩,就拿他本身的生辰八字去给乡下的老者算了一下,结果那个老人说了不少,并说出了我老丈人出车祸的那一天的准确的日期,精确到那一天的下午大体时间。。。。。这。。。。这就好玩了。。。当年整个空气忽然安静的场景至今历历在目,这件事一直记在内心,毕竟我历来不相信这些鬼鬼乖乖的东西,一直信奉科学是至高无上带咱们飞的惟一真理,可是。。。真的由于这件事,让我菊紧蛋疼不知道怎么去评价。。。。

咦?这跟人工智能有什么关系?我只是在思考,是否是咱们每一个人的生辰八字,就是笛卡尔平面坐标系上的维度,或者说生辰八字就是多项式函数的a、b、c、d、e系数,是否是真的有一个多项式函数方程能把这些生辰八字系数串联起来获得一个公式,这个公式能够描述你的一辈子,记录你的过去,并预测你的未来。。。。。。咱们能不能找到本身对应的维度和发生过的事情联系起来,而后用人工智能去机器学习并训练出一个属于咱们本身一辈子命运轨迹的函数。。。。行 不说了 ,各位读者能看到这里我也是以为对不起大家,好好读书并忘掉我说的话。

上述观点纯属我的意淫,该搬砖搬砖,该带娃带娃,祝各位早日登上前端最强王者的段位。!^_^!

做者:第一名的小蝌蚪

github地址:https://github.com/airuikun

结结语

最后,TNFE团队为前端开发人员整理出了小程序以及web前端技术领域的最新优质内容,每周更新✨,欢迎star,github地址:https://github.com/Tnfe/TNFE-...

图片描述

相关文章
相关标签/搜索