m0_66391544 2025-07-29 15:53 采纳率: 0%
浏览 6

(关键词-network)

trainnetwork中出现如下报错:错误使用 trainNetwork,训练序列具有特征维度 10 9,但输入层需要特征维度为 9 的序列,如何解决?
运行到182 行时特征数为9:“原始输入特征维度: 样本数×特征数 = 43359x9
训练序列数据维度: 时间步×特征数×序列数 = 10x9x30342
模型输入层期望的特征数: 9
训练前最终检查 - 训练数据维度: 10x9x30342
训练前最终检查 - 特征维度位置的值: 9 (应等于9)”
但运行到199行时出现“错误使用 trainNetwork
训练序列具有特征维度 10 9,但输入层需要特征维度为 9 的序列。

出错 ZTD4 (第 182 行)
trainedModel = trainNetwork(XTrain, YTrain, layers, options);

% 基于LSTM神经网络的ZTD预测模型
% 输入参数:温度(Ts)、水汽压(e)、气压(P)、纬度、经度、高度、年、年积日、小时
% 输出参数:ZTD值

clear; clc; close all;

%% 1. 数据准备
stationFiles = {'56691+.xlsx', '56739+.xlsx', '56778+.xlsx', ...
                '56964+.xlsx', '56985+.xlsx', '57816+.xlsx'};

allData = [];

for i = 1:length(stationFiles)
    data = readtable(stationFiles{i}, 'VariableNamingRule', 'preserve');
    
    disp(['站点', num2str(i), '的变量名:']);
    disp(data.Properties.VariableNames);
    
    variables = {
        'mjd', '约化儒略日';
        'Ts', 'Ts';
        'longitude', '经度';
        'latitude', '纬度';
        'height', '测站高';
        'doy', '年积日';
        'ztd', 'ZTD';
        'P', 'P';
    };
    
    extracted = struct();
    
    for j = 1:size(variables, 1)
        varName = variables{j, 1};
        colName = variables{j, 2};
        
        if ~ismember(colName, data.Properties.VariableNames)
            error(['站点', num2str(i), '中不存在列:', colName]);
        end
        
        [numericData, hasErrors] = convertToNumeric(data.(colName), true);
        
        if hasErrors
            warning(['站点', num2str(i), '的"', colName, '"列包含非数值数据,已替换为NaN']);
        end
        
        validRows = ~isnan(numericData);
        numericData = numericData(validRows);
        extracted.(varName) = numericData(:);
    end
    
    % 计算年份
    jd = extracted.mjd + 2400000.5;
    matlab_datenum = jd - 1721058.5;
    date_vec = datevec(matlab_datenum);
    year = date_vec(:,1);
    year = year(:);
    
    % 计算小时
    hour = (extracted.mjd - floor(extracted.mjd)) * 24;
    hour = hour(:);
    
    % 处理水汽压e
    if ismember('e', data.Properties.VariableNames)
        [e, eErrors] = convertToNumeric(data.e, true);
        if eErrors
            warning(['站点', num2str(i), '的"e"列包含非数值数据,已替换为NaN']);
        end
        e = e(validRows);
        e = e(:);
    else
        e = 0.06108 * exp((17.625 * extracted.Ts) / (extracted.Ts + 243.04));
        disp('注意:使用温度计算水汽压,请确认是否有直接的e数据可用');
    end
    
    % 检查变量长度一致性
    checkVariableLengths({extracted.longitude, extracted.latitude, extracted.height, ...
                         year, extracted.doy, hour, extracted.Ts, e, extracted.P, extracted.ztd});
    
    % 组织输入特征(9个)和输出
    inputFeatures = [extracted.longitude, extracted.latitude, extracted.height, ...
                    year, extracted.doy, hour, extracted.Ts, e, extracted.P];
    outputZTD = extracted.ztd;
    
    stationData = [inputFeatures, outputZTD];
    allData = [allData; stationData];
    
    fprintf('站点%d数据处理完成,有效样本数:%d,输入特征数:%d\n', ...
            i, size(stationData, 1), size(inputFeatures, 2));
end

if isempty(allData)
    error('没有有效的数据可供处理,请检查输入文件');
end

%% 2. 数据预处理
X = allData(:, 1:9);  % 9个输入特征
Y = allData(:, 10);   % ZTD输出

fprintf('原始输入特征维度: 样本数×特征数 = %dx%d\n', size(X));

% 数据归一化
[X_norm, xMean, xStd] = normalize(X);
[Y_norm, yMean, yStd] = normalize(Y);

