编写C语言版本的卷积神经网络CNN之三:CNN的误差反向传播过程

原创文章

转载请注册来源http://blog.csdn.net/tostq

上一节我们介绍了卷积神经网络的前向传播过程,这一节我们重点介绍反向传播过程,反向传播过程反映神经网络的学习训练过程。

误差反向传播方法是神经网络学习的基础,网络上已经有许多相关的内容了,不过关于卷积网络的误差反向传递的公式推导却比较少,而且也不是很清晰,本文将会详细推导这个过程,虽然内容很复杂,但却值得学习.

首先我们需要知道的是误差反向传播的学习方法,实际是梯度下降法求最小误差的权重过程。当然我们的目的是求误差能量关于参数(权重)的导数.

梯度下降法更新权重公式如下所示:

这里W表示权重,E表示误差能量,n表示第n轮更新迭代,η表示学习参数,Y表示输出,δ表示局域梯度。

而另一方面误差能量关于参数(权重)的导数同当前层输入是相关的,所以我们需要一个更好地将当前层误差传递给下一层的量,因为这个δ同当前层的输出无关,其只是反映了当前层的固定结构,所以我们可以将这个固有性质δ反向传递给下一层,其定义为:

接下来我们分层分析整个网络的反向传播过程。在本文的卷积神经网络中主要有以下四种情况:

一、输出层(单层神经网络层)

(1)误差能量定义为实际输出与理想输出的误差

这里的d是理想预期输出,y指实际输出,i指输出位,本文的网络输出为10位,所以N=10.

(2)误差能量关于参数(权重)的导数。

这一层是比较简单的

由于本文是采用Sigmoid系数的激活函数,所以其导数可以求出为:

其局域梯度δ表示为:

二、后接输出层的采样层S4

后接输出层的采样层向多层感知器的隐藏神经元的反向传播是类似的。

由于这一层没有权重,所以不需要进行权重更新,但是我们也需要将误差能量传递给下一层,所以需要计算局域梯度δ,其定义如下,这里j指输出图像中的像素序号,S4层共有12*4*4=192个输出像素,所以j=1~192。

另外输出层O5的局域梯度δ也已经计算过了:

由于采样层没有激活函数,所以φ的导数为1,则最终可以得到

通过上式,我们就可以算出由输出层O5传递到S4层的局域梯度δ值。可以看出传递到采样层各输出像素j的局域梯度δ值,实际是相当于与其相连的下层输出的局域梯度δ值乘上相连权重的总和。

三、后接采样层的卷积层C1、C3

前面为了方便计算,S4层和O5层的输出都被展开成了一维,所以像素都是以i和j作为标号的,到了C3层往前,我们以像素的坐标m(x,y)来标号,m(x,y)表示第m张输出模板的(x,y)位置的像素。局域梯度δ值定义为:

传递到该像素的误差能量等于所有与其相连的像素误差能量和,这里的i指的m(x,y)采样邻域Θ内的所有像素

因为本文采用的是平均Pooling方法,S4的输出就是该像素邻域内的所有像素的平均值,这里的S指邻域Θ内的所有像素的总数,本文采用的是2*2的采样块,所以S=4。

(1)因此由S4传递到C3层的局域梯度δ值为:

接下来我们依据局域梯度δ值,来计算C3层的权重更新值。

(2)C3层的权重更新值。

C3层共有6*12个5*5的模板,我们首先定义n=1~6,m=1~12表示模板的标号,s,t表示模板中参数的位置

(3)C1层的权重更新公式和局域梯度δ值

同理,我们也可以得到C1层的权重更新公式,这里的M=6,N=1,而y是指输入图像

四、后接卷积层的采样层S2

这里的n为当前S2层的输出图像序号(n=1~6),n为当前C3层的输出图像序号(m=1~12)。

因此第n块图像的局域梯度δ值为

五、误差反向传播过程的代码展示

