如何解决在PyTorch中,计算欧式距离而不是矩阵乘法
假设我们有2个矩阵:
mat = torch.randn([20,7]) * 100
mat2 = torch.randn([7,20]) * 100
n,m = mat.shape
最简单的常用矩阵乘法如下所示:
def mat_vec_dot_product(mat,vect):
n,m = mat.shape
res = torch.zeros([n])
for i in range(n):
for j in range(m):
res[i] += mat[i][j] * vect[j]
return res
res = torch.zeros([n,n])
for k in range(n):
res[:,k] = mat_vec_dot_product(mat,mat2[:,k])
但是,如果我需要应用L2规范而不是点积怎么办?代码如下:
def mat_vec_l2_mult(mat,m = mat.shape
res = torch.zeros([n])
for i in range(n):
for j in range(m):
res[i] += (mat[i][j] - vect[j]) ** 2
res = res.sqrt()
return res
for k in range(n):
res[:,k] = mat_vec_l2_mult(mat,k])
我们可以使用Torch或其他任何库以某种最佳方式进行此操作吗?因为天真的O(n ^ 3)Python代码的工作速度非常慢。
解决方法
首先,PyTorch中的矩阵乘法具有内置运算符:@
。
因此,只需乘以mat和mat2即可:
mat @ mat2
(应该工作,假设尺寸一致)。
现在,要计算似乎要在第二个块中计算的平方差和(SSD或L2范数),您可以做一个简单的技巧。
由于平方L2范数||m_i - v||^2
(其中m_i
是矩阵M
的第i行,v
是向量)等于点积{{1 }}-从点积的线性获得:<m_i - v,m_i-v>
,因此您可以通过计算每行一次L2范数的平方来从向量<m_i,m_i> - 2<m_i,v> + <v,v>
计算M
中每一行的SSD ,一次是每行与向量之间的点积,一次是向量的L2范数。可以在v
中完成。
但是,对于2个矩阵之间的SSD,您仍然会得到O(n^2)
。尽管可以通过向量化操作而不是使用循环来进行改进。
这是2种矩阵的简单实现:
O(n^3)
所得矩阵将在def mat_mat_l2_mult(mat,mat2):
rows_norm = (torch.norm(mat,dim=1,p=2,keepdim=True)**2).repeat(1,mat2.shape[1])
cols_norm = (torch.norm(mat2,dim=0,keepdim=True)**2).repeat(mat.shape[0],1)
rows_cols_dot_product = mat @ mat2
ssd = rows_norm -2*rows_cols_dot_product + cols_norm
return ssd.sqrt()
mat = torch.randn([20,7])
mat2 = torch.randn([7,20])
print(mat_mat_l2_mult(mat,mat2))
的每个像元处具有i,j
的每一行i
与{{1}的每一列mat
之间的差的L2-范数}。
将torch.cdist
用于L2范数-欧几里德距离
res = torch.cdist(mat,mat2.permute(1,0),p=2)
在这里,我已经使用permute
将mat2
的暗淡从7,20
切换到20,7
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。