《量化投资:以MATLAB为工具》

MATLAB技术论坛

 找回密码
 注册账号
查看: 415|回复: 0
收起左侧

[提问] BP网络中权值反馈传递中的代码问题

[复制链接]
发表于 2017-8-16 15:50:45 | 显示全部楼层 |阅读模式
仿照例程写了一个利用BP网络来实现预测的程序,结果发现差距有点大,好几个数量级的差别,一直在检查哪出了问题,有一句代码不理解,希望大家一起探讨一下,共同进步。
delta = net.w2(:,1:end-1)'*DELTA.*dlogsig(hid_input,hid_out);
就是这句代码,特别是net.w2(:,1:end-1)'这句
全部代码如下:
%script:main_batch.m
%批量方式训练BP网络,实现函数计算
clear all
clc
%读入数据
xlsfile = 'shiyanshuju.xls';
[data,Acdi] = getdata('shiyanshuju.xls');
%%数据划分
[ train_data,train_ans,test_data,test_ans ] = divide( data,Acdi );
%%设置参数
rng('default')
rng(0)
nTrainNum = 100;    %100个训练样本
nSampDim = 8;       %样本是8维的

%%网络
net.nIn=8;          %八个输入节点
net.nHidden = 3;    %隐含层节点数目的确定是一个问题,需要仔细考虑,目前按照之前文献中的学习将其设置为3
net.nOut=1;         %一个输出节点
w = 2*(rand(net.nHidden , net.nIn)-1/2);    %在最开始随机确定一个输入层到隐含层的权值矩阵,3X8
b = 2*(rand(net.nHidden , 1)-1/2);          %在最开始随机确定一个输入层到隐含层的阈值矩阵,3X1
net.w1 = [w,b];                             %输入层至隐含层的权值矩阵,3X9
W = 2*(rand(net.nOut , net.nHidden)-1/2);   %在最开始随机确定一个隐含层到输出层的权值矩阵,1X3
B = 2*(rand(net.nOut , 1)-1/2);             %在最开始随机确定一个隐含层到输出层的阈值矩阵,1X1
net.w2 = [W,B];                             %隐含层至输出层的权值矩阵,1X4

%在此不进行归一化,因为提前对数据进行了标准化处理
%归一化的方法待定,如何进行反归一
%%训练数据归一化       %归一化需要多学习、了解,为什么需要归一化,什么情况需要归一化,如何避免可能出现的问题
%%mm = mean(train_data);      %求得训练数据的平均值
%将均值进行平移
%%for i=1:8
    %%train_s(:,i) = train_data(:,i)-mm(i);   %train_s保存平移后的数据
%%end
%方差标准化
%%ml(1) = std(train_s(:,1));
%%ml(2) = std(train_s(:,2));
%%ml(3) = std(train_s(:,3));
%%ml(3) = std(train_s(:,4));
%%ml(5) = std(train_s(:,5));
%%ml(6) = std(train_s(:,6));
%%ml(7) = std(train_s(:,7));
%%ml(8) = std(train_s(:,8));
%%for i=1:8
    %%train_s(:,i)=train_s(:,i)/ml(i);
%%end