void cnnbp(CNN* cnn,float* outputData) // 网络的后向传播
{
    int i,j,c,r; // 将误差保存到网络中
    for(i=0;i<cnn->O5->outputNum;i++)
        cnn->e[i]=cnn->O5->y[i]-outputData[i];

    /*从后向前反向计算*/
    // 输出层O5
    for(i=0;i<cnn->O5->outputNum;i++)
        cnn->O5->d[i]=cnn->e[i]*sigma_derivation(cnn->O5->y[i]);

    // S4层,传递到S4层的误差
    // 这里没有激活函数
    nSize outSize={cnn->S4->inputWidth/cnn->S4->mapSize,cnn->S4->inputHeight/cnn->S4->mapSize};
    for(i=0;i<cnn->S4->outChannels;i++)
        for(r=0;r<outSize.r;r++)
            for(c=0;c<outSize.c;c++)
                for(j=0;j<cnn->O5->outputNum;j++){
                    int wInt=i*outSize.c*outSize.r+r*outSize.c+c;
                    cnn->S4->d[i][r][c]=cnn->S4->d[i][r][c]+cnn->O5->d[j]*cnn->O5->wData[j][wInt];
                }

    // C3层
    // 由S4层传递的各反向误差,这里只是在S4的梯度上扩充一倍
    int mapdata=cnn->S4->mapSize;
    nSize S4dSize={cnn->S4->inputWidth/cnn->S4->mapSize,cnn->S4->inputHeight/cnn->S4->mapSize};
    // 这里的Pooling是求平均,所以反向传递到下一神经元的误差梯度没有变化
    for(i=0;i<cnn->C3->outChannels;i++){
        float** C3e=UpSample(cnn->S4->d[i],S4dSize,cnn->S4->mapSize,cnn->S4->mapSize);
        for(r=0;r<cnn->S4->inputHeight;r++)
            for(c=0;c<cnn->S4->inputWidth;c++)
                cnn->C3->d[i][r][c]=C3e[r][c]*sigma_derivation(cnn->C3->y[i][r][c])/(float)(cnn->S4->mapSize*cnn->S4->mapSize);
        for(r=0;r<cnn->S4->inputHeight;r++)
            free(C3e[r]);
        free(C3e);
    }

    // S2层,S2层没有激活函数,这里只有卷积层有激活函数部分
    // 由卷积层传递给采样层的误差梯度,这里卷积层共有6*12个卷积模板
    outSize.c=cnn->C3->inputWidth;
    outSize.r=cnn->C3->inputHeight;
    nSize inSize={cnn->S4->inputWidth,cnn->S4->inputHeight};
    nSize mapSize={cnn->C3->mapSize,cnn->C3->mapSize};
    for(i=0;i<cnn->S2->outChannels;i++){
        for(j=0;j<cnn->C3->outChannels;j++){
            float** corr=correlation(cnn->C3->mapData[i][j],mapSize,cnn->C3->d[j],inSize,full);
            addmat(cnn->S2->d[i],cnn->S2->d[i],outSize,corr,outSize);
            for(r=0;r<outSize.r;r++)
                free(corr[r]);
            free(corr);
        }
        /*
        for(r=0;r<cnn->C3->inputHeight;r++)
            for(c=0;c<cnn->C3->inputWidth;c++)
                // 这里本来用于采样的激活
        */
    }

    // C1层,卷积层
    mapdata=cnn->S2->mapSize;
    nSize S2dSize={cnn->S2->inputWidth/cnn->S2->mapSize,cnn->S2->inputHeight/cnn->S2->mapSize};
    // 这里的Pooling是求平均,所以反向传递到下一神经元的误差梯度没有变化
    for(i=0;i<cnn->C1->outChannels;i++){
        float** C1e=UpSample(cnn->S2->d[i],S2dSize,cnn->S2->mapSize,cnn->S2->mapSize);
        for(r=0;r<cnn->S2->inputHeight;r++)
            for(c=0;c<cnn->S2->inputWidth;c++)
                cnn->C1->d[i][r][c]=C1e[r][c]*sigma_derivation(cnn->C1->y[i][r][c])/(float)(cnn->S2->mapSize*cnn->S2->mapSize);
        for(r=0;r<cnn->S2->inputHeight;r++)
            free(C1e[r]);
        free(C1e);
    }
}
时间: 2024-10-07 08:07:55

编写C语言版本的卷积神经网络CNN之三:CNN的误差反向传播过程的相关文章

神经网络和深度学习之——误差反向传播算法

在讲解误差反向传播算法之前,我们来回顾一下信号在神经网络中的流动过程.请细细体会,当输入向量\(X\)输入感知器时,第一次初始化权重向量\(W\)是随机组成的,也可以理解成我们任意设置了初始值,并和输入做点积运算,然后模型通过权重更新公式来计算新的权重值,更新后的权重值又接着和输入相互作用,如此迭代多次,得到最终的权重. 信号向前传播,权重的更新反向传播,是这样吗? 是的,你的直觉没错,确实是反向传播. 1. 前馈的实质 反向传播这个术语经常被误解为用于多层神经网络的整个学习算法.实际上,反向传

循环神经网络(RNN)模型与前向反向传播算法

在前面我们讲到了DNN,以及DNN的特例CNN的模型和前向反向传播算法,这些算法都是前向反馈的,模型的输出和模型本身没有关联关系.今天我们就讨论另一类输出和模型间有反馈的神经网络:循环神经网络(Recurrent Neural Networks ,以下简称RNN),它广泛的用于自然语言处理中的语音识别,手写书别以及机器翻译等领域. 1. RNN概述 在前面讲到的DNN和CNN中,训练样本的输入和输出是比较的确定的.但是有一类问题DNN和CNN不好解决,就是训练样本输入是连续的序列,且序列的长短不

基于误差反向传播法的神经网络学习的全貌图

前提 神经网络中有合适的权重和偏置,调整权重和偏置以便拟合训练数据的过程称为学习.神经网络的学习分为下面4 个步骤. 步骤1(mini-batch)     从训练数据中随机选择一部分数据.步骤2(计算梯度)      计算损失函数关于各个权重参数的梯度.步骤3(更新参数)      将权重参数沿梯度方向进行微小的更新.步骤4(重复)      重复步骤1.步骤2.步骤3. 原文地址:https://www.cnblogs.com/latencytime/p/11079285.html

【转】Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现

原作者:zouxy09 原文链接:http://blog.csdn.net/zouxy09/article/details/9993371 Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现 [email protected] http://blog.csdn.net/zouxy09          自己平时看了一些论文,但老感觉看完过后就会慢慢的淡忘,某一天重新拾起来的时候又好像没有看过一样.所以想习惯地把一些感觉有用的论文中的知识点总结整理一下,一方面在整理过程中,自己

Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现(转)

Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现 [email protected] http://blog.csdn.net/zouxy09          自己平时看了一些论文,但老感觉看完过后就会慢慢的淡忘,某一天重新拾起来的时候又好像没有看过一样.所以想习惯地把一些感觉有用的论文中的知识点总结整理一下,一方面在整理过程中,自己的理解也会更深,另一方面也方便未来自己的勘察.更好的还可以放到博客上面与大家交流.因为基础有限,所以对论文的一些理解可能不太正确,还望大家不

Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现

https://blog.csdn.net/zouxy09/article/details/9993371 自己平时看了一些论文,但老感觉看完过后就会慢慢的淡忘,某一天重新拾起来的时候又好像没有看过一样.所以想习惯地把一些感觉有用的论文中的知识点总结整理一下,一方面在整理过程中,自己的理解也会更深,另一方面也方便未来自己的勘察.更好的还可以放到博客上面与大家交流.因为基础有限,所以对论文的一些理解可能不太正确,还望大家不吝指正交流,谢谢. 本文的论文来自: Notes on Convolutio

卷积神经网络CNN介绍:结构框架,源码理解【转】

1. 卷积神经网络结构 卷积神经网络是一个多层的神经网络,每层都是一个变换(映射),常用卷积convention变换和pooling池化变换,每种变换都是对输入数据的一种处理,是输入特征的另一种特征表达:每层由多个二维平面组成,每个平面为各层处理后的特征图(feature map). 常见结构: 输入层为训练数据,即原始数据,网络中的每一个特征提取层(C-层)都紧跟着一个二次提取的计算层(S-层),这种特有的两次特征提取结构使网络在识别时对输入样本有较高的畸变容忍能力.具体C层和S层的个数不确定

人工智能之卷积神经网络(CNN)

前言:人工智能机器学习有关算法内容,请参见公众号“科技优化生活”之前相关文章.人工智能之机器学习主要有三大类:1)分类;2)回归;3)聚类.今天我们重点探讨一下卷积神经网络(CNN)算法. ^_^ 20世纪60年代,Hubel和Wiesel在研究猫脑皮层中用于局部敏感和方向选择的神经元时发现其独特的网络结构可以有效地降低反馈神经网络的复杂性,继而提出了卷积神经网络CNN(Convolutional Neural Networks). 1980年,K.Fukushima提出的新识别机是卷积神经网络

CNN卷积神经网络

CNN是一种多层神经网络,基于人工神经网络,在人工神经网络前,用滤波器进行特征抽取,使用卷积核作为特征抽取器,自动训练特征抽取器,就是说卷积核以及阈值参数这些都需要由网络去学习. 图像可以直接作为网络的输入,避免了传统识别算法中复杂的特征提取和数据重建过程. 一般卷积神经网络的结构: 前面feature extraction部分体现了CNN的特点,feature extraction部分最后的输出可以作为分类器的输入.这个分类器你可以用softmax或RBF等等. 局部感受野与权值共享 局部感受