4

我正在尝试将张量 (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来获得这个乘法。我认为 Tensorflowtf.tensordot也会有类似的功能。

预期的解决方案应该是这样的:

def tensordot_multplication(A, B, C):
    """
    use np.tensordot
    """
4

2 回答 2

3

不要认为np.tensordot在这里对您有帮助,因为它需要分散不参与减和的轴,因为我们的对齐要求是在执行乘法时保持最后一个轴在三个输入之间对齐。因此,使用tensordot,您将需要额外的处理并在那里有更多的内存需求。

我会建议两种方法 - 一种 withbroadcasting和另一种 with np.einsum

方法#1:使用broadcasting-

(A[:,None,None,:]*B[:,None,:]*C).sum(-1)

解释 :

  • 通过在None/np.newaxis处引入新轴,扩展A到。4Daxis=(1,2)

  • 类似地,通过在 处引入新轴来扩展B到。3Daxis=(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可能不是。

于 2017-04-06T11:27:39.947 回答
1

您引用的代码实际上并不是 TensorLy 如何实现它,而只是文档中给出的替代实现。

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)

其中khatri_rao是使用 numpy.einsum 以概括 Divakar 建议的方式实现的。

于 2017-06-06T00:32:09.263 回答