% 划分数据集
rng(42);
n = size(X_norm, 1);
idx = randperm(n);

trainRatio = 0.7;
valRatio = 0.1;
testRatio = 0.2;

trainIdx = idx(1:floor(trainRatio*n));
valIdx = idx(floor(trainRatio*n)+1:floor((trainRatio+valRatio)*n));
testIdx = idx(floor((trainRatio+valRatio)*n)+1:end);

X_train = X_norm(trainIdx, :);
Y_train = Y_norm(trainIdx, :);
X_val = X_norm(valIdx, :);
Y_val = Y_norm(valIdx, :);
X_test = X_norm(testIdx, :);
Y_test = Y_norm(testIdx, :);

% 转换为LSTM输入格式
sequenceLength = 10;

% 准备序列数据(修正版本)
[XTrain, YTrain] = prepareData(X_train, Y_train, sequenceLength);
[XVal, YVal] = prepareData(X_val, Y_val, sequenceLength);
[XTest, YTest] = prepareData(X_test, Y_test, sequenceLength);

% **关键检查:确保 XTrain 的特征维度为 9**
if size(XTrain, 2) ~= 9
    error(['训练数据特征数为 ', num2str(size(XTrain, 2)), ',应为 9']);
end
 
% 显示序列数据维度(关键检查)
fprintf('训练序列数据维度: 时间步×特征数×序列数 = %dx%dx%d\n', size(XTrain));
fprintf('模型输入层期望的特征数: %d\n', 9);


% % 检查序列数据有效性
% if isempty(XTrain) || isempty(YTrain)
%     error('无法生成有效的序列数据,请减小sequenceLength');
% end
% 
% % 显示序列数据维度(关键检查)
% fprintf('训练序列数据维度: 时间步×特征数×序列数 = %dx%dx%d\n', size(XTrain));
% fprintf('模型输入层期望的特征数: %d\n', 9);

%% 3. 构建LSTM模型
inputSize = 9;       % 输入特征数
hiddenSize = 50;
outputSize = 1;

layers = [ ...
    sequenceInputLayer(inputSize)  % 明确接收9维特征
    lstmLayer(hiddenSize)
    fullyConnectedLayer(outputSize)
    regressionLayer];

%% 4. 训练模型前的最终维度验证
if size(XTrain, 2) ~= inputSize
    error(['维度不匹配:训练数据特征数为', num2str(size(XTrain, 2)), ...
          ',模型需要', num2str(inputSize), '个特征']);
end

% 再次确认维度信息
fprintf('训练前最终检查 - 训练数据维度: %dx%dx%d\n', size(XTrain));
fprintf('训练前最终检查 - 特征维度位置的值: %d (应等于9)\n', size(XTrain, 2));

options = trainingOptions('adam', ...
    'MaxEpochs', 50, ...
    'MiniBatchSize', 64, ...
    'Shuffle', 'every-epoch', ...
    'Verbose', 1, ...
    'Plots', 'training-progress', ...
    'ValidationData', {XVal, YVal});

% 训练模型
trainedModel = trainNetwork(XTrain, YTrain, layers, options);

%% 5. 模型预测与评估
YPred = predict(trainedModel, XTest);

% 反归一化
YPred_actual = YPred * yStd + yMean;
YTest_actual = YTest * yStd + yMean;

% 计算评估指标
rmse = sqrt(mean((YPred_actual - YTest_actual).^2));
mae = mean(abs(YPred_actual - YTest_actual));
r2 = 1 - sum((YTest_actual - YPred_actual).^2) / sum((YTest_actual - mean(YTest_actual)).^2);

fprintf('测试集评估结果:\n');
fprintf('RMSE: %.4f\n', rmse);
fprintf('MAE: %.4f\n', mae);
fprintf('R²: %.4f\n', r2);

%% 6. 结果可视化
figure;
plot(YTest_actual, 'b', 'LineWidth', 1.2);
hold on;
plot(YPred_actual, 'r--', 'LineWidth', 1.2);
xlabel('样本索引');
ylabel('ZTD值');
title('ZTD预测值与实际值对比');
legend('实际值', '预测值');
grid on;

figure;
scatter(YTest_actual, YPred_actual);
hold on;
plot([min(YTest_actual), max(YTest_actual)], [min(YTest_actual), max(YTest_actual)], 'r--');
xlabel('实际ZTD值');
ylabel('预测ZTD值');
title('预测值 vs 实际值');
grid on;

