形状为K
的2D卷积核(k1, k2, n_channel, n_filter)
应用于形状为A
的2D向量(m1, m2, n_channel)
并生成另一个2D向量{{1} },形状为B
(具有 valid 填充)。
对于每个(m1 - k1 + 1, m2 - k2 + 1, n_filter)
,确实存在形状为K
的{{1}},因此W_K
和(m1 - k1 + 1, m2 - k2 + 1, n_filter, m1, m2, n_channel)
的张量点相等到W_K
。即A
。
我正在尝试寻找一种纯粹的NumPy解决方案,以从B
生成此B = np.tensordot(W_K, A, 3)
,而不使用任何python循环。
我可以看到W_K
或简单地看到K
。
我正在寻找的东西几乎类似于Toeplitz矩阵。但是我需要多维的内容。
循环代码示例:
W_K[i,j,f] == np.pad(K[...,f], ((i,m1-i-k1), (j,m2-j-k2)), 'constant', constant_values=0)
答案 0 :(得分:3)
您想要的内容需要一点fancy indexing的体操技巧,但是编写代码并不是很麻烦。这个想法是创建应用第二个循环示例的W_K[i, j, i:i+2, j:j+2, ...]
部分的4维索引数组。
这里是示例的略微修改版本,只是为了确保某些相关维度有所不同(因为这使错误更易于发现:它们将是适当的错误,而不是值不正确的错误):
import numpy as np
# parameter setup
k1, k2, nch, nf = 2, 4, 3, 2
m1, m2 = 5, 6
w1, w2 = m1 - k1 + 1, m2 - k2 + 1
K = np.random.random((k1, k2, nch, nf))
A = np.random.random((m1, m2, nch))
# your loopy version for comparison
W_K = np.zeros((w1, w2, nf, m1, m2, nch))
for i, j in np.ndindex(w1, w2):
W_K[i, j, :, i:i+k1, j:j+k2, ...] = K.transpose(-1, 0, 1, 2)
W_K2 = np.zeros((w1, w2, m1, m2, nch, nf)) # to be transposed back
i,j = np.mgrid[:w1, :w2][..., None, None] # shape (w1, w2, 1, 1)
k,l = np.mgrid[:k1, :k2] # shape (k1, k2) ~ (1, 1, k1, k2)
W_K2[i, j, i+k, j+l, ...] = K
W_K2 = np.moveaxis(W_K2, -1, 2)
print(np.array_equal(W_K, W_K2)) # True
我们首先创建一个跨越i,j
前两个维度的索引网格W_K
,然后创建一个跨越其{pre {moveaxis
)第二和第三个维度的相似网格。通过将两个尾随的单例维度注入到前者中,我们得到4d索引数组,这些数组一起跨越W_K
的前四个维度。
剩下的就是使用原始的K
将此切片分配给该切片,然后移回该尺寸。当表达式中的切片索引(非高级索引)不是彼此相邻时,由于高级索引如何改变行为,因此使用moveaxis
方法更容易做到。我首先尝试创建具有最终尺寸的W_K2
,但随后我们的W_K[i, j, :, i+k, j+l, ...]
的行为却有所不同(特别是形状不同)。