卷积图解_(图解)一步一步使用CPP实现深度学习中的卷积

【导语】卷积操作在深度学习中的重要性,想必大家都很清楚了。接下来将通过图解的方式,使用cpp一步一步从简单到复杂来实现卷积操作。

  • 符号约定F为输入;width为输入的宽;height为输入的高;channel为输入的通道;K为kernel;kSizeX为kernel的宽;kSizeY为kernel的高;filters为kernel的个数;O为输出;outWidth为输出的宽;outHeight为输出的高;outChannel为输出的通道;

  • 卷积输出尺寸计算公式

  • 1. 最简单的3x3卷积首先, 我们不考虑任何padding, stride, 多维度等情况,来一个最简单的3x3卷积操作.计算思路很简单, 对应元素相乘最后相加即可.此处:

    • width=3

    • height=3

    • channel=1

    • paddingX=0

    • paddingY=0

    • strideX=1

    • strideY=1

    • dilationX=1

    • dilationY=1

    • kSizeX=3

    • kSizeY=3

    • filters=1

      可根据卷积输出尺寸计算公式,得到:

    • outWidth=1

    • outHeight=1

    • outChannel=1

4ddf26b18de94fa634f444740b36de10.png
图1 最简单的3x3卷积

cpp代码:

void demo0()
{
    float F[] = {1,2,3,4,5,6,7,8,9};
    float K[] = {1,2,3,4,5,6,7,8,9};
    float O = 0;

    int width  = 3;
    int height = 3;
    int kSizeX = 3;
    int kSizeY = 3;

    for(int m=0;m    {
        for(int n=0;n        {
            O+=K[m*kSizeX+n]*F[m*width+n];
        }
    }

    std::cout<" ";
}
  • 2. 最简单卷积(1)接下来考虑能适用于任何尺寸的简单卷积, 如输入为4x4x1, kernel为3x3x1. 这里考虑卷积步长为1, 则此处的参数为:

    cpp代码:

    • width=4

    • height=4

    • channel=1

    • paddingX=0

    • paddingY=0

    • strideX=1

    • strideY=1

    • dilationX=1

    • dilationY=1

    • kSizeX=3

    • kSizeY=3

    • filters=1

      可根据卷积输出尺寸计算公式,得到:

    • outWidth=2

    • outHeight=2

    • outChannel=182de461094b73ac24790bc69303d2308.png

      图2 最简单卷积(1)
void demo1()
{
    float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    float K[] = {1,2,3,4,5,6,7,8,9};
    float O[] = {0,0,0,0};

    int padX = 0;
    int padY = 0;

    int dilationX = 1;
    int dilationY = 1;

    int strideX  = 1;
    int strideY  = 1;

    int width = 4;
    int height = 4;

    int kSizeX = 3;
    int kSizeY = 3;

    int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;

    for(int i=0;i    {
        for(int j=0;j        {
            for(int m=0;m            {
                for(int n=0;n                {
                    O[i*outW+j]+=K[m*kSizeX+n]*F[(m+i)*width+(n+j)];
                }
            }
        }
    }

    for (int i = 0; i     {
        for (int j = 0; j         {
            std::cout<" ";
        }
        std::cout<<:endl>    }
}
  • 3. 最简单卷积(2)接下来考虑在步长上为任意步长的卷积,  如输入为4x4x1, kernel为2x2x1. 这里考虑卷积步长为2, 则此处的参数为:

    • width=4

    • height=4

    • channel=1

    • paddingX=0

    • paddingY=0

    • strideX=2

    • strideY=2

    • dilationX=1

    • dilationY=1

    • kSizeX=2

    • kSizeY=2

    • filters=1

      可根据卷积输出尺寸计算公式,得到:

    • outWidth=2

    • outHeight=2

    • outChannel=1

c3e719328b99c9d12dcb96a204ae0429.png
图3 最简单卷积(2)

cpp代码:

void demo2()
{
    float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    float K[] = {1,2,3,4};
    float O[] = {0,0,0,0};

    int padX = 0;
    int padY = 0;

    int dilationX = 1;
    int dilationY = 1;

    int strideX  = 2;
    int strideY  = 2;

    int width = 4;
    int height = 4;

    int kSizeX = 2;
    int kSizeY = 2;

    int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;

    for(int i=0;i    {
        for(int j=0;j        {
            for(int m=0;m            {
                for(int n=0;n                {
                    O[i*outW+j]+=K[m*kSizeX+n]*F[(m+i*strideY)*width+(n+j*strideX)];
                }
            }
        }
    }

    for (int i = 0; i     {
        for (int j = 0; j         {
            std::cout<" ";
        }
        std::cout<<:endl>    }
}
  • 4. 带padding的卷积接下来考虑带padding的卷积,  如输入为4x4x1, kernel为3x3x1. 卷积步长为1, padding为1 则此处的参数为:

    cpp代码:

    • width=4

    • height=4

    • channel=1

    • paddingX=1

    • paddingY=1

    • strideX=1

    • strideY=1

    • dilationX=1

    • dilationY=1

    • kSizeX=3

    • kSizeY=3

    • filters=1

      可根据卷积输出尺寸计算公式,得到:

    • outWidth=2

    • outHeight=2

    • outChannel=1ac4b943ebd5dd139b232311470de5553.png

      图4 考虑padding卷积
void demo3()
{
    float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    float K[] = {1,2,3,4,5,6,7,8,9};
    float O[] = {0,0,0,0};

    int padX = 1;
    int padY = 1;

    int dilationX = 1;
    int dilationY = 1;

    int strideX  = 2;
    int strideY  = 2;

    int width = 4;
    int height = 4;

    int kSizeX = 3;
    int kSizeY = 3;

    int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;

    for(int i=0;i    {
        for(int j=0;j        {
            for(int m=0;m            {
                for(int n=0;n                {
                    float fVal = 0;  
                    //考虑边界强情况
                    if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height) 
                    {
                        fVal = F[(m+i*strideY-padX)*width+(n+j*strideX-padY)];
                    }
                    O[i*outW+j]+=K[m*kSizeX+n]*fVal;
                }
            }
        }
    }

    for (int i = 0; i     {
        for (int j = 0; j         {
            std::cout<" ";
        }
        std::cout<<:endl>    }
}
  • 5. 多通道卷积接下来考虑多通道卷积,  如输入为4x4x1, kernel为3x3x1. 卷积步长为1, padding为1, 输入通道为2, 则此处的参数为:

    cpp代码:

    • width=4

    • height=4

    • channel=2

    • paddingX=1

    • paddingY=1

    • strideX=1

    • strideY=1

    • dilationX=1

    • dilationY=1

    • kSizeX=3

    • kSizeY=3

    • filters=1

      可根据卷积输出尺寸计算公式,得到:

    • outWidth=2

    • outHeight=2

    • outChannel=1768d6c1cfd44cfaafc31d5fdea6bf5ed.png

      图5 多通道卷积
void demo4()
{
    float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9};
    float O[] = {0,0,0,0};

    int padX = 1;
    int padY = 1;

    int dilationX = 1;
    int dilationY = 1;

    int strideX  = 2;
    int strideY  = 2;

    int width = 4;
    int height = 4;

    int kSizeX = 3;
    int kSizeY = 3;

    int channel = 2;

    int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;

    for (int c = 0; c     {
        for(int i=0;i        {
            for(int j=0;j            {
                for(int m=0;m                {
                    for(int n=0;n                    {
                        float fVal = 0;
                        if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height)
                        {
                            fVal = F[c*width*height + (m+i*strideY-padX)*width+(n+j*strideX-padY)];
                        }
                        O[i*outW+j]+=K[c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
                    }
                }
            }
        }
    }

    for (int i = 0; i     {
        for (int j = 0; j         {
            std::cout<" ";
        }
        std::cout<<:endl>    }
}
  • 6. 多kernel卷积接下来考虑多kernel卷积,  如输入为4x4x1, kernel为3x3x1. 卷积步长为1, padding为1, 输入通道为2, filters为2, 则此处的参数为:

    • width=4

    • height=4

    • channel=2

    • paddingX=1

    • paddingY=1

    • strideX=1

    • strideY=1

    • dilationX=1

    • dilationY=1

    • kSizeX=3

    • kSizeY=3

    • filters=2

      可根据卷积输出尺寸计算公式,得到:

    • outWidth=2

    • outHeight=2

    • outChannel=2

4462aababe09886096bfe53d86a74457.png
图6 多kernel卷积

cpp代码:

void demo5()
{
    float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,
                 1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9
                };
    float O[] = {0,0,0,0,0,0,0,0};

    int padX = 1;
    int padY = 1;

    int dilationX = 1;
    int dilationY = 1;

    int strideX  = 2;
    int strideY  = 2;

    int width = 4;
    int height = 4;

    int kSizeX = 3;
    int kSizeY = 3;

    int channel = 2;

    int filters = 2;

    int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;

    int outC = filters;

    for (int oc = 0; oc     {
        for (int c = 0; c         {
            for(int i=0;i            {
                for(int j=0;j                {
                    for(int m=0;m                    {
                        for(int n=0;n                        {
                            float fVal = 0;
                            if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height)
                            {
                                fVal = F[c*width*height + (m+i*strideY-padX)*width+(n+j*strideX-padY)];
                            }
                            O[oc*outH*outW+i*outW+j]+=K[oc*outC*kSizeX*kSizeY+c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
                        }
                    }
                }
            }
        }
    }

    for (int oc = 0; oc     {
        for (int i = 0; i         {
            for (int j = 0; j             {
                std::cout<" ";
            }
            std::cout<<:endl>        }
        std::cout<<:endl>    }
}
  • 7. 膨胀卷积接下来考虑多膨胀卷积,  如输入为4x4x1, kernel为3x3x1. 卷积步长为1, padding为1, 输入通道为2, filters为2, dilate为2则此处的参数为:

    • width=4

    • height=4

    • channel=2

    • paddingX=1

    • paddingY=1

    • strideX=1

    • strideY=1

    • dilationX=2

    • dilationY=2

    • kSizeX=3

    • kSizeY=3

    • filters=2

      可根据卷积输出尺寸计算公式,得到:

    • outWidth=2

    • outHeight=2

    • outChannel=2

2160702964d60571fe0c1cc88393e249.png
图7 膨胀卷积

cpp代码:

void demo6()
{
    float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,
                 1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9
                };
    float O[] = {0,0,0,0,0,0,0,0};

    int padX = 1;
    int padY = 1;

    int dilationX = 2;
    int dilationY = 2;

    int strideX  = 1;
    int strideY  = 1;

    int width = 4;
    int height = 4;

    int kSizeX = 3;
    int kSizeY = 3;

    int channel = 2;

    int filters = 2;

    int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;

    int outC = filters;

    for (int oc = 0; oc     {
        for (int c = 0; c         {
            for(int i=0;i            {
                for(int j=0;j                {
                    for(int m=0;m                    {
                        for(int n=0;n                        {
                            float fVal = 0;
                            if( ((n+j*strideX)*dilationX-padX)>-1 && ((m+i*strideY)*dilationY-padY)>-1&&
                               ((n+j*strideX)*dilationX-padX)<=width && ((m+i*strideY)*dilationY-padY>-1)<=height)
                            {
                                fVal = F[c*width*height + ((m+i*strideY)*dilationX-padX)*width+((n+j*strideX)*dilationY-padY)];
                            }
                            O[oc*outH*outW+i*outW+j]+=K[oc*outC*kSizeX*kSizeY+c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
                        }
                    }
                }
            }
        }
    }

    for (int oc = 0; oc     {
        for (int i = 0; i         {
            for (int j = 0; j             {
                std::cout<" ";
            }
            std::cout<<:endl>        }
        std::cout<<:endl>    }
}
  • git源码https://github.com/msnh2012/ConvTest

推荐阅读:

推荐!CV预训练模型全集!

国内外优秀的计算机视觉团队汇总|最新版

YOLOv4中的数据增强

f884401f96f121f277c28716cfc31c51.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
卷积神经网络(Convolutional Neural Network,CNN)是一种深度学习模型,广泛应用于像识别、语音识别、自然语言处理等领域。Python是一种功能强大的编程语言,具有广泛的应用和支持,而且有许多流行的深度学习框架可供使用,如TensorFlow、PyTorch、Keras等,因此Python成为卷积神经网络实现的首选语言。 通过Python实现卷积神经网络,可以便捷地构建高级深度学习模型。在Python的各种深度学习框架,提供了许多卷积神经网络的类和函数,这些类和函数可以轻松地创建卷积层、池化层和全连接层等各种网络层,并调整参数、优化模型,最终得到一个准确率高、效果好的深度学习模型。 卷积神经网络在Python实现主要分为以下几个步骤: 1.准备数据集:选择对应的数据集,使用Python的数据处理库对数据进行读取、清洗和预处理。 2.构建卷积神经网络模型:使用Python的深度学习框架,通过堆叠卷积层、池化层和全连接层等组成卷积神经网络模型。 3.训练模型:使用Python的深度学习框架对模型进行训练,通过对数据集进行多次迭代训练,对卷积神经网络模型进行优化,提高模型准确率。 4.测试模型:使用Python的深度学习框架对卷积神经网络模型进行测试,测试不同数据集下模型的准确率和性能。 通过Python实现卷积神经网络,可以有效提高深度学习模型的准确度和可靠性,为像识别、语音识别等领域提供了强有力的支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值