溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

TensorFlow.js中JavaScript機(jī)器學(xué)習(xí)的示例分析

發(fā)布時(shí)間:2020-12-02 10:08:06 來(lái)源:億速云 閱讀:351 作者:小新 欄目:web開(kāi)發(fā)

小編給大家分享一下TensorFlow.js中JavaScript機(jī)器學(xué)習(xí)的示例分析,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討吧!

雖然python或r編程語(yǔ)言有一個(gè)相對(duì)容易的學(xué)習(xí)曲線,但是Web開(kāi)發(fā)人員更喜歡在他們舒適的javascript區(qū)域內(nèi)做事情。目前來(lái)看,node.js已經(jīng)開(kāi)始向每個(gè)領(lǐng)域應(yīng)用javascript,在這一大趨勢(shì)下我們需要理解并使用JS進(jìn)行機(jī)器學(xué)習(xí)。由于可用的軟件包數(shù)量眾多,python變得流行起來(lái),但是JS社區(qū)也緊隨其后。這篇文章會(huì)幫助初學(xué)者學(xué)習(xí)如何構(gòu)建一個(gè)簡(jiǎn)單的分類器。

創(chuàng)建

我們可以創(chuàng)建一個(gè)使用tensorflow.js在瀏覽器中訓(xùn)練模型的網(wǎng)頁(yè)。考慮到房屋的“avgareanumberofrows”,模型可以學(xué)習(xí)去預(yù)測(cè)房屋的“價(jià)格”。

為此我們要做的是:

加載數(shù)據(jù)并為培訓(xùn)做好準(zhǔn)備。

定義模型的體系結(jié)構(gòu)。

訓(xùn)練模型并在訓(xùn)練時(shí)監(jiān)控其性能。

通過(guò)做出一些預(yù)測(cè)來(lái)評(píng)估經(jīng)過(guò)訓(xùn)練的模型。

第一步:讓我們從基礎(chǔ)開(kāi)始

創(chuàng)建一個(gè)HTML頁(yè)面并包含JavaScript。將以下代碼復(fù)制到名為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>

為代碼創(chuàng)建javascript文件

在與上面的HTML文件相同的文件夾中,創(chuàng)建一個(gè)名為script.js的文件,并將以下代碼放入其中。

console.log('Hello TensorFlow');

測(cè)試

既然已經(jīng)創(chuàng)建了HTML和JavaScript文件,那么就測(cè)試一下它們。在瀏覽器中打開(kāi)index.html文件并打開(kāi)devtools控制臺(tái)。

如果一切正常,那么應(yīng)該在devtools控制臺(tái)中創(chuàng)建并可用兩個(gè)全局變量:

  • tf是對(duì)tensorflow.js庫(kù)的引用
  • tfvis是對(duì)tfjs vis庫(kù)的引用

現(xiàn)在你應(yīng)該可以看到一條消息,上面寫著“Hello TensorFlow”。如果是這樣,你就可以繼續(xù)下一步了。

TensorFlow.js中JavaScript機(jī)器學(xué)習(xí)的示例分析

注意:可以使用Bit來(lái)共享可重用的JS代碼

Bit(GitHub上的Bit)是跨項(xiàng)目和應(yīng)用程序共享可重用JavaScript代碼的最快和最可擴(kuò)展的方式??梢栽囈辉?,它是免費(fèi)的:

組件發(fā)現(xiàn)與協(xié)作·Bit

Bit是開(kāi)發(fā)人員共享組件和協(xié)作,共同構(gòu)建令人驚嘆的軟件的地方。發(fā)現(xiàn)共享的組件…
Bit.dev

例如:Ramda用作共享組件

Ramda by Ramda·Bit

一個(gè)用于JavaScript程序員的實(shí)用函數(shù)庫(kù)。-256個(gè)javascript組件。例如:等號(hào),乘…
Bit.dev

第2步:加載數(shù)據(jù),格式化數(shù)據(jù)并可視化輸入數(shù)據(jù)

我們將加載“house”數(shù)據(jù)集,可以在這里找到。它包含了特定房子的許多不同特征。對(duì)于本教程,我們只需要有關(guān)房間平均面積和每套房子價(jià)格的數(shù)據(jù)。

將以下代碼添加到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;
}

這可以刪除沒(méi)有定義價(jià)格或房間數(shù)量的任何條目。我們可以將這些數(shù)據(jù)繪制成散點(diǎn)圖,看看它是什么樣子的。

