Multi-variate regression in TensorFlow.js

Viewed 21

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.

0 Answers
Related