%%训练
%因为将阈值也作为一个权值,则默认其对应的那个输入始终为1,则在此添加一个1X100的矩阵,即ones(1,nTrainNum)
SampInEx = [train_data',;ones(1,nTrainNum)];    %在此用train_data代替train_s,因为我们提前在表格中进行了预处理,即归一化,9X100
expectedOut = train_ans';    %1X100
eb = 0.01;    %误差容限
eta = 0.6;      %学习率
mc = 0.8;       %动量因子
maxiter = 2000; %最大迭代次数
iteration = 0;  %迭代次数
errRec = zeros(1,maxiter);    %1X2000
outRec = zeros(nTrainNum,maxiter);    %1X2000
%记录
NET=[];

sse_rec=0;

%开始迭代
for i=1:maxiter
    hid_input = net.w1 * SampInEx;                %3X100
    hid_out = logsig(hid_input);                  %3X100  
    ou_input1 = [hid_out;ones(1,nTrainNum)];      %4X100,在这增加了一个1X100且都为1的输入以匹配将阈值归到权值矩阵的矩阵系数
    ou_input2 = net.w2 * ou_input1;               %1X100
    out_out =logsig(ou_input2);                   %1X100
    %out_Rec(:,i) = out_out;                       %记录每次的输出
    err = expectedOut-out_out;
    sse = sumsqr(err);
    errRec(i) = sse;                    %记录每次的错误
    fprintf('第%d次迭代  误差: %f\n',i,sse);
    iteration = iteration+1;
   
    if sse>sse_rec
        break;
    end
   
    sse_rec=sse;
   
    %判断是否收敛
    if sse<=eb
        break;
    end
   
    %误差反向传播
    %隐含层与输出层之间的局部梯度度
    DELTA = err.*dlogsig(ou_input2,out_out);   %dlogsig(ou_input2,out_out)为1X100,最后结果也为1X100
    %输入层与隐含层之间的局部梯度
    delta = net.w2(:,1:end-1)'*DELTA.*dlogsig(hid_input,hid_out);    %3X100
    %权值修改量
    dWEX=DELTA*ou_input1';      %在此ou_input1即为权值修正公式中隐含层y
    dwex=delta*SampInEx';       %在此SampInEx即为权值修正公式中输入层x
    %修改权值,如果不是第一次修改,则使用动量因子
    if i==1
        net.w2 = net.w2+eta*dWEX;      %在此eta即为权值修正公式中的n
        net.w1 = net.w1+eta*dwex;
    else
        %在此使用了附加动量法
        net.w2 = net.w2+(1-mc)*eta*dWEX+mc*dWEXOld;
        net.w1 = net.w1+(1-mc)*eta*dwex+mc*dwexOld;
    end
   
    %记录上一次的权值修改量
    dWEXOld = dWEX;
    dwexOld = dwex;
end

%在此记录一下训练数据的输出
out_record=out_out';

%测试
%测试数据归一化
%for i=1:8
    %test_s(:,i) = test_data(:,i)-mm(i); %这里为什么用mm(i)需要思考
%end
%for i=1:8
    %test_s(:,i) = test_data(:,i)/ml(i);
%end

%计算测试输出
InEx = [test_data';ones(1,300-nTrainNum)];   %在此用test_data代替test_s,因为我们提前在表格中进行了预处理,即归一化
hid_input = net.w1*InEx;
hid_out = logsig(hid_input);  %output of the hidden layer nodes  
ou_input1 = [hid_out;ones(1,300-nTrainNum)];
ou_input2 = net.w2*ou_input1;
out_out = logsig(ou_input2);  
out_out1 = out_out;

%反归一化
%%因为本实例中输出本身即为0-1,并没有进行归一化,故在此不需要进行归一化,计算输出即为实际输出

%取整
%在这书上的例程可能不适用,因此将其设为了注释,并给出了自己的写法将其进行取整分类
%out_out = (out_out<0.5) = 0;
%out_out = (out_out>=0.5) = 1;
%out_int = zeros(size(out_out));
%for i=1:9
    %if out_out(i)>=0.5
        %out_int(i)=1;
    %end
%end
%out_out = out_int;

%按照书上实例显示正确率的地方,这个很尴尬,在计算答案而不是分类的情况下,正确率为0的情况有很大几率出现
%%rate = sum(out_out==test_ans)/length(out_out);

%%显示训练样本,因为有8个输入,所以以列表形式展出
train_show = train_data;
train_sequence_num = length(train_show);
fprintf('---------------------------------------------------------------训练数据----------------------------------------------------------------------------\n');
fprintf('   日照百分率    太阳高度角正弦值  太阳赤纬角余弦值   纬度余弦值        相对湿度        平均温度        饱和蒸气压        含湿量       日平均晴空指数\n');
for i=1:train_sequence_num
    fprintf('  %9d    %9d    %9d    %9d    %d    %1d    %9d    %9d    %9d    %9d\n',train_show(i,1),train_show(i,2),...
    train_show(i,3),train_show(i,4),train_show(i,5),train_show(i,6),train_show(i,7),train_show(i,8),train_ans(i),out_record(i));
end

%------------------------------------------------------------------------------------------------------------------
%%显示结果,选择不同输入进行搭配
test_show = test_data;
test_ans_show=out_out1';
test_sequence_num = length(test_data);
fprintf('---------------------------------------------------------------测试数据----------------------------------------------------------------------------\n');
fprintf('   日照百分率    太阳高度角正弦值  太阳赤纬角余弦值   纬度余弦值        相对湿度        平均温度        饱和蒸气压        含湿量       日平均晴空指数\n');
for i=1:test_sequence_num
    fprintf('  %9d    %9d    %9d    %9d    %d    %1d    %9d    %9d    %9d\n',test_show(i,1),...
    test_show(i,2),test_show(i,3),test_show(i,4),test_show(i,5),test_show(i,6),test_show(i,7),test_show(i,8),test_ans_show(i));
end
%------------------------------------------------------------------------------------------------------------------

fprintf('最终迭代次数\n   %d\n',iteration);

%在此计算正确率
Total_num=length(data);    %数据总数
test_num=Total_num-nTrainNum;
right_num=0;
for i=1:test_num
    if (test_ans(i)-test_ans_show(i))/test_ans(i)<0.1&&(test_ans(i)-test_ans_show(i))/test_ans(i)>(-0.1)
        right_num=right_num+1;
    end
end
right_rate=100*right_num/test_num;
fprintf('正确率为%2d%%\n',right_rate);

您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

QQ|网站地图|MATLAB技术论坛|Simulink仿真论坛 ( 蜀ICP备19014457号 

GMT+8, 2020-8-5 12:37 , Processed in 0.045498 second(s), 10 queries , Gzip On, MemCached On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表