%% 辅助函数
function [num, hasErrors] = convertToNumeric(var, allowNaN)
    hasErrors = false;
    num = [];
    
    try
        if iscell(var)
            num = cellfun(@str2double, var);
        elseif isstring(var) || ischar(var)
            num = str2double(var);
        elseif iscategorical(var)
            num = double(var);
        elseif isnumeric(var)
            num = var;
        else
            num = double(var);
        end
        
        if any(isnan(num))
            hasErrors = true;
            if ~allowNaN
                error('存在无法转换为数值的数据');
            end
        end
    catch
        hasErrors = true;
        if allowNaN
            num = NaN(size(var));
        else
            rethrow(lasterror);
        end
    end
end

function checkVariableLengths(vars)
    lengths = cellfun(@length, vars);
    uniqueLengths = unique(lengths);
    
    if length(uniqueLengths) > 1
        error(['变量长度不一致: ', num2str(uniqueLengths)]);
    end
end

% 修正的序列准备函数(确保维度顺序正确)
function [XSequence, YSequence] = prepareData(X, Y, sequenceLength)
    numObservations = size(X, 1);  % 样本数量
    numFeatures = size(X, 2);      % 特征数量(必须为9)
    
    % 检查输入特征数是否正确
    if numFeatures ~= 9
        error(['输入特征数错误:实际为', num2str(numFeatures), ',期望为9']);
    end
    
    numSequences = numObservations - sequenceLength + 1;
    
    if numSequences <= 0
        XSequence = [];
        YSequence = [];
        warning('数据量不足,无法生成序列,请减小sequenceLength');
        return;
    end
    
    % 初始化序列数据 (时间步 × 特征数 × 序列数)
    XSequence = zeros(sequenceLength, numFeatures, numSequences);
    YSequence = zeros(numSequences, 1);
    
    % 填充序列数据
    for i = 1:numSequences
        % 提取连续的sequenceLength个样本,形状为[sequenceLength × numFeatures]
        sequenceData = X(i:i+sequenceLength-1, :);
        
        % 强制检查提取的序列维度
        if size(sequenceData, 1) ~= sequenceLength
            error(['第', num2str(i), '个序列时间步错误:实际', num2str(size(sequenceData, 1)), ...
                  ',期望', num2str(sequenceLength)]);
        end
        if size(sequenceData, 2) ~= numFeatures
            error(['第', num2str(i), '个序列特征数错误:实际', num2str(size(sequenceData, 2)), ...
                  ',期望', num2str(numFeatures)]);
        end
        
        % 确保数据维度正确 - 转置以保证特征数为第二维
        XSequence(:, :, i) = sequenceData;
        YSequence(i) = Y(i + sequenceLength - 1);
    end
    
    % 最终验证序列数据的维度顺序
    if size(XSequence, 1) ~= sequenceLength || size(XSequence, 2) ~= numFeatures
        error(['序列数据维度顺序错误:实际为', num2str(size(XSequence)), ...
              ',正确应为[', num2str(sequenceLength), '×', num2str(numFeatures), '×N]']);
    end
