【问题标题】:2D convolution with padding=same via Toeplitz matrix multiplication通过 Toeplitz 矩阵乘法,具有填充 = 相同的 2D 卷积
【发布时间】:2020-03-11 20:11:36
【问题描述】:

我正在尝试使用 padding=same(类似于 keras)为 2D 卷积实现 Block Toeplitz 矩阵。我看到、阅读和搜索了很多信息,但我没有得到它的实现。

我引用的一些参考资料(我也在阅读论文,但有人谈论带有填充的 convd,只有完整或有效):

麦克劳伦斯的回答:answer。他从字面上说:“他是用于填充 = 0,但可以通过更改 h_blocks 和 w_blocks 和 W_conv[i+j, :, j, :] 轻松调整。”但我不知道如何实现这种变化。

Warren 的 Weckesser 回答:answer:解释什么是块矩阵。

Salvador 的 Dali 回答:answer:解释了执行 blockTeoeplitz 的 padding="valid" 矩阵的方法,并且, Ali Salehi,解释了 padding="full" 的方法。

修改 McLawrence 答案的代码,我实现了与 keras conv2d with padding="same" 相同的结果,但仅适用于 2x2 内核维度和方形输入矩阵。代码是:

k_h, k_w = kernel.shape
i_h, i_w = input.shape
o_h, o_w = input.shape

s_c = o_h-o_w
# construct 1d conv toeplitz matrices for each row of the kernel
toeplitz = []
for r in range(k_h):
    toeplitz.append(linalg.toeplitz(c=(kernel[r,0], *np.zeros(i_w-1)), r=(*kernel[r], *np.zeros(i_w-k_w))) ) 

# construct toeplitz matrix of toeplitz matrices (just for padding=0)
h_blocks, w_blocks = input.shape
h_block, w_block = toeplitz[0].shape

W_conv = np.zeros((h_blocks, h_block, w_blocks, w_block))

for i, B in enumerate(toeplitz):
    for j in range(o_h):
        if i == len(toeplitz)-1 and j == o_h-1:
            continue
        W_conv[j, :, i+j, :] = B

W_conv.shape = (h_blocks*h_block, w_blocks*w_block)
return W_conv

有任何可能有用的论文或参考资料吗?

【问题讨论】:

    标签: python tensorflow keras conv-neural-network


    【解决方案1】:

    希望这会有所帮助,这适用于“相同”的填充:

    def toeplitz_1_ch(kernel, input_size):
        # shapes
        k_h, k_w = kernel.shape
        i_h, i_w = input_size
        #o_h, o_w = i_h-k_h+1, i_w-k_w+1
        o_h, o_w = i_h, i_w
        # construct 1d conv toeplitz matrices for the kernel, with "same" padding
        n = i_h
    
        K1 = np.zeros((n,))
        K1[:2] = (kernel[1,1], kernel[1,2] )
        K2 = np.zeros((n,))
        K2[:2] = (kernel[1,1], kernel[1,0])
    
        K = linalg.toeplitz(c=K2, r = K1)
        KK = np.identity(n)
    
        L1 = np.zeros((n,))
        L1[:2] = (kernel[2,1], kernel[2,2])
        L2 = np.zeros((n,))
        L2[:2] = (kernel[2,1], kernel[2,0])
    
        t=np.zeros(n)
        s= np.zeros(n)
        s[1] = 1
        L=linalg.toeplitz(c=L2, r = L1)
        LL=linalg.toeplitz(r = s, c = t)
    
        A = np.kron(LL, L) + np.kron(KK, K)
    
        L1 = np.zeros((n,))
        L1[:2] = (kernel[0,1], kernel[0,2])
        L2 = np.zeros((n,))
        L2[:2] = (kernel[0,1], kernel[0,0])
    
        L=linalg.toeplitz(c=L2, r = L1)
        LL=linalg.toeplitz(c = s, r = t)
        A = A + np.kron(LL, L)
        return A
    
    def toeplitz_mult_ch(kernel, input_size):
        """Compute toeplitz matrix for 2d conv with multiple in and out channels.
        Args:
            kernel: shape=(n_out, n_in, H_k, W_k)
            input_size: (n_in, H_i, W_i)"""
    
        kernel_size = kernel.shape
        output_size = (kernel_size[0], input_size[1], input_size[2])
        T = np.zeros((output_size[0], int(np.prod(output_size[1:])), input_size[0], int(np.prod(input_size[1:]))))
    
        for i,ks in enumerate(kernel):  # loop over output channel
            for j,k in enumerate(ks):  # loop over input channel
                T_k = toeplitz_1_ch(k, input_size[1:])
                T[i, :, j, :] = T_k
        T.shape = (np.prod(output_size), np.prod(input_size))
    
        return T
    
    import torch
    import torch.nn.functional as F
    k = np.random.randn(4*3*3*3).reshape((4,3,3,3))
    i = np.random.randn(3,9,9)
    T = toeplitz_mult_ch(k, i.shape)
    out = T.dot(i.flatten()).reshape((1,4,9,9))
    
    # check correctness of convolution via toeplitz matrix
    print(np.sum((out - F.conv2d(torch.tensor(i).view(1,3,9,9), torch.tensor(k), padding = 1).numpy())**2))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-31
      • 2021-05-25
      • 1970-01-01
      • 1970-01-01
      • 2013-05-23
      • 1970-01-01
      • 1970-01-01
      • 2016-12-11
      相关资源
      最近更新 更多