【问题标题】:Is it possible to extend "im2col" and "col2im" to N-D images?是否可以将“im2col”和“col2im”扩展到 N 维图像?
【发布时间】:2020-01-27 06:47:25
【问题描述】:

“Im2col”已经实现,Implement MATLAB's im2col 'sliding' in Python,在 Python 中有效地用于二维图像。我想知道是否可以将其扩展到任意 N-D 图像?许多应用都涉及高维数据(例如卷积、过滤、最大池化等)。

【问题讨论】:

    标签: python keras convolution max-pooling


    【解决方案1】:

    所以这个问题的目的实际上只是公开发布我对这个问题的解决方案。我似乎无法在 Google 上找到这样的解决方案,所以我决定自己尝试一下。事实证明,从我的问题中引用的帖子中的“方法#2”扩展实现实际上非常简单!

    N-D“im2col”的高效实现

    def im2col(im, win, strides = 1):
        # Dimensions
        ext_shp = tuple(np.subtract(im.shape, win) + 1)
        shp = tuple(win) + ext_shp
        strd = im.strides*2
        win_len = np.prod(win)
        try:
            len(strides)
        except:
            strides = [strides]*im.ndim
        strides = [min(i, s) for i, s in zip(im.shape, strides)]
    
        # Stack all possible patches as an N-D array using a strided view followed by reshaping
        col = np.lib.stride_tricks.as_strided(im, shape = shp, strides = strd).reshape(win_len, -1).reshape(-1, *ext_shp)
    
        # Extract patches with stride and reshape into columns
        slcs = tuple([slice(None, None, None)] + [slice(None, None, s) for s in strides])
        col = col[slcs].reshape(win_len, -1)
    
        return col
    

    N-D "col2im" 的高效实现

    def col2im(col, im_shp, win, strides = 1):
        # Dimensions
        try:
            len(strides)
        except:
            strides = [strides]*len(im_shp)
        strides = [min(i, s) for i, s in zip(im_shp, strides)]
    
        # Reshape columns into image
        if col.ndim > 1:
            im = col.reshape((-1, ) + tuple(np.subtract(im_shp, win)//np.array(strides) + 1))[0]
        else:
            im = col.reshape(tuple(np.subtract(im_shp, win)//np.array(strides) + 1))
    
        return im
    

    验证它是否有效

    让我们定义一个任意的 3-D 输入:

    x = np.arange(216).reshape(6, 6, 6)
    print(x)
    
    [[[  0   1   2   3   4   5]
      [  6   7   8   9  10  11]
      [ 12  13  14  15  16  17]
      [ 18  19  20  21  22  23]
      [ 24  25  26  27  28  29]
      [ 30  31  32  33  34  35]]
    
     [[ 36  37  38  39  40  41]
      [ 42  43  44  45  46  47]
      [ 48  49  50  51  52  53]
      [ 54  55  56  57  58  59]
      [ 60  61  62  63  64  65]
      [ 66  67  68  69  70  71]]
    
     [[ 72  73  74  75  76  77]
      [ 78  79  80  81  82  83]
      [ 84  85  86  87  88  89]
      [ 90  91  92  93  94  95]
      [ 96  97  98  99 100 101]
      [102 103 104 105 106 107]]
    
     [[108 109 110 111 112 113]
      [114 115 116 117 118 119]
      [120 121 122 123 124 125]
      [126 127 128 129 130 131]
      [132 133 134 135 136 137]
      [138 139 140 141 142 143]]
    
     [[144 145 146 147 148 149]
      [150 151 152 153 154 155]
      [156 157 158 159 160 161]
      [162 163 164 165 166 167]
      [168 169 170 171 172 173]
      [174 175 176 177 178 179]]
    
     [[180 181 182 183 184 185]
      [186 187 188 189 190 191]
      [192 193 194 195 196 197]
      [198 199 200 201 202 203]
      [204 205 206 207 208 209]
      [210 211 212 213 214 215]]]
    

    让我们提取所有具有非均匀窗口和相等步幅的补丁:

    y = im2col(x, [1, 3, 2], strides = [1, 3, 2])
    print(y.T) # transposed for ease of visualization
    
    [[  0   1   6   7  12  13]
     [  2   3   8   9  14  15]
     [  4   5  10  11  16  17]
     [ 18  19  24  25  30  31]
     [ 20  21  26  27  32  33]
     [ 22  23  28  29  34  35]
     [ 36  37  42  43  48  49]
     [ 38  39  44  45  50  51]
     [ 40  41  46  47  52  53]
     [ 54  55  60  61  66  67]
     [ 56  57  62  63  68  69]
     [ 58  59  64  65  70  71]
     [ 72  73  78  79  84  85]
     [ 74  75  80  81  86  87]
     [ 76  77  82  83  88  89]
     [ 90  91  96  97 102 103]
     [ 92  93  98  99 104 105]
     [ 94  95 100 101 106 107]
     [108 109 114 115 120 121]
     [110 111 116 117 122 123]
     [112 113 118 119 124 125]
     [126 127 132 133 138 139]
     [128 129 134 135 140 141]
     [130 131 136 137 142 143]
     [144 145 150 151 156 157]
     [146 147 152 153 158 159]
     [148 149 154 155 160 161]
     [162 163 168 169 174 175]
     [164 165 170 171 176 177]
     [166 167 172 173 178 179]
     [180 181 186 187 192 193]
     [182 183 188 189 194 195]
     [184 185 190 191 196 197]
     [198 199 204 205 210 211]
     [200 201 206 207 212 213]
     [202 203 208 209 214 215]]
    

    让我们将其转换回(下采样)图像:

    z = col2im(y, x.shape, [1, 3, 2], strides = [1, 3, 2])
    print(z)
    
    [[[  0   2   4]
      [ 18  20  22]]
    
     [[ 36  38  40]
      [ 54  56  58]]
    
     [[ 72  74  76]
      [ 90  92  94]]
    
     [[108 110 112]
      [126 128 130]]
    
     [[144 146 148]
      [162 164 166]]
    
     [[180 182 184]
      [198 200 202]]]
    

    如您所见,最终输出确实是我们期望的下采样图像(您可以通过逐个值轻松检查这一点)。我选择的维度和步幅纯粹是说明性的。没有理由说窗口大小必须与您的步幅相同,或者您不能超过 3 个维度。

    应用程序

    如果你想实际使用它,你所要做的就是在将 im2col 的输出转换回图像之前截取它。例如,如果要进行池化,则可以在第 0 轴上取平均值或最大值。如果要进行卷积,只需将其乘以扁平卷积滤波器即可。

    可能有比“im2col”更快的 Tensorflow 等已经实现的更有效的替代方案。这并不意味着是最有效的实现。当然,您可以通过消除“im2col”中的中间重塑步骤来进一步优化我的代码,但这对我来说并不是很明显,所以我就把它留在了那里。如果您有更好的解决方案,请告诉我。无论如何,希望这可以帮助其他人寻找相同的答案!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-21
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多