前端人工智能:經過機器學習推導函數方程式--鉑金Ⅲ

圖片描述

什麼是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-...

圖片描述

相關文章
相關標籤/搜索