NumPyでテンソル積を取得するtensordot()関数の使い方

Numpyのtensordot()関数は、2つのテンソル(3次元配列)からテンソル積を求める関数です。

2つのテンソルa とb を渡して、第三引数に (aの次元軸, bの次元軸)をタプルで渡すと、a とb の指定の次元軸の要素の積の和を求めます。第三引数に1つの整数N だけを渡した場合は、a の最後からN個目の次元軸とb の最初からN個目の次元軸の要素の積の和を求めます。

実際にサンプルコードを見ながら確認していきましょう。

目次

1. numpy.tensordot()の使い方

まずは、numpy.outer()の書式を確認しましょう。

numpy.tensordot関数

書き方:

np.tensordot(a, b, axes=2)

パラメーター:

引数 解説
a   array_like  テンソル積を求めるためのテンソル
b   array_like   同上
axes   int or  array_like
of shape(2,)
・整数N を渡した場合は、a の最後からN番目の次元軸と、b の最初からN番目の次元軸の要素を合計します。お互いの次元軸の要素数は一致している必要があります。
・shape(2,)の配列やリストで合計を求める次元軸を指定します。最初の要素はa の次元軸、2番目の要素はb の次元軸として適用されます。指定の次元軸の要素数が揃っている必要があります。 

戻り値: 

配列
テンソル積を要素とする配列を戻します。

一緒に確認したい関数:

  • dot
  • einsum

Notes

最初はaxesの設定に戸惑うかもしれません。しかし、一般的な使用例は以下の3通りなので、まずはこれらを知っておけば十分です。

  • axes=0: テンソル積 a⊗b
  • axes=1: テンソル内積 a・b
  • axes=2: テンソルの二重縮約 a:b (※デフォルト)

axes に整数(integer_like)Nを渡した場合、式は a の axis=-N とb のaxis=0 で始まり、a のaxis=-1 とb のaxis=N で終わります。

複数の次元軸を設定する場合で、それらが aの最初の軸またはbの最後の軸でない場合、引数 axesは、同じ要素数の2つのシーケンスになっている必要があります。

出力結果のshapeは、(最初のテンソルの非縮約軸, 2つ目のテンソルの非縮約軸)という並びになります。

2. サンプルコード

それではサンプルコードを確認しましょう。

まずはテンソル(3次元配列)のa とb を作成します。

In [1]:
import numpy as np
a = np.arange(60).reshape(3,4,5)
b = np.arange(24).reshape(4,3,2)

最も一般的なテンソル積は次のものでしょう。

In [2]:
# テンソル積を取得
c = np.tensordot(a,b, axes=([1,0],[0,1]))
c
Out[2]:
array([[4400, 4730],
       [4532, 4874],
       [4664, 5018],
       [4796, 5162],
       [4928, 5306]])

戻り値の配列のshapeは、それぞれのテンソルの非縮約軸を組み合わせたものになります。

In [3]:
# shapeはa とb の非縮約軸を組み合わせたもの
# この場合はa,bともに最後の軸が非縮約軸
c.shape
Out[3]:
(5, 2)

なお、これは次のように書くのと同じですが、numpy.tensordot()関数を使った方がコードも処理も軽いです。

In [4]:
# 以下のコードを計算しているのと同じ
d = np.zeros((5, 2))
for i in range(5):
    for j in range(2):
        for k in range(3):
            for l in range(4):
                d[i,j] += a[k,l,i] * b[l,k,j]
d
Out[4]:
array([[4400., 4730.],
       [4532., 4874.],
       [4664., 5018.],
       [4796., 5162.],
       [4928., 5306.]])

テンソルa, bのそれぞれの次元軸要素の計算関係は、次のようなコードで見てみると分かりやすいでしょう。

In [1]:
import numpy as np
a = np.arange(1, 9).reshape(2, 2, 2)
A = np.array([['a', 'b', 'c', 'd']], dtype=object).reshape(2, 2)
In [2]:
np.tensordot(a, A) # デフォルトはaxes=2
Out[2]:
array(['abbcccdddd', 'aaaaabbbbbbcccccccdddddddd'], dtype=object)
In [3]:
np.tensordot(a, A, 1) # axes=1
Out[3]:
array([[['acc', 'bdd'],
        ['aaacccc', 'bbbdddd']],

       [['aaaaacccccc', 'bbbbbdddddd'],
        ['aaaaaaacccccccc', 'bbbbbbbdddddddd']]], dtype=object)
In [4]:
np.tensordot(a, A, 0)  # axes=0
Out[4]:
array([[[[['a', 'b'],
          ['c', 'd']],

         [['aa', 'bb'],
          ['cc', 'dd']]],


        [[['aaa', 'bbb'],
          ['ccc', 'ddd']],

         [['aaaa', 'bbbb'],
          ['cccc', 'dddd']]]],



       [[[['aaaaa', 'bbbbb'],
          ['ccccc', 'ddddd']],

         [['aaaaaa', 'bbbbbb'],
          ['cccccc', 'dddddd']]],


        [[['aaaaaaa', 'bbbbbbb'],
          ['ccccccc', 'ddddddd']],

         [['aaaaaaaa', 'bbbbbbbb'],
          ['cccccccc', 'dddddddd']]]]], dtype=object)
In [5]:
np.tensordot(a, A, (0, 1))  # axes=(0, 1)
Out[5]:
array([[['abbbbb', 'cddddd'],
        ['aabbbbbb', 'ccdddddd']],

       [['aaabbbbbbb', 'cccddddddd'],
        ['aaaabbbbbbbb', 'ccccdddddddd']]], dtype=object)
In [6]:
np.tensordot(a, A, (2, 1)) # axes=(2, 1)
Out[6]:
array([[['abb', 'cdd'],
        ['aaabbbb', 'cccdddd']],

       [['aaaaabbbbbb', 'cccccdddddd'],
        ['aaaaaaabbbbbbbb', 'cccccccdddddddd']]], dtype=object)
In [7]:
np.tensordot(a, A, ((0, 1), (0, 1))) # axes=((0, 1), (0, 1))
Out[7]:
array(['abbbcccccddddddd', 'aabbbbccccccdddddddd'], dtype=object)
In [8]:
np.tensordot(a, A, ((2, 1), (1, 0)))
Out[8]:
array(['acccbbdddd', 'aaaaacccccccbbbbbbdddddddd'], dtype=object)

3. まとめ

以上がnumpy.tensordot()の使い方です。



よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

目次
閉じる