Pytorch im2col (nn.Unfold) 将卷积运算转为矩阵相乘

      im2col这个名称是“image to column”的缩写,翻译过来就是“从图像到矩阵”的意思。

      im2col是将一个[C,H,W]矩阵变成一个[H,W]矩阵的一个方法,其原理是利用了行列式进行等价转换。im2col原本是matlab中的一个操作

      在Pytorch中可以用torch.unfoldtorch.cattorch.transpose的组合实现im2col操作.

      im2col:将卷积运算转为矩阵相乘

      将卷积运算转化为矩阵乘法,从乘法和加法的运算次数上看,两者没什么差别,但是转化成矩阵后,运算时需要的数据被存在连续的内存上,这样访问速度大大提升(cache),同时,矩阵乘法有很多库提供了高效的实现方法,像BLAS、MKL等,转化成矩阵运算后可以通过这些库进行加速。

      缺点呢?这是一种空间换时间的方法,消耗了更多的内存——转化的过程中数据被冗余存储

这是不带padding的,即输入数据在输入im2col之前,如果有padding要先做了

def im2col(img, kernel_h, kernel_w, stride=1):
    """
    Parameters
    ----------
    input_data : 由(数据量, 通道, 高, 长)的4维数组构成的输入数据
    kernel_h : 滤波器的高
    kernel_w : 滤波器的长
    stride : 步幅
    Returns
    -------
    col : 2维数组
    """
    N, C, H, W = img.shape
    out_h = (H - kernel_h)//stride + 1
    out_w = (W - kernel_w)//stride + 1
 
    col = torch.zeros((N, C, kernel_h, kernel_w, out_h, out_w))
 
    for y in range(kernel_h):
        y_max = y + stride*out_h
        for x in range(kernel_w):
            x_max = x + stride*out_w
            col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
 
    col = col.permute(0, 4, 5, 1, 2, 3).contiguous().reshape(N*out_h*out_w, -1)
    #col = col.permute(0, 4, 5, 1, 2, 3).contiguous().reshape(N, out_h*out_w, -1)
    return col

这是带padding的

def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
    """

    Parameters
    ----------
    input_data : 由(数据量, 通道, 高, 长)的4维数组构成的输入数据
    filter_h : 滤波器的高
    filter_w : 滤波器的长
    stride : 步幅
    pad : 填充

    Returns
    -------
    col : 2维数组
    """
    N, C, H, W = input_data.shape
    out_h = (H + 2*pad - filter_h)//stride + 1
    out_w = (W + 2*pad - filter_w)//stride + 1

    img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
    col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))

    for y in range(filter_h):
        y_max = y + stride*out_h
        for x in range(filter_w):
            x_max = x + stride*out_w
            col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]

    col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
    #col = col.permute(0, 4, 5, 1, 2, 3).contiguous().reshape(N, out_h*out_w, -1)
    return col

 

nn.Unfold

其实Pytorch中有现成的函数实现这个功能,nn.Unfold()

结果的size和我们上面实现的略有不同

import torch
from torch import nn
import numpy as np


def im2col(img, kernel_h, kernel_w, stride=1):
    """
    Parameters
    ----------
    input_data : 由(数据量, 通道, 高, 长)的4维数组构成的输入数据
    kernel_h : 滤波器的高
    kernel_w : 滤波器的长
    stride : 步幅
    Returns
    -------
    col : 2维数组
    """
    N, C, H, W = img.shape
    out_h = (H - kernel_h)//stride + 1
    out_w = (W - kernel_w)//stride + 1
 
    col = torch.zeros((N, C, kernel_h, kernel_w, out_h, out_w))
 
    for y in range(kernel_h):
        y_max = y + stride*out_h
        for x in range(kernel_w):
            x_max = x + stride*out_w
            col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]
 
    # col = col.permute(0, 4, 5, 1, 2, 3).contiguous().reshape(N*out_h*out_w, -1)
    col = col.permute(0, 4, 5, 1, 2, 3).contiguous().reshape(N, out_h*out_w, -1)
    return col

x = torch.rand(4,2,5,5)
unfold = nn.Unfold(kernel_size=3)
output = unfold(x)

output1 = im2col(x, kernel_h=3, kernel_w=3)

assert torch.allclose(output, output1.permute(0,2,1).contiguous())

用nn.Unfold()实现Conv2d

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值