【问题标题】:python convolution with different dimension不同维度的python卷积
【发布时间】:2017-01-06 08:25:46
【问题描述】:

我正在尝试在 Python 中实现卷积神经网络。
但是,当我使用 signal.convolve 或 np.convolve 时,它​​不能对 X、Y(X 是 3d,Y 是 2d)进行卷积。 X 是训练小批量。 Y 是过滤器。 我不想为每个训练向量做 for 循环,例如:

for i in xrange(X.shape[2]):
    result = signal.convolve(X[:,:,i], Y, 'valid')
    ....

那么,有什么函数可以用来有效地进行卷积吗?

【问题讨论】:

    标签: python numpy scipy deep-learning


    【解决方案1】:

    Scipy 实现了标准的 N 维卷积,使得要卷积的矩阵和内核都是 N 维的。

    一个快速的解决方法是向Y 添加一个额外的维度,以便Y 是3 维的:

    result = signal.convolve(X, Y[..., None], 'valid')
    

    我在这里假设最后一个轴对应于图像索引,如您的示例[width, height, image_idx](或[height, width, image_idx])。如果反过来并且图像在第一个轴上被索引(因为它在 C 排序数组中更常见),则应将 Y[..., None] 替换为 Y[None, ...]

    Y[..., None] 线将为Y 添加一个额外的轴,使其成为 3 维 [kernel_width, kernel_height, 1],从而将其转换为有效的 3 维卷积核。

    注意:这假设您的所有输入小批量都具有相同的width x height,这是 CNN 的标准。


    编辑:@Divakar 建议的一些时间安排。

    测试框架设置如下:

    def test(S, N, K):
        """ S: image size, N: num images, K: kernel size"""
        a = np.random.randn(S, S, N)
        b = np.random.randn(K, K)
        valid = [slice(K//2, -K//2+1), slice(K//2, -K//2+1)]
    
        %timeit signal.convolve(a, b[..., None], 'valid')
        %timeit signal.fftconvolve(a, b[..., None], 'valid')
        %timeit ndimage.convolve(a, b[..., None])[valid]
    

    查找以下针对不同配置的测试:

    • 改变图像大小S:

      >>> test(100, 50, 11) # 100x100 images
      1 loop, best of 3: 909 ms per loop
      10 loops, best of 3: 116 ms per loop
      10 loops, best of 3: 54.9 ms per loop
      
      >>> test(1000, 50, 11) # 1000x1000 images
      1 loop, best of 3: 1min 51s per loop
      1 loop, best of 3: 16.5 s per loop
      1 loop, best of 3: 5.66 s per loop
      
    • 不同数量的图像N

      >>> test(100, 5, 11) # 5 images
      10 loops, best of 3: 90.7 ms per loop
      10 loops, best of 3: 26.7 ms per loop
      100 loops, best of 3: 5.7 ms per loop
      
      >>> test(100, 500, 11) # 500 images
      1 loop, best of 3: 9.75 s per loop
      1 loop, best of 3: 888 ms per loop
      1 loop, best of 3: 727 ms per loop
      
    • 改变内核大小K:

      >>> test(100, 50, 5) # 5x5 kernels
      1 loop, best of 3: 217 ms per loop
      10 loops, best of 3: 100 ms per loop
      100 loops, best of 3: 11.4 ms per loop
      
      >>> test(100, 50, 31) # 31x31 kernels
      1 loop, best of 3: 4.39 s per loop
      1 loop, best of 3: 220 ms per loop
      1 loop, best of 3: 560 ms per loop
      

    所以,简而言之,ndimage.convolve 总是更快,除非内核非常大(如上次测试中的K = 31)。

    【讨论】:

    • 好发现!要获得更快的版本,请使用 ndimage.filters.convolve(X,Y[...,None]) 可能会进行一些切片?
    • @Divakar 最好安排时间(如果我有时间我会这样做),但我认为ndimage,filters.convolve 对于大内核大小应该更慢(因为它确实卷积在空间域中,而signal.convolve 在傅立叶域中进行)。 ndimage 过滤器的优点是支持不同的边界条件(不同于傅立叶,我认为根据定义相当于用 0 填充图像)。我会尽快安排时间!
    • @Divakar 测试完成!我觉得这是某种dejavu。正如您所建议的,ndimage.convolve 通常会更快。我记得在不同的线程中有过类似的对话哈哈
    • 你知道什么是美好的记忆,而不仅仅是似曾相识! ;) 这是我认为您所指的帖子:stackoverflow.com/a/38232755/3293881
    • @Divakar 哈哈,没错!那个时候我提议uniform_filter 超过signal.convolve 哈哈。尽管uniform_filter 由于内核的可分离性而更快,但上述结果似乎证实了我们在该线程中得出的结论:对于大内核大小傅里叶(fftconvolve)> 空间,如果不是空间>傅里叶。
    猜你喜欢
    • 2017-07-03
    • 1970-01-01
    • 2017-12-20
    • 2017-09-28
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多