將以下代碼添加到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);

刷新頁(yè)面時(shí),你可以在頁(yè)面左側(cè)看到一個(gè)面板,上面有數(shù)據(jù)的散點(diǎn)圖,如下圖。

TensorFlow.js中JavaScript機(jī)器學(xué)習(xí)的示例分析

通常,在處理數(shù)據(jù)時(shí),最好找到方法來(lái)查看數(shù)據(jù),并在必要時(shí)對(duì)其進(jìn)行清理??梢暬瘮?shù)據(jù)可以讓我們了解模型是否可以學(xué)習(xí)數(shù)據(jù)的任何結(jié)構(gòu)。

從上面的圖中可以看出,房間數(shù)量與價(jià)格之間存在正相關(guān)關(guān)系,即隨著房間數(shù)量的增加,房屋價(jià)格普遍上漲。

第三步:建立待培訓(xùn)的模型

這一步我們將編寫代碼來(lái)構(gòu)建機(jī)器學(xué)習(xí)模型。模型主要基于此代碼進(jìn)行架構(gòu),所以這是一個(gè)比較重要的步驟。機(jī)器學(xué)習(xí)模型接受輸入,然后產(chǎn)生輸出。對(duì)于tensorflow.js,我們必須構(gòu)建神經(jīng)網(wǎng)絡(luò)。

將以下函數(shù)添加到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中定義的最簡(jiǎn)單的模型之一,我們來(lái)試下簡(jiǎn)單分解每一行。

實(shí)例化模型

const model = tf.sequential();

這將實(shí)例化一個(gè)tf.model對(duì)象。這個(gè)模型是連續(xù)的,因?yàn)樗妮斎胫苯恿飨蛩妮敵?。其他類型的模型可以有分支,甚至可以有多個(gè)輸入和輸出,但在許多情況下,你的模型是連續(xù)的。

添加層

model.add(tf.layers.dense({inputShape: [1], units: 1, useBias: true}));

這為我們的網(wǎng)絡(luò)添加了一個(gè)隱藏層。因?yàn)檫@是網(wǎng)絡(luò)的第一層,所以我們需要定義我們的輸入形狀。輸入形狀是[1],因?yàn)槲覀冇?這個(gè)數(shù)字作為輸入(給定房間的房間數(shù))。

單位(鏈接)設(shè)置權(quán)重矩陣在層中的大小。在這里將其設(shè)置為1,我們可以說(shuō)每個(gè)數(shù)據(jù)輸入特性都有一個(gè)權(quán)重。

model.add(tf.layers.dense({units: 1}));

上面的代碼創(chuàng)建了我們的輸出層。我們將單位設(shè)置為1,因?yàn)槲覀円敵?這個(gè)數(shù)字。

創(chuàng)建實(shí)例

將以下代碼添加到前面定義的運(yùn)行函數(shù)中。

// Create the model
const model = createModel();  
tfvis.show.modelSummary({name: 'Model Summary'}, model);

這樣可以創(chuàng)建實(shí)例模型,并且在網(wǎng)頁(yè)上有顯示層的摘要。

TensorFlow.js中JavaScript機(jī)器學(xué)習(xí)的示例分析

步驟4:為創(chuàng)建準(zhǔn)備數(shù)據(jù)

為了獲得TensorFlow.js的性能優(yōu)勢(shì),使培訓(xùn)機(jī)器學(xué)習(xí)模型實(shí)用化,我們需要將數(shù)據(jù)轉(zhuǎn)換為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).p(inputMax.sub(inputMin));
    const normalizedLabels = labelTensor.sub(labelMin).p(labelMax.sub(labelMin));
    return {
      inputs: normalizedInputs,
      labels: normalizedLabels,
      // Return the min/max bounds so we can use them later.
      inputMax,
      inputMin,
      labelMax,
      labelMin,
    }
  });  
}

接下來(lái),我們可以分析一下將會(huì)出現(xiàn)什么情況。

隨機(jī)播放數(shù)據(jù)

// Step 1\. Shuffle the data    
tf.util.shuffle(data);

