Help us understand the problem. What is going on with this article?

Tensornetwork+Kerasを実行してみる

はじめに

よくわからないですが、話の流れでテンソルネットワークが出てきたのでまとめながら実行します。

テンソルとテンソルネットワーク

テンソルは線形的な量を一般化したもので、基底を選べば多次元の配列として表現できるようなもの。そして、テンソルネットワークは大きなテンソルをより小さなテンソルに分解してネットワーク化したものです。

記法

足の数によって記法が変わります。*をノード、-をエッジとして見たときに、

・足が一つはベクトルになります。

---*
v_j =
\begin{bmatrix}
v_1\\
v_2\\
\vdots\\
v_n
\end{bmatrix}

・足が2つは行列になります。

---*---
M_{ij} = 
\begin{bmatrix}
M_{11} & \cdots & M_{1n}\\
\vdots\\
M_{m1} & \cdots & M_{mn}
\end{bmatrix}

・足が3つはオーダー3のテンソルになります。

---*---
   |
T_{ijk} = 
\begin{bmatrix}
T_{111} & \cdots & T_{1n1}\\
\vdots\\
T_{m11} & \cdots & T_{mn1}
\end{bmatrix}
,
\begin{bmatrix}
T_{112} & \cdots & T_{1n2}\\
\vdots\\
T_{m12} & \cdots & T_{mn2}
\end{bmatrix},
\cdots

(多分こうかな、、、)

縮約

ノード同士はエッジで接続され、それぞれ計算されます。

・ベクトルと行列
ベクトルと行列は縮約するとベクトルになります。

--*--* = ----*
v'_i = \sum_jM_{ij}v_j

・行列同士
行列同士は行列になります。足の数も変わりません。

--*--*-- = --*--
M_{ik} = A_{ij}B_{jk}

具体的にTensornetwork

イメージ湧かないので、Googleから提供されているオープンソースソフトウェアを使ってみます。インストールはpip経由で、

pip3 install tensornetwork

となります。Google colabでも使えます。

基本の形

基本はテンソルネットワークの形を決めてそれぞれをつなぎます。参考は下記になります。

import numpy as np
import tensornetwork as tn

a = tn.Node(np.ones((10,))) 
b = tn.Node(np.ones((10,)))
edge = a[0] ^ b[0]
final_node = tn.contract(edge)
print(final_node.tensor)

こうすると

10.0

が得られます。

少しずつ見てみる

まず読み込みます

import numpy as np
import tensornetwork as tn

次にノードを指定します。今回はAとBというベクトルを指定します。

a = tn.Node(np.ones((10,))) 
b = tn.Node(np.ones((10,)))

aとbにエッジを指定します。

edge = a[0] ^ b[0]

そして、これらのテンソル縮約をとって表示をして見ます。

final_node = tn.contract(edge)
print(final_node.tensor)

今回は、AとB共に下記のような10この要素が全て1のベクトルなので、

\begin{bmatrix}
1\\1\\\vdots\\1
\end{bmatrix}

計算結果は、

1∗1+1∗1+...+1∗1=10

と、スカラー量となります。

ベクトルと行列

aのベクトルとbの行列の縮約を取ると、

a = tn.Node(np.ones((5))) 
b = tn.Node(np.ones((5,5)))
edge = a[0] ^ b[0]
final_node = tn.contract(edge)
print(final_node.tensor)

これはベクトルになります。

[5. 5. 5. 5. 5.]
\begin{bmatrix}
1&1&1&1&1\\
1&1&1&1&1\\
1&1&1&1&1\\
1&1&1&1&1\\
1&1&1&1&1
\end{bmatrix}

\begin{bmatrix}
1\\1\\1\\1\\1
\end{bmatrix}
=

\begin{bmatrix}
5\\5\\5\\5\\5
\end{bmatrix}

Speeding up neural networks using TensorNetwork in Keras

Kerasと組み合わせてできるそうです。やってみたい。例題動かすだけで申し訳ないですが、
https://blog.tensorflow.org/2020/02/speeding-up-neural-networks-using-tensornetwork-in-keras.html

基本的には計算の重たい行列部分を分解します。

Screen Shot 2020-02-11 at 11.21.38 AM.png

!pip install tensornetwork

#ツールを読み込みます。今回はtensorflow2.0を利用
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
tf.enable_v2_behavior()

import tensornetwork as tn

