Python 用np.tensordot求矩阵的Khatri积
我试图将张量(m,n,o)分解成矩阵a(m,r),B(n,r)和C(k,r)。这被称为PARAFAC分解。已经进行了这种分解 一个重要的步骤是将A、B和C相乘,得到形状张量(m、n、o) 张力如下所示:Python 用np.tensordot求矩阵的Khatri积,python,numpy,tensorflow,tensor,scikit-tensor,Python,Numpy,Tensorflow,Tensor,Scikit Tensor,我试图将张量(m,n,o)分解成矩阵a(m,r),B(n,r)和C(k,r)。这被称为PARAFAC分解。已经进行了这种分解 一个重要的步骤是将A、B和C相乘,得到形状张量(m、n、o) 张力如下所示: def kt_to_tensor(A, B, C): factors = [A, B, C] for r in range(factors[0].shape[1]): vecs = np.ix_(*[u[:, r] for u in factors])
def kt_to_tensor(A, B, C):
factors = [A, B, C]
for r in range(factors[0].shape[1]):
vecs = np.ix_(*[u[:, r] for u in factors])
if r:
res += reduce(np.multiply, vecs)
else:
res = reduce(np.multiply, vecs)
return res
def new_kt_to_tensor(A, B, C):
m, n, o = A.shape[0], B.shape[0], C.shape[0]
out = np.zeros((m, n, o))
k_max = A.shape[1]
for alpha in range(0, m):
for beta in range(0, n):
for delta in range(0, o):
for k in range(0, k_max):
out[alpha, beta, delta]=out[alpha, beta, delta]+ A[alpha, k]*B[beta, k]*C[delta, k]
return out
但是,我正在使用的包(Autograd)不支持np.ix
操作。因此,我写了一个更简单的定义如下:
def kt_to_tensor(A, B, C):
factors = [A, B, C]
for r in range(factors[0].shape[1]):
vecs = np.ix_(*[u[:, r] for u in factors])
if r:
res += reduce(np.multiply, vecs)
else:
res = reduce(np.multiply, vecs)
return res
def new_kt_to_tensor(A, B, C):
m, n, o = A.shape[0], B.shape[0], C.shape[0]
out = np.zeros((m, n, o))
k_max = A.shape[1]
for alpha in range(0, m):
for beta in range(0, n):
for delta in range(0, o):
for k in range(0, k_max):
out[alpha, beta, delta]=out[alpha, beta, delta]+ A[alpha, k]*B[beta, k]*C[delta, k]
return out
然而,事实证明,这种实现也有一些autograd不支持的方面。但是,autograd确实支持np.tensordot
我想知道如何使用np.tensordot
来获得这个乘法。我认为Tensorflow的tf.tensordot
也会有类似的功能
预期的解决方案应类似于:
def tensordot_multplication(A, B, C):
"""
use np.tensordot
"""
不要认为
np.tensordot
会对您有所帮助,因为它需要展开不参与求和的轴,因为我们有一个对齐要求,即在执行乘法时保持三个输入之间的最后一个轴对齐。因此,使用tensordot
,您将需要额外的处理,并且需要更多的内存
我建议使用两种方法,一种是使用,另一种是使用
方法#1:使用广播
-
(A[:,None,None,:]*B[:,None,:]*C).sum(-1)
说明:
- 将
扩展到A
,方法是在4D
处引入具有None/np.newaxis的新轴轴=(1,2)
- 同样地,通过在轴=(1)处引入新的轴,将
扩展到B
3D
- 保持
原样,执行元素乘法,生成C
数组4D
- 最后,总和减少沿
数组的最后一个轴进行4D
A : m r
B : n r
C : k r
=> A*B*C : m n k r
=> out : m n k # (sum-reduction along last axis)
方法#2:带有np.einsum
-
np.einsum('il,jl,kl->ijk',A,B,C)
这里的想法与之前的广播
相同,但字符串符号帮助我们以更简洁的方式传递轴信息
Broadcasting
当然可以在tensorflow
上使用,因为它有工具可以使用,而np.einsum
可能不是。您提到的代码实际上不是如何紧张地实现它,而只是文档中给出的替代实现
在TensorLy中使用的是:
def kruskal_to_tensor(factors):
shape = [factor.shape[0] for factor in factors]
full_tensor = np.dot(factors[0], khatri_rao(factors[1:]).T)
return fold(full_tensor, 0, shape)
其中使用numpy.einsum以概括Divakar建议的方式实现。谢谢!这太棒了!如果您可以添加几行解释每个解决方案,那就太好了!谢谢你的编辑。现在真的很有用了!我对你的评论感到惊讶。这已经成为numpy的一部分很长时间了。
reduce
可能需要在PY3中导入。@hpaulj:Numpy不支持这些。但是,Autograd不允许使用.ix_u计算梯度。请参阅:ix
只进行Divakar第一种方法所做的维度扩展。reduce
应用乘法部分。好的。只是Autograd目前不支持ix_,我看的是Autograd
。显然,它解析numpy代码,并实现自己的“符号”渐变。它实际上并没有运行你的函数ix
位于一个名为np.lib.index
的文件中,提供了多种索引快捷方式,但没有新功能。