在訓(xùn)練模型的過(guò)程中,數(shù)據(jù)集被分成更小的集合,每個(gè)集合稱為一個(gè)批。然后將這些批次送入模型運(yùn)行。整理數(shù)據(jù)很重要,因?yàn)槟P筒粦?yīng)該一次又一次地得到相同的數(shù)據(jù)。如果模型一次又一次地得到相同的數(shù)據(jù),那么模型將無(wú)法歸納數(shù)據(jù),并為運(yùn)行期間收到的輸入提供指定的輸出。洗牌將有助于在每個(gè)批次中擁有各種數(shù)據(jù)。

轉(zhuǎn)換為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]);

這里我們制作了兩個(gè)數(shù)組,一個(gè)用于輸入示例(房間條目數(shù)),另一個(gè)用于實(shí)際輸出值(在機(jī)器學(xué)習(xí)中稱為標(biāo)簽,在我們的例子中是每個(gè)房子的價(jià)格)。然后我們將每個(gè)數(shù)組數(shù)據(jù)轉(zhuǎn)換為一個(gè)二維張量。

規(guī)范化數(shù)據(jù)

//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).p(inputMax.sub(inputMin));
const normalizedLabels = labelTensor.sub(labelMin).p(labelMax.sub(labelMin));

接下來(lái),我們規(guī)范化數(shù)據(jù)。在這里,我們使用最小-最大比例將數(shù)據(jù)規(guī)范化為數(shù)值范圍0-1。規(guī)范化很重要,因?yàn)槟鷮⑹褂胻ensorflow.js構(gòu)建的許多機(jī)器學(xué)習(xí)模型的內(nèi)部設(shè)計(jì)都是為了使用不太大的數(shù)字。規(guī)范化數(shù)據(jù)以包括0到1或-1到1的公共范圍。

返回?cái)?shù)據(jù)和規(guī)范化界限

return {
  inputs: normalizedInputs,
  labels: normalizedLabels,
  // Return the min/max bounds so we can use them later.
  inputMax,
  inputMin,
  labelMax,
  labelMin,
}

我們可以在運(yùn)行期間保留用于標(biāo)準(zhǔn)化的值,這樣我們就可以取消標(biāo)準(zhǔn)化輸出,使其恢復(fù)到原始規(guī)模,我們就可以用同樣的方式規(guī)范化未來(lái)的輸入數(shù)據(jù)。

步驟5:運(yùn)行模型

通過(guò)創(chuàng)建模型實(shí)例、將數(shù)據(jù)表示為張量,我們可以準(zhǔn)備開(kāi)始運(yùn)行模型。

將以下函數(shù)復(fù)制到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'] }
    )
  });
}

我們把它分解一下。

準(zhǔn)備運(yùn)行

// Prepare the model for training.  
model.compile({
  optimizer: tf.train.adam(),
  loss: tf.losses.meanSquaredError,
  metrics: ['mse'],
});

我們必須在訓(xùn)練前“編譯”模型。要做到這一點(diǎn),我們必須明確一些非常重要的事情:

優(yōu)化器:這是一個(gè)算法,它可以控制模型的更新,就像上面看到的例子一樣。TensorFlow.js中有許多可用的優(yōu)化器。這里我們選擇了Adam優(yōu)化器,因?yàn)樗趯?shí)踐中非常有效,不需要進(jìn)行額外配置。

損失函數(shù):這是一個(gè)函數(shù),它用于檢測(cè)模型所顯示的每個(gè)批(數(shù)據(jù)子集)方面完成的情況如何。在這里,我們可以使用meansquaredrror將模型所做的預(yù)測(cè)與真實(shí)值進(jìn)行比較。

度量:這是我們要在每個(gè)區(qū)塊結(jié)束時(shí)用來(lái)計(jì)算的度量數(shù)組。我們可以用它計(jì)算整個(gè)訓(xùn)練集的準(zhǔn)確度,這樣我們就可以檢查自己的運(yùn)行結(jié)果了。這里我們使用mse,它是meansquaredrror的簡(jiǎn)寫。這是我們用于損失函數(shù)的相同函數(shù),也是回歸任務(wù)中常用的函數(shù)。

const batchSize = 28;
const epochs = 50;

接下來(lái),我們選擇一個(gè)批量大小和一些時(shí)間段:

batchSize指的是模型在每次運(yùn)行迭代時(shí)將看到的數(shù)據(jù)子集的大小。常見(jiàn)的批量大小通常在32-512之間。對(duì)于所有問(wèn)題來(lái)說(shuō),并沒(méi)有一個(gè)真正理想的批量大小,描述各種批量大小的精確方式這一知識(shí)點(diǎn)本教程沒(méi)有相關(guān)講解,對(duì)這些有興趣可以通過(guò)別的渠道進(jìn)行了解學(xué)習(xí)。

