• CNN学习(7):用C++实现简单不同参数的卷积模型


    目录

    一、参数说明和计算公式

    1、符号约定

    2、输出大小计算公式

    二、不同类型的卷积

    1、输入3*3*1,卷积核3*3*1,输出1*1*1

    (1)实现代码

    (2)代码说明

    2、输入4*4*1,卷积核3*3*1,步长1*1,输出2*2*1

    (1)实现代码

    (2)代码说明

    3、输入4*4*1,卷积核2*2*1,步长2*2,输出2*2*1

    (1)实现代码

    4、输入4*4*1,卷积核3*3*1,步长1*1,padding为1*1,输出2*2*1

    ​编辑

    (1)实现代码

    (2)代码说明

    5、输入4*4*2,卷积核3*3*2,步长1*1,padding为1*1,输出2*2*1

    (1)实现代码

    6、输入4*4*1,卷积核3*3*1,卷积核个数2,步长1*1,padding为1*1,输出2*2*1

    (1)实现代码

    (2)代码说明

    7、输入4*4*2,卷积核3*3*2,步长1*1,padding为1*1,膨胀系数2,输出2*2*2

    三、可执行的卷积操作代码


    参考资料:

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

    其实在上述链接里已经写的非常详细了,为了便于后续理解和学习,所以写个理解的备忘录。

    一、参数说明和计算公式

    1、符号约定

    1. F[] 为输入;
    2. width 为输入的宽;
    3. height 为输入的高;
    4. channel 为输入的通道;
    5. K[] 为 kernel;
    6. kSizeX 为 kernel 的宽;
    7. kSizeY 为 kernel 的高;
    8. filters 为 kernel 的个数;
    9. padX 为水平方向的填充;
    10. padY 为垂直方向的填充;
    11. strideX 为水平方向的步长;
    12. strideY 为垂直方向的步长;
    13. O[] 为输出;
    14. outW 为输出的宽;
    15. outH 为输出的高;
    16. outChannel 为输出的通道;

    2、输出大小计算公式

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

    公式说明:

    • height + 2 * padY: 首先,将输入图像的高度加上两倍的填充量,这是因为填充是对称地加在图像的顶部和底部。

    • dilationY * (kSizeY - 1): 这是计算卷积核中除了中心元素外,其他元素之间的总间隔。kSizeY - 1表示卷积核的高度减去中心元素,乘以膨胀系数dilationY,得到这些元素之间的间隔数。

    • dilationY * (kSizeY - 1) + 1: 将上述间隔数加上1,是因为我们还要包括卷积核的中心元素。

    • (height + 2 * padY - (dilationY * (kSizeY - 1) + 1)): 这个表达式计算了在考虑填充和膨胀后,输入图像实际上被卷积核覆盖的区域的高度。

    • / strideY: 将上述计算得到的高度除以步长,得到在垂直方向上卷积核可以覆盖的步数。

    • + 1: 最后,由于输出的高度至少要有一个元素,即使计算结果为0,我们也需要加1,以确保输出尺寸至少为1。

    二、不同类型的卷积

    1、输入3*3*1,卷积核3*3*1,输出1*1*1

    (1)实现代码

    封装成demo0(),main()函数可直接调用

    1. void demo0()
    2. {
    3. float F[] = {1,2,3,4,5,6,7,8,9};
    4. float K[] = {1,2,3,4,5,6,7,8,9};
    5. float O = 0;
    6. int width = 3;
    7. int height = 3;
    8. int kSizeX = 3;
    9. int kSizeY = 3;
    10. for(int m=0;m
    11. {
    12. for(int n=0;n
    13. {
    14. O+=K[m*kSizeX+n]*F[m*width+n];
    15. }
    16. }
    17. std::cout<" ";
    18. }

    (2)代码说明

    1. 前面都是定义输入矩阵和卷积核,同时定义一个浮点数变量O并初始化为0,用于累加结果。
    2. 两个嵌套循环遍历卷积核的每个元素:
      1. for(int m=0; m
      2. for(int n=0; n
      3. 嵌套循环内部,O += K[m*kSizeX + n] * F[m*width + n];用来执行卷积操作。这行代码将卷积核的当前元素 K[m*kSizeX + n] 与输入矩阵的对应元素 F[m*width + n] 相乘,并将结果累加到 O 中【其中位置是相同的,m只是用来决定以kSize为单位的轮次】。

    2、输入4*4*1,卷积核3*3*1,步长1*1,输出2*2*1

    (1)实现代码

    1. void demo1()
    2. {
    3. float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    4. float K[] = {1,2,3,4,5,6,7,8,9};
    5. float O[] = {0,0,0,0};
    6. int padX = 0;
    7. int padY = 0;
    8. int dilationX = 1;
    9. int dilationY = 1;
    10. int strideX = 1;
    11. int strideY = 1;
    12. int width = 4;
    13. int height = 4;
    14. int kSizeX = 3;
    15. int kSizeY = 3;
    16. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    17. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    18. for(int i=0;i
    19. {
    20. for(int j=0;j
    21. {
    22. for(int m=0;m
    23. {
    24. for(int n=0;n
    25. {
    26. O[i*outW+j]+=K[m*kSizeX+n]*F[(m+i)*width+(n+j)];
    27. }
    28. }
    29. }
    30. }
    31. for (int i = 0; i < outH; ++i)
    32. {
    33. for (int j = 0; j < outW; ++j)
    34. {
    35. std::cout<" ";
    36. }
    37. std::cout<
    38. }
    39. }

    (2)代码说明

    1. 前面都是定义输入矩阵和卷积核,同时定义一个浮点数变量O并初始化【和前面后面一样,都是先计算出来输出结果的大小,然后再执行】,用于累加结果。
    2. 四个嵌套循环开始进行卷积计算:
      1. 外层两个循环遍历输出特征图的每个位置。
      2. 内层两个循环遍历卷积核的每个元素。
    3. 在内层循环中,计算卷积核覆盖的输入特征图区域的加权和,并将结果累加到输出特征图的相应位置。

    3、输入4*4*1,卷积核2*2*1,步长2*2,输出2*2*1

    (1)实现代码

    1. void demo2()
    2. {
    3. // (height + 2 * paddingY - (dilationY * (kSizeY - 1) + 1)) / strideY + 1;
    4. // (width + 2 * paddingX - (dilationX * (kSizeX - 1) + 1)) / strideX + 1;
    5. float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    6. float K[] = {1,2,3,4};
    7. //float K[] = {1,2,3,4,5,6,7,8,9};
    8. float O[] = {0,0,0,0};
    9. int padX = 0;
    10. int padY = 0;
    11. int dilationX = 1;
    12. int dilationY = 1;
    13. int strideX = 2;
    14. int strideY = 2;
    15. int width = 4;
    16. int height = 4;
    17. int kSizeX = 2;
    18. int kSizeY = 2;
    19. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    20. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    21. for(int i=0;i
    22. {
    23. for(int j=0;j
    24. {
    25. for(int m=0;m
    26. {
    27. for(int n=0;n
    28. {
    29. O[i*outW+j]+=K[m*kSizeX+n]*F[(m+i*strideY)*width+(n+j*strideX)];
    30. }
    31. }
    32. }
    33. }
    34. for (int i = 0; i < outH; ++i)
    35. {
    36. for (int j = 0; j < outW; ++j)
    37. {
    38. std::cout<" ";
    39. }
    40. std::cout<
    41. }
    42. }

    这个和上一段代码解释相同,只不过步长和卷积核大小有改变。

    4、输入4*4*1,卷积核3*3*1,步长1*1,padding为1*1,输出2*2*1

    (1)实现代码

    1. void demo3()
    2. {
    3. float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    4. float K[] = {1,2,3,4,5,6,7,8,9};
    5. float O[] = {0,0,0,0};
    6. int padX = 1;
    7. int padY = 1;
    8. int dilationX = 1;
    9. int dilationY = 1;
    10. int strideX = 2;
    11. int strideY = 2;
    12. int width = 4;
    13. int height = 4;
    14. int kSizeX = 3;
    15. int kSizeY = 3;
    16. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    17. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    18. for(int i=0;i
    19. {
    20. for(int j=0;j
    21. {
    22. for(int m=0;m
    23. {
    24. for(int n=0;n
    25. {
    26. float fVal = 0;
    27. //考虑边界强情况
    28. if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height)
    29. {
    30. fVal = F[(m+i*strideY-padX)*width+(n+j*strideX-padY)];
    31. }
    32. O[i*outW+j]+=K[m*kSizeX+n]*fVal;
    33. }
    34. }
    35. }
    36. }
    37. for (int i = 0; i < outH; ++i)
    38. {
    39. for (int j = 0; j < outW; ++j)
    40. {
    41. std::cout<" ";
    42. }
    43. std::cout<
    44. }
    45. }

    (2)代码说明

    按照正常计算输出规模公式计算的话,应该输出是4*4*1。但是考虑到边界墙问题。

    if 语句块用来检查当前卷积核的 mn 索引是否在输入特征图的边界内。这里考虑了填充(padding)的情况:

    • (n+j*strideX - padX) 计算了卷积核的左边界在输入特征图上的索引。
    • (m+i*strideY - padY) 计算了卷积核的上边界在输入特征图上的索引。
    • 条件 > -1 确保索引不会是负数。
    • 条件 <= width 和 <= height 确保索引不会超出输入特征图的边界。

    5、输入4*4*2,卷积核3*3*2,步长1*1,padding为1*1,输出2*2*1

    其中依旧考虑了边界墙问题。

    (1)实现代码

    1. void demo4()
    2. {
    3. 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};
    4. float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9};
    5. float O[] = {0,0,0,0};
    6. int padX = 1;
    7. int padY = 1;
    8. int dilationX = 1;
    9. int dilationY = 1;
    10. int strideX = 2;
    11. int strideY = 2;
    12. int width = 4;
    13. int height = 4;
    14. int kSizeX = 3;
    15. int kSizeY = 3;
    16. int channel = 2;
    17. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    18. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    19. for (int c = 0; c < channel; ++c)
    20. {
    21. for(int i=0;i
    22. {
    23. for(int j=0;j
    24. {
    25. for(int m=0;m
    26. {
    27. for(int n=0;n
    28. {
    29. float fVal = 0;
    30. if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height)
    31. {
    32. fVal = F[c*width*height + (m+i*strideY-padX)*width+(n+j*strideX-padY)];
    33. }
    34. O[i*outW+j]+=K[c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
    35. }
    36. }
    37. }
    38. }
    39. }
    40. for (int i = 0; i < outH; ++i)
    41. {
    42. for (int j = 0; j < outW; ++j)
    43. {
    44. std::cout<" ";
    45. }
    46. std::cout<
    47. }
    48. }

    6、输入4*4*1,卷积核3*3*1,卷积核个数2,步长1*1,padding为1*1,输出2*2*1

    (1)实现代码

    1. void demo5()
    2. {
    3. 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};
    4. float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,
    5. 1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9
    6. };
    7. float O[] = {0,0,0,0,0,0,0,0};
    8. int padX = 1;
    9. int padY = 1;
    10. int dilationX = 1;
    11. int dilationY = 1;
    12. int strideX = 2;
    13. int strideY = 2;
    14. int width = 4;
    15. int height = 4;
    16. int kSizeX = 3;
    17. int kSizeY = 3;
    18. int channel = 2;
    19. int filters = 2;
    20. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    21. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    22. int outC = filters;
    23. for (int oc = 0; oc < outC; ++oc)
    24. {
    25. for (int c = 0; c < channel; ++c)
    26. {
    27. for(int i=0;i
    28. {
    29. for(int j=0;j
    30. {
    31. for(int m=0;m
    32. {
    33. for(int n=0;n
    34. {
    35. float fVal = 0;
    36. if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height)
    37. {
    38. fVal = F[c*width*height + (m+i*strideY-padX)*width+(n+j*strideX-padY)];
    39. }
    40. O[oc*outH*outW+i*outW+j]+=K[oc*outC*kSizeX*kSizeY+c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
    41. }
    42. }
    43. }
    44. }
    45. }
    46. }
    47. for (int oc = 0; oc < outC; ++oc)
    48. {
    49. for (int i = 0; i < outH; ++i)
    50. {
    51. for (int j = 0; j < outW; ++j)
    52. {
    53. std::cout<" ";
    54. }
    55. std::cout<
    56. }
    57. std::cout<
    58. }
    59. }

    (2)代码说明

    1. 六个嵌套循环实现了卷积操作

      • 最外层循环遍历输出特征图的每个通道。
      • 第二个循环遍历输入特征图的每个通道。
      • 第三个和第四个循环遍历输出特征图的每个元素。
      • 最内层两个循环遍历每个卷积核的元素。
    2. 在最内层循环中,首先检查当前卷积核的索引是否在输入特征图的边界内,如果是,则从输入特征图中取出相应的元素 fVal

    3. 然后,将 fVal 与对应卷积核的元素相乘,并将结果累加到输出特征图的对应位置。

    7、输入4*4*2,卷积核3*3*2,步长1*1,padding为1*1,膨胀系数2,输出2*2*2

    1. void demo6()
    2. {
    3. 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};
    4. float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,
    5. 1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9
    6. };
    7. float O[] = {0,0,0,0,0,0,0,0};
    8. int padX = 1;
    9. int padY = 1;
    10. int dilationX = 2;
    11. int dilationY = 2;
    12. int strideX = 1;
    13. int strideY = 1;
    14. int width = 4;
    15. int height = 4;
    16. int kSizeX = 3;
    17. int kSizeY = 3;
    18. int channel = 2;
    19. int filters = 2;
    20. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    21. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    22. int outC = filters;
    23. for (int oc = 0; oc < outC; ++oc)
    24. {
    25. for (int c = 0; c < channel; ++c)
    26. {
    27. for(int i=0;i
    28. {
    29. for(int j=0;j
    30. {
    31. for(int m=0;m
    32. {
    33. for(int n=0;n
    34. {
    35. float fVal = 0;
    36. if( ((n+j*strideX)*dilationX-padX)>-1 && ((m+i*strideY)*dilationY-padY)>-1&&
    37. ((n+j*strideX)*dilationX-padX)<=width && ((m+i*strideY)*dilationY-padY>-1)<=height)
    38. {
    39. fVal = F[c*width*height + ((m+i*strideY)*dilationX-padX)*width+((n+j*strideX)*dilationY-padY)];
    40. }
    41. O[oc*outH*outW+i*outW+j]+=K[oc*outC*kSizeX*kSizeY+c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
    42. }
    43. }
    44. }
    45. }
    46. }
    47. }
    48. for (int oc = 0; oc < outC; ++oc)
    49. {
    50. for (int i = 0; i < outH; ++i)
    51. {
    52. for (int j = 0; j < outW; ++j)
    53. {
    54. std::cout<" ";
    55. }
    56. std::cout<
    57. }
    58. std::cout<
    59. }
    60. }

    三、可执行的卷积操作代码

    1. #include
    2. void demo0() //输入3*3*1,卷积核3*3*1,输出为1*1*1
    3. {
    4. float F[] = {1,2,3,4,5,6,7,8,9};
    5. float K[] = {1,2,3,4,5,6,7,8,9};
    6. float O = 0;
    7. int width = 3;
    8. int height = 3;
    9. int kSizeX = 3;
    10. int kSizeY = 3;
    11. for(int m=0;m
    12. {
    13. for(int n=0;n
    14. {
    15. O+=K[m*kSizeX+n]*F[m*width+n];
    16. }
    17. }
    18. std::cout<" ";
    19. }
    20. void demo1() //输入4*4*1,卷积核3*3*1,步长为1*1,no padding,输出为1*1*1
    21. {
    22. //计算公式
    23. // (height + 2 * paddingY - (dilationY * (kSizeY - 1) + 1)) / strideY + 1;
    24. // (width + 2 * paddingX - (dilationX * (kSizeX - 1) + 1)) / strideX + 1;
    25. float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    26. float K[] = {1,2,3,4,5,6,7,8,9};
    27. float O[] = {0,0,0,0};
    28. int padX = 0;
    29. int padY = 0;
    30. int dilationX = 1;
    31. int dilationY = 1;
    32. int strideX = 1;
    33. int strideY = 1;
    34. int width = 4;
    35. int height = 4;
    36. int kSizeX = 3;
    37. int kSizeY = 3;
    38. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    39. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    40. for(int i=0;i
    41. {
    42. for(int j=0;j
    43. {
    44. for(int m=0;m
    45. {
    46. for(int n=0;n
    47. {
    48. O[i*outW+j]+=K[m*kSizeX+n]*F[(m+i)*width+(n+j)];
    49. /* int inputIndex = (i * strideY + m) * width + (j * strideX + n);
    50. O[i * outW + j] += K[m * kSizeX + n] * F[inputIndex]; */
    51. }
    52. }
    53. }
    54. }
    55. for (int i = 0; i < outH; ++i)
    56. {
    57. for (int j = 0; j < outW; ++j)
    58. {
    59. std::cout<" ";
    60. }
    61. std::cout<
    62. }
    63. }
    64. void demo2()
    65. {
    66. float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    67. float K[] = {1,2,3,4};
    68. //float K[] = {1,2,3,4,5,6,7,8,9};
    69. float O[] = {0,0,0,0};
    70. int padX = 0;
    71. int padY = 0;
    72. int dilationX = 1;
    73. int dilationY = 1;
    74. int strideX = 2;
    75. int strideY = 2;
    76. int width = 4;
    77. int height = 4;
    78. int kSizeX = 2;
    79. int kSizeY = 2;
    80. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    81. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    82. for(int i=0;i
    83. {
    84. for(int j=0;j
    85. {
    86. for(int m=0;m
    87. {
    88. for(int n=0;n
    89. {
    90. O[i*outW+j]+=K[m*kSizeX+n]*F[(m+i*strideY)*width+(n+j*strideX)];
    91. }
    92. }
    93. }
    94. }
    95. for (int i = 0; i < outH; ++i)
    96. {
    97. for (int j = 0; j < outW; ++j)
    98. {
    99. std::cout<" ";
    100. }
    101. std::cout<
    102. }
    103. }
    104. void demo3()
    105. {
    106. float F[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
    107. //float K[] = {1,2,3,4};
    108. float K[] = {1,2,3,4,5,6,7,8,9};
    109. float O[] = {0,0,0,0};
    110. int padX = 1;
    111. int padY = 1;
    112. int dilationX = 1;
    113. int dilationY = 1;
    114. int strideX = 2;
    115. int strideY = 2;
    116. int width = 4;
    117. int height = 4;
    118. int kSizeX = 3;
    119. int kSizeY = 3;
    120. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    121. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    122. for(int i=0;i
    123. {
    124. for(int j=0;j
    125. {
    126. for(int m=0;m
    127. {
    128. for(int n=0;n
    129. {
    130. float fVal = 0;
    131. //考虑边界强情况
    132. if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height)
    133. {
    134. fVal = F[(m+i*strideY-padX)*width+(n+j*strideX-padY)];
    135. }
    136. O[i*outW+j]+=K[m*kSizeX+n]*fVal;
    137. }
    138. }
    139. }
    140. }
    141. for (int i = 0; i < outH; ++i)
    142. {
    143. for (int j = 0; j < outW; ++j)
    144. {
    145. std::cout<" ";
    146. }
    147. std::cout<
    148. }
    149. }
    150. void demo4()
    151. {
    152. 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};
    153. //float K[] = {1,2,3,4};
    154. float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9};
    155. float O[] = {0,0,0,0};
    156. int padX = 1;
    157. int padY = 1;
    158. int dilationX = 1;
    159. int dilationY = 1;
    160. int strideX = 2;
    161. int strideY = 2;
    162. int width = 4;
    163. int height = 4;
    164. int kSizeX = 3;
    165. int kSizeY = 3;
    166. int channel = 2;
    167. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    168. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    169. for (int c = 0; c < channel; ++c)
    170. {
    171. for(int i=0;i
    172. {
    173. for(int j=0;j
    174. {
    175. for(int m=0;m
    176. {
    177. for(int n=0;n
    178. {
    179. float fVal = 0;
    180. if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height)
    181. {
    182. fVal = F[c*width*height + (m+i*strideY-padX)*width+(n+j*strideX-padY)];
    183. }
    184. O[i*outW+j]+=K[c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
    185. }
    186. }
    187. }
    188. }
    189. }
    190. for (int i = 0; i < outH; ++i)
    191. {
    192. for (int j = 0; j < outW; ++j)
    193. {
    194. std::cout<" ";
    195. }
    196. std::cout<
    197. }
    198. }
    199. void demo5()
    200. {
    201. 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};
    202. //float K[] = {1,2,3,4};
    203. float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,
    204. 1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9
    205. };
    206. float O[] = {0,0,0,0,0,0,0,0};
    207. int padX = 1;
    208. int padY = 1;
    209. int dilationX = 1;
    210. int dilationY = 1;
    211. int strideX = 2;
    212. int strideY = 2;
    213. int width = 4;
    214. int height = 4;
    215. int kSizeX = 3;
    216. int kSizeY = 3;
    217. int channel = 2;
    218. int filters = 2;
    219. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    220. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    221. int outC = filters;
    222. for (int oc = 0; oc < outC; ++oc)
    223. {
    224. for (int c = 0; c < channel; ++c)
    225. {
    226. for(int i=0;i
    227. {
    228. for(int j=0;j
    229. {
    230. for(int m=0;m
    231. {
    232. for(int n=0;n
    233. {
    234. float fVal = 0;
    235. if((n+j*strideX-padX)>-1&&(m+i*strideY-padY>-1)&&(n+j*strideX-padX)<=width&&(m+i*strideY-padY>-1)<=height)
    236. {
    237. fVal = F[c*width*height + (m+i*strideY-padX)*width+(n+j*strideX-padY)];
    238. }
    239. O[oc*outH*outW+i*outW+j]+=K[oc*channel*kSizeX*kSizeY+c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
    240. }
    241. }
    242. }
    243. }
    244. }
    245. }
    246. for (int oc = 0; oc < outC; ++oc)
    247. {
    248. for (int i = 0; i < outH; ++i)
    249. {
    250. for (int j = 0; j < outW; ++j)
    251. {
    252. std::cout<" ";
    253. }
    254. std::cout<
    255. }
    256. std::cout<
    257. }
    258. }
    259. void demo6()
    260. {
    261. // (height + 2 * paddingY - (dilationY * (kSizeY - 1) + 1)) / strideY + 1;
    262. // (width + 2 * paddingX - (dilationX * (kSizeX - 1) + 1)) / strideX + 1;
    263. 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};
    264. //float K[] = {1,2,3,4};
    265. float K[] = {1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,
    266. 1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9
    267. };
    268. float O[] = {0,0,0,0,0,0,0,0};
    269. int padX = 1;
    270. int padY = 1;
    271. int dilationX = 2;
    272. int dilationY = 2;
    273. int strideX = 1;
    274. int strideY = 1;
    275. int width = 4;
    276. int height = 4;
    277. int kSizeX = 3;
    278. int kSizeY = 3;
    279. int channel = 2;
    280. int filters = 2;
    281. int outH = (height+2*padY-(dilationY*(kSizeY-1)+1)) / strideY + 1;
    282. int outW = (width+2*padX-(dilationX*(kSizeX-1)+1)) / strideX + 1;
    283. int outC = filters;
    284. for (int oc = 0; oc < outC; ++oc)
    285. {
    286. for (int c = 0; c < channel; ++c)
    287. {
    288. for(int i=0;i
    289. {
    290. for(int j=0;j
    291. {
    292. for(int m=0;m
    293. {
    294. for(int n=0;n
    295. {
    296. float fVal = 0;
    297. if( ((n+j*strideX)*dilationX-padX)>-1 && ((m+i*strideY)*dilationY-padY)>-1&&
    298. ((n+j*strideX)*dilationX-padX)<=width && ((m+i*strideY)*dilationY-padY>-1)<=height)
    299. {
    300. fVal = F[c*width*height + ((m+i*strideY)*dilationX-padX)*width+((n+j*strideX)*dilationY-padY)];
    301. }
    302. O[oc*outH*outW+i*outW+j]+=K[oc*channel*kSizeX*kSizeY+c*kSizeX*kSizeY+m*kSizeX+n]*fVal;
    303. }
    304. }
    305. }
    306. }
    307. }
    308. }
    309. for (int oc = 0; oc < outC; ++oc)
    310. {
    311. for (int i = 0; i < outH; ++i)
    312. {
    313. for (int j = 0; j < outW; ++j)
    314. {
    315. std::cout<" ";
    316. }
    317. std::cout<
    318. }
    319. std::cout<
    320. }
    321. }
    322. int main(int argc, char *argv[])
    323. {
    324. //demo0();
    325. demo1();
    326. //demo2();
    327. //demo3();
    328. //demo4();
    329. //demo5();
    330. //demo6();
    331. }

    (1)将上述文件为my_code.cc源文件。

    如果要使用不同类型的demo,可以直接在main函数中调用。

    (2)然后在终端运行:

    g++ -o my_code my_code.cc

    此时已编译出可执行的二进制my_code。

    (3)执行my_code文件

    ./my_code

    最后说明:其实我个人觉得这种方式使用起来除了简单易懂,但在实际操作中并不可取。主要是所有的变量值都需要在demo()函数中手工赋值,耦合性和实用性较差。但是目前也没有更好的实测,等过阵子我的程序写完后,再和大家分享。

  • 相关阅读:
    汇总selenium利用xpath等找网页节点的方法(二)
    Selenium4之CDP
    远程代码执行渗透测试—Server2128
    12000条招聘数据告诉Python的学习方向和就业方向
    2d关键点转bvh fbx
    京东资深架构师教你搭建高可用高并发系统,亿级流量核心架构文档
    每日一练2——C++排序子序列问&&倒置字符串问题
    基于springboot农机电招平台设计与实现的源码+文档
    编码踩坑——多线程可能带来意想不到的OOM
    基于SpringBoot+Vue+uniapp的疫情期间高校人员的详细设计和实现(源码+lw+部署文档+讲解等)
  • 原文地址:https://blog.csdn.net/zhenz0729/article/details/139644768