進入TensorFlow.js的世界
Day8 初探TensorFlow.js,不用設定環境的機器學習
論效能瀏覽器內的TensorFlow.js比不上原生TensorFlow(Python版本)
但要使用的時候完全不用設定環境,只要有瀏覽器(必須支持WebGL,但哪加沒有?),就可以進行開發跟試驗了。
1.在HTML中載入TensorFlow.js的程式碼
<!-- TensorFlow.js Core -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.2.7/dist/tf.min.js"></script>
<!-- TensorFlow.js Visualiztion -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis@1.1.0/dist/tfjs-vis.umd.min.js"></script>
.首先先載入Google預設好的測試檔案
let tutorial_data_path='https://storage.googleapis.com/tfjs-tutorials/carsData.json';
async function getData() {
//拿到資料
const carsDataReq = await fetch(tutorial_data_path);
//轉成JSON
const carsData = await carsDataReq.json();
//將Miles_per_Gallon跟.Horsepower取出
//篩掉空資料
const cleaned = carsData.map(car => ({
mpg: car.Miles_per_Gallon,
horsepower: car.Horsepower,
})).filter(car => (car.mpg != null && car.horsepower != null));
//回傳清理過後的資料
return cleaned;
}
然後將其視覺化
async function visualiztion() {
const values = (await getData()).map(d => ({
x: d.horsepower,
y: d.mpg,
}));
tfvis.render.scatterplot(
{name: 'Horsepower v MPG'},
{values},
{
xLabel: 'Horsepower',
yLabel: 'MPG',
height: 300
}
);
}
document.addEventListener('DOMContentLoaded', visualiztion);
基本上會看到這張圖
可以看出馬力與單位加侖走的距離呈現負相關
這樣的資料還不錯,看得出來有一定的模式,如果沒有任何隱藏的關聯,也就是說資料間事隨機的話,機器是學習不到什麼東西的
那他這裡的目標是透過機器學習,建立一個可以用馬力來預測單位加侖走的距離的模型
接下來就是建立模型了
function createModel() {
// Create a sequential model
const model = tf.sequential();
// Add a single hidden layer
model.add(tf.layers.dense({ inputShape: [1], units: 20, useBias: true }));
model.add(tf.layers.dense({units: 50, activation: 'sigmoid'}));
model.add(tf.layers.dense({units: 10, activation: 'sigmoid'}));
// Add an output layer
model.add(tf.layers.dense({ units: 1, useBias: true }));
// 加入最佳化的求解器、用MSE做為損失計算方式
model.compile({
optimizer: tf.train.adam(),
loss: tf.losses.meanSquaredError,
metrics: ['mse'],
});
return model;
}
首先是創造TensorFlow裡面的Model
在API中,顯示TensorFlow.js 1.2.7版本有兩種創建模型的方式,一種是上面用的tf.sequential(),另外一種是tf.model(),兩者的差別是tf.sequential()提供的神經元網路層與層是線性堆疊的,而tf.model()定義的神經元網路層與層之間的關係較為隨意。
然後就要把資料轉成Tensor
function convertToTensor(data) {
// 使用tf.tidy讓除了回傳值以外,中間過程中的所佔用的空間釋放掉
return tf.tidy(() => {
// 打亂資料,在訓練最好都要做打亂資料的動作
tf.util.shuffle(data);
// 將資料轉成tensor
const inputs = data.map(d => d.horsepower)
const labels = data.map(d => d.mpg);
const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
const labelTensor = tf.tensor2d(labels, [labels.length, 1]);
//取最大值與最小值
const inputMax = inputTensor.max();
const inputMin = inputTensor.min();
const labelMax = labelTensor.max();
const labelMin = labelTensor.min();
//正規化 將 (tensor內的資料-最小值)/(最大值-最小值)) 出來的結果在0-1之間
const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin));
const normalizedLabels = labelTensor.sub(labelMin).div(labelMax.sub(labelMin));
return {
inputs: normalizedInputs,
labels: normalizedLabels,
inputMax,
inputMin,
labelMax,
labelMin,
}
});
}
接下來就是訓練的程式碼
async function trainModel(model, inputs, labels) {
//每次訓練的樣本數
const batchSize = 32;
//訓練多少代
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'] }
)
});
}
把上面得程式拼在一起
async function runTensorFlow(){
const model = createModel();
const data = await getData();
const tensorData = convertToTensor(data);
await trainModel(model, tensorData.inputs, tensorData.labels);
console.log('Done Training');
}
document.addEventListener('DOMContentLoaded', runTensorFlow);
這時候會看到類似這樣的圖
嘗試預測資料
function getPrediction(model, normalizationData) {
const { inputMax, inputMin, labelMin, labelMax } = normalizationData;
return tf.tidy(() => {
//tf.linspace(start_value,end_value,number_of_value);
const input_x = tf.linspace(0, 1, 100);
//將產生的資料轉成[num_examples, num_features_per_example]
const preds = model.predict(input_x.reshape([100, 1]));
//轉回原本的數= 數字*(最大值-最小值)+最小值
const toOrignalX = input_x
.mul(inputMax.sub(inputMin))
.add(inputMin);
const toOrignalY = preds
.mul(labelMax.sub(labelMin))
.add(labelMin);
//tensor.dataSync() return data from tensor to array
return [toOrignalX.dataSync(), toOrignalY.dataSync()];
});
}
將預測資料視覺化
function visualiztionPrediction(originalData,predictedData){
const originalPoints = originalData.map(d => ({
x: d.horsepower, y: d.mpg,
}));
const [px,py]=predictedData;
const predictedPoints = Array.from(px).map((val, i) => {
return {x: val, y: py[i]}
});
tfvis.render.scatterplot(
{name: 'Model Predictions vs Original Data'},
{values: [originalPoints, predictedPoints], series: ['original', 'predicted']},
{
xLabel: 'Horsepower',
yLabel: 'MPG',
height: 300
}
);
}
加到執行過程
async function runTensorFlow(){
const model = createModel();
const data = await getData();
const tensorData = convertToTensor(data);
await trainModel(model, tensorData.inputs, tensorData.labels);
console.log('Done Training');
const predictedData= getPrediction(model,tensorData);
visualiztionPrediction(data,predictedData)
}
這時候會看到最後的結果,完成了簡單的回歸