BP神经网络算法的理论推导和源代码

一、算法详解(来自互联网)

“BP(Back Propagation)网络是1986年由Rumelhart和McCelland为首的科学家小组提出,是一种按误差逆传播算法训练的多层前馈网络,是目前应用最广泛的神经网络模型之一。BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程。它的学习规则是使用最速下降法,通过反向传播来不断调整网络的权值和阈值,使网络的误差平方和最小。BP神经网络模型拓扑结构包括输入层(input)、隐层(hide layer)和输出层(output layer)。”

我们现在来分析下这些话:

  • “是一种按误差逆传播算法训练的多层前馈网络”

BP是后向传播的英文缩写,那么传播对象是什么?传播的目的是什么?传播的方式是后向,可这又是什么意思呢。

传播的对象是误差,传播的目的是得到所有层的估计误差,后向是说由后层误差推导前层误差:

即BP的思想可以总结为

利用输出后的误差来估计输出层的直接前导层的误差,再用这个误差估计更前一层的误差,如此一层一层的反传下去,就获得了所有其他各层的误差估计。 

  • “BP神经网络模型拓扑结构包括输入层(input)、隐层(hide layer)和输出层(output layer)”

我们来看一个最简单的三层BP:

《BP神经网络算法的理论推导和源代码》

  • “BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程。”

BP利用一种称为激活函数来描述层与层输出之间的关系,从而模拟各层神经元之间的交互反应。

激活函数必须满足处处可导的条件。那么比较常用的是一种称为S型函数的激活函数:

《BP神经网络算法的理论推导和源代码》

那么上面的函数为什么称为是S型函数呢:

我们来看它的形态和它导数的形态:

p.s. S型函数的导数:

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

神经网络的学习目的:

希望能够学习到一个模型,能够对输入输出一个我们期望的输出。
 
学习的方式:
在外界输入样本的刺激下不断改变网络的连接权值
 
学习的本质:
对各连接权值的动态调整

学习的核心:

权值调整规则,即在学习过程中网络中各神经元的连接权变化所依据的一定的调整规则。

二,有监督的BP模型训练过程

1. 思想

有监督的BP模型训练表示我们有一个训练集,它包括了: input X 和它被期望拥有的输出 output Y

所以对于当前的一个BP模型,我们能够获得它针对于训练集的误差

所以BP的核心思想就是:将输出误差以某种形式通过隐层向输入层逐层反传,这里的某种形式其实就是:

《BP神经网络算法的理论推导和源代码》

也就是一种 “信号的正向传播 —-> 误差的反向传播”的过程:

《BP神经网络算法的理论推导和源代码》

2.具体

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

这里解释下根据误差对权值的偏导数来修订权值:

《BP神经网络算法的理论推导和源代码》

《BP神经网络算法的理论推导和源代码》

二、BP神经网络代码(matlab)
function []=bp11()
%程序功能:训练BP神经网络权值。
%采用了主成分分析法,将输入层从400维降至100维
%网络一层输入层(100),一层中间层(20),一层输出层(10)
%只有当权值变化量很小且能量损失也很小时,才停止训练

%网络构建
overallinput=zcf();%获得输入层(已经降维),规模为100*100
middle=20;%中间元有20个
w1=0.1*rand(100,middle);%第一层权重,w1(a,b)表示连接第a个输入到第b个隐层神经元的权重
w2=rand(middle,10);  %第二层权重,w2(a,b)表示连接第a个隐层神经元到第b个输出的权重
output1=zeros(1,middle);%第一层输出
output2=zeros(1,10); %第二层输出

%训练集
amount=100;%训练图片数量
k=1;%从第一张图开始训练
result=0*ones(1,10);%记录训练集内容
for i=1:(amount/10-1)
    result=[result,i*ones(1,10)];
end

%训练参数
times=100000;%最大训练次数
time=0;%当前已训练次数
acye=0.0001;%可以接受的能量损失
error=1;%当前的能量损失
acyc=0.001;%可以接受的最大权值变化量
change=1;%当前的最大权值变化量
r=1;%初始的学习速录设为1!真的好重要。。。如果太小,像0.1,0.05这种就陷入局部极小值了。。。
preerror=1;%记录上一次的预测误差,以此来调整学习速录
ra=1;%当误差比上次小时,学习速录为上次学习速录的ra倍
rb=1;%当误差比上次大时,学习速录为上次学习速录的rb倍

%开始训练
%达到训练次数,或者误判率可以接受了,才跳出循环
while (change>acyc||error>acye)&& time<times 
        time=time+1;
        input=overallinput(k,:);
        %第一层输出
        for i=1:middle
            output1(i)=input*w1(:,i);
            output1(i)=(1+exp(-output1(i)))^(-1);
        end 
        %第二层输出 
        fprintf(‘\n%d @@output:\n’,time);
        for i=1:10
            output2(i)=output1*w2(:,i);
            output2(i)=(1+exp(-output2(i)))^(-1);
            fprintf(‘%1.7f  ‘,output2(i));
        end
        fprintf(‘\n’);
        %反向
        correctOutput=zeros(1,10);
        correctOutput(result(k)+1)=1;  
        %计算总误差(标准值的两倍,为了节省运算时间,为了比较效果明显)
        error=sum((output2-correctOutput).*(output2-correctOutput));
        fprintf(‘@@error:%1.7f\n’,error);
        %beta2
        beta2=(output2-correctOutput).*(output2).*(ones(1,10)-output2);   
        %beta1
        beta1=output1.* (ones(1,middle)-output1).*(w2*beta2′)’ ;
        %deltaW2
        change2=output1’*beta2;
        %deltaW1
        change1=input’*beta1; 
        change=max( max(max(abs(change1))),max(max(abs(change2))) );
        fprintf(‘change:%1.7f\n’,change);
        %自适应的学习速录
        if error>preerror
            r=r*rb;
        else
            if error<preerror
                r=r*ra;
            end
        end
        prew1=w1;
        prew2=w2;
        w1=w1-r*change1;
        w2=w2-r*change2;
        %记录这次的权值变化情况,为下次留下记录
        preerror=error;
        if k==amount
            k=1;
        else
            k=k+1;
        end
