Kronecker Product及pytorch實現
原始文檔:https://www.yuque.com/lart/idh721/gb2h93
計算過程
PyTorch實現
起因是看到了這篇文章:https://zhuanlan.zhihu.com/p/79295551介紹了一種新穎的卷積方式,其中使用了kronecker product方法來實現。這種計算理解很容易,但是實現起來該如何編程,這是一個值得思考的問題。文章結尾作者推薦的代碼中給出了一種實現https://github.com/d-li14/dgconv.pytorch/blob/master/dgconv.py#L26:
def kronecker_product(mat1, mat2):
out_mat = torch.ger(mat1.view(-1), mat2.view(-1))
# 這裏的(mat1.size() + mat2.size())表示的是將兩個list拼接起來
out_mat = out_mat.reshape(*(mat1.size() + mat2.size())).permute([0, 2, 1, 3])
out_mat = out_mat.reshape(mat1.size(0) * mat2.size(0), mat1.size(1) * mat2.size(1))
return out_mat
這裏應該參考的是這裏的方法https://discuss.pytorch.org/t/kronecker-product/3919/7?u=i-love-u。但是該帖子後面給出了一種更簡單的方法https://discuss.pytorch.org/t/kronecker-product/3919/10:
def kronecker(A, B):
AB = torch.einsum("ab,cd->acbd", A, B)
AB = AB.view(A.size(0)*B.size(0), A.size(1)*B.size(1))
return AB
二者實際上是一致的,也就是說這裏的out_mat = torch.ger(mat1.view(-1), mat2.view(-1)), ``out_mat = out_mat.reshape(*(mat1.size() + mat2.size())).permute([0, 2, 1, 3])
,與這裏的enisum AB = torch.einsum("ab,cd->acbd", A, B)
表示的是一樣的行爲。
在前者中,假設 A=mat1
且 B=mat2
,二者分別爲axb和cxd大小的矩陣。對於二者先通過矢量化後,利用外積操作計算出了各個元素之間的乘積構成的矩陣,大小爲abxcd,再將結果調整爲axbxcxd大小的形狀,利用permute
操作調整後,變成了axcxbxd大小的形狀。這也正是符合einsum
中的維度索引的調整 'ab, cd->acbd'
。殊途同歸。
簡單的解釋。我們最終的目標是得到這樣一個結果:
注意!這裏有下角的2x2方陣中的b的下標有誤,注意!
這裏我標註了A和B對應的下標的變化範圍。由於我們利用PyTorch實現這些處理,那我們必定是要使用對應的矩陣運算和形狀變換的。從這裏的圖可以看出來,若是對於這裏的結果直接使用 view
操作,那麼可以得到這樣的結果:
注意!這裏和前圖相同對應的位置上下標有誤,注意!
這實際上也就是索引爲 (i,m,j,n)
的2D矩陣。 也就是更直接的,對於 torch.einsum("ab,cd->acbd", A, B)
的結果的表示。所以也就出現了前面的兩種形式的代碼。
參考資料
- http://mathworld.wolfram.com/KroneckerProduct.html
- 淺談張量分解(四):外積、Kronecker積和張量積 - Xinyu Chen的文章 - 知乎:https://zhuanlan.zhihu.com/p/26774182
- 畫圖工具:http://asciiflow.com/
- 輕量型網絡:可微分組卷積 - Happy的文章 - 知乎
https://zhuanlan.zhihu.com/p/79295551