編寫C語(yǔ)言版本的卷積神經(jīng)網(wǎng)絡(luò)CNN之二:CNN網(wǎng)絡(luò)的總體結(jié)構(gòu)

https://blog.csdn.net/tostq/article/details/51786315

上一節(jié)我們總體介紹項(xiàng)目并說明Minst手寫數(shù)字?jǐn)?shù)據(jù)庫(kù)的使用憾朴,這一節(jié)我們將重點(diǎn)介紹CNN網(wǎng)絡(luò)總體結(jié)構(gòu)膊毁。

image.png

上圖我們已經(jīng)非常熟悉富玷,其為Yann在1998年介紹的LeNet-5網(wǎng)絡(luò)的結(jié)構(gòu),其剛被提出淀零,就在學(xué)術(shù)和工業(yè)領(lǐng)域上得到廣泛應(yīng)用烛缔,而本文的CNN卷積網(wǎng)絡(luò)卻是如下圖所示(博主自己畫的,畫這個(gè)圖還是挺麻煩的:L砍鸠,不清晰請(qǐng)?jiān)彛蚅eNet-5相比主要有以下三點(diǎn)不同:

(1)LeNet-5給輸入圖像增加了一圈黑邊耕驰,使輸入圖像大小變成了32x32爷辱,這樣的目的是為了在下層卷積過程中保留更多原圖的信息。
(2)LeNet-5的卷積層C3只有16個(gè)模板朦肘,得到16個(gè)輸出饭弓,而本文的卷積層C3由于是全連接,所以有6*12個(gè)模板媒抠,得到12個(gè)輸出圖像
(3)LeNet-5多了兩種弟断,分別是C5到F6的全連接神經(jīng)網(wǎng)絡(luò)層,和F6到OUTPUT高斯連接網(wǎng)絡(luò)層趴生。而本文的直接由采樣層S4直接經(jīng)過一層全連接神經(jīng)網(wǎng)絡(luò)層到OUTPUT阀趴。

下面我們將重點(diǎn)介紹各層的結(jié)構(gòu)及數(shù)據(jù)的前向傳播。

image.png

一苍匆、各層的解釋

(1)卷積層C1

輸入為28\times28的灰度圖像刘急,灰度圖像分別同6個(gè)5\times5的模板進(jìn)行卷積操作,分別得到了6個(gè)24\times24的卷積圖像浸踩,圖像里的每個(gè)像素加上一個(gè)權(quán)重叔汁,并經(jīng)過一個(gè)激活函數(shù),得到該層的輸出检碗。

所以該層的相關(guān)參數(shù)為:6個(gè)5\times5的模板參數(shù)w据块,6個(gè)模板對(duì)應(yīng)的權(quán)重參數(shù)b,共6\times5\times5+6個(gè)參數(shù)

Tips:
關(guān)于激活函數(shù):激活函數(shù)我們?cè)趯W(xué)習(xí)神經(jīng)網(wǎng)絡(luò)時(shí)就已經(jīng)接觸過了后裸,其主要有兩個(gè)目的瑰钮,第一是將數(shù)據(jù)鉗制在一定范圍內(nèi)(如Sigmoid函數(shù)將數(shù)據(jù)壓縮在-1到1之間),不太高也不太低微驶,第二是用來加入非線性因素的浪谴,因?yàn)榫€性模型的表達(dá)能力不夠。傳統(tǒng)神經(jīng)網(wǎng)絡(luò)中最常用的兩個(gè)激活函數(shù)Sigmoid系和Tanh系因苹,而Sigmoid系(Logistic-Sigmoid苟耻、Tanh-Sigmoid)被視為神經(jīng)網(wǎng)絡(luò)的核心所在。本文的例子就是Sigmoid系扶檐。

