使用np.tensordot

时间:2017-04-06 11:19:10

标签: python numpy tensorflow tensor scikit-tensor

我试图将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
    """

2 个答案:

答案 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