#### 卷积输出尺寸计算公式

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

#### outChannel=1

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<kSizeY;m++)
{
for(int n=0;n<kSizeX;n++)
{
O+=K[m*kSizeX+n]*F[m*width+n];
}
}
std::cout<<O<<" ";
}
``````

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

cpp代码:

#### outHeight=2

outChannel=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 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<outH;i++)
{
for(int j=0;j<outW;j++)
{
for(int m=0;m<kSizeY;m++)
{
for(int n=0;n<kSizeX;n++)
{
O[i*outW+j]+=K[m*kSizeX+n]*F[(m+i)*width+(n+j)];
}
}
}
}
for (int i = 0; i < outH; ++i)
{
for (int j = 0; j < outW; ++j)
{
std::cout<<O[i*outW+j]<<" ";
}
std::cout<<std::endl;
}
}
``````

3. 最简单卷积(2)接下来考虑在步长上为任意步长的卷积,  如输入为4x4x1, kernel为2x2x1. 这里考虑卷积步长为2, 则此处的参数为:

#### outChannel=1

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 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<outH;i++)
{
for(int j=0;j<outW;j++)
{
for(int m=0;m<kSizeY;m++)
{
for(int n=0;n<kSizeX;n++)
{
O[i*outW+j]+=K[m*kSizeX+n]*F[(m+i*strideY)*width+(n+j*strideX)];
}
}
}
}
for (int i = 0; i < outH; ++i)
{
for (int j = 0; j < outW; ++j)
{
std::cout<<O[i*outW+j]<<" ";
}
std::cout<<std::endl;
}
}
``````

cpp代码:

#### outHeight=2

outChannel=1

``````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 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<outH;i++)
{
for(int j=0;j<outW;j++)
{
for(int m=0;m<kSizeY;m++)
{
for(int n=0;n<kSizeX;n++)
{
float fVal = 0;

{
}
O[i*outW+j]+=K[m*kSizeX+n]*fVal;
}
}
}
}
for (int i = 0; i < outH; ++i)
{
for (int j = 0; j < outW; ++j)
{
std::cout<<O[i*outW+j]<<" ";
}
std::cout<<std::endl;
}
}
``````

5. 多通道卷积接下来考虑多通道卷积,  如输入为4x4x1, kernel为3x3x1. 卷积步长为1, padding为1, 输入通道为2, 则此处的参数为:

cpp代码:

#### outHeight=2

outChannel=1

``````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 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 < channel; ++c)
{
for(int i=0;i<outH;i++)
{
for(int j=0;j<outW;j++)
{
for(int m=0;m<kSizeY;m++)
{
for(int n=0;n<kSizeX;n++)
{
float fVal = 0;
{
}
O[i*outW+j]+=K[c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
}
}
}
}
}
for (int i = 0; i < outH; ++i)
{
for (int j = 0; j < outW; ++j)
{
std::cout<<O[i*outW+j]<<" ";
}
std::cout<<std::endl;
}
}
``````

6. 多kernel卷积接下来考虑多kernel卷积,  如输入为4x4x1, kernel为3x3x1. 卷积步长为1, padding为1, 输入通道为2, filters为2, 则此处的参数为:

#### outChannel=2

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 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 < outC; ++oc)
{
for (int c = 0; c < channel; ++c)
{
for(int i=0;i<outH;i++)
{
for(int j=0;j<outW;j++)
{
for(int m=0;m<kSizeY;m++)
{
for(int n=0;n<kSizeX;n++)
{
float fVal = 0;
{
}
O[oc*outH*outW+i*outW+j]+=K[oc*outC*kSizeX*kSizeY+c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
}
}
}
}
}
}
for (int oc = 0; oc < outC; ++oc)
{
for (int i = 0; i < outH; ++i)
{
for (int j = 0; j < outW; ++j)
{
std::cout<<O[oc*outH*outW+i*outW+j]<<" ";
}
std::cout<<std::endl;
}
std::cout<<std::endl<<std::endl;
}
}
``````

7. 膨胀卷积接下来考虑多膨胀卷积,  如输入为4x4x1, kernel为3x3x1. 卷积步长为1, padding为1, 输入通道为2, filters为2, dilate为2则此处的参数为:

#### outChannel=2

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 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 < outC; ++oc)
{
for (int c = 0; c < channel; ++c)
{
for(int i=0;i<outH;i++)
{
for(int j=0;j<outW;j++)
{
for(int m=0;m<kSizeY;m++)
{
for(int n=0;n<kSizeX;n++)
{
float fVal = 0;
{
}
O[oc*outH*outW+i*outW+j]+=K[oc*outC*kSizeX*kSizeY+c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
}
}
}
}
}
}
for (int oc = 0; oc < outC; ++oc)
{
for (int i = 0; i < outH; ++i)
{
for (int j = 0; j < outW; ++j)
{
std::cout<<O[oc*outH*outW+i*outW+j]<<" ";
}
std::cout<<std::endl;
}
std::cout<<std::endl;
}
}
``````

git源码https://github.com/msnh2012/ConvTest