index.html完整代码
<!DOCTYPE html>
<html>
<head>
<title>TensorFlow.js Tutorial</title>
<!-- Import TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.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>
script.js完整代码
/**
* Get the car data reduced to just the variables we are interested
* and cleaned of missing data.
*/
async function getData() {
const carsDataResponse = await fetch('https://storage.googleapis.com/tfjs-tutorials/carsData.json');
const carsData = await carsDataResponse.json();
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 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.horsepower,
y: d.mpg,
}));
tfvis.render.scatterplot({ name: 'Horsepower v MPG' }, { values }, {
xLabel: 'Horsepower',
yLabel: 'MPG',
height: 300
});
// More code will be added below
const model = createModel();
tfvis.show.modelSummary({ name: 'Model Summary' }, model);
// 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');
// Make some predictions using the model and compare them to the
// original data
testModel(model, data, tensorData);
}
document.addEventListener('DOMContentLoaded', run);
function createModel() {
// Create a sequential model
const model = tf.sequential();
// Add a single input layer
// dense 是一种层,可将输入与矩阵(称为“权重”)相乘,并向结果添加一个数字(称为“偏差”)
// inputShape 是 [1],因为我们将 1 数字用作输入(某辆指定汽车的马力)
// units 用于设置权重矩阵在层中的大小。将其设置为 1 即表示数据的每个输入特征的权重为 1
model.add(tf.layers.dense({ inputShape: [1], units: 1, useBias: true }));
model.add(tf.layers.dense({ units: 10, activation: 'sigmoid' }));
model.add(tf.layers.dense({ units: 20, activation: 'sigmoid' }));
// model.add(tf.layers.dense({ units: 50, activation: 'sigmoid' }));
// Add an output layer
model.add(tf.layers.dense({ units: 1, useBias: true }));
return model;
}
/**
* Convert the input data to tensors that we can use for machine
* learning. We will also do the important best practices of _shuffling_
* the data and _normalizing_ the data
* MPG on the y-axis.
* 数据重排和归一化
*/
function convertToTensor(data) {
// Wrapping these calculations in a tidy will dispose any
// intermediate tensors.
return tf.tidy(() => {
// Step 1. Shuffle the data
tf.util.shuffle(data);
// Step 2. Convert data to 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]);
//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,
}
});
}
// 创建模型实例并将数据表示为张量之后,我们就可以开始训练过程了。
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 = 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'] })
});
}
// 预测
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.horsepower,
y: d.mpg,
}));
tfvis.render.scatterplot({ name: 'Model Predictions vs Original Data' }, { values: [originalPoints, predictedPoints], series: ['original', 'predicted'] }, {
xLabel: 'Horsepower',
yLabel: 'MPG',
height: 300
});
}