2017-04-06 91 views
4

我試圖將矩陣A(m,r),B(n,r)和C(k,r)分解一個張量(m,n,o)。這就是所謂的PARAFAC分解。 Tensorly已經做了這種分解。使用np.tensordot的矩陣Khatri產品

一個重要的步驟是乘以A,B和C以獲得形狀張量(m,n,o)。

Tensorly做到這一點,如下所示:

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

我很驚訝你的'ix_'評論。這已經是很長一段時間了。 'reduce'可能需要在PY3中導入。 – hpaulj

+0

@hpaulj:Numpy確實支持這些。但是,Autograd不允許使用.ix_來計算漸變。請參閱:https://github.com/HIPS/autograd/issues/210 –

+0

'ix_'只是Divakar第一種方法所做的維度擴展。 'reduce'應用乘法部分。 – hpaulj

回答

3

不要以爲np.tensordot將幫助你在這裏,因爲它需要展開的的不參與總和,減少軸,如我們有對齊要求,在執行乘法時保持最後一個軸在三個輸入之間對齊。因此,使用tensordot時,您需要額外的處理並且在那裏有更多的內存需求。

我會建議兩種方法 - 一種是broadcasting,另一種是np.einsum

方法#1:隨着broadcasting -

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

說明:

  • 擴展A4D,通過在與axis=(1,2)無/ np.newaxis引入新的軸。

  • 通過在axis=(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之一,但串符號以更簡潔的方式幫助我們傳達軸信息。

Broadcasting肯定可以在tensorflow,因爲它有工具expand dimensions,而np.einsum可能不是。

+0

謝謝!這很棒!如果您可以添加幾行解釋每個解決方案,那將是非常棒的! –

+0

感謝您的編輯。這真的使它非常有用! –

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) 

其中khatri_rao在一般化什麼Divakar建議的方式使用numpy.einsum實現。

+0

非常感謝您的澄清! –