I'm following the tutorials for TensorFlow.js: I've followed along their basic regression tutorial and it worked perfectly fine.
Then I tried to expand on that to perform a multi-variate prediction, but I can't understand what I'm doing wrong. I loaded my structured data, created the model specifying the input shape, then I changed the tensor conversion to obtain an array of arrays with the correct shape. When I pass the inputs to the model.fit() function, I get the following error:
Error when checking model input: the Array of Tensors that you are passing to your model is not the size the model expected. Expected to see 1 Tensor(s), but instead got the following list of Tensor(s): 0.3263888888888889,0.42857142857142855,0.22580645161290322,0.75,1,0.2,0.7583333333333333,0.42857142857142855,0.22580645161290322,0.75,0,0.4,0.3236111111111111,0.14285714285714285,0.3870967741935484,0.75,1,0.2,0.7590277777777777,0.7142857142857143,0.2903225806451613,0.75,0,0.2,0.7763888888888889,0.2857142857142857,0.1935483870967742,0.75,0,0.4,0.32430555555555557,0.5714285714285714,0.25806451612903225,0.75,1,0.2,0.325,0.7142857142857143,0.2903225806451613,0.75,1,0.2,0.32569444444444445,0.14285714285714285,0.16129032258064516,0.75,1,0.2,0.7687499999999999,0.14285714285714285,0.16129032258064516,0.75,0,0.4,0.32916666666666666,0.2857142857142857,0.1935483870967742,0.75,1,0.4
Here is my code:
async function getData() {
return [
{"direction":1,"dow":1,"month":9,"dom":5,"start":749,"arrival":832,"variant1":1,"startHour":7.816666666666666,"arrivalHour":8.533333333333333,"timeTaken":0.7166666666666668},
{"direction":0,"dow":1,"month":9,"dom":5,"start":1827,"arrival":1917,"variant1":2,"startHour":18.45,"arrivalHour":19.283333333333335,"timeTaken":0.8333333333333357},
{"direction":1,"dow":2,"month":9,"dom":6,"start":754,"arrival":846,"variant1":2,"startHour":7.9,"arrivalHour":8.766666666666667,"timeTaken":0.8666666666666671},
{"direction":0,"dow":2,"month":9,"dom":6,"start":1838,"arrival":1934,"variant1":2,"startHour":18.633333333333333,"arrivalHour":19.566666666666666,"timeTaken":0.9333333333333336},
{"direction":1,"dow":3,"month":9,"dom":7,"start":750,"arrival":836,"variant1":1,"startHour":7.833333333333333,"arrivalHour":8.6,"timeTaken":0.7666666666666666},
{"direction":0,"dow":3,"month":9,"dom":7,"start":1812,"arrival":1855,"variant1":2,"startHour":18.2,"arrivalHour":18.916666666666668,"timeTaken":0.7166666666666686},
{"direction":1,"dow":4,"month":9,"dom":8,"start":747,"arrival":834,"variant1":1,"startHour":7.783333333333333,"arrivalHour":8.566666666666666,"timeTaken":0.7833333333333332},
{"direction":1,"dow":5,"month":9,"dom":9,"start":748,"arrival":834,"variant1":1,"startHour":7.8,"arrivalHour":8.566666666666666,"timeTaken":0.7666666666666666},
{"direction":0,"dow":5,"month":9,"dom":9,"start":1813,"arrival":1855,"variant1":1,"startHour":18.216666666666665,"arrivalHour":18.916666666666668,"timeTaken":0.7000000000000028},
{"direction":1,"dow":1,"month":9,"dom":12,"start":746,"arrival":833,"variant1":1,"startHour":7.766666666666667,"arrivalHour":8.55,"timeTaken":0.7833333333333341}
]
}
async function run() {
// Load the original input data that we are going to train on.
const data = await getData();
// Create the model
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
console.log('Starting Training');
await trainModel(model, inputs, labels);
console.log('Done Training');
}
document.addEventListener('DOMContentLoaded', run);
function createModel() {
const model = tf.sequential()
model.add(tf.layers.dense({inputShape: [ 6 ], units: 10}))
model.add(tf.layers.dense({units: 5}))
return model
}
function convertToTensor(data) {
return tf.tidy(() => {
tf.util.shuffle(data)
// Ad-hoc normalization. Variant1 is one of a few values (1, 2, 3...): dividing by 5 should never give much more than 1 in the future
const inputs = data.map(d => [
d.startHour / 24,
d.dow / 7,
d.dom / 31,
d.month / 12,
d.direction,
d.variant1 / 5,
])
const labels = data.map(d => d.timeTaken)
const inputTensor = tf.tensor2d(inputs, [ inputs.length, 6 ])
const labelTensor = tf.tensor2d(labels, [ labels.length, 1 ])
return {
inputs,
labels,
}
});
}
async function trainModel(model, inputs, labels) {
model.compile({
optimizer: tf.train.adam(),
loss: tf.losses.meanSquaredError,
metrics: ['mse'],
})
const batchSize = 2
const epochs = 100
return await model.fit(inputs, labels, {
batchSize,
epochs,
shuffle: true,
callbacks: tfvis.show.fitCallbacks(
{ name: 'Training Performance' },
['loss', 'mse'],
{ height: 200, callbacks: ['onEpochEnd'] }
)
})
}
<!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>
</head>
<body>
<!-- Import the main script file -->
<script type="module" src="tfjs-regression-commute-times.so.js"></script>
</body>
</html>
I have a decent grasp of ML concepts, but it's the first time I try to actually implement them, so please point out any misconception I may have about layers or models or whatnot.