近年來凶杖,在深度學(xué)習(xí)領(lǐng)域中效果最好,應(yīng)用更為廣泛的是ReLu激活函數(shù)款筑,其相較于Sigmoid系智蝠,主要變化有三點(diǎn):①單側(cè)抑制 ②相對(duì)寬闊的興奮邊界 ③稀疏激活性腾么。特別是在神經(jīng)科學(xué)方面,除了新的激活頻率函數(shù)之外杈湾,神經(jīng)科學(xué)家還發(fā)現(xiàn)了的稀疏激活性廣泛存在于大腦的神經(jīng)元解虱,神經(jīng)元編碼工作方式具有稀疏性和分布性。大腦同時(shí)被激活的神經(jīng)元只有1~4%漆撞。 從信號(hào)方面來看殴泰,即神經(jīng)元同時(shí)只對(duì)輸入信號(hào)的少部分選擇性響應(yīng),大量信號(hào)被刻意的屏蔽了浮驳,這樣可以提高學(xué)習(xí)的精度悍汛,更好更快地提取稀疏特征。而在經(jīng)驗(yàn)規(guī)則的初始化W之后至会,傳統(tǒng)的Sigmoid系函數(shù)同時(shí)近乎有一半的神經(jīng)元被激活离咐,這不符合神經(jīng)科學(xué)的研究,而且會(huì)給深度網(wǎng)絡(luò)訓(xùn)練帶來巨大問題奋献。Softplus照顧到了新模型的前兩點(diǎn)健霹,卻沒有稀疏激活性旺上。因而瓶蚂,校正函數(shù)\max(0,x)即ReLu函數(shù)成了最大贏家。

(2)采樣層S2及S4(Pooling層)

采樣層S又名Pooling層宣吱,Pooling主要是為了減少數(shù)據(jù)處理的維度窃这,常見的pooling方法有max pooling和average pooling等。

  • max pooling 就是選擇當(dāng)前塊內(nèi)最大像素值來表示當(dāng)前局部塊

  • average pooling 就是選擇當(dāng)前塊的像素值平均值來代替

本文的選擇Pooling方法是average pooling征候,而使用廣泛效果較好的方法卻是max pooling杭攻。(看到這里,你可能會(huì)吐槽疤坝,為什么不用效果好兆解,因?yàn)槠骄?jì)算相比而言,有那么一丟丟簡(jiǎn)單E苋唷)

(3)卷積層C3

這里的卷積層是一個(gè)全連接的卷積層锅睛。輸出的卷積公式如下,這里I表示圖像历谍,W表示卷積模板现拒,b表示偏重,φ表示激活函數(shù)望侈,i表示輸入圖像序號(hào)(i=1~6)印蔬,j表示該層輸出圖像序號(hào)(j=1~12)

由此可以看到在卷積層C3中輸入為6個(gè)12\times12的圖像,輸出為12個(gè)8\times8的圖像
所需要訓(xùn)練的參數(shù)有6\times12個(gè)5\times5的卷積模板w和12個(gè)偏重b(每個(gè)模板對(duì)應(yīng)的偏重都是相同的)
而實(shí)際上由于神經(jīng)網(wǎng)絡(luò)的稀疏結(jié)構(gòu)和減少訓(xùn)練時(shí)間的需要脱衙,該卷積層一般不是利用全連接的侥猬,就比如前面介紹LeNet-5網(wǎng)絡(luò)例驹,只需要利用16個(gè)卷積模板就可以了,而不是全連接的6\times12個(gè)退唠,其連接方法如下眠饮,其最終得到16個(gè)輸出圖像。

這里X表示選擇卷積铜邮,比如第0張輸出圖像是由第0仪召、1、2張輸入圖像分別同第0個(gè)卷積模板卷積相加松蒜,再加上偏重扔茅,經(jīng)過激活函數(shù)得到的。而第15張圖像是由第0秸苗、1召娜、2、3惊楼、4玖瘸、5張輸入圖像分別同第15個(gè)卷積模板卷積相加得到的。

(4)輸出層O5:

采樣層S4后檀咙,我們將得到12張4\times4的圖像雅倒,將所有圖像展開成一維,就得到了12\times4\times4=192位的向量弧可。
輸出層是由輸入192位蔑匣,輸出10位的全連接單層神經(jīng)網(wǎng)絡(luò),共有10個(gè)神經(jīng)元構(gòu)成棕诵,每個(gè)神經(jīng)元都同192位輸入相連裁良,即都有192位的輸入和1位輸出,其處理公式如下校套,這里j表示輸出神經(jīng)元的序號(hào)价脾,i表示輸入的序號(hào)。

所以該層參數(shù)共有192\times10個(gè)權(quán)重w笛匙,和10個(gè)偏重b侨把。

二、卷積神經(jīng)網(wǎng)絡(luò)的相關(guān)數(shù)據(jù)結(jié)構(gòu)

這個(gè)卷積網(wǎng)絡(luò)主要有五層網(wǎng)絡(luò)膳算,主要結(jié)構(gòu)是卷積層座硕、采樣層(Pooling)、卷積層涕蜂、采樣層(Pooling)和全連接的單層神經(jīng)網(wǎng)絡(luò)層(輸出層)华匾,所以我們建立了三個(gè)基本層的結(jié)構(gòu)及一個(gè)總的卷積網(wǎng)絡(luò)結(jié)構(gòu)。

這里結(jié)構(gòu)內(nèi)除了必要的權(quán)重參數(shù),而需要記錄該層輸入輸出數(shù)據(jù)y蜘拉,及需要傳遞到下一層的局部梯度d萨西。

(1)卷積層

// 卷積層
    typedef struct convolutional_layer{
        int inputWidth;   //輸入圖像的寬
        int inputHeight;  //輸入圖像的長(zhǎng)
        int mapSize;      //特征模板的大小,模板一般都是正方形
     
        int inChannels;   //輸入圖像的數(shù)目
        int outChannels;  //輸出圖像的數(shù)目
     
        // 關(guān)于特征模板的權(quán)重分布旭旭,這里是一個(gè)四維數(shù)組
        // 其大小為inChannels*outChannels*mapSize*mapSize大小
        // 這里用四維數(shù)組谎脯,主要是為了表現(xiàn)全連接的形式,實(shí)際上卷積層并沒有用到全連接的形式
        // 這里的例子是DeapLearningToolboox里的CNN例子持寄,其用到就是全連接
        float**** mapData;     //存放特征模塊的數(shù)據(jù)
        float**** dmapData;    //存放特征模塊的數(shù)據(jù)的局部梯度
     
        float* basicData;   //偏置源梭,偏置的大小,為outChannels
        bool isFullConnect; //是否為全連接
        bool* connectModel; //連接模式(默認(rèn)為全連接)
     
        // 下面三者的大小同輸出的維度相同
        float*** v; // 進(jìn)入激活函數(shù)的輸入值
        float*** y; // 激活函數(shù)后神經(jīng)元的輸出
     
        // 輸出像素的局部梯度
        float*** d; // 網(wǎng)絡(luò)的局部梯度,δ值  
    }CovLayer;

(2)采樣層

    // 采樣層 pooling
    typedef struct pooling_layer{
        int inputWidth;   //輸入圖像的寬
        int inputHeight;  //輸入圖像的長(zhǎng)
        int mapSize;      //特征模板的大小
     
        int inChannels;   //輸入圖像的數(shù)目
        int outChannels;  //輸出圖像的數(shù)目
     
        int poolType;     //Pooling的方法
        float* basicData;   //偏置
     
        float*** y; // 采樣函數(shù)后神經(jīng)元的輸出,無激活函數(shù)
        float*** d; // 網(wǎng)絡(luò)的局部梯度,δ值
    }PoolLayer;

(3)全連接的單層神經(jīng)網(wǎng)絡(luò)

    // 輸出層 全連接的神經(jīng)網(wǎng)絡(luò)
    typedef struct nn_layer{
        int inputNum;   //輸入數(shù)據(jù)的數(shù)目
        int outputNum;  //輸出數(shù)據(jù)的數(shù)目
     
        float** wData; // 權(quán)重?cái)?shù)據(jù)稍味,為一個(gè)inputNum*outputNum大小
        float* basicData;   //偏置废麻,大小為outputNum大小
     
        // 下面三者的大小同輸出的維度相同
        float* v; // 進(jìn)入激活函數(shù)的輸入值
        float* y; // 激活函數(shù)后神經(jīng)元的輸出
        float* d; // 網(wǎng)絡(luò)的局部梯度,δ值
     
        bool isFullConnect; //是否為全連接
    }OutLayer;

(4)各層共同組成一個(gè)完整的卷積網(wǎng)絡(luò)

    typedef struct cnn_network{
        int layerNum;
        CovLayer* C1;
        PoolLayer* S2;
        CovLayer* C3;
        PoolLayer* S4;
        OutLayer* O5;
     
        float* e; // 訓(xùn)練誤差
        float* L; // 瞬時(shí)誤差能量
    }CNN;

(5)另外還有一個(gè)用于存放訓(xùn)練參量的結(jié)構(gòu)

    typedef struct train_opts{
        int numepochs; // 訓(xùn)練的迭代次數(shù)
        float alpha; // 學(xué)習(xí)速率
    }CNNOpts;

三、卷積神經(jīng)網(wǎng)絡(luò)的初始化

卷積神經(jīng)網(wǎng)絡(luò)的初始化主要包含了各數(shù)據(jù)的空間初始化及權(quán)重的隨機(jī)賦值模庐,沒有什么復(fù)雜烛愧,按照結(jié)構(gòu)分配空間就可以了,這里不再詳細(xì)贅述了掂碱,可以直接參考代碼內(nèi)cnnsetup()函數(shù)

四怜姿、卷積神經(jīng)網(wǎng)絡(luò)的前向傳播過程

前向傳播過程實(shí)際上就是指輸入圖像數(shù)據(jù),得到輸出結(jié)果的過程疼燥,而后向傳播過程就是將輸出結(jié)果的誤差由后向前傳遞給各層沧卢,各層依次調(diào)整權(quán)重的過程。所以前向傳播過程相比而是比較直觀悴了,而且簡(jiǎn)單的搏恤。

前向傳播過程在項(xiàng)目中主要是由cnnff()函數(shù)完成违寿,下面我們將按層介紹其過程

(1)卷積層C1

卷積層C1共有6個(gè)卷積模板湃交,每個(gè)模板同輸入圖像卷積將會(huì)得到一個(gè)輸出,即共6個(gè)輸出藤巢,以下是圖像的卷積公式:

C1層的相關(guān)代碼搞莺,這里cov()函數(shù)是卷積函數(shù),在mat.cpp是具體的定義掂咒,activation\_Sigma()是激活函數(shù)

        int outSizeW=cnn->S2->inputWidth;
        int outSizeH=cnn->S2->inputHeight;
        // 第一層的傳播
        int i,j,r,c;
        // 第一層輸出數(shù)據(jù)
        nSize mapSize={cnn->C1->mapSize,cnn->C1->mapSize};
        nSize inSize={cnn->C1->inputWidth,cnn->C1->inputHeight};
        nSize outSize={cnn->S2->inputWidth,cnn->S2->inputHeight};
        for(i=0;i<(cnn->C1->outChannels);i++){
            for(j=0;j<(cnn->C1->inChannels);j++){
                float** mapout=cov(cnn->C1->mapData[j][i],mapSize,inputData,inSize,valid);
                addmat(cnn->C1->v[i],cnn->C1->v[i],outSize,mapout,outSize);
                for(r=0;r<outSize.r;r++)
                    free(mapout[r]);
                free(mapout);
            }
            for(r=0;r<outSize.r;r++)
                for(c=0;c<outSize.c;c++)
                    cnn->C1->y[i][r][c]=activation_Sigma(cnn->C1->v[i][r][c],cnn->C1->basicData[i]);
        }

(2)采樣層S2才沧,avgPooling()是平均Pooling函數(shù)

     // 第二層的輸出傳播S2,采樣層
        outSize.c=cnn->C3->inputWidth;
        outSize.r=cnn->C3->inputHeight;
        inSize.c=cnn->S2->inputWidth;
        inSize.r=cnn->S2->inputHeight;
        for(i=0;i<(cnn->S2->outChannels);i++){
            if(cnn->S2->poolType==AvePool)
                avgPooling(cnn->S2->y[i],outSize,cnn->C1->y[i],inSize,cnn->S2->mapSize);
        }

(3)卷積層C3绍刮,同C1很類似

    // 第三層輸出傳播,這里是全連接
        outSize.c=cnn->S4->inputWidth;
        outSize.r=cnn->S4->inputHeight;
        inSize.c=cnn->C3->inputWidth;
        inSize.r=cnn->C3->inputHeight;
        mapSize.c=cnn->C3->mapSize;
        mapSize.r=cnn->C3->mapSize;
        for(i=0;i<(cnn->C3->outChannels);i++){
            for(j=0;j<(cnn->C3->inChannels);j++){
                float** mapout=cov(cnn->C3->mapData[j][i],mapSize,cnn->S2->y[j],inSize,valid);
                addmat(cnn->C3->v[i],cnn->C3->v[i],outSize,mapout,outSize);
                for(r=0;r<outSize.r;r++)
                    free(mapout[r]);
                free(mapout);
            }
            for(r=0;r<outSize.r;r++)
                for(c=0;c<outSize.c;c++)
                    cnn->C3->y[i][r][c]=activation_Sigma(cnn->C3->v[i][r][c],cnn->C3->basicData[i]);
        }

(4)采樣層S4温圆,同S2很類似

    // 第四層的輸出傳播
        inSize.c=cnn->S4->inputWidth;
        inSize.r=cnn->S4->inputHeight;
        outSize.c=inSize.c/cnn->S4->mapSize;
        outSize.r=inSize.r/cnn->S4->mapSize;
        for(i=0;i<(cnn->S4->outChannels);i++){
            if(cnn->S4->poolType==AvePool)
                avgPooling(cnn->S4->y[i],outSize,cnn->C3->y[i],inSize,cnn->S4->mapSize);
        }

(5)輸出層O5

        // 輸出層O5的處理
        // 首先需要將前面的多維輸出展開成一維向量
        float* O5inData=(float*)malloc((cnn->O5->inputNum)*sizeof(float)); 
        for(i=0;i<(cnn->S4->outChannels);i++)
            for(r=0;r<outSize.r;r++)
                for(c=0;c<outSize.c;c++)
                    O5inData[i*outSize.r*outSize.c+r*outSize.c+c]=cnn->S4->y[i][r][c];
     
        nSize nnSize={cnn->O5->inputNum,cnn->O5->outputNum};
        nnff(cnn->O5->v,O5inData,cnn->O5->wData,cnn->O5->basicData,nnSize);
        for(i=0;i<cnn->O5->outputNum;i++)
            cnn->O5->y[i]=activation_Sigma(cnn->O5->v[i],cnn->O5->basicData[i]);  // 這里多加了一個(gè)bias, 感謝wydbyxr的指出!
        free(O5inData);
    }

項(xiàng)目代碼地址:https://github.com/tostq/DeepLearningC/tree/master/CNN

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末孩革,一起剝皮案震驚了整個(gè)濱河市岁歉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌膝蜈,老刑警劉巖锅移,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熔掺,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡非剃,警方通過查閱死者的電腦和手機(jī)置逻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來备绽,“玉大人券坞,你說我怎么就攤上這事》嗡兀” “怎么了报慕?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)压怠。 經(jīng)常有香客問我眠冈,道長(zhǎng),這世上最難降的妖魔是什么菌瘫? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任蜗顽,我火速辦了婚禮,結(jié)果婚禮上雨让,老公的妹妹穿的比我還像新娘雇盖。我一直安慰自己,他們只是感情好栖忠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布崔挖。 她就那樣靜靜地躺著,像睡著了一般庵寞。 火紅的嫁衣襯著肌膚如雪狸相。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天捐川,我揣著相機(jī)與錄音脓鹃,去河邊找鬼。 笑死古沥,一個(gè)胖子當(dāng)著我的面吹牛瘸右,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播岩齿,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼太颤,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了盹沈?” 一聲冷哼從身側(cè)響起龄章,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后瓦堵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體基协,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年菇用,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了澜驮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惋鸥,死狀恐怖杂穷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卦绣,我是刑警寧澤耐量,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站滤港,受9級(jí)特大地震影響廊蜒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜溅漾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一山叮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧添履,春花似錦屁倔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至往衷,卻和暖如春钞翔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背炼绘。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工嗅战, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人俺亮。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像疟呐,于是被迫代替她去往敵國(guó)和親脚曾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容