前言
最近公司向員工搜集公司雜志的文章,剛好最近學習了機器學習相關課程,為了賺取購買課程的費用,所以寫了如下文章投稿賺取稿費,
如下文章可能涉及一些我所購買課程的內容,所以不便將所有資源進行展示,
當初寫這篇文章的目的除了賺取公司的稿費外,還有就是給現有web開發的同事提供一些新的開發方向,認識新的開發領域,
一、人工智能、機器學習、Tensorflow三者關系
人工智能是近幾年火熱的話題,同時人工智能也是一門很龐大的學科,那么如何實作人工智能?機器學習就是其中一種實作方式,
機器學習又是什么?“機器學習”如同字面意思,讓計算機自己學習提供的資料特征,最終達到識別相應的類似資料,
那么如何以編程的形式使程式擁有機器學習能力?Tensorflow庫是一款很好的機器學習的編程庫,而本文的Tensorflow.js是Tensorflow的JS版本,除了JS版本,Tensorflow還有Python、C++、Java等多種語言版本,
綜上所述可以下圖總結這三者關系:

二、為什么要學習機器學習
學習機器學習并不是為了蹭人工智能的熱度,而是為了更好的迎接未來的發展趨勢,現有絕大多數開發人員面向的是規則編程,根據規則寫固定規則程式,但是需求的復雜性提高就無法再通過撰寫規則來編程,
比如產品需求要讓程式識別貓的圖片篩選出來做專題,那么程式猿不可能將所有貓的圖片進行撰寫規則來識別,因為每新增一張圖片就意味著要修改代碼增加一個判斷規則,這就是傳統編程的短板,
學習人工智能,學習機器學習編程就是為了彌補這個短板,讓程式能更好的適應未來復雜多變的需求,
三、為什么選擇Tensorflow.js
本文主要是針對web開發者認識機器學習這個領域,而web開發者必備的語言技能就是Javascript,Tensorflow.js就是以純Javascript來撰寫機器學習程式的開發庫,而且運行環境可以選擇瀏覽器,可以很好的可視化程式的訓練程序,這就是本文選擇Tensorflow.js的最重要原因,
除了這個重要原因,Tensorflow.js還有如下優勢:
1、Tensorflow.js是開箱即用的開發庫,開發者無需花精力去撰寫基礎復雜的數學問題,
2、由于可運行于瀏覽器,減少服務器的運算,提高服務器資源利用,增強客戶端回應運算結果的速度,
3、使用語言就是Javascript,前端工程師不需要學習其他后端語言,降低入門門檻,
4、由于瀏覽器的WebGL可呼叫GPU,所以Tensorflow.js會使用GPU加速模型的運算,提高運算效率,
5、由于Node和Python一樣都是使用C++撰寫的環境,所以在Node環境進行運算的速度目前與Python速度不相上下,
6、Tensorflow.js的模型可以跟Python等其他語言模型進行互轉,就是js寫了一個機器模型可以轉換模型到Python環境下使用,
7、瀏覽器可以很好可視化機器訓練程序,同時瀏覽器可呼叫設備的攝像頭、麥克風等增加機器學習的應用場景,讓機器學習跟接近用戶,
有優勢比如有它的劣勢:
1、部署在瀏覽器,js就是公開的,那么訓練模型就是公開的,商業保密性低,
2、瀏覽器端不適合部署體積過大的訓練模型,不然用戶加載頁面會相當耗時,
3、在Node環境目前無法做到分布式訓練,使用多臺服務器對一個模型進行大規模訓練,
4、Tensorflow.js的社區活躍度、資源等方面都不如Python社區,但是可以從Python社區去尋找資源運用到js平臺,
綜合上面優劣,選擇Tensorflow.js是為了進入機器學習領域,讓web開發者體驗到機器學習編程和傳統的規則編程兩者之間的不同,深入學習之后可以平滑過度到其他人工智能開發的開發庫,
四、體驗Tensorflow.js開箱即用編程
(一)安裝和參考Tensorflow.js
在html頁面中可直接參考一個js檔案即可,cdn地址是:
https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js
npm安裝使用:npm i @tensorflow/tfjs即可,
以上是瀏覽器端的安裝方式,如果運行在node環境可選擇安裝node版本,
npm安裝:npm i @tensorflow/tfjs-node,因為node版本是運行c++環境,所以在執行這個命令前需要下載很多c++環境的安裝包,
(二)第一個TF程式:
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js " type="text/javascript"></script> <script type="text/javascript"> var a=tf.tensor([1,2]); a.print(); console.log(a) </script>
就是這么簡單,跟使用jquery這些庫是一樣的,
(三)體驗機器學習編程思想,初識Tensorflow.js的API