end
fprintf(‘\nTotaltime:%d\n’,time);

%训练结束
%将权值写入文件
        [m,n]=size(prew1);
        fid=fopen(‘w1.txt’,’wt’);
        for i=1:m
            for j=1:n
                if j==n
                    fprintf(fid,’%1.7f\n’,prew1(i,j));
                else
                    fprintf(fid,’%1.7f\t’,prew1(i,j));
                end
            end
        end
        fclose(fid);
        [m,n]=size(prew2);
        fid=fopen(‘w2.txt’,’wt’);
        for i=1:m
            for j=1:n
                if j==n
                    fprintf(fid,’%1.7f\n’,prew2(i,j));
                else
                    fprintf(fid,’%1.7f\t’,prew2(i,j));
                end
            end
        end
        fclose(fid);

end

%使用主成分分析法
function [mappedX]=zcf()
 predimen=400;%初始维数
 afterdimen=100;%降维后的维数
 
 %原始图片信息(100*400)
 overall=zeros(100,predimen);
 for i=1:100
     overall(i,:)=translate400(i);
 end
 %主成分降维,mappedX为降维后的图片信息(100*100)
 [mappedX, mapping] = compute_mapping(overall, ‘PCA’, afterdimen);

 %将原始维度平均值写入文件meaning.txt
 [m,n]=size( mapping.mean);
 fid=fopen(‘meaning.txt’,’wt’);
        for i=1:m
            for j=1:n
                if j==n
                    fprintf(fid,’%1.7f\n’,mapping.mean(i,j));
                else
                    fprintf(fid,’%1.7f\t’,mapping.mean(i,j));
                end
            end
        end
        fclose(fid);
 %将映射基写入文件mapping.txt
 [m,n]=size(mapping.M);
 fid=fopen(‘mapping.txt’,’wt’);
        for i=1:m
            for j=1:n
                if j==n
                    fprintf(fid,’%1.7f\n’,mapping.M(i,j));
                else
                    fprintf(fid,’%1.7f\t’,mapping.M(i,j));
                end
            end
        end
        fclose(fid);
end

function [input]=translate400(name)
%函数功能:将一幅图像抽象成输入层矩阵 大小为20*20
%name是图片名
%input是bp神经网络输入层矩阵

row=240;    %图像行数
colum=240;  %图像列数
numa=20;     %输入层矩阵行
numb=20;     %输入层矩阵列

    %读入图像,二值化

    I=imread(strcat(num2str(name),’.jpg’));
    Igray = rgb2gray(I); 
    Igray=im2bw(Igray);
   
    u=1;%真正存有图像的第一行
    rsum=colum;
    empty=1; 
    while empty<=row && rsum ==colum
        rsum=sum(Igray(empty,:));
        if rsum==colum
            empty=empty+1;
        end
    end
    u=empty;
    
    d=row;%真正存有图像的最后一行
    rsum=colum;
    empty=row; 
    while empty>=1 && rsum ==240
        rsum=sum(Igray(empty,:));
        if rsum==colum
            empty=empty-1;
        end
    end
    d=empty;
    
    l=1;%%真正存有图像的第一列
    rsum=row;
    empty=1; 
    while empty<=colum && rsum ==240
        rsum=sum(Igray(:,empty));
        if rsum==row
            empty=empty+1;
        end
    end
    l=empty;
    
    r=colum;%真正存有图像的最后一列
    rsum=240;
    empty=colum; 
    while empty>=1 && rsum ==240
        rsum=sum(Igray(:,empty));
        if rsum==row
            empty=empty-1;
        end
    end
    r=empty;
    
    picture=Igray(u:d,l:r);
    %数字为1时,拉伸图像会过于倾斜
    if round((d-u)/(r-l))>=6
        ad=ones(d-u+1,round((d-u)/3));
        picture=[ad,picture]; 
        picture=[picture,ad];    
    end 
    picture=imresize(picture,[row colum]);
    
    %获得输入层
    intervala=round(row/numa);
    intervalb=round(colum/numb);
    input=zeros(numa,numb);
    %行划分
    for i=1:numa
        %列划分
        for j=1:numb
           rsum=sum(picture( ((i-1)*intervala+1):i*intervala,((j-1)*intervalb+1):j*intervalb ));
           %得到的是子矩阵各行的和,仍是矩阵
           rsum=sum(rsum);%得到子矩阵各行和的总和,为数
           if rsum~=intervala*intervalb;
               input(i,j)=0;
           else
               input(i,j)=1; 
           end
        end
    end
    %imshow(input);
   input =reshape(input,1,(numa*numb));%按列,将矩阵转成行向量
   
end


    原文作者:神经网络算法
    原文地址: https://blog.csdn.net/greatji_1994/article/details/43247201
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