CNN中的padding如何影响位置学习

最近在知乎上看到大家都在说CNN学习目标的位置时是根据padding来学习的,下面是利用C++实现的矩阵之间的卷积运算
注: 有个假设就是,认为feature map中的1是背景,4567是前景

1、feature map和卷积核都不带padding

例1:feature map为4维矩阵,卷积核为3维

目标在中心时:
在这里插入图片描述
目标向左上角平移:
在这里插入图片描述
目标向右下角平移:
在这里插入图片描述

例2:feature map为6维矩阵,卷积核为3维

目标在中心时:
在这里插入图片描述
目标向左上角平移:
在这里插入图片描述

2、feature map加padding,而卷积核不加padding

目标在中心时:
在这里插入图片描述
目标向左上角平移:
在这里插入图片描述

3、feature map加padding,卷积核也加padding

注: 这里是实验SiameseDW单目标跟踪网络时的padding影响
在以前的博客中解读过这篇论文:论文阅读:SiamDW

例一:feature map为6维矩阵,卷积核为5维矩阵

目标在中心时:
在这里插入图片描述
目标向左上角平移:
在这里插入图片描述
例2:feature map为8维矩阵,卷积核为5维矩阵

目标在中心时:
在这里插入图片描述
目标向左上角平移:
在这里插入图片描述
继续向左上平移:
在这里插入图片描述

矩阵卷积运算代码(C++版):

#include<iostream>
#include<vector>
using namespace std;

int main()
{
    //定义被卷积的矩阵(其实是一个数组,数组元素的个数8*8)
    // int const map = 4;
    // float  A[map*map] =
    // {
    //     0, 0, 0, 0, 
    //     0, 1, 2, 0, 
    //     0, 3, 4, 0, 
    //     0, 0, 0, 0, 
    // };
    // 1相当于背景  4567相当于背景
    int const map = 6;
    float  A[map*map] =
    {
        1, 1, 1, 1, 1, 1,
        1, 4, 5, 1, 1, 1,
        1, 6, 7, 1, 1, 1,
        1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 
        1, 1, 1, 1, 1, 1
    };
    //加上padding之后进行平移
    // int const map = 6;
    // float  A[map*map] =
    // {
    //     0, 0, 0, 0, 0, 0,
    //     0, 1, 1, 1, 1, 0,
    //     0, 1, 4, 5, 1, 0,
    //     0, 1, 6, 7, 1, 0,
    //     0, 1, 1, 1, 1, 0,
    //     0, 0, 0, 0, 0, 0
    // };
    // int const map = 8;
    // float  A[map*map] =
    // {
    //     0, 0, 0, 0, 0, 0, 0, 0,
    //     0, 1, 1, 1, 1, 1, 1, 0,
    //     0, 1, 4, 5, 1, 1, 1, 0,
    //     0, 1, 6, 7, 1, 1, 1, 0,
    //     0, 1, 1, 1, 1, 1, 1, 0,
    //     0, 1, 1, 1, 1, 1, 1, 0,
    //     0, 1, 1, 1, 1, 1, 1, 0,
    //     0, 0, 0, 0, 0, 0, 0, 0
    // };


    //定义卷积核矩阵(其实也是一个数组,数组元素的个数3*3)
    int const kernel = 3;
    float B[kernel*kernel] =
    {
      1, 1, 1,
      1, 1, 1,
      1, 1, 1
    };
    // int const kernel = 5;
    // float B[kernel*kernel] =
    // { 0, 0, 0, 0, 0,
    //   0, 1, 1, 1, 0,
    //   0, 1, 1, 1, 0,
    //   0, 1, 1, 1, 0,
    //   0, 0, 0, 0, 0
    // };

    //计算卷积输出矩阵的维数(其实是输出数组元素个数的开根号)
    int const outm = map - kernel + 1;   //被卷积矩阵的维数-卷积核的维数+1  即4-3+1=2

    //计算卷积过程中的被卷积矩阵的宽和高(就是把宽拉成和卷积核的高一样,这样才好对应相乘)
    int const convAw = kernel*kernel;//3*3=9
    int const convAh = map*map;//4*4=16

    float A_convert[convAh*convAw] = { 0 };//定义一个卷积过程中的矩阵(也就是被拉长过后的矩阵)

    for (int i = 0; i < outm; i++)
    {
        for (int j = 0; j < outm; j++)
        {
            int wh = i * outm * convAw + j * convAw; 

            int col1 = i * map + j;
            A_convert[wh] = A[col1];        //第一次循环时把A[0] 的值赋给 A_convert[0]
            A_convert[wh + 1] = A[col1 + 1];//第一次循环时把A[1] 的值赋给 A_convert[1]
            A_convert[wh + 2] = A[col1 + 2];//第一次循环时把A[2] 的值赋给 A_convert[2]

            int col2 = (i + 1) * map + j;
            A_convert[wh + 3] = A[col2];    //第一次循环时把A[8] 的值赋给 A_convert[3]
            A_convert[wh + 4] = A[col2 + 1];//第一次循环时把A[9] 的值赋给 A_convert[4]
            A_convert[wh + 5] = A[col2 + 2];//第一次循环时把A[10] 的值赋给 A_convert[5]

            int col3 = (i + 2) * map + j;
            A_convert[wh + 6] = A[col3];     //第一次循环时把A[16] 的值赋给 A_convert[6]
            A_convert[wh + 7] = A[col3 + 1]; //第一次循环时把A[17] 的值赋给 A_convert[7]
            A_convert[wh + 8] = A[col3 + 2]; //第一次循环时把A[18] 的值赋给 A_convert[8]
        }

    }
    vector<int> C;
    for (int i = 0; i < outm; i++)
    {

        for (int j = 0; j < outm; j++)
        {
            int a = 0;
            int wh = i * outm * convAw + j * convAw;
            for (int m =0; m < convAw; m++)
            {
                a += A_convert[wh + m] * B[m] ;

            }
            C.push_back(a); //在C中添加数据a

        }

    }


    //输出被卷积矩阵
    cout << "被卷积矩阵 :" << endl;
    for (int i = 0; i < map; i++)
    {
        for (int j = 0; j < map; j++)
        {
            cout << A[i*map + j] << " ";
        }
        cout << endl;
    }
    cout << endl;



    //输出卷积核矩阵
    cout << "卷积核矩阵:" << endl;
    for (int i = 0; i < kernel; i++)
    {
        for (int j = 0; j < kernel; j++)
        {
            cout << B[i*kernel + j] << " ";
        }
        cout << endl;
    }
    cout << endl;


    //输出卷积后输出矩阵
    cout << "卷积后输出矩阵:" << endl;
    for (int i = 0; i < outm; i++)
    {
        for (int j = 0; j < outm; j++)
        {
            cout << C[i*outm + j] << " ";
        }
        cout << endl;
    }

    //system("pause");
    return 0;
}

参考文献:

谈谈CNN中的位置和尺度问题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值