上圖代碼:
const model = tf.sequential(); model.add(tf.layers.dense({ units: 4, inputShape: [2], activation: 'relu' })); model.add(tf.layers.dense({ units: 1, activation: 'sigmoid' })); model.compile({ loss: tf.losses.logLoss, optimizer: tf.train.adam(0.1) }); const inputs = tf.tensor(data.map(p => [p.x, p.y])); const labels = tf.tensor(data.map(p => p.label)); await model.fit(inputs, labels, { epochs: 10 }); window.predict = (form) => { const pred = model.predict(tf.tensor([[form.x.value * 1, form.y.value * 1]])); alert(`預測結果:${pred.dataSync()[0]}`); };
上面代碼是使用Tensorflow.js分析XOR資料集的部分代碼,代碼描述了從創建神經網路到訓練神經網路最終進行預測,
從代碼中可以看出,沒有寫一句IF判斷陳述句,全部都是在使用Tensorflow.js提供的API進行構建神經網路,所以機器學習的編程是通過構建神經網路來實作程式,而不是通過規則判斷來撰寫程式,
于此同時可以看出使用Tensorflow.js構建神經網路相當容易,只需要呼叫API設定你想要的構建元素即可完成,無需撰寫過多的數學理論方法,比如激活函式sigmoid,你無需重新撰寫實作sigmoid數學函式,TF已經提供了該函式,設定呼叫即可,
途中的注釋中描述了很多名詞,比如:神經元、損失函式、優化器、神經層、激活函式等等,這些名詞都是學習機器學習的一些基礎知識,本文不對這些基礎知識做一一詳解,如有機會再詳細對這些基礎知識做一次整合講解,
五、使用Tensorflow.js解決問題
下面我們看下Tensorflow.js如何進行機器學習編程的實體,除了上面介紹需要npm安裝@tensorflow/tfjs這個包外,還需要額外安裝@tensorflow/tfjs-vis可視化包,這個包不影響機器訓練,功能是為了將訓練程序可視化到瀏覽器當中,
(一)線性回歸問題:
已知x軸值1、2、3、4對應y軸值為1、3、5、7,可得如下坐標圖:

傳統的規則編程也可輕松完成這樣的線性回歸函式,并且還能準確預測,比方說x軸為100.5時對應的y值是多少,下面我們看下在Tensorflow.js中如何用機器學習的編程方式實作,
import * as tf from '@tensorflow/tfjs'; import * as tfvis from '@tensorflow/tfjs-vis'; window.onload = async () => { const xs = [1, 2, 3, 4]; const ys = [1, 3, 5, 7]; tfvis.render.scatterplot( { name: '線性回歸訓練集' }, { values: xs.map((x, i) => ({ x, y: ys[i] })) }, { xAxisDomain: [0, 5], yAxisDomain: [0, 8] } ); const model = tf.sequential(); model.add(tf.layers.dense({ units: 1, inputShape: [1] })); model.compile({ loss: tf.losses.meanSquaredError, optimizer: tf.train.sgd(0.1) }); const inputs = tf.tensor(xs); const labels = tf.tensor(ys); await model.fit(inputs, labels, { batchSize: 4, epochs: 200, callbacks: tfvis.show.fitCallbacks( { name: '訓練程序' }, ['loss'] ) }); const output = model.predict(tf.tensor([5])); alert(`如果 x 為 5,那么預測 y 為 ${output.dataSync()[0]}`); };
以上代碼將輸入值[1,2,3,4]和輸出結果[1,3,5,7]作為訓練集,這個訓練集只有4組個資料,但是通過機器反復學習這4個資料集,就能預測出很接近的最終值,
這里使用sequential模型構建學習的神經網路,模型損失函式采用均方誤差即代碼中的tf.losses.meanSquaredError,優化器使用隨機梯度下降即tf.train.sgd(0.1),
最后將訓練資料集給model進行訓練,也就是呼叫了model.fit方法,batchSize是指每次訓練資料個數,epochs是指訓練次數,代碼中表示每次訓練4個資料,一共訓練200次,
運行程式,瀏覽器中會顯示整個訓練程序:

由圖可以看出loss也就是訓練損失已平滑的曲線不斷降低,損失越低表示訓練結果越接近真實結果,
最終訓練完畢會執行model.predict方法進行預測,代碼中預測x為5時y值是多少,根據人類的大腦對這個簡單函式的預測應該是為9,而程式實際輸出是:

無限接近于9,這雖然沒有完全等于9,但是已經相當有參考價值,因為訓練損失是很難降低到0,而且這段機器學習程式只重復訓練4個資料集,
(二)解決邏輯回歸問題:

如圖,我們要輸入xy的坐標軸,然后預測該坐標屬于黃色還是藍色,這張圖中,黃色和藍色之間有少許的雜音而且還有很多空白地區沒有顯示出對應資料,圖表也不可能顯示完全部資料,這個時候就無法使用傳統的規則編程進行書寫,
我們看下Tensorflow.js如何解決這邏輯回歸問題:
import * as tf from '@tensorflow/tfjs'; import * as tfvis from '@tensorflow/tfjs-vis'; import { getData } from './data.js'; window.onload = async () => { const data = getData(400); tfvis.render.scatterplot( { name: '邏輯回歸訓練資料' }, { values: [ data.filter(p => p.label === 1), data.filter(p => p.label === 0), ] } ); const model = tf.sequential(); model.add(tf.layers.dense({ units: 1, inputShape: [2], activation: 'sigmoid' })); model.compile({ loss: tf.losses.logLoss, optimizer: tf.train.adam(0.1) }); const inputs = tf.tensor(data.map(p => [p.x, p.y])); const labels = tf.tensor(data.map(p => p.label)); await model.fit(inputs, labels, { batchSize: 40, epochs: 20, callbacks: tfvis.show.fitCallbacks( { name: '訓練效果' }, ['loss'] ) }); window.predict = (form) => { const pred = model.predict(tf.tensor([[form.x.value * 1, form.y.value * 1]])); alert(`預測結果:${pred.dataSync()[0]}`); }; };
這種邏輯回歸問題比上面的線性回歸問題明顯復雜很多,但是使用Tensorflow.js進行編程卻沒有復雜多少,用的API是一樣的,只是將損失函式從均方誤差meanSquaredError變成了對數損失函式logLoss,因為邏輯回歸問題無法使用均方誤差進行很好的訓練(這是一個數學問題,需要理解對數函式),優化器采用了adam,當然優化器也可以使用隨機梯度下降(至于優化器函式的選擇也是一個數學問題),
除了這兩塊有明顯的區別,其他代碼基本和線性回歸的使用的API沒有差別,
執行代碼后我們可以看到整個訓練程序的損失變化:

在頁面輸入框可以輸入我們想要預測的坐標:

此例中預測結果接近0的是黃點,接近于1的是藍點,如果預測值是0.5左右,那么所預測結果應該是兩塊區域之間的臨界點,
(三)卷積神經網路的撰寫
卷積神經網路是一個偉大的發明,它可以讓機器更加高效的學習圖片、聲音這些檔案特征,
我們來看下Tensorflow.js如何構建卷積神經網路來識別手寫數字的,在撰寫之前需要在網路上找到mnist資料集,這是經典的手寫數字資料集,為我們節約了收集手寫數字的圖片集,下面看下代碼的具體實作:
import * as tf from '@tensorflow/tfjs'; import * as tfvis from '@tensorflow/tfjs-vis'; import { MnistData } from './data'; window.onload = async () => { const data = new MnistData(); await data.load(); const examples = data.nextTestBatch(20); const surface = tfvis.visor().surface({ name: '輸入示例' }); for (let i = 0; i < 20; i += 1) { const imageTensor = tf.tidy(() => { return examples.xs .slice([i, 0], [1, 784]) .reshape([28, 28, 1]); }); const canvas = document.createElement('canvas'); canvas.width = 28; canvas.height = 28; canvas.style = 'margin: 4px'; await tf.browser.toPixels(imageTensor, canvas); surface.drawArea.appendChild(canvas); } const model = tf.sequential(); model.add(tf.layers.conv2d({ inputShape: [28, 28, 1], kernelSize: 5, filters: 8, strides: 1, activation: 'relu', kernelInitializer: 'varianceScaling' })); model.add(tf.layers.maxPool2d({ poolSize: [2, 2], strides: [2, 2] })); model.add(tf.layers.conv2d({ kernelSize: 5, filters: 16, strides: 1, activation: 'relu', kernelInitializer: 'varianceScaling' })); model.add(tf.layers.maxPool2d({ poolSize: [2, 2], strides: [2, 2] })); model.add(tf.layers.flatten()); model.add(tf.layers.dense({ units: 10, activation: 'softmax', kernelInitializer: 'varianceScaling' })); model.compile({ loss: 'categoricalCrossentropy', optimizer: tf.train.adam(), metrics: ['accuracy'] }); const [trainXs, trainYs] = tf.tidy(() => { const d = data.nextTrainBatch(1000); return [ d.xs.reshape([1000, 28, 28, 1]), d.labels ]; }); const [testXs, testYs] = tf.tidy(() => { const d = data.nextTestBatch(200); return [ d.xs.reshape([200, 28, 28, 1]), d.labels ]; }); await model.fit(trainXs, trainYs, { validationData: [testXs, testYs], batchSize: 500, epochs: 20, callbacks: tfvis.show.fitCallbacks( { name: '訓練效果' }, ['loss', 'val_loss', 'acc', 'val_acc'], { callbacks: ['onEpochEnd'] } ) }); const canvas = document.querySelector('canvas'); canvas.addEventListener('mousemove', (e) => { if (e.buttons === 1) { const ctx = canvas.getContext('2d'); ctx.fillStyle = 'rgb(255,255,255)'; ctx.fillRect(e.offsetX, e.offsetY, 25, 25); } }); window.clear = () => { const ctx = canvas.getContext('2d'); ctx.fillStyle = 'rgb(0,0,0)'; ctx.fillRect(0, 0, 300, 300); }; clear(); window.predict = () => { const input = tf.tidy(() => { return tf.image.resizeBilinear( tf.browser.fromPixels(canvas), [28, 28], true ).slice([0, 0, 0], [28, 28, 1]) .toFloat() .div(255) .reshape([1, 28, 28, 1]); }); const pred = model.predict(input).argMax(1); alert(`預測結果為 ${pred.dataSync()[0]}`); }; };
上面代碼中,有一大半是canvas畫布的操作代碼,可以不進行研究,在創建模型model之前的代碼是將20張實體圖片掛載到頁面顯示,也可以不進行研究,而Tensorflow.js的實際書寫代碼比線性回歸相比之多了十來行,我們來決議下這部分代碼,
這個卷積神經網路構建一共就分了5層,2層2D卷積層,2層池化層,1層輸出層,tf.layers.conv2d創建的是2d卷積層,卷積層之后創建一個tf.layers.maxPool2d最大池化層對上一次卷積特征進行優化,進行兩次卷積提取特征和池化后使用了tf.layers.flatten將立體資料平鋪,最后根據平鋪資料通過tf.layers.dense全鏈接層作為預測輸出,這樣一個簡單的卷積神經網路就構建完成,
后面是將圖片資料讀取1000張圖片轉換成Tensorflow.js可運算的資料Tensor(張量),以及隨機讀取這1000張以外的200張驗證資料,
model.fit方法進行模型的訓練,這里將訓練集和驗證集都放入訓練程序,驗證集的目的是為了驗證模型訓練效果是否偏離了軌道,也就是是否出現過擬合或者欠擬合的情況,
運行代碼后的結果如圖:

我們可以看到loss訓練損失在平滑下降,acc是訓練準確度,val_loss和val_acc是驗證集的損失值和準確度,這里的模型我們只訓練了1000張圖片,然后只訓練了20次,在如此小的資料集以及訓練次數的情況下已經可以達到驚人的效果,
我們在頁面畫布上可以隨意寫數字0-9,模型就可以進行判斷我們寫的是什么數字,如圖效果:

案例使用小結:
上面例子只是讓大家通過具體案例和代碼實作來更加深入了解機器學習是如何編程的,以及Tensorflow.js的強大,
機器學習的編程和傳統編程有著思維上的不同,傳統編程要求程式邏輯縝密,對條件判斷做出人為認定,而機器學習編程不在拘泥于規則撰寫,而是構建神經網路讓計算機進行特征的學習,
而Tensorflow給我們程式猿封裝了很多構建神經網路、訓練模型的API,
六、本篇小結
上述簡要介紹了人工智能、機器學習這些AI領域的概念,以及讓大家感受了一下Tensorflow.js在機器學習上是如何編程的,本篇文章主要目的是帶大家認識人工智能編程的世界,
Tensorflow.js并不是最熱門最高效的機器學習框架,但是由于它使用的語言是Javascript以及開箱即用的API,這些條件可以讓WEB開發者們用比較低的學習成本進行人工智能編程領域的學習,
如今很多大廠對人工智能的研發都投入了大量的人力資金,Tensorflow.js在移動端也出現很多應用,最近比較有名的實時彩妝就是使用Tensorflow.js進行撰寫的小程式,至于未來AI的發展是迅猛的,人工智能編程未來很可能是每個程式猿的必修課,所以在此勉勵程式猿任重而道遠,大家共勉之,
七、其他拓展
人工智能是一門龐大的學科,機器學習只是它的一個分支,它的分支可以用網上的下面這張圖來描述:

從上圖中可以看到機器學習也有龐大的分支,其中Deep Learning(深度學習)是近年來最火熱的課題,深度學習訓練的效果會更加智能,Tensorflow可以進行深度學習的編程,不過深度學習需要龐大的資料量以及強大的計算量,傳統的機器學習不需要龐大的資料量,所以兩者有著不可分割的關系,
下面是一些有關人工智能的一些學習網站,這些網站不僅限于Tensorflow.js,更多是關于機器學習的基礎知識:
Tensorflow模擬:http://playground.tensorflow.org
谷歌機器學習速成教程:https://developers.google.cn/machine-learning/crash-course
機器學習演算法課程:http://wiki.fast.ai/index.php/Main_Page
卷積神經網路原理:https://setosa.io/ev/image-kernels/
以上就是在公司投稿有關tensorflow.js的文章,希望對人工智能有興趣的朋友有所幫助,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/83602.html
標籤:其他
