通过Toeplitz矩阵乘法对padding = same进行2D卷积

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

我已经摘录了一些参考资料(也正在阅读论文,但是任何人都在谈论用填充填充convd,只有完整或有效):

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

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

萨尔瓦多(Salvador)的达利(Dali)答案:answer:介绍了执行padTeedplitz矩阵以进行padding =“ valid”的方法, 阿里·萨利希(Ali Salehi)解释了填充“完整”的方法。

修改McLawrence答案的代码,我获得了与padas =“ same”的keras conv2d相同的结果,但仅适用于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

任何论文或参考文献可能会有所帮助?

delong521 回答:通过Toeplitz矩阵乘法对padding = same进行2D卷积

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

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,0])

    K = linalg.toeplitz(c=K2,r = K1)
    KK = np.identity(n)

    L1 = np.zeros((n,))
    L1[:2] = (kernel[2,kernel[2,2])
    L2 = np.zeros((n,))
    L2[:2] = (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,kernel[0,))
    L2[:2] = (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))
i = np.random.randn(3,9,9)
T = toeplitz_mult_ch(k,i.shape)
out = T.dot(i.flatten()).reshape((1,4,9))

# check correctness of convolution via toeplitz matrix
print(np.sum((out - F.conv2d(torch.tensor(i).view(1,9),torch.tensor(k),padding = 1).numpy())**2))
本文链接:https://www.f2er.com/2661919.html

大家都在问