Credits: aijs.rocksjavascript
雖然python或r編程語言有一個相對容易的學習曲線,可是Web開發人員更喜歡在他們溫馨的javascript區域內作事情。目前來看,node.js已經開始向每一個領域應用javascript,在這一大趨勢下咱們須要理解並使用JS進行機器學習。因爲可用的軟件包數量衆多,python變得流行起來,可是JS社區也緊隨其後。這篇文章會幫助初學者學習如何構建一個簡單的分類器。html
擴展:
2019年11個javascript機器學習庫
很棒的機器學習庫,能夠在你的下一個應用程序中添加一些人工智能!
Big.bitsrc.io前端
建立java
咱們能夠建立一個使用tensorflow.js在瀏覽器中訓練模型的網頁。考慮到房屋的「avgareanumberofrows」,模型能夠學習去預測房屋的「價格」。node
爲此咱們要作的是:python
加載數據併爲培訓作好準備。git
定義模型的體系結構。程序員
訓練模型並在訓練時監控其性能。github
經過作出一些預測來評估通過訓練的模型。算法
第一步:讓咱們從基礎開始
建立一個HTML頁面幷包含JavaScript。將如下代碼複製到名爲index.html的HTML文件中。
<!DOCTYPE html> <html> <head> <title>TensorFlow.js Tutorial</title> <!-- Import TensorFlow.js --> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js"></script> <!-- Import tfjs-vis --> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis@1.0.2/dist/tfjs-vis.umd.min.js"></script> <!-- Import the main script file --> <script src="script.js"></script> </head> <body> </body> </html>
爲代碼建立javascript文件
在與上面的HTML文件相同的文件夾中,建立一個名爲script.js的文件,並將如下代碼放入其中。
console.log('Hello TensorFlow');
測試
既然已經建立了HTML和JavaScript文件,那麼就測試一下它們。在瀏覽器中打開index.html文件並打開devtools控制檯。
若是一切正常,那麼應該在devtools控制檯中建立並可用兩個全局變量:
如今你應該能夠看到一條消息,上面寫着「Hello TensorFlow」。若是是這樣,你就能夠繼續下一步了。
須要這樣的輸出
注意:可使用Bit來共享可重用的JS代碼
Bit(GitHub上的Bit)是跨項目和應用程序共享可重用JavaScript代碼的最快和最可擴展的方式。能夠試一試,它是免費的:
Bit是開發人員共享組件和協做,共同構建使人驚歎的軟件的地方。發現共享的組件…
Bit.dev
例如:Ramda用做共享組件
一個用於JavaScript程序員的實用函數庫。-256個javascript組件。例如:等號,乘…
Bit.dev
第2步:加載數據,格式化數據並可視化輸入數據
咱們將加載「house」數據集,能夠在這裏找到。它包含了特定房子的許多不一樣特徵。對於本教程,咱們只須要有關房間平均面積和每套房子價格的數據。
將如下代碼添加到script.js文件中。
async function getData() { Const houseDataReq=await fetch('https://raw.githubusercontent.com/meetnandu05/ml1/master/house.json'); const houseData = await houseDataReq.json(); const cleaned = houseData.map(house => ({ price: house.Price, rooms: house.AvgAreaNumberofRooms, })) .filter(house => (house.price != null && house.rooms != null)); return cleaned; }
這能夠刪除沒有定義價格或房間數量的任何條目。咱們能夠將這些數據繪製成散點圖,看看它是什麼樣子的。
將如下代碼添加到script.js文件的底部。
async function run() { // Load and plot the original input data that we are going to train on. const data = await getData(); const values = data.map(d => ({ x: d.rooms, y: d.price, })); tfvis.render.scatterplot( {name: 'No.of rooms v Price'}, {values}, { xLabel: 'No. of rooms', yLabel: 'Price', height: 300 } ); // More code will be added below } document.addEventListener('DOMContentLoaded', run);
刷新頁面時,你能夠在頁面左側看到一個面板,上面有數據的散點圖,以下圖。
散點圖
一般,在處理數據時,最好找到方法來查看數據,並在必要時對其進行清理。可視化數據可讓咱們瞭解模型是否能夠學習數據的任何結構。
從上面的圖中能夠看出,房間數量與價格之間存在正相關關係,即隨着房間數量的增長,房屋價格廣泛上漲。
第三步:創建待培訓的模型
這一步咱們將編寫代碼來構建機器學習模型。模型主要基於此代碼進行架構,因此這是一個比較重要的步驟。機器學習模型接受輸入,而後產生輸出。對於tensorflow.js,咱們必須構建神經網絡。
將如下函數添加到script.js文件中以定義模型。
function createModel() { // Create a sequential model const model = tf.sequential(); // Add a single hidden layer model.add(tf.layers.dense({inputShape: [1], units: 1, useBias: true})); // Add an output layer model.add(tf.layers.dense({units: 1, useBias: true})); return model; }
這是咱們能夠在tensorflow.js中定義的最簡單的模型之一,咱們來試下簡單分解每一行。
實例化模型
const model = tf.sequential();
這將實例化一個tf.model對象。這個模型是連續的,由於它的輸入直接流向它的輸出。其餘類型的模型能夠有分支,甚至能夠有多個輸入和輸出,但在許多狀況下,你的模型是連續的。
添加層
model.add(tf.layers.dense({inputShape: [1], units: 1, useBias: true}));
這爲咱們的網絡添加了一個隱藏層。由於這是網絡的第一層,因此咱們須要定義咱們的輸入形狀。輸入形狀是[1],由於咱們有1這個數字做爲輸入(給定房間的房間數)。
單位(連接)設置權重矩陣在層中的大小。在這裏將其設置爲1,咱們能夠說每一個數據輸入特性都有一個權重。
model.add(tf.layers.dense({units: 1}));
上面的代碼建立了咱們的輸出層。咱們將單位設置爲1,由於咱們要輸出1這個數字。
建立實例
將如下代碼添加到前面定義的運行函數中。
// Create the model const model = createModel(); tfvis.show.modelSummary({name: 'Model Summary'}, model);
這樣能夠建立實例模型,而且在網頁上有顯示層的摘要。
步驟4:爲建立準備數據
爲了得到TensorFlow.js的性能優點,使培訓機器學習模型實用化,咱們須要將數據轉換爲Tensors。
將如下代碼添加到script.js文件中。
function convertToTensor(data) { return tf.tidy(() => { // Step 1. Shuffle the data tf.util.shuffle(data); // Step 2. Convert data to Tensor const inputs = data.map(d => d.rooms) const labels = data.map(d => d.price); const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]); const labelTensor = tf.tensor2d(labels, [labels.length, 1]); //Step 3. Normalize the data to the range 0 - 1 using min-max scaling const inputMax = inputTensor.max(); const inputMin = inputTensor.min(); const labelMax = labelTensor.max(); const labelMin = labelTensor.min(); const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin)); const normalizedLabels = labelTensor.sub(labelMin).div(labelMax.sub(labelMin)); return { inputs: normalizedInputs, labels: normalizedLabels, // Return the min/max bounds so we can use them later. inputMax, inputMin, labelMax, labelMin, } }); }
接下來,咱們能夠分析一下將會出現什麼狀況。
隨機播放數據
// Step 1. Shuffle the data tf.util.shuffle(data);
在訓練模型的過程當中,數據集被分紅更小的集合,每一個集合稱爲一個批。而後將這些批次送入模型運行。整理數據很重要,由於模型不該該一次又一次地獲得相同的數據。若是模型一次又一次地獲得相同的數據,那麼模型將沒法概括數據,併爲運行期間收到的輸入提供指定的輸出。洗牌將有助於在每一個批次中擁有各類數據。
轉換爲Tensor
// Step 2. Convert data to Tensor const inputs = data.map(d => d.rooms) const labels = data.map(d => d.price); const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]); const labelTensor = tf.tensor2d(labels, [labels.length, 1]);
這裏咱們製做了兩個數組,一個用於輸入示例(房間條目數),另外一個用於實際輸出值(在機器學習中稱爲標籤,在咱們的例子中是每一個房子的價格)。而後咱們將每一個數組數據轉換爲一個二維張量。
規範化數據
//Step 3. Normalize the data to the range 0 - 1 using min-max scaling const inputMax = inputTensor.max(); const inputMin = inputTensor.min(); const labelMax = labelTensor.max(); const labelMin = labelTensor.min(); const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin)); const normalizedLabels = labelTensor.sub(labelMin).div(labelMax.sub(labelMin));
接下來,咱們規範化數據。在這裏,咱們使用最小-最大比例將數據規範化爲數值範圍0-1。規範化很重要,由於您將使用tensorflow.js構建的許多機器學習模型的內部設計都是爲了使用不太大的數字。規範化數據以包括0到1或-1到1的公共範圍。
返回數據和規範化界限
return { inputs: normalizedInputs, labels: normalizedLabels, // Return the min/max bounds so we can use them later. inputMax, inputMin, labelMax, labelMin, }
咱們能夠在運行期間保留用於標準化的值,這樣咱們就能夠取消標準化輸出,使其恢復到原始規模,咱們就能夠用一樣的方式規範化將來的輸入數據。
步驟5:運行模型
經過建立模型實例、將數據表示爲張量,咱們能夠準備開始運行模型。
將如下函數複製到script.js文件中。
async function trainModel(model, inputs, labels) { // Prepare the model for training. model.compile({ optimizer: tf.train.adam(), loss: tf.losses.meanSquaredError, metrics: ['mse'], }); const batchSize = 28; const epochs = 50; return await model.fit(inputs, labels, { batchSize, epochs, shuffle: true, callbacks: tfvis.show.fitCallbacks( { name: 'Training Performance' }, ['loss', 'mse'], { height: 200, callbacks: ['onEpochEnd'] } ) }); }
咱們把它分解一下。
準備運行
// Prepare the model for training. model.compile({ optimizer: tf.train.adam(), loss: tf.losses.meanSquaredError, metrics: ['mse'], });
咱們必須在訓練前「編譯」模型。要作到這一點,咱們必須明確一些很是重要的事情:
優化器:這是一個算法,它能夠控制模型的更新,就像上面看到的例子同樣。TensorFlow.js中有許多可用的優化器。這裏咱們選擇了Adam優化器,由於它在實踐中很是有效,不須要進行額外配置。
損失函數:這是一個函數,它用於檢測模型所顯示的每一個批(數據子集)方面完成的狀況如何。在這裏,咱們可使用meansquaredrror將模型所作的預測與真實值進行比較。
度量:這是咱們要在每一個區塊結束時用來計算的度量數組。咱們能夠用它計算整個訓練集的準確度,這樣咱們就能夠檢查本身的運行結果了。這裏咱們使用mse,它是meansquaredrror的簡寫。這是咱們用於損失函數的相同函數,也是迴歸任務中經常使用的函數。
const batchSize = 28; const epochs = 50;
接下來,咱們選擇一個批量大小和一些時間段:
batchSize指的是模型在每次運行迭代時將看到的數據子集的大小。常見的批量大小一般在32-512之間。對於全部問題來講,並無一個真正理想的批量大小,描述各類批量大小的精確方式這一知識點本教程沒有相關講解,對這些有興趣能夠經過別的渠道進行了解學習。
epochs指的是模型將查看你提供的整個數據集的次數。在這裏,咱們經過數據集進行50次迭代。
啓動列車環路
return model.fit(inputs, labels, { batchSize, epochs, callbacks: tfvis.show.fitCallbacks( { name: 'Training Performance' }, ['loss', 'mse'], { height: 200, callbacks: ['onEpochEnd'] } ) });
model.fit是咱們調用的啓動循環的函數。它是一個異步函數,所以咱們返回它給咱們的特定值,以便調用者能夠肯定運行結束時間。
爲了監控運行進度,咱們將一些回調傳遞給model.fit。咱們使用tfvis.show.fitcallbacks生成函數,這些函數能夠爲前面指定的「損失」和「毫秒」度量繪製圖表。
把它們放在一塊兒
如今咱們必須調用從運行函數定義的函數。
將如下代碼添加到運行函數的底部。
// Convert the data to a form we can use for training. const tensorData = convertToTensor(data); const {inputs, labels} = tensorData; // Train the model await trainModel(model, inputs, labels); console.log('Done Training');
刷新頁面時,幾秒鐘後,你應該會看到圖形正在更新。
這些是由咱們以前建立的回調建立的。它們在每一個時代結束時顯示丟失(在最近的批處理上)和毫秒(在整個數據集上)。
當訓練一個模型時,咱們但願看到損失減小。在這種狀況下,由於咱們的度量是一個偏差度量,因此咱們但願看到它也降低。
第6步:作出預測
既然咱們的模型通過了訓練,咱們想作一些預測。讓咱們經過觀察它預測的低到高數量房間的統一範圍來評估模型。
將如下函數添加到script.js文件中
function testModel(model, inputData, normalizationData) { const {inputMax, inputMin, labelMin, labelMax} = normalizationData; // Generate predictions for a uniform range of numbers between 0 and 1; // We un-normalize the data by doing the inverse of the min-max scaling // that we did earlier. const [xs, preds] = tf.tidy(() => { const xs = tf.linspace(0, 1, 100); const preds = model.predict(xs.reshape([100, 1])); const unNormXs = xs .mul(inputMax.sub(inputMin)) .add(inputMin); const unNormPreds = preds .mul(labelMax.sub(labelMin)) .add(labelMin); // Un-normalize the data return [unNormXs.dataSync(), unNormPreds.dataSync()]; }); const predictedPoints = Array.from(xs).map((val, i) => { return {x: val, y: preds[i]} }); const originalPoints = inputData.map(d => ({ x: d.rooms, y: d.price, })); tfvis.render.scatterplot( {name: 'Model Predictions vs Original Data'}, {values: [originalPoints, predictedPoints], series: ['original', 'predicted']}, { xLabel: 'No. of rooms', yLabel: 'Price', height: 300 } ); }
在上面的函數中須要注意的一些事情。
const xs = tf.linspace(0, 1, 100); const preds = model.predict(xs.reshape([100, 1]));
咱們生成100個新的「示例」以提供給模型。model.predict是咱們如何將這些示例輸入到模型中的。注意,他們須要有一個相似的形狀([num_的例子,num_的特色每一個_的例子])當咱們作培訓時。
// Un-normalize the data const unNormXs = xs .mul(inputMax.sub(inputMin)) .add(inputMin); const unNormPreds = preds .mul(labelMax.sub(labelMin)) .add(labelMin);
爲了將數據恢復到原始範圍(而不是0–1),咱們使用規範化時計算的值,但只需反轉操做。
return [unNormXs.dataSync(), unNormPreds.dataSync()];
.datasync()是一種方法,咱們可使用它來獲取存儲在張量中的值的typedarray。這容許咱們在常規的javascript中處理這些值。這是一般首選的.data()方法的同步版本。
最後,咱們使用tfjs-vis來繪製原始數據和模型中的預測。
將如下代碼添加到運行函數中。
testModel(model, data, tensorData);
刷新頁面,如今已經完成啦!
如今你已經學會使用tensorflow.js建立一個簡單的機器學習模型了。這裏是Github存儲庫供參考。
結論
我開始接觸這些是由於機器學習的概念很是吸引我,還有就是我想看看有沒有方法可讓它在前端開發中實現,我很高興發現tensorflow.js庫能夠幫助我實現個人目標。這只是前端開發中機器學習的開始,TensorFlow.js還能夠完成不少工做。謝謝你的閱讀!
原文連接 本文爲雲棲社區原創內容,未經容許不得轉載。