JavaScript 也能玩機器學習 - TensorFlow.js
關於 TensorFlow.js
-
TensorFlow.js 是在 2018 年 3 月發表的開源程序庫(library),前身是 deeplearn.js。
- TensorFlow.js 分成低階與高階兩組 API。
-
低階 API:由 deeplearn.js 衍生,負責處理一些低階如線性代數的資料運算等等,來協助我們處理機器學習中的數學運算部分。
-
高階 API:則是用來包裝一些常用的機器學習演算法,同時允許我們載入訓練好的模型,像是由Keras訓練的模型等等。
-
-
TensorFlow.js 剛推出時不支援 Node.js 開發,因此我們只能在瀏覽器上使用。
-
Node.js 上最近也可使用 TensorFlow.js 了,套件名稱為
tfjs-node
,但請注意此為 alpha 測試版本。 - 簡單的問題,例如一元一次方程式,
Learning Rate
不宜過大。
code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.13.0"> </script>
</head>
<body>
<div style="border: 1px solid green; width: 200px; margin: 0 auto; margin-bottom: 10px; text-align: center;">
正確模型:y = 2x
</div>
<div style="border: 1px solid blue; width: 200px; margin: 0 auto; text-align: center;">
預測模型:y = ax,求 a
</div>
<p>Before Training: <span id="before_ans"></span></p>
<p>After Training: <span id="after_ans"></span></p>
<button id="btn">訓練</button>
<script>
// 要被訓練的參數,這個參數隨著訓練次數增加會越來越準確
let trainingAnswer;
// 產生一個一元一次預測模型公式 y = a * x
function predict(x) {
return tf.tidy(() => {
return trainingAnswer.mul(x)
});
}
/*
tf.tidy()是用來避免變數在TensorFlow運算中占用過多記憶體的一種管理機制
.mul(),則是TensorFlow.js低階運算API的一種,主要用來進行乘法運算。
透過這個predict()函式,我們能運算出目前模式產生出來的預測值
*/
// 定義損失函式(Loss Function)
/*
損失函式是用來評估預測值與正確地案的差距,在訓練過程中,
這個損失函式的輸出應該會越來越小,
在這邊我們使用Mean Square Error函式作為評估的公式,
代表的是預測結果與訓練資料中所有答案平方差的平均
*/
function loss(predictions, labels) {
const meanSquareError = predictions.sub(labels).square().mean();
return meanSquareError;
}
// 定義訓練函式
// Stochastic Gradient Descent(SGD)演算法
function train(xs, ys, numIterations) {
// 參數xs代表訓練用問題資料集,ys代表答案資料集,numIterations代表訓練次數
const learningRate = 0.1;
const optimizer = tf.train.sgd(learningRate);
// tf.train.sgd(learningRate)代表使用 SGD 訓練演算法,並以 learningRate 的學習率進行訓練。
for (let iter = 0; iter < numIterations; iter++) {
optimizer.minimize(() => {
const predsYs = predict(xs);
return loss(predsYs, ys);
});
}
/*
optimizer.minimize()方法,來調整參數,方法的callback中,
我們將透過損失函式算出誤差值並回傳,minimize()方法會自動幫助我們調整損失函式中關聯到的參數,
並透過調整參數把誤差值降到最低。
*/
}
// 產生訓練資料
function generateData(numPoints, answer) {
return tf.tidy(() => {
// 產生常態分佈的隨機資料
const xs = tf.randomNormal([numPoints], -1, 1);
// 套用正確模型產生答案
const ans = tf.scalar(answer);
const ys = ans.mul(xs);
// 回傳訓練資料與答案
return {
xs,
ys
};
})
}
// 執行訓練
async function learnCoefficients(dataCount, iterations) {
const correctAnswer = 2; // 正確答案
const trainingData = generateData(dataCount, correctAnswer);
// console.log('Before Training: ', await trainingAnswer.data());
document.querySelector('#before_ans').innerHTML = await trainingAnswer.data();
// Train the model!
await train(trainingData.xs, trainingData.ys, iterations);
// 印出訓練結果
// console.log('After TRaining: ', await trainingAnswer.data());
document.querySelector('#after_ans').innerHTML = await trainingAnswer.data();
}
document.querySelector('#btn').addEventListener('click', function () {
trainingAnswer = tf.variable(tf.scalar(Math.random()));
/*
透過tf.scalar()將Math.random()的隨機值當作TensorFlow的數值資料,
再使用tf.variable()將這個數值當作是一個變數,因此上面程式我們可以解讀為:
在TensorFlow中宣告一個變數,並給予一個隨機數值。
*/
learnCoefficients(100, 1000);
})
</script>
</body>
</html>
一元二次方程式
// y = a * x ^ 2 + b * x + c
// Define function
function predict(input) {
// More on tf.tidy in the next section
return tf.tidy(() => {
const x = tf.scalar(input);
const ax2 = a.mul(x.square());
const bx = b.mul(x);
const y = ax2.add(bx).add(c);
return y;
});
}
// Define constants: y = 2x^2 + 4x + 8
const a = tf.scalar(2);
const b = tf.scalar(4);
const c = tf.scalar(8);
// Predict output for input of 2
const result = predict(2);
result.print() // Output: 24
一元三次方程式
// y = a * x ^ 3 + b * x ^ 2 + c * x + d
// Define function
function predict(input) {
return tf.tidy(() => {
const ax3 = a.mul(x.pow(tf.scalar(3, 'int32')));
const bx2 = b.mul(x.square());
const cx = c.mul(x);
const y = ax3.add(bx2).add(cx).add(d);
return y;
});
}