javascript - LSTM 在训练数据上表现良好,但在测试数据上表现不佳
问题描述
我正在尝试实现用于序列预测的 LSTM 模型。训练后,模型在训练数据上表现良好,但在测试数据上表现不佳。
下面是对训练数据的模型预测
下面是对测试数据的模型预测
总数据数为 429。350 我用于训练,其余用于测试数据。我有 1 个 LSTM 层,有 30 个单元和一个密集层。
有人可以指导我,我该如何改善结果。是过拟合的情况吗?
下面是代码
/**
* Get the stock data reduced to just the variables we are interested
* and cleaned of missing data.
*/
async function getData() {
const stockDataReq = await fetch('http://localhost:8080/stockdata.json?v=0.2');
let stockData = await stockDataReq.json();
const cleaned = stockData.map((stock,i) => ({
day: i,
value: stock["Close Price"],
}))
.filter(n=>n.value);
return generateSequence(cleaned,10);
}
function generateSequence(data, window_size)
{
/*returns [
{
set:[[834],[831],[823],[674],[787],[626],[727],[727],[736],[789]],
value:832
},
...
]
*/
const closePrices = data.map((stock)=>stock["value"]);
let r_avgs = [], avg_prev = 0;
for (let i = 0; i < data.length - window_size; i++){
let set = closePrices.slice(i, i + window_size);
set = set.map(n=>[n]);
r_avgs.push({ set: set, value:closePrices[i+window_size] });
}
return r_avgs;
}
async function run() {
// Load and plot the original input data that we are going to train on.
const data = await getData();
const trainingData = data.slice(0,350);
const validationData = data.slice(350)
const model = createModel();
// Convert the data to a form we can use for training.
const trainingTensors = convertToTensor(trainingData);
const {inputs, labels} = trainingTensors;
// Train the model
await trainModel(model, inputs, labels);
console.log('Done Training');
const validationTensor = convertToTensor(validationData);
testModel(model, validationTensor);
//model.predict(inputs).print();
}
/**
* Convert the input data to tensors that we can use for machine
* learning. We will also do the important best practices of _shuffling_
* the data and _normalizing_ the data
* MPG on the y-axis.
*/
function convertToTensor(data) {
// 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 => d.set)
const labels = data.map(d => d.value);
const inputTensor = tf.tensor3d(inputs, [inputs.length, inputs[0].length,1]);
const labelTensor = tf.tensor1d(labels);
//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.div(inputMax.sub(inputMin));
const normalizedLabels = labelTensor.div(labelMax.sub(labelMin));
normalizedInputs.print();
normalizedLabels.print()
return {
inputs: normalizedInputs,
labels: normalizedLabels,
// Return the min/max bounds so we can use them later.
inputMax,
inputMin,
labelMax,
labelMin,
}
});
}
function createModel() {
// Create a sequential model
const model = tf.sequential();
// Add a single input layer
model.add(tf.layers.lstm({units: 30,inputShape:[10,1]}));
model.add(tf.layers.dropout({rate:0.2}));
model.add(tf.layers.dense({units:1}))
model.summary()
return model;
}
async function trainModel(model, inputs, labels) {
// Prepare the model for training.
model.compile({
optimizer: tf.train.adam(),
loss: tf.losses.meanSquaredError,
});
const epochs = 10;
const batchSize = 32;
return await model.fit(inputs, labels, {
epochs,
batchSize,
callbacks: tfvis.show.fitCallbacks(
{ name: 'Training Performance' },
['loss', 'mse'],
{ height: 200, callbacks: ['onEpochEnd'] })
});
}
function testModel(model, normalizationData) {
const {inputMax, inputMin, labelMin, labelMax, inputs, labels} = 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 preds = model.predict(inputs);
/*const [xs, preds] = tf.tidy(() => {
const xs = tf.linspace(0, 429, 1);
xs.print()
return;
const preds = model.predict(xs.reshape([429, 10,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 originalPoints = inputData.map(d => ({
x: d.day, y: d.value,
}));
*/
const unNormXs = labels
.mul(labelMax.sub(labelMin))
.add(labelMin);
const unNormPreds = preds
.mul(labelMax.sub(labelMin))
.add(labelMin);
let predictedPoints = unNormPreds.dataSync();
predictedPoints = Array.from(predictedPoints);
predictedPoints = predictedPoints.map((val,i)=>({x:i,y:val}))
let originalPoints = unNormXs.dataSync();
originalPoints = Array.from(originalPoints);
originalPoints = originalPoints.map((val,i)=>({x:i,y:val}))
tfvis.render.linechart(
{name: 'Model Predictions vs Original Data'},
{values: [predictedPoints,originalPoints], series: ['predicted','original']},
{
xLabel: 'Horsepower',
yLabel: 'MPG',
height: 300
}
);
}
document.addEventListener('DOMContentLoaded', run);
解决方案
是的,这肯定是过度拟合的情况。因为您的数据中的样本数量太少(<1000),所以,您可以采取以下措施避免过度拟合。
- 玩弄辍学。
- 减少 LSTM 中的单元数。
- 增加样本数量肯定会有所帮助。
推荐阅读
- java - 如何在 Spring Boot 项目中配置多文件 keycloak.json
- c# - 使用asp.net C#上传Excel工作表时数据不保存
- javascript - 根据前一个请求执行多个请求
- javascript - 请协助使用以下代码默认打开一个选项卡,最好是第一个名为“概述”的选项卡
- angular - 有条件地声明查看孩子
- deep-learning - 如何修复“RuntimeError:函数 AddBackward0 在索引 1 处返回无效梯度 - 预期类型为 torch.FloatTensor 但得到了 torch.LongTensor”
- javascript - 单击按钮时Reactjs从firestore获取数据
- python - 我很难理解 Idle 和 Pycharm 之间的区别
- python - 在上下文管理器(with)和异常处理程序中使用“as”分配给成员
- docker - docker login in custom gitlab-runner:没有这样的主机(http://docker:2375/v1.39/auth: dial tcp: lookup docker on 172.31.0.2:53: no such host)