epochs指的是模型將查看你提供的整個(gè)數(shù)據(jù)集的次數(shù)。在這里,我們通過(guò)數(shù)據(jù)集進(jìn)行50次迭代。

啟動(dòng)列車環(huán)路

return model.fit(inputs, labels, {
  batchSize,
  epochs,
  callbacks: tfvis.show.fitCallbacks(
    { name: 'Training Performance' },
    ['loss', 'mse'], 
    { 
      height: 200, 
      callbacks: ['onEpochEnd']
    }
  )
});

model.fit是我們調(diào)用的啟動(dòng)循環(huán)的函數(shù)。它是一個(gè)異步函數(shù),因此我們返回它給我們的特定值,以便調(diào)用者可以確定運(yùn)行結(jié)束時(shí)間。

為了監(jiān)控運(yùn)行進(jìn)度,我們將一些回調(diào)傳遞給model.fit。我們使用tfvis.show.fitcallbacks生成函數(shù),這些函數(shù)可以為前面指定的“損失”和“毫秒”度量繪制圖表。

把它們放在一起

現(xiàn)在我們必須調(diào)用從運(yùn)行函數(shù)定義的函數(shù)。

將以下代碼添加到運(yùn)行函數(shù)的底部。

// 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');

刷新頁(yè)面時(shí),幾秒鐘后,你應(yīng)該會(huì)看到圖形正在更新。

這些是由我們之前創(chuàng)建的回調(diào)創(chuàng)建的。它們?cè)诿總€(gè)時(shí)代結(jié)束時(shí)顯示丟失(在最近的批處理上)和毫秒(在整個(gè)數(shù)據(jù)集上)。

當(dāng)訓(xùn)練一個(gè)模型時(shí),我們希望看到損失減少。在這種情況下,因?yàn)槲覀兊亩攘渴且粋€(gè)誤差度量,所以我們希望看到它也下降。

第6步:做出預(yù)測(cè)

既然我們的模型經(jīng)過(guò)了訓(xùn)練,我們想做一些預(yù)測(cè)。讓我們通過(guò)觀察它預(yù)測(cè)的低到高數(shù)量房間的統(tǒng)一范圍來(lái)評(píng)估模型。

將以下函數(shù)添加到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
    }
  );
}

在上面的函數(shù)中需要注意的一些事情。

const xs = tf.linspace(0, 1, 100);      
const preds = model.predict(xs.reshape([100, 1]));

我們生成100個(gè)新的“示例”以提供給模型。model.predict是我們?nèi)绾螌⑦@些示例輸入到模型中的。注意,他們需要有一個(gè)類似的形狀([num_的例子,num_的特點(diǎn)每個(gè)_的例子])當(dāng)我們做培訓(xùn)時(shí)。

// Un-normalize the data
const unNormXs = xs
  .mul(inputMax.sub(inputMin))
  .add(inputMin);

const unNormPreds = preds
  .mul(labelMax.sub(labelMin))
  .add(labelMin);

為了將數(shù)據(jù)恢復(fù)到原始范圍(而不是0–1),我們使用規(guī)范化時(shí)計(jì)算的值,但只需反轉(zhuǎn)操作。

return [unNormXs.dataSync(), unNormPreds.dataSync()];

.datasync()是一種方法,我們可以使用它來(lái)獲取存儲(chǔ)在張量中的值的typedarray。這允許我們?cè)诔R?guī)的javascript中處理這些值。這是通常首選的.data()方法的同步版本。

最后,我們使用tfjs-vis來(lái)繪制原始數(shù)據(jù)和模型中的預(yù)測(cè)。

將以下代碼添加到運(yùn)行函數(shù)中。

testModel(model, data, tensorData);

刷新頁(yè)面,現(xiàn)在已經(jīng)完成啦!

現(xiàn)在你已經(jīng)學(xué)會(huì)使用tensorflow.js創(chuàng)建一個(gè)簡(jiǎn)單的機(jī)器學(xué)習(xí)模型了。

看完了這篇文章,相信你對(duì)TensorFlow.js中JavaScript機(jī)器學(xué)習(xí)的示例分析有了一定的了解,想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI