训练数据归一化后如何预测?

How to predict after training data is normalized?

我正在学习 TensorFlow.js 使用官方文档并修改代码 mentioned in Codelab 以在给定公斤值作为输入时输出磅数。

所以我有一个 run 函数,它在加载 DOM 时 运行s。

async function run() {
    const model = createModel();
    const data = createData();
    const tensorData = convertToTensor(data);
    const { inputs, labels } = tensorData;

    // Train Model
    await trainModel(model, inputs, labels);
    console.log('Training Complete');

    // Predict
    const normalizedPredictData = normalizeData([5]);
    const { normalizedPredictDataVal, predictValMax, predictValMin } = normalizedPredictData;
    const output = model.predict(normalizedPredictDataVal);
    const finalOutput = unNormalizeData(output, predictValMax, predictValMin);
    console.log(finalOutput.print());
}

document.addEventListener('DOMContentLoaded', run);

createModel 创建一个具有 2 层的简单顺序模型 - 一个隐藏层和一个输出层。

function createModel() {
    const model = tf.sequential();

    // Hidden Layer
    model.add(tf.layers.dense({ units: 1, inputShape: [1] }));

    // Output Layer
    model.add(tf.layers.dense({ units: 1 }));

    return model;
}

createData 是一个生成 500 个训练值的函数。

function createData() {
    const data = {
        inputs: Array.from({ length: 500 }, (x, i) => i),
        labels: Array.from({ length: 500 }, (x, i) => i * 2.2)
    };

    return data;
}

输入 运行 从 0 到 499 和标签只是输入 * 2.2 因为我想在给定公斤值作为输入时预测磅数。

convertToTensor 函数将生成的数据转换为张量后对其进行归一化。

function convertToTensor(data) {
    return tf.tidy(() => {
        tf.util.shuffle(data);

        const inputs = data.inputs;
        const labels = data.labels;

        const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
        const labelTensor = tf.tensor2d(labels, [labels.length, 1]);

        // Normalize Data
        const inputMax = inputTensor.max();
        const inputMin = inputTensor.min();
        const labelMax = inputTensor.max();
        const labelMin = inputTensor.min();

        const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin));
        const normalizedLabels = labelTensor.sub(labelMin).div(labelMax.sub(labelMin));

        return {
            inputs: normalizedInputs,
            labels: normalizedLabels,
            inputMax,
            inputMin,
            labelMax,
            labelMin
        };
    });
}

最后使用trainModel

