面白いデータを探して

適当に書く。間違えていたら教えてください。

tf.SparseTensorとone hot表現

tensorflowのSparseTensorとone hot表現の関係についての備忘録

12/26 tf.one_hotについて追記

one hot表現

ある行列 Wに対してこの W i行目だけを抜き出してきたい場合について、前からone hotベクトル( i番目の要素だけ1でそれ以外は0のベクトル)をかけてやればいい。

具体例として、Wの2行目と1行目を順に抜き出す場合には *1

W = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
a = np.array([[0, 1, 0], [1, 0, 0]])
b = np.matmul(a, W)
print(b)

[[5 6 7 8]
 [1 2 3 4]]

また、行列積の転置の性質( (AB)^{\mathrm{T}}=B^{\mathrm{T}}A^{\mathrm{T}})を使うことにより、第一引数にWを使わなければ行けない場合には

W = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
a = np.array([[0, 1, 0], [1, 0, 0]])
Wt = np.transpose(W)
at = np.transpose(a)
b = np.matmul(Wt, at)
bt = np.transpose(b)
print(b)
print(bt)

[[5 1]
 [6 2]
 [7 3]
 [8 4]]
[[5 6 7 8]
 [1 2 3 4]]

のようにすればよい。

tf.SparseTensor

ほとんどの要素が0でいくつかの要素のみが具体的な値を持つような行列をSparse Matrixとかよぶ。Sparse Matrixをtf.Variableのような形でメモリにおいておくのは非効率なので、そのような場合にはSparseMatrixとかを使う。

使い方は

x = tf.SparseTensor(indices=[[0, 0], [1, 2]], values=[1, 2], dense_shape=[3, 4])

というような感じ。indicesは要素の位置、valuesはその値、dense_shapeは行列の形。上の例では(0, 0)の値が1、(1, 2)の値が2でその他の値が0の3行4列の行列になる。つまり、

[[1, 0, 0, 0]
 [0, 0, 2, 0]
 [0, 0, 0, 0]]

Sparse Matrixの掛け算

tf.sparse.matmulを使う

tf.sparse.matmul(sparse_matrix, dense_matrix)

sparse matrixとdense matrixの順番を逆にすることはできない。また、返り値はdense matrixになる。

Sparse Matrixとone hot表現

Sparse matrixの第 i行を抜き出して来たければ次のようにすればいいらしい。*2

import tensorflow as tf
import numpy as np

indices = [[i, j] for i in range(3) for j in range(4)]
values = [i for i in range(1, 13)]
W = tf.SparseTensor(indices=indices, values=values, dense_shape=[3, 4] # 上の例と同じ
a = tf.Variable(np.array([[0, 1, 0], [1, 0, 0]]), dtype=tf.int32)
Wt = tf.sparse.transpose(W)
at = tf.transpose(a)
b = tf.sparse.matmul(Wt, at)
bt = tf.transpose(b)

with tf.Session() as sess:
  sess.run(tf.global_variables_initializer())
  print(sess.run(b))
  print(sess.run(bt))

[[5 1]
 [6 2]
 [7 3]
 [8 4]]
[[5 6 7 8]
 [1 2 3 4]]

上と同じ結果が得られた。

追記: tf.one_hot

tf.one_hotを使うとone hotベクトルを作ることができる。引数はindicesとdepth。indicesは何番目に1をたてるか、depthは行の長さ。

import tensorflow as tf
import numpy as np

indices = [[i, j] for i in range(3) for j in range(4)]
values = [i for i in range(1, 13)]
W = tf.SparseTensor(indices=indices, values=values, dense_shape=[3, 4])
one_hot_indices = tf.placeholder(tf.int32, shape=[None])
one_hot_depth = tf.placeholder(tf.int32)
a = tf.one_hot(one_hot_indices, one_hot_depth, dtype=tf.int32)
Wt = tf.sparse.transpose(W)
at = tf.transpose(a)
b = tf.sparse.matmul(Wt, at)
bt = tf.transpose(b)

with tf.Session() as sess:
  sess.run(tf.global_variables_initializer())
  feed_dict={one_hot_indices: [1, 0], one_hot_depth:3}
  print(sess.run(b, feed_dict=feed_dict))
  print(sess.run(bt, feed_dict=feed_dict))

[[5 1]
 [6 2]
 [7 3]
 [8 4]]
[[5 6 7 8]
 [1 2 3 4]]

結果は同じ。

*1:numpyの場合、np.matmulと*の使い分けに注意

*2:例なのでスパースじゃないです。