我试图将Tensor(m,n,o)分解为矩阵A(m,r),B(n,r)和C(k,r)。这称为PARAFAC分解。 Tensorly已经进行了这种分解。
重要的一步是将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])
if r:
res += reduce(np.multiply, vecs)
else:
res = reduce(np.multiply, vecs)
return res
但是,我使用的程序包(Autograd)不支持np.ix_
操作。因此我写了一个更简单的定义如下:
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
"""
答案 0 :(得分:3)
不要认为np.tensordot
会对您有所帮助,因为它需要展开不参与减税的轴,正如我们所拥有的那样在执行乘法时保持最后一个轴在三个输入之间对齐的对齐要求。因此,对于tensordot
,您需要额外的处理并且在那里有更多的内存要求。
我建议使用两种方法 - 一种使用broadcasting
,另一种使用np.einsum
。
方法#1:使用broadcasting
-
(A[:,None,None,:]*B[:,None,:]*C).sum(-1)
说明:
通过在A
处使用None / np.newaxis引入新轴,将4D
扩展为axis=(1,2)
。
同样通过在B
引入新轴将3D
扩展为axis=(1)
。
保持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
相同,但使用字符串表示法可帮助我们以更简洁的方式传达轴信息。
Broadcasting
肯定可以在tensorflow
上使用,因为它有expand dimensions
的工具,而np.einsum
可能不是。{/ p>
答案 1 :(得分:1)
您所引用的代码实际上并不是TensorLy如何实现它,而只是文档中给出的替代实现。
TensorLy中使用的actual code是:
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建议的方式实现khatri_rao。