深度理解卷积--使用im2col实现卷积

2021-01-29 10:36:08 浏览数 (1)

在上一篇我们了解了卷积的概念,并且使用numpy实现了卷积。另一篇介绍了如何在tensorflow框架中调用API进行卷积操作。今天再介绍一个实现卷积操作的方案,使用im2col实现卷积,实际在OpenCV源码中也可以看到im2col的算法,顺便提一下opencv也可以直接部署深度学习模型,调用方法可以参考这里。

im2col

im2col算法原理

im2col就是把图像转化为列向量,很多文章都有讲解,https://zhuanlan.zhihu.com/p/63974249 链接讲的比较详细。我按自己理解画了几个图,也方面大家理解

上图就是im2col的原理,把一个矩阵转化为一行。(实际应该是im2row)

如果看过numpy实现卷积的文章应该都知道卷积的过程,如果是二维图像,卷积核会在图像上滑动进行卷积,那在im2col实现卷积,怎么操作呢?

如果核大小是3*3,那每次卷积的图像就是依次为右边的四个矩阵了~

再把四个矩阵按图一的方式转化为一行,就是下图

同样,我们把卷积核也按im2col进行转化

总结下

一个6_3的图像,我们转换为了9_4的矩阵

一个3_3的卷积核,我们转换为了9_1的矩阵

两个矩阵相乘,是不是一个41的矩阵~

_如果是正常卷积呢?回忆下卷积过程,或者跑下代码,应该也是得到一个4_1的结果~(以VALID方式)

对比下:

标准卷积的计算过程:4次3_3矩阵和3_3矩阵相乘累加

im2col实现卷积的计算过程:9_4矩阵和1_9矩阵相乘

根据矩阵相乘的定义,两个结果是一致的,但im2col肯定是优化版的卷积过程~

通过上面几个图,大家应该就就了解了什么叫im2col,以及它如何实现卷积了。

下面简单直接~上代码

im2col实现卷积代码实现

对于基础知识reshape和transpose的加深理解这里

下面我们直接写im2col的代码,注释已经比较详细

代码语言:javascript复制
def im2col(inputs,filter,padding="SAME",stride=1):
    N, C, H ,W = inputs.shape
    filter_size = filter.shape[2]
    # default np.floor
    filter_center = int(filter_size / 2.0)
    filter_center_ceil = int(np.ceil(filter_size / 2.0))
    # SAME模式,输入和输出大小一致,所以要在外面填充0
    if padding == "SAME":
        padding_inputs = np.zeros([N,C,H   filter_center_ceil, W   filter_center_ceil], np.float32)
        padding_inputs[:,:,filter_center:-filter_center, filter_center:-filter_center] = inputs
        inputs = padding_inputs
    N ,C,H2, W2 = inputs.shape
    print("N ,C,H2, W2",N ,C,H2, W2,"inputsn",inputs)
    out_h = H
    out_w = W
    col = np.empty((N * H * W, filter_size * filter_size * C))
    outsize = out_w * out_h
    #每个样本outsize行,每行就是fs*fs*C按行顺序reshape,如果是N个样本就是N行
    for y in range(out_h):
        y_min = y * stride
        y_max = y_min   filter_size
        y_start = y * out_w
        for x in range(out_w):
            x_min = x * stride
            x_max = x_min   filter_size
            #取出kernel大小的数据块reshape为一行,N个样本reshape为N行
            #这里::outsize就是间隔outsize放下一个样本的行
            col[y_start   x::outsize, :] = inputs[:,:,y_min:y_max, x_min:x_max].reshape(N, -1)
    return col

同样把filter进行im2col操作

代码语言:javascript复制
def trans_weight(filter):
    # print("filtern",filter)
    C_out, C_in, K, K = filter.shape
    weight = filter.reshape(C_out,-1)
    # print("weightn",weight)
    return weight

然后进行卷积操作,为了和之前numpy实现的卷积以及Tensorflow进行卷积的结果对比,我们输入和之前一样:

代码语言:javascript复制
inputs = np.zeros([1, 3, 9, 9])
    for n in range(1):
        for i in range(3):
            for j in range(9):
                for z in range(9):
                    inputs[n][i][j][z] = i   j   z

filter = np.zeros([2, 3, 3, 3])
    for i in range(2):
        for j in range(3):
            for x in range(3):
                for y in range(3):
                    filter[i][j][x][y] = i   j   x   y
conv_out = conv_im2col(inputs, filter)
#[1,9,9,2]---[1,2,9,9]
conv_out =np.transpose(conv_out,(0,3,1,2))
print(conv_out)

大家可以自己动手跑下,卷积结果和之前我们使用numpy实现卷积结果是一致的~

0 人点赞