TensorLy で テンソル分解

最終更新日: 2020年6月1日

TensorLyは、Pythonでシンプルで高速なテンソル学習ができるパッケージです

インストール

pipやcondaでインストールできます。

pip
pip install -U tensorly
conda
conda install -c tensorly tensorly

テンソルの作成

Numpy 配列から変換できます。3次のテンソル(3×4×23 \times 4 \times 2)を作成します。

python
import tensorly as tl
import numpy as np

tensor = tl.tensor(np.arange(24).reshape((3, 4, 2)), dtype=tl.float64)
print(tensor)
output
[[[ 0.  1.]
  [ 2.  3.]
  [ 4.  5.]
  [ 6.  7.]]

 [[ 8.  9.]
  [10. 11.]
  [12. 13.]
  [14. 15.]]

 [[16. 17.]
  [18. 19.]
  [20. 21.]
  [22. 23.]]]

バックエンドは、Numpy, MXNet, PyTorch, TensorFlow, CuPy が使える模様です。デフォルトは Numpy となっています。


テンソル分解とは?

テンソルをより次数の少ないテンソルの積和で表現する手法です。行列分解のテンソルへの拡張とも言えます。分解したテンソルは元のテンソルの特徴を集約して表現するため、画像処理や言語処理などに用いられています

参考:

CP分解(Canonical Polyadic Decomposition)

CP分解は、PARAFAC や CANDECOMP とも呼ばれる方法で、テンソルを次数と同じ数のベクトルの積の和で表す方法です。3次のテンソルの場合、以下のような演算が成立するように分解されます。

χijk=r=1Rair(1)ajr(2)akr(3)\chi_{ijk} = \sum_{r=1}^{R} a_{ir}^{(1)} a_{jr}^{(2)} a_{kr}^{(3)}

このとき、aa をまとめてベクトル、行列として表示できます。

A(m)=[a1(m)a2(m)aR(m)]A^{(m)} = \begin{bmatrix} a_1^{(m)} & a_2^{(m)} & \cdots & a_R^{(m)} \end{bmatrix} \\
A(m)=[a11(m)a12(m)a1R(m)aim1(m)aim2(m)aimR(m)]A^{(m)}= \begin{bmatrix} a_{11}^{(m)} & a_{12}^{(m)} & \cdots & a_{1R}^{(m)} \\ \vdots & \vdots & \ddots & \vdots \\ a_{i_m1}^{(m)} & a_{i_m2}^{(m)} & \cdots & a_{i_mR}^{(m)} \end{bmatrix}

3次のテンソル(3×4×23 \times 4 \times 2)を R=2R=2 で CP分解すると、因子A(m)A^{(m)} は(3×23 \times 2)と(4×24 \times 2)と(2×22 \times 2)になります。

TensorLy では、tensorly.decomposition.parafac で CP分解ができます。因子からテンソルを復元するには、tensorly.kruskal_to_tensor を使います。

python
from tensorly.decomposition import parafac

factors = parafac(tensor, rank=2)
reconstructed_tensor = tl.kruskal_to_tensor(factors)

print([f.shape for f in factors])
output
[(3, 2), (4, 2), (2, 2)]

参考:Alternating Least Square (ALS) でCP分解 - でかいチーズをベーグルする

タッカー分解(Tucker Decomposition)

タッカー分解は、テンソルをコアテンソルと次数と同じ数のベクトルの積の和で表す方法です。3次のテンソルの場合、以下のような演算が成立するように分解されます。

χijk=r=1Rs=1St=1Tgrstair(1)ajr(2)akr(3)\chi_{ijk} = \sum_{r=1}^{R} \sum_{s=1}^{S} \sum_{t=1}^{T} g_{rst} a_{ir}^{(1)} a_{jr}^{(2)} a_{kr}^{(3)}

このとき、grstg_{rst} はコアテンソル G\mathcal{G} の要素となります。

3次のテンソル(3×4×23 \times 4 \times 2)を (R,S,T)=(2,2,2)(R,S,T)=(2,2,2) で タッカー分解すると、コアテンソル G\mathcal{G} は(2×2×22 \times 2 \times 2)に、 因子A(m)A^{(m)} は(3×23 \times 2)と(4×24 \times 2)と(2×22 \times 2)になります。

TensorLy では、tensorly.decomposition.tucker で タッカー分解ができます。コアテンソルと因子からテンソルを復元するには、tensorly.tucker_to_tensor を使います。

python
from tensorly.decomposition import tucker

core, factors = tucker(tensor, rank=[2, 2, 2])
reconstructed_tensor = tl.tucker_to_tensor(core, factors)

print(core.shape)
print([f.shape for f in factors])
output
[output]
(2, 2, 2)
[(3, 2), (4, 2), (2, 2)]

参考:Tucker分解の導出と実装 - でかいチーズをベーグルする

テンソルトレイン分解(Tensor-Train Decomposition)

テンソルトレイン分解は、テンソルを3次のテンソルの積の和で表す方法です。3次のテンソルの場合、以下のような演算が成立するように分解されます。

χijk=r0=1R0r1=1R1r2=1R2r3=1R3gr0ir1(1)gr1ir2(2)gr2ir3(3)\chi_{ijk} = \sum_{r_0=1}^{R_0} \sum_{r_1=1}^{R_1} \sum_{r_2=1}^{R_2} \sum_{r_3=1}^{R_3} g_{r_0 i r_1}^{(1)} g_{r_1 i r_2}^{(2)} g_{r_2 i r_3}^{(3)}

3次のテンソル(3×4×23 \times 4 \times 2)を TT-Rank =(1,2,2,1)=(1,2,2,1) で テンソルトレイン分解すると、TTコア G(m)\mathcal{G}^{(m)} は(1×3×21 \times 3 \times 2)と(2×4×22 \times 4 \times 2)と(2×2×12 \times 2 \times 1)になります。

TensorLy では、tensorly.decomposition.matrix_product_state で テンソルトレイン分解ができます。TTコアからテンソルを復元するには、tensorly.mps_to_tensor を使います。

python
from tensorly.decomposition import matrix_product_state

ttcore = matrix_product_state(tensor, rank=[1,2,2,1])
reconstructed_tensor = tl.mps_to_tensor(ttcore)

print([c.shape for c in ttcore])
output
[output]
[(1, 3, 2), (2, 4, 2), (2, 2, 1)]

参考:Rでtensor train decomposition してみた


Reference