#デフォルトのバックエンドをnumpyからtensorflowに変更
tn.set_default_backend("tensorflow")
class TNLayer(tf.keras.layers.Layer):

  def __init__(self):
    super(TNLayer, self).__init__()
    # 各層の変数を決めます。
    self.a_var = tf.Variable(tf.random.normal(
            shape=(32, 32, 2), stddev=1.0/32.0),
             name="a", trainable=True)
    self.b_var = tf.Variable(tf.random.normal(shape=(32, 32, 2), stddev=1.0/32.0),
                             name="b", trainable=True)
    self.bias = tf.Variable(tf.zeros(shape=(32, 32)), name="bias", trainable=True)

  def call(self, inputs):
    # 縮約を定義し、並列計算を可能にする
    def f(input_vec, a_var, b_var, bias_var):
      # ベクトルの代わりに行列に
      input_vec = tf.reshape(input_vec, (32,32))

      # ネットワークを決める
      a = tn.Node(a_var)
      b = tn.Node(b_var)
      x_node = tn.Node(input_vec)
      a[1] ^ x_node[0]
      b[1] ^ x_node[1]
      a[2] ^ b[2]

      # 行列をaとbに分解
      #   |     |
      #   a --- b
      #    \   /
      #      x

      # 縮約実行
      c = a @ x_node
      result = (c @ b).tensor

      # バイアスを付加
      return result + bias_var

    # バッチ処理に tf.vectorized_map を利用する
    result = tf.vectorized_map(
        lambda vec: f(vec, self.a_var, self.b_var, self.bias), inputs)
    return tf.nn.relu(tf.reshape(result, (-1, 1024)))

テンソル分解する前のモデルは、

Dense = tf.keras.layers.Dense
fc_model = tf.keras.Sequential(
    [
     tf.keras.Input(shape=(2,)),
     Dense(1024, activation=tf.nn.relu),
     Dense(1024, activation=tf.nn.relu),
     Dense(1, activation=None)])
fc_model.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_5 (Dense)              (None, 1024)              3072      
_________________________________________________________________
dense_6 (Dense)              (None, 1024)              1049600   
_________________________________________________________________
dense_7 (Dense)              (None, 1)                 1025      
=================================================================
Total params: 1,053,697
Trainable params: 1,053,697
Non-trainable params: 0
_________________________________________________________________

パラメータ数は100万あります。これをテンソルネットワークレイヤーに置き換えると、

tn_model = tf.keras.Sequential(
    [
     tf.keras.Input(shape=(2,)),
     Dense(1024, activation=tf.nn.relu),
     # MPSで書き換えた結果
     TNLayer(),
     Dense(1, activation=None)])
tn_model.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_8 (Dense)              (None, 1024)              3072      
_________________________________________________________________
tn_layer_1 (TNLayer)         (None, 1024)              5120      
_________________________________________________________________
dense_9 (Dense)              (None, 1)                 1025      
=================================================================
Total params: 9,217
Trainable params: 9,217
Non-trainable params: 0
_________________________________________________________________

9200程度に削減できました。]

訓練

訓練させてみます

X = np.concatenate([np.random.randn(20, 2) + np.array([3, 3]), 
             np.random.randn(20, 2) + np.array([-3, -3]), 
             np.random.randn(20, 2) + np.array([-3, 3]), 
             np.random.randn(20, 2) + np.array([3, -3]),])

Y = np.concatenate([np.ones((40)), -np.ones((40))])
tn_model.compile(optimizer="adam", loss="mean_squared_error")
tn_model.fit(X, Y, epochs=300, verbose=1)

イメージをプロットさせてみます

# Plotting code, feel free to ignore.
h = 1.0
x_min, x_max = X[:, 0].min() - 5, X[:, 0].max() + 5
y_min, y_max = X[:, 1].min() - 5, X[:, 1].max() + 5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))

# here "model" is your model's prediction (classification) function
Z = tn_model.predict(np.c_[xx.ravel(), yy.ravel()]) 

# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z)
plt.axis('off')

# Plot also the training points
plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired)

ダウンロード.png

比較

fc_model.compile(optimizer="adam", loss="mean_squared_error")
fc_model.fit(X, Y, epochs=300, verbose=0)
# Plotting code, feel free to ignore.
h = 1.0
x_min, x_max = X[:, 0].min() - 5, X[:, 0].max() + 5
y_min, y_max = X[:, 1].min() - 5, X[:, 1].max() + 5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                     np.arange(y_min, y_max, h))

# here "model" is your model's prediction (classification) function
Z = fc_model.predict(np.c_[xx.ravel(), yy.ravel()]) 

# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z)
plt.axis('off')

# Plot also the training points
plt.scatter(X[:, 0], X[:, 1], c=Y, cmap=plt.cm.Paired)

ダウンロード (1).png

まとめ

とりあえず使ってみただけですが、簡単に統合できるので、この線をしばらく突き詰めてみたいと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした