Convolution and Max Pooling of CNN (卷积和池化的实现)

Convolution and Max Pooling of CNN (卷积和池化的实现)

  1. 卷积和池化的具体解释(比较清晰直观):
    http://www.hackcv.com/index.php/archives/104/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

  2. 图像卷积的实现

    • 图像卷积的原理图解
      这里写图片描述
    • 具体实现——卷积模板(Filter)
    double filter0[3][3]={{0,0,0},{0,1,0},{0,0,0}};
    double filter1[3][3]={{1/16.0,1/16.0,1/16.0},{1/16.0,8/16.0,1/16.0},{1/16.0,1/16.0,1/16.0}};
    
    double filter2[3][3]={{-1,0,0},{0,1,0},{0,0,0}};
    double filter3[3][3]={{0,-1,0},{0,1,0},{0,0,0}};
    double filter4[3][3]={{0,0,0},{-1,0,1},{0,0,0}};
    double filter5[3][3]={{1.0/9,1.0/9,1.0/9},{1.0/9,1.0/9,1.0/9},{1.0/9,1.0/9,1.0/9}};
    double filter6[3][3]={{0,0,0},{-1,2,-1},{0,0,0}};
    double filter7[3][3]={{0,1,0},{1,-4,1},{0,1,0}};
    
    double filter8[3][3]={{0,0,-1},{0,1,0},{0,0,0}};
    double filter9[3][3]={{0,0,0},{-1,1,0},{0,0,0}};
    double filter10[3][3]={{0,-1,0},{0,0,0},{0,1,0}};
    double filter11[3][3]={{1/16.0,2/16.0,1/16.0},{2/16.0,4/16.0,2/16.0},{1/16.0,2/16.0,1/16.0}};
    double filter12[3][3]={{0,-1,0},{0,2,0},{0,-1,0}};
    double filter13[3][3]={{1,1,1},{1,-7,1},{1,1,1}};
    
    double filter14[3][3]={{0,0,0},{0,1,-1},{0,0,0}};
    double filter15[3][3]={{0,0,0},{0,1,0},{-1,0,0}};
    double filter16[3][3]={{-1,0,0},{0,0,0},{0,0,1}};
    double filter17[3][3]={{1/16.0,1/16.0,1/16.0},{2/16.0,6/16.0,2/16.0},{1/16.0,1/16.0,1/16.0}};
    double filter18[3][3]={{-1,0,0},{0,2,0},{0,0,-1}};
    double filter19[3][3]={{-1,-1,-1},{-1,8,-1},{-1,-1,-1}};
    
    double filter20[3][3]={{0,0,0},{0,1,0},{0,-1,0}};
    double filter21[3][3]={{0,0,0},{0,1,0},{0,0,-1}};
    double filter22[3][3]={{0,0,-1},{0,0,0},{1,0,0}};
    double filter23[3][3]={{1/16.0,2/16.0,1/16.0},{1/16.0,6/16.0,1/16.0},{1/16.0,2/16.0,1/16.0}};
    double filter24[3][3]={{0,0,-1},{0,2,0},{-1,0,0}};
    double filter25[3][3]={{0,-1,0},{-1,5,-1},{0,-1,0}};
    • 具体实现——输入输出数据格式
    typedef struct{
    int W;//图像的宽
    int H;//图像的高
    int num;//图像个数
    byte ***data;//具体数据
    }Data;
    • 具体实现——卷积的实现
    /*
    功能:卷积
    输入:
    Data input:要进行卷积的图像数据的总和
    out_num:指定卷积之后图像的个数
    start_filter:指定从哪一个filter开始进行卷积
    border:true代表保留原图像的边界,图像大小不变;false忽略边界,图像大小发生变化
    输出:
    Data &output:卷积之后的图像的总和
    */
    bool convolution(Data input,Data &output,int out_num,int start_filter,bool border)
    {
    if(!init_output(output,input,out_num,MAX_FILTERS,border))
        return false;
    for(int i=0;i<input.num;i++)
    {
        for(int j=0;j<out_num;j++)
        {
            int filter=(j+start_filter)%MAX_FILTERS;
            if(border)
                convolution_once_border(input.data[i],output.data[j],
                                       input.W,input.H,filter);
            else
                convolution_once_noborder(input.data[i],output.data[j],
                                     input.W,input.H,filter);
        }
    }
    return true;
    }
    /*
    功能:初始化output
    */
    bool init_output(Data &output,Data input,int out_num,int use_filter,bool border)
    {
    cout <<"Conv: ";
    if(input.num*use_filter<out_num)
    {
        cout <<"Inputs :"<<input.num<<" | ";
        cout <<"Filters:"<<use_filter<<" | ";
        cout <<"Max outputs:"<<input.num*use_filter<<endl;
        cout <<"Require outputs:"<<out_num<<endl;
        return false;
    }
    
    if(!border)
    {
        if(input.W<5||input.H<5)
        {
            cout <<"Use border mode, Output Image too small:"<<
                 input.W-2<<" "<<input.H-2<<endl;
            return false;
        }
        output.W=input.W-2;
        output.H=input.H-2;
    }
    else
    {
        output.W=input.W;
        output.H=input.H;
    }
    output.num=out_num;
    printf("Input Image:%d*%d*%d  |  Output Image:%d*%d*%d\n",
              input.num,input.W,input.H,output.num,output.W,output.H);
    malloc_data(output);
    return true;
    }
    /*
    功能:为output的data字段分配实际的空间
    */
    void malloc_data(Data &output)
    {
    output.data=(byte ***)malloc(sizeof(byte **)*output.num);
    for(int i=0;i<output.num;i++)
    {
        output.data[i]=(byte **)malloc(sizeof(byte *)*output.H);
        for(int j=0;j<output.H;j++)
            output.data[i][j]=(byte*)malloc(sizeof(byte)*output.W);
    }
    }
    /*
    功能:考虑边界的单张图像的卷积操作
    输入:
    byte **input:单张图像的数据
    int W,int H:图像的长宽
    int filter:卷积要使用的filter
    输出:
    byte **output
    */
    void convolution_once_border(byte **input,byte **output,int W,int H,int filter)
    {
    double m[3][3]={0};
    for(int r=0;r<H;r++)
    {
        for(int c=0;c<W;c++)
        {
                 //拷贝出3*3大小的矩阵数据用于卷积
            copy_metrix(input,r-1,c-1,W,H,m);
                 //卷积:矩阵乘法
            byte t=(byte)mult_metrix(m,Filters[filter]);
            output[r][c]=t;
        }
    }
    for(int r=0;r<H;r++)
    {
        output[r][0]=output[r][1];
        output[r][W-1]=output[r][W-2];
    }
    for(int c=0;c<W;c++)
    {
        output[0][c]=output[1][c];
        output[H-1][c]=output[H-2][c];
    }
    }
    
    /*
    功能:不考虑边界的单张图像的卷积操作
    输入:
    byte **input:单张图像的数据
    int W,int H:图像的长宽
    int filter:卷积要使用的filter
    输出:
    byte **output
    */
    oid convolution_once_noborder(byte **input,byte **output,int W,int H,int filter)
    {
    double m[3][3];
    for(int r=1;r<H-1;r++)
    {
        for(int c=1;c<W-1;c++)
        {
            copy_metrix(input,r-1,c-1,W,H,m);
            output[r-1][c-1]=(byte)mult_metrix(m,Filters[filter]);
        }
    }
    }
    /*
    功能:拷贝用于卷积运算的3*3矩阵
    输入:
    byte **input:单张图像的数据
    int r,int c:3*3矩阵的(0,0)点的实际位置
    int W,int H:图像的长宽
    输出:
    double m[3][3]
    */
    void copy_metrix(byte **input,int r,int c,int W,int H,double m[3][3])
    {
    for(int i=0;i<3;i++)
    {
        for(int j=0;j<3;j++)
        {
            int t1=r+i;
            int t2=c+j;
            if(t1<0)t1=0;
            if(t2<0)t2=0;
            if(t1>=H)t1=H-1;
            if(t2>=W)t2=W-1;
            m[i][j]=input[t1][t2];
        }
    }
    }
  3. 最大池化的实现

    • 最大池化的原理
      这里写图片描述

    • 具体实现

    /*
    功能:最大池化
    输入:
    Data input:要进行池化的图像数据的总和
    int step:池化的步长,上图中的窗口大小
    输出:
    Data &output:池化之后的图像的总和
    */
    bool max_pooling(Data input,Data &output,int step)
    {
    if(!init_output(input,output,step))
        return false;
    for(int i=0;i<input.num;i++)
    {
        max_pooling_once(input.data[i],output.data[i],
                            input.W,input.H,output.W,output.H,step);
    }
    return true;
    }
    /*
    功能:初始化output
    */
    bool init_output(Data input,Data &output,int step)
    {
    cout <<"Pooling:";
    if(input.W/step+1<3||input.H/step+1<3)
    {
        cout <<"The Output Image too small:"<<input.W/step+1<<" "<<input.H/step+1<<endl;
        return false;
    }
    output.num=input.num;
    output.H=input.H/step+1;
    output.W=input.W/step+1;
    printf("Input Image:%d*%d*%d  |  Output Image:%d*%d*%d\n",input.num,input.W,input.H,output.num,output.W,output.H);
    malloc_data(output);
    return true;
    }
    /*
    功能:单张图像的最大池化操作
    输入:
    byte **input:单张图像的数据
    int W,int H:图像的长宽
    int dW,int dH:目的图像的长宽
    int step:池化步长
    输出:
    byte **output
    */
    void max_pooling_once(byte **input,byte **output,int W,int H,int dW,int dH,int step)
    {
    byte *m=(byte *)malloc(sizeof(byte)*step*step);
    for(int r=0;r<dH;r++)
    {
        for(int c=0;c<dW;c++)
        {
            copy_array(input,r*step,c*step,W,H,step,m);
            output[r][c]=find_max(m,step);
        }
    }
    }
    
    //  功能:拷贝池化窗口内的数据到数组内
    void copy_array(byte **input,int r,int c,int W,int H,int step,byte *m)
    {
    for(int i=0;i<step;i++)
    {
        for(int j=0;j<step;j++)
        {
            int t1=r+i;
            int t2=c+j;
            if(t1>=H)t1=H-1;
            if(t2>=W)t2=W-1;
            m[i*step+j]=input[t1][t2];
        }
    }
    }
    /*
    功能:寻找数组中的最大值
    */
    byte find_max(byte *m,int step)
    {
    int l=step*step;
    int max=0;
    for(int i=0;i<l;i++)
        if(m[i]>max)
            max=m[i];
    return max;
    }
  4. 示例结果

    输出数据
    Raw Image Size (516*415) convert to (500*400)
    Conv: Input Image:1*500*400  |  Output Image:18*500*400
    Pooling:Input Image:18*500*400  |  Output Image:18*126*101
    Conv: Input Image:18*126*101  |  Output Image:36*126*101
    Pooling:Input Image:36*126*101  |  Output Image:36*32*26
    Conv: Input Image:36*32*26  |  Output Image:161*32*26
    Pooling:Input Image:161*32*26  |  Output Image:161*17*14
    Conv: Input Image:161*17*14  |  Output Image:528*17*14
    Pooling:Input Image:528*17*14  |  Output Image:528*9*8

    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述

github:https://github.com/Shuiliusheng/2018/tree/master/C-_for_NN/Feature-Convolution_and_Pool

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shuiliusheng/article/details/79949113
个人分类: computer
上一篇MNIST的手写数字识别
下一篇An Event-Triggered Programmable Prefetcher for Irregular Workloads (2018 asplos)
想对作者说点什么? 我来说一句

CNN详细介绍

2018年05月09日 766KB 下载

UFLDL exercise9 Convolution and Pooling

2016年04月13日 1.48MB 下载

max pooling with dropout

2014年03月31日 10.28MB 下载

进阶CNN对cifar10分类

2017年08月23日 5KB 下载

Java实现卷积神经网络(CNN)

2017年11月18日 1.81MB 下载

卷积与反卷积运算

2018年05月13日 5.2MB 下载

深度学习框架mxnet源码

2016年05月03日 1.77MB 下载

没有更多推荐了,返回首页

关闭
关闭