TensorFlow Model (Cont.)


Data Normalization
Data should be normalized before being used in a neural network. A range of 0 - 1 using min-max are often best for numerical data:

1const inputMin = inputTensor.min( );
2const inputMax = inputTensor.max( );
3const labelMin = labelTensor.min( );
4const labelMax = labelTensor.max( );
5const nmInputs = inputTensor.sub( inputMin ).div( inputMax.sub( inputMin ) );
6const nmLabels = labelTensor.sub( labelMin ).div( labelMax.sub( labelMin ) );

TensorFlow Model
A machine learning model is an algorithm that produces output from input. This example uses 3 lines to define a ML model:

1const model = tf.sequential( );
2model.add( tf.layers.dense( { inputShape: [1], units: 1, useBias: true } ) );
3model.add( tf.layers.dense( { units: 1, useBias: true } ) );
const model = tf.sequential( );
It creates a sequential ML model, which the input flows directly to the output. Other models can have multiple inputs and multiple outputs. The sequential one is the easiest ML model. It allows you to build a model layer by layer, with weights that correspond to the next layer.

model.add( )
It is used to add two layers to the model.

tf.layer.dense
It is a layer type that works in most cases. It multiplies its inputs by a weight-matrix and adds a number (bias) to the result.

inputShape: [1]
It is because we have 1 input (x = horsepower).

units: 1
It defines the size of the weight matrix: 1 weight for each input (x value).
http://undcemcs01.und.edu/~wen.chen.hu/course/525/13/car.html
001<html>
002 <head>
003  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
005  <title>Car TensorFlow.js</title>
006 </head>
007 <body>
008  <form>
009   Horsepower:
010   <input name="hp" id="hp" size="7" value="85" />
011   <input type="button" onClick="runTF( )" value="Train and test" />
012   <input type="reset" />
013   The predicted MPG is <span id="answer">0.00</span> miles per gallon.
014   <div id="plot1"></div>
015   <div id="plot2"></div>
016  </form>
017 
018  <script>
019   // Extracting the required data
020   function extractData( obj ) {
021    return { x:obj.Horsepower, y:obj.Miles_per_Gallon };
022   }
023   function removeErrors( obj ) {
024    return ( ( obj.x != null ) && ( obj.y != null ) );
025   }
026 
027   // Plotting the extracted data
028   function tfPlot( values, surface ) {
029    tfvis.render.scatterplot( surface,
030     { values:values, series:[ 'Original', 'Predicted' ] },
031     { xLabel:'Horsepower', yLabel:'MPG' } );
032   }
033 
034   // Main function
035   async function runTF( ) {
036    const jsonData = await fetch( "carsData.json" );
037    let values = await jsonData.json( );
038    values = values.map( extractData ).filter( removeErrors );
039 
040    // Plotting the Data
041    const surface1 = document.getElementById( "plot1" );
042    const surface2 = document.getElementById( "plot2" );
043    tfPlot( values, surface1 );
044 
045    // Converting the input to Tensors
046    const inputs = values.map( obj => obj.x );
047    const labels = values.map( obj => obj.y );
048    const inputTensor = tf.tensor2d( inputs, [inputs.length, 1] );
049    const labelTensor = tf.tensor2d( labels, [labels.length, 1] );
050    const inputMin = inputTensor.min( ); 
051    const inputMax = inputTensor.max( );
052    const labelMin = labelTensor.min( );
053    const labelMax = labelTensor.max( );
054    const nmInputs = inputTensor.sub(inputMin).div( inputMax.sub(inputMin) );
055    const nmLabels = labelTensor.sub(labelMin).div( labelMax.sub(labelMin) );
056 
057    // Creating a Tensorflow model
058    const model = tf.sequential( );
059    model.add( tf.layers.dense( { inputShape:[1], units:1, useBias:true } ) );
060    model.add( tf.layers.dense( { units: 1, useBias: true } ) );
061    model.compile( { loss:'meanSquaredError', optimizer:'sgd' } );
062 
063    // Starting training
064    await trainModel( model, nmInputs, nmLabels, surface2 );
065 
066    // Un-normalizing the data
067    let unX = tf.linspace( 0, 1, 100 );     
068    let unY = model.predict( unX.reshape( [100, 1] ) );     
069    const unNormunX = unX
070     .mul( inputMax.sub( inputMin ) )
071     .add( inputMin );
072    const unNormunY = unY
073     .mul( labelMax.sub( labelMin ) )
074     .add( labelMin );
075    unX = unNormunX.dataSync( );
076    unY = unNormunY.dataSync( );
077 
078    // Testing the model
079    const predicted = Array.from(unX).map( (val, i) => {
080     return { x: val, y: unY[i] }
081    } );
082    tfPlot( [values, predicted], surface1 );
083 
084    // Finding the MPG of the input horsepower
085    var hp = parseInt( document.getElementById( "hp" ).value );
086    unX.sort( ( a, b ) => a[0] - b[0] );
087    let x1 = unX[0];
088    for ( let i = 1; i < unX.length-1; i++ ) {
089     let x2 = unX[i];
090     if ( ( x1 <= hp ) && ( hp < x2 ) ) {
091      document.getElementById("answer").innerHTML = Math.round( unY[i-1] );
092      break;
093     }
094     x1 = x2;
095    }
096   }     // End of the main function runTF( )
097 
098   // Asyncronous function to train the model
099   async function trainModel( model, inputs, labels, surface ) {
100    const batchSize = 25;
101    const epochs = 50;
102    const callbacks = tfvis.show.fitCallbacks(
103     surface, ['loss'], { callbacks:['onEpochEnd'] } );
104    return await model.fit( inputs, labels,
105     { batchSize, epochs, shuffle:true, callbacks:callbacks } );
106   }     // End of trainModel
107  </script>
108 </body>
109</html>