训练数据
async function trainModel(model, inputs, labels) {
    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 normalizeData(value) {
    const predictValTensor = tf.tensor2d(value, [value.length, 1]);

    const predictValMax = predictValTensor.max();
    const predictValMin = predictValTensor.min();

    const normalizedPredictDataVal = predictValTensor.sub(predictValMin).div(predictValMax.sub(predictValMin));

    return {
        normalizedPredictDataVal,
        predictValMax,
        predictValMin
    };
}

上述函数将值转换为张量,对其进行归一化,然后将结果 returns 传递给预测函数以获得输出值。由于输入已标准化,因此需要对输出进行非标准化,因此创建了一个函数来对其进行非标准化。

function unNormalizeData(value, predictMax, predictMin) {
    const unNormPredictVal = value.mul(predictMax.sub(predictMin)).add(predictMin);
    return unNormPredictVal;
}

一旦输出未规范化,我只是将其记录到控制台。但它只是输出我作为输入给出的值。在本例中,该值为 5.

编码直到训练数据工作正常。我认为错误在于我试图规范化和非规范化预测值的地方。

应使用训练样本的最大值和最小值对预测值进行归一化。

不应该有predictValMax(分别predictValMin)不同于inputMax(分别inputMin

const predictValMax = predictValTensor.max();
const predictValMin = predictValTensor.min();

特征的预测应该是特征数据集不变的。 特征训练集

[-5, 5], inputMin = -5, inputMax = 5; normalized = [0, 0.5]

鉴于这两个测试集的特征:

[5, 6], predictMin = 5, predictMax = 6; normalized = [0, 1]; 

[5], predictMin = 5, predictMax = 6; normalize = [1] // ( though a division by zero occurs here).

5 的归一化值在测试集中不同。它也不同于训练数据中的归一化值。该模型每次出现时都会为相同的特征 5 预测不同的值,因为它的归一化值取决于数据集。

如果对每个预测值应用相同的归一化参数(inputMininputMax),则不会发生这种情况。

function createModel() {
    const model = tf.sequential();

    // Hidden Layer
    model.add(tf.layers.dense({ units: 1, inputShape: [1] }));

    // Output Layer
    model.add(tf.layers.dense({ units: 1 }));

    return model;
}

let inputMin, inputMax, labelMin, labelMax

function createData() {
    const data = {
        inputs: Array.from({ length: 500 }, (x, i) => i),
        labels: Array.from({ length: 500 }, (x, i) => i * 2.2)
    };

    return data;
}

function convertToTensor(data) {
    return tf.tidy(() => {
        tf.util.shuffle(data);

        const inputs = data.inputs;
        const labels = data.labels;

        const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
        const labelTensor = tf.tensor2d(labels, [labels.length, 1]);
      
      inputTensor.print();
labelTensor.print()
        // Normalize Data
        inputMax = inputTensor.max();
        inputMin = inputTensor.min();
        labelMax = inputTensor.max();
        labelMin = inputTensor.min();

        const normalizedInputs = inputTensor.sub(inputMin).div(inputMax.sub(inputMin));
        const normalizedLabels = labelTensor.sub(labelMin).div(labelMax.sub(labelMin));

        return {
            inputs: normalizedInputs,
            labels: normalizedLabels,
            inputMax,
            inputMin,
            labelMax,
            labelMin
        };
    });
}

async function trainModel(model, inputs, labels) {
const learningRate = 0.01;
const optimizer = tf.train.sgd(learningRate);
  // tf.train.adam()
    model.compile({
        optimizer: optimizer ,
        loss: tf.losses.meanSquaredError,
        metrics: ['mse']
    });

    const batchSize = 32;
    const epochs = 200;
  inputs.print()
  labels.print()

    return await model.fit(inputs, labels, {
        batchSize,
        epochs,
        shuffle: true,
        callbacks: tfvis.show.fitCallbacks(
            { name: 'Training Performance' },
            ['loss', 'mse'],
            { height: 200, callbacks: ['onEpochEnd'] }
        )
    });
}

function normalizeData(value) {
    const predictValTensor = tf.tensor2d(value, [value.length, 1]);

    //const predictValMax = predictValTensor.max();
    //const predictValMin = predictValTensor.min();

    const normalizedPredictDataVal = predictValTensor.sub(inputMin).div(inputMax.sub(inputMin));

    return {
        normalizedPredictDataVal,
        inputMax,
        inputMin
    };
}

function unNormalizeData(value, predictMax, predictMin) {
    const unNormPredictVal = value.mul(inputMax.sub(inputMin)).add(inputMin);
    return unNormPredictVal;
}

async function run() {
    const model = createModel();
    const data = createData();
    const tensorData = convertToTensor(data);
    const { inputs, labels } = tensorData;

    await trainModel(model, inputs, labels);
    console.log('Training Complete');

    const normalizedPredictData = await normalizeData([1000, 6, 7]);
  console.log('normalizedinput')
  normalizedPredictData.normalizedPredictDataVal.print()
    const { normalizedPredictDataVal, predictValMax, predictValMin } = normalizedPredictData;
    const output = await model.predict(normalizedPredictDataVal);
    console.log(output.print());
    const finalOutput = await unNormalizeData(output, predictValMax, predictValMin);
     console.log(finalOutput.print());
}

document.addEventListener('DOMContentLoaded', run);
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-vis@1.0.2/dist/tfjs-vis.umd.min.js"></script>
    <script src="index.js"></script>
</body>
</html>