end


  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-07-29 15:54
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    您遇到的错误是:

    错误使用 trainNetwork,训练序列具有特征维度 10 9,但输入层需要特征维度为 9 的序列

    这个错误表明在调用 trainNetwork 函数时,输入数据的特征维度与模型输入层定义的特征维度不一致


    ✅ 问题分析

    从您的描述来看:

    • 原始输入特征维度: 样本数×特征数 = 43359x9
    • 训练序列数据维度: 时间步×特征数×序列数 = 10x9x30342
    • 模型输入层期望的特征数: 9
    • 错误发生在第182行,即调用 trainNetwork(XTrain, YTrain, layers, options);

    然而,在运行到第199行时出现了错误,提示:

    训练序列具有特征维度 10 9,但输入层需要特征维度为 9 的序列

    这说明在 XTrain 中,特征维度被错误地设置为 10,而不是预期的 9。


    🔍 原因分析

    1. prepareData 函数可能存在问题

      • 您的 prepareData 函数可能没有正确处理输入数据,导致输出的 XTrain 的特征维度变成了 10 而不是 9。
      • 可能是因为在准备序列时,错误地将某些列重复或添加了额外的特征。
    2. LSTM 输入格式问题

      • LSTM 网络要求输入格式为:[时间步数, 特征数, 序列数]
      • 如果 XTrain 的维度是 [10, 10, 30342],则说明每个时间步有 10 个特征,而模型只接受 9 个。

    🛠️ 解决方案

    第一步:检查 prepareData 函数

    请确保 prepareData 函数返回的数据格式为:

    XTrain = [时间步数, 特征数, 序列数]
    

    例如,如果 sequenceLength = 10,且每条序列有 9 个特征,则应为:

    XTrain = [10, 9, 30342]
    

    ✅ 修改建议(假设您目前的 prepareData 函数存在错误):

    如果您没有提供 prepareData 函数的实现,请参考以下标准实现方式:

    function [X, Y] = prepareData(Xdata, Ydata, sequenceLength)
        % Xdata: [样本数, 特征数]
        % Ydata: [样本数, 1]
        % sequenceLength: 每个序列的时间步数
    
        n = size(Xdata, 1);
        numSequences = floor(n / sequenceLength);
    
        X = zeros(sequenceLength, 9, numSequences);
        Y = zeros(1, 1, numSequences);
    
        for i = 1:numSequences
            startIdx = (i - 1) * sequenceLength + 1;
            endIdx = i * sequenceLength;
            X(:, :, i) = Xdata(startIdx:endIdx, :);
            Y(:, :, i) = Ydata(endIdx, :);
        end
    end
    

    注意:此函数假定 Xdata[样本数, 特征数] 格式,且 Ydata[样本数, 1] 格式。
    Xdata 的维度为 [样本数, 特征数],那么 XTrain 的维度应该是 [时间步数, 特征数, 序列数]


    第二步:验证 XTrain 的维度

    在调用 trainNetwork 之前,加入以下代码进行检查:

    % 显示 XTrain 维度
    disp('训练数据维度: ');
    disp(size(XTrain));
    
    % 检查特征维度是否为 9
    if size(XTrain, 2) ~= 9
        error(['训练数据特征数为 ', num2str(size(XTrain, 2)), ',应为 9']);
    end
    

    第三步:确认模型输入层的特征数

    确保您的网络结构中,输入层的特征数为 9。例如:

    layers = [
        sequenceInputLayer(9, 'Name', 'input') % 9 个特征
        lstmLayer(100, 'Name', 'lstm1')
        fullyConnectedLayer(1, 'Name', 'fc')
        regressionLayer
    ];
    

    ✅ 总结解决方案(有序列表)

    1. 检查并修正 prepareData 函数,确保其返回的数据格式为 [时间步数, 特征数, 序列数],其中特征数为 9。
    2. 在调用 trainNetwork 前,加入维度检查代码,确保 XTrain 的特征维度为 9。
    3. 确认模型输入层的特征数为 9,避免输入与模型不匹配。
    4. 调试时打印 size(XTrain)size(YTrain),确保它们符合预期格式。

    🧪 示例修改后的代码片段

    % 准备序列数据(修正版本)
    [XTrain, YTrain] = prepareData(X_train, Y_train, sequenceLength);
    [XVal, YVal] = prepareData(X_val, Y_val, sequenceLength);
    [XTest, YTest] = prepareData(X_test, Y_test, sequenceLength);
    
    % **关键检查:确保 XTrain 的特征维度为 9**
    if size(XTrain, 2) ~= 9
        error(['训练数据特征数为 ', num2str(size(XTrain, 2)), ',应为 9']);
    end
    
    % 显示序列数据维度(关键检查)
    fprintf('训练数据维度: %d x %d x %d\n', size(XTrain));
    fprintf('训练标签维度: %d x %d x %d\n', size(YTrain));
    
    % 定义网络结构
    layers = [
        sequenceInputLayer(9, 'Name', 'input') % 9 个特征
        lstmLayer(100, 'Name', 'lstm1')
        fullyConnectedLayer(1, 'Name', 'fc')
        regressionLayer
    ];
    
    % 训练网络
    options = trainingOptions('adam', ...
        'MaxEpochs', 10, ...
        'InitialLearnRate', 0.001, ...
        'Verbose', false, ...
        'Shuffle', 'every epoch', ...
        'ValidationData', {XVal, YVal}, ...
        'Plots', 'training-progress');
    
    trainedModel = trainNetwork(XTrain, YTrain, layers, options);
    

    ✅ 最终建议

    • 务必检查 prepareData 函数是否正确构建了 [时间步数, 特征数, 序列数] 格式的输入数据
    • 确保所有数据预处理步骤都保持一致性,尤其是归一化和序列构建过程。

    如需进一步帮助,您可以提供 prepareData 函数的完整代码,我可以帮您更具体地调试。

    评论

报告相同问题?

问题事件

  • 创建了问题 7月29日