首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >col2im在ConvNet中的实现

col2im在ConvNet中的实现
EN

Stack Overflow用户
提问于 2018-08-06 08:21:52
回答 2查看 2.3K关注 0票数 4

我正在尝试实现CNN,只使用numpy。

在进行反向传播时,我发现必须使用col2im来重塑dx,因此我检查了https://github.com/huyouare/CS231n/blob/master/assignment2/cs231n/im2col.py的实现。

代码语言:javascript
复制
import numpy as np


def get_im2col_indices(x_shape, field_height, field_width, padding=1, stride=1):
  # First figure out what the size of the output should be
  N, C, H, W = x_shape
  assert (H + 2 * padding - field_height) % stride == 0
  assert (W + 2 * padding - field_height) % stride == 0
  out_height = (H + 2 * padding - field_height) / stride + 1
  out_width = (W + 2 * padding - field_width) / stride + 1

  i0 = np.repeat(np.arange(field_height), field_width)
  i0 = np.tile(i0, C)
  i1 = stride * np.repeat(np.arange(out_height), out_width)
  j0 = np.tile(np.arange(field_width), field_height * C)
  j1 = stride * np.tile(np.arange(out_width), out_height)
  i = i0.reshape(-1, 1) + i1.reshape(1, -1)
  j = j0.reshape(-1, 1) + j1.reshape(1, -1)

  k = np.repeat(np.arange(C), field_height * field_width).reshape(-1, 1)

  return (k, i, j)


def im2col_indices(x, field_height, field_width, padding=1, stride=1):
  """ An implementation of im2col based on some fancy indexing """
  # Zero-pad the input
  p = padding
  x_padded = np.pad(x, ((0, 0), (0, 0), (p, p), (p, p)), mode='constant')

  k, i, j = get_im2col_indices(x.shape, field_height, field_width, padding,
                               stride)

  cols = x_padded[:, k, i, j]
  C = x.shape[1]
  cols = cols.transpose(1, 2, 0).reshape(field_height * field_width * C, -1)
  return cols


def col2im_indices(cols, x_shape, field_height=3, field_width=3, padding=1,
                   stride=1):
  """ An implementation of col2im based on fancy indexing and np.add.at """
  N, C, H, W = x_shape
  H_padded, W_padded = H + 2 * padding, W + 2 * padding
  x_padded = np.zeros((N, C, H_padded, W_padded), dtype=cols.dtype)
  k, i, j = get_im2col_indices(x_shape, field_height, field_width, padding,
                               stride)
  cols_reshaped = cols.reshape(C * field_height * field_width, -1, N)
  cols_reshaped = cols_reshaped.transpose(2, 0, 1)
  np.add.at(x_padded, (slice(None), k, i, j), cols_reshaped)
  if padding == 0:
    return x_padded
  return x_padded[:, :, padding:-padding, padding:-padding]

pass

我预计,当我将im2col_indices,中的X放回col2im_indices中时,输出将返回相同的X,但事实并非如此。

我不明白col2im到底做了什么。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-08-07 01:14:37

如果我是对的,输出不是相同的X,因为X的每个单元格被转换成多个cols,并且在im2col_indices期间它被乘以。

假设您有这样一个简单的图像X

代码语言:javascript
复制
 1 2 3
 4 5 6
 7 8 9

然后用内核大小3、stride 1和same填充来转换它,结果是

代码语言:javascript
复制
0 0 0 0 1 2 0 4 5
0 0 0 1 2 3 4 5 6
0 0 0 2 3 0 5 6 0
0 1 2 0 4 5 0 7 8
1 2 3 4 5 6 7 8 9
2 3 0 5 6 0 8 9 0
0 4 5 0 7 8 0 0 0
4 5 6 7 8 9 0 0 0
5 6 0 8 9 0 0 0 0
* *   * *

如您所见,值1的第一个单元格显示在四个cols中: 0、1、3、4。

im2col_indices首先零初始化填充大小的图像,然后将每个col添加到图像中。集中在第一个单元格上,这个过程应该像

1.零初始化图像

代码语言:javascript
复制
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

2.加入col 0

代码语言:javascript
复制
0 0 0 0 0     0 0 0 - -     0 0 0 0 0
0 0 0 0 0     0 1 2 - -     0 1 2 0 0
0 0 0 0 0  +  0 4 5 - -  =  0 4 5 0 0
0 0 0 0 0     - - - - -     0 0 0 0 0
0 0 0 0 0     - - - - -     0 0 0 0 0

3.加入col 1

代码语言:javascript
复制
0 0 0 0 0     - 0 0 0 -     0  0  0  0  0
0 1 2 0 0     - 1 2 3 -     0  2  4  3  0
0 4 5 0 0  +  - 4 5 6 -  =  0  8 10  6  0
0 0 0 0 0     - - - - -     0  0  0  0  0
0 0 0 0 0     - - - - -     0  0  0  0  0

4.加入col 3

代码语言:javascript
复制
0  0  0  0  0     - - - - -     0  0  0  0  0
0  2  4  3  0     0 1 2 - -     0  3  6  3  0
0  8 10  6  0  +  0 4 5 - -  =  0 12 15  6  0
0  0  0  0  0     0 7 8 - -     0  7  8  0  0 
0  0  0  0  0     - - - - -     0  0  0  0  0

5.加入col 4

代码语言:javascript
复制
0  0  0  0  0     - - - - -     0  0  0  0  0
0  3  6  3  0     - 1 2 3 -     0  4  8  6  0
0 12 15  6  0  +  - 4 5 6 -  =  0 16 20 12  0
0  7  8  0  0     - 7 8 9 -     0 14 16  9  0
0  0  0  0  0     - - - - -     0  0  0  0  0 

当转换回时,第一个单元被乘以4。对于这个简单的图像,col2im_indices(im2col_indices(X))应该给您

代码语言:javascript
复制
 4  12  12
24  45  36
28  48  36

与原始图像相比,四个角单元1 3 7 9乘以4,四个边缘单元2 4 6 8乘以6,中心单元5乘以9。

对于大图像,大部分细胞会被乘以9,我认为这大致意味着你的学习率实际上比你想象的要高9倍。

票数 3
EN

Stack Overflow用户

发布于 2020-10-21 05:10:53

回覆这两年前的线,它可能会对未来的人有所帮助。

这是我的理解。在CNN反向传播上下文中,col2im矩阵是滤波器和反向传播误差的乘积。必须指出的是,矩阵已经是两个矩阵的乘积,而在im2col用例中,我们只是将输入扩展到im2col矩阵中,以便进行乘法(卷积)。由于im2col和col2im之间的差异,在col2im中,我们需要将传播的错误添加到所有的贡献输入索引中。

让我们考虑一个例子,1x5x5输入,单个1x3x3过滤器,0填充,大步1。

代码语言:javascript
复制
[0,0] [0,1] [0,2] [0,3] [0,4]
[1,0] [1,1] [1,2] [1,3] [1,4]
[2,0] [2,1] [2,2] [2,3] [2,4]
[3,0] [3,1] [3,2] [3,3] [3,4]
[4,0] [4,1] [4,2] [4,3] [4,4]

为前向传播矩阵乘法计算得到的9x9 im2col索引如下所示:

im2col指数

代码语言:javascript
复制
<-----------------------  9 ----------------------------->
[ 0] [0,0] [0,1] [0,2] [1,0] [1,1] [1,2] [2,0] [2,1] [2,2] 
[ 1] [0,1] [0,2] [0,3] [1,1] [1,2] [1,3] [2,1] [2,2] [2,3] 
[ 2] [0,2] [0,3] [0,4] [1,2] [1,3] [1,4] [2,2] [2,3] [2,4] 
[ 3] [1,0] [1,1] [1,2] [2,0] [2,1] [2,2] [3,0] [3,1] [3,2] 
[ 4] [1,1] [1,2] [1,3] [2,1] [2,2] [2,3] [3,1] [3,2] [3,3] 
[ 5] [1,2] [1,3] [1,4] [2,2] [2,3] [2,4] [3,2] [3,3] [3,4] 
[ 6] [2,0] [2,1] [2,2] [3,0] [3,1] [3,2] [4,0] [4,1] [4,2] 
[ 7] [2,1] [2,2] [2,3] [3,1] [3,2] [3,3] [4,1] [4,2] [4,3] 
[ 8] [2,2] [2,3] [2,4] [3,2] [3,3] [3,4] [4,2] [4,3] [4,4] 

在向后传递过程中,当我们通过对反向传播的误差dout和滤波器产生col2im矩阵时,所得到的指数,如上面所示,已经是乘法的结果了。当我们将其转换回输入错误时,需要在输入错误数组中的给定位置添加相应的索引。

例如:

代码语言:javascript
复制
input_error[0,0] = im2col_error[0,0]
input_error[0,1] = im2col_error[0,1] + im2col_error[1,0]
input_error[0,2] = im2col_error[0,2] + im2col_error[1,1] + im2col_error[2,0]
....
....

从上面的指数矩阵可以看出这一点。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51703367

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档