"Making Predictions from 2D Data" 代码实验室在每次刷新时给出随机结果

"Making Predictions from 2D Data" code lab gives random results on each refresh

我一直在关注这个 code lab 但是我在测试经过训练的模型时得到的结果看起来很不对劲,代码实验室显示了这个图表

但是当我 运行 下面的代码时,直接从代码实验室获取,我的图表看起来像这样..

如果我再次刷新我得到

再一次

为什么每次页面刷新的结果差异如此之大?

我试过延迟测试但没有更好的结果

      setTimeout(function(){ 
        console.log('Testing');
        testModel(model, data, tensorData);
       }, 6000);

我不明白为什么它们看起来如此不同,我的代码如下...

import React, { useEffect } from "react";
import * as tf from "@tensorflow/tfjs";
import * as tfvis from "@tensorflow/tfjs-vis";

function App() {
  useEffect(() => {
    const testModel = (model: any, inputData: any, normalizationData: any) => {
      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:any) => ({
        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
        }
      );
    }

    function convertToTensor(data:any) {
      // 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:any) => d.horsepower)
        const labels = data.map((d:any) => 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,
        }
      });  
    }
    const trainModel = async(model:any, inputs:any, labels:any) => {
      // 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'] }
        )
      });
    }

    const createModel = () => {
      // Create a sequential model
      const model = tf.sequential(); 
      // Add a single input layer
      model.add(tf.layers.dense({inputShape: [1], units: 1, useBias: true}));
      // Add an output layer
      model.add(tf.layers.dense({units: 1, useBias: true}));
      return model;
    }

    const getData = async () => {
      const carsDataReq = await fetch("https://storage.googleapis.com/tfjs-tutorials/carsData.json");
      const carsData = await carsDataReq.json();
      const cleaned = carsData.map((car: any) => ({
          mpg: car.Miles_per_Gallon,
          horsepower: car.Horsepower
        }))
        .filter((car:any) => car.mpg != null && car.horsepower != null);
      return cleaned;
    }



    const run = async () => {
      const data = await getData();
      const values = data.map((d:any) => ({
        x: d.horsepower,
        y: d.mpg,
      }));

      tfvis.render.scatterplot(
        {name: 'Horsepower v MPG'},
        {values}, 
        {
          xLabel: 'Horsepower',
          yLabel: 'MPG',
          height: 300
        }
      );
      const model = createModel();  
      tfvis.show.modelSummary({name: 'Model Summary'}, model);

      const tensorData = convertToTensor(data);
      const {inputs, labels} = tensorData;

      // Train the model  
      await trainModel(model, inputs, labels);
      console.log('Done Training');
      testModel(model, data, tensorData);
    }
    run();
  });

  return <div className="App"></div>;
}

export default App;

每次刷新的预测值都不同,因为每次刷新都有新的训练。模型权重用随机值初始化。在训练期间,权重可以收敛到最佳值或发散。这取决于许多参数。实际上,即使是最好的模型也不会总是在固定数量的训练时期收敛。

要始终具有相同的值,可以使用固定数据设置权重的初始值。但是,如何再次找到可以得出最佳预测的数据呢?找到这些权重并不总是那么容易。初始化图层权重的一种简单方法是使用图层的 kernelInitializer

model.add(tf.layers.dense({inputShape: [1], units: 1, useBias: true, kernelInitializer : 'zeros'}));

这个新层的权重将初始化为 0。也可以使用 ones。其他初始化程序是可能的。使用固定权重,预测不会改变。但在实践中,由于上面提到的原因,权重很少被初始化,除非人们确定知道什么可能的值会导致良好的准确性。另一方面做的是跟踪模型的准确性,一旦有一个模型具有令人满意的准确性,就创建一个检查点。