赞
踩
我的数据是1万6千多的数据,想用4个特征(这个特征未加输出)预测2个输出,也就是多对多的预测。
先用对一的预测简单一些,就是用一段时序数据取预测,代码例子看的MATLAB工具箱的例子
%代码测试可行。大致看了下,没看蛮懂,继续看 %后用我的数据带入进去看下 clc clear all; close all; %% 加载示例数据。 %chickenpox_dataset 包含一个时序,其时间步对应于月份,值对应于病例数。 %输出是一个元胞数组,其中每个元素均为单一时间步。将数据重构为行向量。 [num1,str1,raw1]=xlsread("shuju1.xlsx"); % data = num1(1:5:3000,7)'; %600个行数据 data = num1(1:5:16374,7)'; %600个行数据 % data = chickenpox_dataset;%自带的数据集 % data = [data{:}]; %cell变double figure(1); plot(data) xlabel("Month") ylabel("Cases") title("Monthly Cases of Chickenpox") %% 对训练数据和测试数据进行分区。 %序列的前 90% 用于训练,后 10% 用于测试。 numTimeStepsTrain = floor(0.9*numel(data));%numTimeStepsTrain训练集数目 ;字面翻译:训练的时间步长 dataTrain = data(1:numTimeStepsTrain+1); %1行n列 dataTest = data(numTimeStepsTrain+1:end); %% 标准化数据 %为了获得较好的拟合并防止训练发散,将训练数据标准化为具有零均值和单位方差。 %在预测时,您必须使用与训练数据相同的参数来标准化测试数据。 mu = mean(dataTrain');% mean函数默认是列的均值 。我这里转置了的,但是原始文件之前没有,结果一样。 sig = std(dataTrain'); dataTrainStandardized = (dataTrain - mu) / sig; %% 准备预测变量和响应 %要预测序列在将来时间步的值,请将响应指定为将值移位了一个时间步的训练序列。 %也就是说,在输入序列的每个时间步,LSTM 网络都学习预测下一个时间步的值。预测变量是没有最终时间步的训练序列。 XTrain = dataTrainStandardized(1:end-1);%这个输入是时间序列的1-n-1 YTrain = dataTrainStandardized(2:end); %这个输出是时间序列的2-n %% 定义 LSTM 网络架构 %创建 LSTM 回归网络。指定 LSTM 层有 200 个隐含单元 numFeatures = 1; %输入 numResponses = 1; %输出 numHiddenUnits = 200;%隐含层层数 layers = [ ... sequenceInputLayer(numFeatures) lstmLayer(numHiddenUnits) fullyConnectedLayer(numResponses) regressionLayer];%第四个参数说明用于回归问题 %指定训练选项。 这里的隐含层似乎可以多层 %将求解器设置为 'adam' 并进行 250 轮训练 这个参数是最大迭代次数,即进行250次训练,每次训练后更新神经网络参数。 %要防止梯度爆炸,请将梯度阈值设置为 1。 %指定初始学习率 0.005,在 125 轮训练后通过乘以因子 0.2 来降低学习率。 options = trainingOptions('adam', ... 'MaxEpochs',250, ... 'GradientThreshold',1, ... 'InitialLearnRate',0.005, ... 'LearnRateSchedule','piecewise', ... 'LearnRateDropPeriod',125, ... 'LearnRateDropFactor',0.2, ... 'Verbose',0, ... 'Plots','training-progress'); %% 训练 LSTM 网络 %使用 trainNetwork 以指定的训练选项训练 LSTM 网络。 net = trainNetwork(XTrain,YTrain,layers,options); %% 预测将来时间步 %要预测将来多个时间步的值,请使用 predictAndUpdateState 函数一次预测一个时间步,并在每次预测时更新网络状态。 对于每次预测,使用前一次预测作为函数的输入。 %使用与训练数据相同的参数来标准化测试数据。 dataTestStandardized = (dataTest - mu) / sig; XTest = dataTestStandardized(1:end-1); %要初始化网络状态,请先对训练数据 XTrain 进行预测。 %接下来,使用训练响应的最后一个时间步 YTrain(end) 进行第一次预测。 %循环其余预测并将前一次预测输入到 predictAndUpdateState。 %对于大型数据集合、长序列或大型网络,在 GPU 上进行预测计算通常比在 CPU 上快;其他情况下,在 CPU 上进行预测计算通常更快;对于单时间步预测,请使用 CPU。 %使用 CPU 进行预测,请将 predictAndUpdateState 的 'ExecutionEnvironment' 选项设置为 'cpu'。 net = predictAndUpdateState(net,XTrain); %请先对训练数据 XTrain 进行预测。 [net,YPred] = predictAndUpdateState(net,YTrain(end)); %使用训练响应的最后一个时间步 YTrain(end) 进行第一次预测。 numTimeStepsTest = size(XTest,2); %返回数组A中元素的数量 字面翻译:测试时间步长 for i = 2:numTimeStepsTest [net,YPred(:,i)] = predictAndUpdateState(net,YPred(:,i-1),'ExecutionEnvironment','cpu'); end %使用先前计算的参数对预测去标准化。 YPred = sig*YPred + mu; %训练进度图会报告根据标准化数据计算出的均方根误差 (RMSE)。根据去标准化的预测值计算 RMSE。 YTest = dataTest(2:end); rmse = sqrt(mean((YPred-YTest).^2)) %使用预测值绘制训练时序。 figure(2); plot(dataTrain(1:end-1)) hold on idx = numTimeStepsTrain:(numTimeStepsTrain+numTimeStepsTest); plot(idx,[data(numTimeStepsTrain) YPred],'.-') hold off xlabel("Month") ylabel("Cases") title("Forecast") legend(["Observed" "Forecast"]) %将预测值与测试数据进行比较。 figure(3) subplot(2,1,1) plot(YTest) hold on plot(YPred,'.-') hold off legend(["Observed" "Forecast"]) ylabel("Cases") title("Forecast") subplot(2,1,2) stem(YPred - YTest);%按照茎状形式绘制 xlabel("Month") ylabel("Error") title("RMSE = " + rmse) %% 使用观测值更新网络状态 %如果您可以访问预测之间的时间步的实际值,则可以使用观测值而不是预测值更新网络状态。 %首先,初始化网络状态。要对新序列进行预测,请使用 resetState 重置网络状态。 %重置网络状态可防止先前的预测影响对新数据的预测。重 %置网络状态,然后通过对训练数据进行预测来初始化网络状态。 net = resetState(net); net = predictAndUpdateState(net,XTrain); %对每个时间步进行预测。对于每次预测,使用前一时间步的观测值预测下一个时间步。 %将 predictAndUpdateState 的 'ExecutionEnvironment' 选项设置为 'cpu'。 YPred = []; numTimeStepsTest = numel(XTest); for i = 1:numTimeStepsTest [net,YPred(:,i)] = predictAndUpdateState(net,XTest(:,i),'ExecutionEnvironment','cpu'); end %使用先前计算的参数对预测去标准化。 YPred = sig*YPred + mu; %计算均方根误差 (RMSE)。 rmse = sqrt(mean((YPred-YTest).^2)) %将预测值与测试数据进行比较。 figure subplot(2,1,1) plot(YTest) hold on plot(YPred,'.-') hold off legend(["Observed" "Predicted"]) ylabel("Cases") title("Forecast with Updates") subplot(2,1,2) stem(YPred - YTest) xlabel("Month") ylabel("Error") title("RMSE = " + rmse)
这里的仿真结果,用的matlab自带的的数据集,效果就很好:对于预测的后49步
明显可以看出效果不错,但是后者更好一些。在一些文章里面提到:前面的才叫多步预测,毕竟都已知真实值了还需要取预测嘛?
我的工作多半只需要单步预测就够了,所以我就用后者也没关系。
但是带入我的数据,对其中一个输出采用上面的代码测试:
明显可以看出效果太差了。前面的简直南辕北辙,可能是我的滑动窗口设置的问题,我取得数据量的0.9,我的总数据量一万多个。后面的还凑合,但是毕竟把前一个的真实值作为输入了的。
所以这个输入输出对于我的数据用这个方案是不合适的。
我目前还不知道多个特征需要加上输出吗?也就是把前一个的输出也作为特征。
我下面的数据是加了的,测试下:
%% 多输入多步预测 %后用我的数据带入进去看下 这个以LSTM1的样式改 多变量多步预测。 %过拟合;梯度爆炸 训练过程中的一系列问题 %代码初步跑通,但是差别太大了。 再调下代码或者加大数据 clc; clear all; close all; % [num1,str1,raw1]=xlsread("shuju1.xlsx"); [num1,~,~]=xlsread("shuju3.xlsx"); %放风阀变化大一些的, 数据三不能做时序数据的预测,由于部分冗余的数据我踢掉了导致有部分数据前后不对。 data = num1(1:5:end,:); input_0_0=data(:,1:4); %增加一个特征,把要预测的也作为特征 input_0_1=zeros(size(data,1),1); input_0_1(1)=data(1,6); for i=2:size(data,1) input_0_1(i)=data(i-1,6); end input_0=horzcat(input_0_0,input_0_1); % output_0=data(:,6:7); output_0=data(:,6); [input_1,input_normopt] =mapminmax(input_0',0,1); [output_1,output_normopt] = mapminmax(output_0',0,1); % 预测的流量压力的滑动窗口大小为16000,初步设置为这个 %分类的LSTM:它必须从序列输入层开始,C是一个包含序列或时间序列预测器的元胞数组。C是d行1列,d代表有多少个训练样本,每个训练样本又包括N行M列,N代表训练样本的数据维度,M代表序列长度, % y是标签的分类向量,是categorical类型。因此,训练数据应该转换成元胞数组,训练数据标签应该转换成categorical类型。 % 对于回归问题,Y是目标矩阵或数字序列的单元数组 k =1; %滑动窗口设置为1 具体设多少需要衡量 for i = 1:size(input_1,2)-k+1 input_cell{i,1} = input_1(:,i:i+k-1); %将其分为101个序列,每个序列长度500,特征5个 output_cell(i,:)= output_1(:,i+k-1); end % 时间步长设置 % 对训练数据和测试数据进行分区。 序列的前 90% 用于训练,后 10% 用于测试。 n = floor(0.8*size(input_cell,1)); %训练集,测试集样本数目划分 input_traincell = input_cell(1:n,:); output_traincell = output_cell(1:n,:); input_testcell = input_cell(n+1:end,:); output_testcell = output_cell(n+1:end,:); %% 定义 LSTM 网络架构 %创建 LSTM 回归网络。 (LSTM1里面用的是两层隐含层) inputSize = 5; %数据输入x的特征维度 ,增加了前一秒的输出作为特征 outputSize = 1; %数据输出y的特征维度 numhidden_units1=200; numhidden_units2=200; % lstm layers = [ ... sequenceInputLayer(inputSize,'name','input') %输入层设置 % lstmLayer(numhidden_units1,'Outputmode','sequence') %学习层设置(cell层) lstmLayer(numhidden_units1,'Outputmode','sequence','name','hidden1') %隐藏层1 dropoutLayer(0.3,'name','dropout_1') %隐藏层1权重丢失率,防止过拟合 lstmLayer(numhidden_units2,'Outputmode','last','name','hidden2') %隐藏层2 dropoutLayer(0.3,'name','dropout_2') %隐藏层2权重丢失率,防止过拟合 是不是丢失太多了 fullyConnectedLayer(outputSize,'name','fullconnect') %全连接层设置(outputsize:预测值的特征维度) regressionLayer('name','out')]; %回归层(因为负荷预测值为连续值,所以为回归层) % r sequence-to-one regression, ----lstmLayer(numHiddenUnits,'OutputMode','last') % sequence-to-sequence regression---lstmLayer(numHiddenUnits,'OutputMode','sequence') options = trainingOptions('adam', ... %优化算法 'MaxEpochs',5000, ... %遍历样本最大循环数 进行MaxEpochs轮训练 这个参数是最大迭代次数,即进行MaxEpochs次训练,每次训练后更新神经网络参数 %似乎迭代次数是他的倍数 'GradientThreshold',1,... %梯度阈值,防止梯度爆炸 'ExecutionEnvironment','cpu',... %运算环境 'InitialLearnRate',0.00001, ... %初始学习率 'LearnRateSchedule','piecewise', ... % 学习率计划 'LearnRateDropPeriod',50, ... %10个epoch后学习率更新 'LearnRateDropFactor',0.2, ... %学习率衰减速度 学习率变为0.0002 'Shuffle','once',... % 是否重排数据顺序,防止数据中因连续异常值而影响预测精度 'MiniBatchSize',300,... % 批处理样本大小 分块尺寸 作为小批量数 'Verbose',0, ... %命令控制台是否打印训练过程 还有verbose=false 'Plots','training-progress'... % 打印训练进度 ); % 'SequenceLength',60,... %LSTM时间步长 这是之前的参数 %指定训练选项,求解器设置为adam, 250 轮训练。 %梯度阈值设置为 1。指定初始学习率 0.005,在 125 轮训练后通过乘以因子 0.2 来降低学习率。 % 'SequenceLength', 'longest',... % bilstmLayer(numHiddenUnits,'OutputMode','last') 双向LSTM层 % options = trainingOptions('adam', ... % 'MaxEpochs',100, ... % 'GradientThreshold',1, ... % 'InitialLearnRate',0.0005, ... % 'LearnRateSchedule','piecewise', ... % 'LearnRateDropPeriod',50, ... % 'LearnRateDropFactor',0.02, ... % 'Verbose',0, ... % 'Plots','training-progress'); %bias: 隐层状态是否带bias,默认为true。bias是偏置值,或者偏移值。没有偏置值就是以0为中轴,或以0为起点。偏置值的作用请参考单层感知器相关结构 %'L2Regularization',0.0010, ... % 'Shuffle','never', ... % 训练 LSTM 网络 %使用 trainNetwork 以指定的训练选项训练 LSTM 网络。 net = trainNetwork(input_traincell,output_traincell,layers,options); %% 预测 代码用的单输入到单输出的样式 代码有问题,不知道是不适合还是我的理解问题 % net = resetState(net); % net = predictAndUpdateState(net,input_traincell); % %对每个时间步进行预测。对于每次预测,使用前一时间步的观测值预测下一个时间步。 % %将 predictAndUpdateState 的 'ExecutionEnvironment' 选项设置为 'cpu'。 % YPred = []; % numTimeStepsTest = numel(output_testcell); % for i = 1:numTimeStepsTest % [net,YPred(:,i)] = predictAndUpdateState(net,input_testcell(:,i),'ExecutionEnvironment','cpu'); % end %% 预测,用的多输入的样式 % %疑问1:这里分k_0次预测,前一个预测会对后一个有影响吗? 疑问2:我的输出的样式对吗?我的有两个参数 疑问3:样本少了所以不准? % k_0=4; %预测4分钟 % for i=1:k_0 % period = 1+(i-1)*12:i*12; %每次预测周期长度,这里为1分钟 % [net,yprenorm] = predictAndUpdateState(net,input_testcell(period,:)); %动态更新,预测 首次运行会报错误 % ypre(:, period ) = mapminmax('reverse',yprenorm',output_normopt); %预测值反归一化 % ytest(:,period) = mapminmax('reverse',output_testcell(period,:)',output_normopt); % figure(1); % subplot(2,2,i) % plot(ypre(1,period),'r--'); % hold on; % plot(ytest(1,period),'b+'); % % stem(ypre(period)-ytest(period)); % legend('ypre','real','Location','westoutside') % % figure(2); % subplot(2,2,i) % plot(ypre(2,period),'r--'); % hold on; % plot(ytest(2,period),'b+'); % end %对于单输出的演示 period = 1:800; %预测测试集 [net,yprenorm] = predictAndUpdateState(net,input_testcell(period,:)); %动态更新,预测 首次运行会报错误 ypre(:, period ) = mapminmax('reverse',yprenorm',output_normopt); %预测值反归一化 ytest(:,period) = mapminmax('reverse',output_testcell(period,:)',output_normopt); figure(1); plot(ypre(1,period),'r--'); hold on; plot(ytest(1,period),'b+'); legend("预测值","真实值"); [c,l]=size(ypre(1,period)); error=ypre(1,period)-ytest(1,period); MAPE1=sum(abs(error)./ytest(1,period))/l;%平均绝对百分比误差MAPE,平均绝对误差没有分母 MAE1=sum(abs(error))/l; %平均绝对误差 MSE1=error*error'/l; %均方误差 RMSE1=MSE1^(1/2); %均方根误差 R_1=1-sum((ypre(1,period)-ytest(1,period)).^2)/sum((ytest(1,period)-mean(ytest(1,period))).^2); %决定系数 %命令行展示模型效果 disp(['-----------------------误差计算--------------------------']) disp(['平均绝对百分比误差MAPE为:',num2str(MAPE1)]) disp(['平均绝对误差MAE为:',num2str(MAE1)]) disp(['均方误差MSE为: ',num2str(MSE1)]) disp(['均方根误差RMSE为: ',num2str(RMSE1)]) disp(['决定系数R为: ',num2str(R_1)])
上述代码对于多对单和多对多的预测都可以跑通,修改为多对多的只需要把输出增加就可以了
数据有4千多个,但是预测效果很差劲…
第一个options 参数仿真过程,特别快,是一条直线,我也不知道为什么
第二个options 参数,仿真过程慢一些 。比上一个好但是趋势和偏差也相差太大了,好垃圾
调了两天的参数,看了csdn和知乎的例子,但是查看的论文也不会具体到所有的参数都会告知,不知道为什么?这个结果太离谱了
我的滑动窗口k就设置的1, 单步预测
不知道是我的数据不适合用lstm,还是代码问题 或者参数没调对 迷茫…
我只是lstm的小白一枚,欢迎大家和我探讨。qq:1003041115
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。