テンソルスライスの基礎

TensorFlow.org で表示 Google Colab で実行 GitHub でソースを表示 ノートブックをダウンロード

オブジェクト検出や NLP などの機械学習アプリケーションでは、テンソルのサブセクション(スライス)を使用する必要がある場合があります。たとえば、モデルアーキテクチャにルーティングが含まれている場合、1 つのレイヤーが次のレイヤーにルーティングされるトレーニングサンプルを制御することがあります。この場合、テンソルスライス演算を使用して、テンソルを分割し、正しい順序に戻すことができます。

NLP アプリケーションでは、トレーニング時にテンソルスライスを使用してワードマスキングを実行できます。たとえば、各文でマスクする単語インデックスを選択し、その単語をラベルとして取り出し、選択した単語をマスクトークンに置き換えることで、文のリストからトレーニングデータを生成できます。

このガイドでは、TensorFlow API を使用して次を実行する方法を学習します。

  • テンソルからスライスを抽出する
  • テンソルの特定のインデックスにデータを挿入する

このガイドは、テンソルのインデキシングに精通していることを前提としています。このガイドを開始する前に、テンソル、および TensorFlow NumPy ガイドのインデキシングセクションをお読みください。

セットアップ

import tensorflow as tf
import numpy as np
2022-12-14 22:54:42.642753: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer.so.7'; dlerror: libnvinfer.so.7: cannot open shared object file: No such file or directory
2022-12-14 22:54:42.642872: W tensorflow/compiler/xla/stream_executor/platform/default/dso_loader.cc:64] Could not load dynamic library 'libnvinfer_plugin.so.7'; dlerror: libnvinfer_plugin.so.7: cannot open shared object file: No such file or directory
2022-12-14 22:54:42.642881: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Cannot dlopen some TensorRT libraries. If you would like to use Nvidia GPU with TensorRT, please make sure the missing libraries mentioned above are installed properly.

テンソルスライスを抽出する

tf.slice を使用して、NumPy のようなテンソルスライスを実行します。

t1 = tf.constant([0, 1, 2, 3, 4, 5, 6, 7])

print(tf.slice(t1,
               begin=[1],
               size=[3]))
tf.Tensor([1 2 3], shape=(3,), dtype=int32)

または、Python 構文を使用することもできます。テンソルスライスは、開始から終了までの範囲で等間隔に配置されていることに注意してください。

print(t1[1:4])
tf.Tensor([1 2 3], shape=(3,), dtype=int32)

print(t1[-3:])
tf.Tensor([5 6 7], shape=(3,), dtype=int32)

2 次元テンソルの場合、次を使用できます。

t2 = tf.constant([[0, 1, 2, 3, 4],
                  [5, 6, 7, 8, 9],
                  [10, 11, 12, 13, 14],
                  [15, 16, 17, 18, 19]])

print(t2[:-1, 1:3])
tf.Tensor(
[[ 1  2]
 [ 6  7]
 [11 12]], shape=(3, 2), dtype=int32)

高次元テンソルでも tf.slice を使用できます。

t3 = tf.constant([[[1, 3, 5, 7],
                   [9, 11, 13, 15]],
                  [[17, 19, 21, 23],
                   [25, 27, 29, 31]]
                  ])

print(tf.slice(t3,
               begin=[1, 1, 0],
               size=[1, 1, 2]))
tf.Tensor([[[25 27]]], shape=(1, 1, 2), dtype=int32)

また、tf.strided_slice を使用して、テンソルの次元をストライドすることでテンソルのスライスを抽出することもできます。

tf.gather を使用して、テンソルの 1 つの軸から特定のインデックスを抽出します。

print(tf.gather(t1,
                indices=[0, 3, 6]))

# This is similar to doing

t1[::3]
tf.Tensor([0 3 6], shape=(3,), dtype=int32)
<tf.Tensor: shape=(3,), dtype=int32, numpy=array([0, 3, 6], dtype=int32)>

tf.gather では、インデックスが等間隔である必要はありません。

alphabet = tf.constant(list('abcdefghijklmnopqrstuvwxyz'))

print(tf.gather(alphabet,
                indices=[2, 0, 19, 18]))
tf.Tensor([b'c' b'a' b't' b's'], shape=(4,), dtype=string)

テンソルの複数の軸からスライスを抽出するには、tf.gather_nd を使用します。これは、行または列だけではなく、行列の要素を収集する場合に役立ちます。

t4 = tf.constant([[0, 5],
                  [1, 6],
                  [2, 7],
                  [3, 8],
                  [4, 9]])

print(tf.gather_nd(t4,
                   indices=[[2], [3], [0]]))
tf.Tensor(
[[2 7]
 [3 8]
 [0 5]], shape=(3, 2), dtype=int32)

t5 = np.reshape(np.arange(18), [2, 3, 3])

print(tf.gather_nd(t5,
                   indices=[[0, 0, 0], [1, 2, 1]]))
tf.Tensor([ 0 16], shape=(2,), dtype=int64)
# Return a list of two matrices

print(tf.gather_nd(t5,
                   indices=[[[0, 0], [0, 2]], [[1, 0], [1, 2]]]))
tf.Tensor(
[[[ 0  1  2]
  [ 6  7  8]]

 [[ 9 10 11]
  [15 16 17]]], shape=(2, 2, 3), dtype=int64)
# Return one matrix

print(tf.gather_nd(t5,
                   indices=[[0, 0], [0, 2], [1, 0], [1, 2]]))
tf.Tensor(
[[ 0  1  2]
 [ 6  7  8]
 [ 9 10 11]
 [15 16 17]], shape=(4, 3), dtype=int64)

データをテンソルに挿入する

tf.scatter_nd を使用して、テンソルの特定のスライス/インデックスにデータを挿入します。値を挿入するテンソルはゼロで初期化されることに注意してください。

t6 = tf.constant([10])
indices = tf.constant([[1], [3], [5], [7], [9]])
data = tf.constant([2, 4, 6, 8, 10])

print(tf.scatter_nd(indices=indices,
                    updates=data,
                    shape=t6))
tf.Tensor([ 0  2  0  4  0  6  0  8  0 10], shape=(10,), dtype=int32)

ゼロで初期化されたテンソルを必要とする tf.scatter_nd のようなメソッドは、スパーステンソルのイニシャライザに似ています。tf.gather_ndtf.scatter_nd を使用して、スパーステンソル演算の動作を模倣できます。

これら 2 つのメソッドを組み合わせて使用してスパーステンソルを構築する例を考えてみましょう。

# Gather values from one tensor by specifying indices

new_indices = tf.constant([[0, 2], [2, 1], [3, 3]])
t7 = tf.gather_nd(t2, indices=new_indices)

# Add these values into a new tensor

t8 = tf.scatter_nd(indices=new_indices, updates=t7, shape=tf.constant([4, 5]))

print(t8)
tf.Tensor(
[[ 0  0  2  0  0]
 [ 0  0  0  0  0]
 [ 0 11  0  0  0]
 [ 0  0  0 18  0]], shape=(4, 5), dtype=int32)

これは次と同様です。

t9 = tf.SparseTensor(indices=[[0, 2], [2, 1], [3, 3]],
                     values=[2, 11, 18],
                     dense_shape=[4, 5])

print(t9)
SparseTensor(indices=tf.Tensor(
[[0 2]
 [2 1]
 [3 3]], shape=(3, 2), dtype=int64), values=tf.Tensor([ 2 11 18], shape=(3,), dtype=int32), dense_shape=tf.Tensor([4 5], shape=(2,), dtype=int64))
# Convert the sparse tensor into a dense tensor

t10 = tf.sparse.to_dense(t9)

print(t10)
tf.Tensor(
[[ 0  0  2  0  0]
 [ 0  0  0  0  0]
 [ 0 11  0  0  0]
 [ 0  0  0 18  0]], shape=(4, 5), dtype=int32)

既存の値を持つテンソルにデータを挿入するには、tf.tensor_scatter_nd_add を使用します。

t11 = tf.constant([[2, 7, 0],
                   [9, 0, 1],
                   [0, 3, 8]])

# Convert the tensor into a magic square by inserting numbers at appropriate indices

t12 = tf.tensor_scatter_nd_add(t11,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[6, 5, 4])

print(t12)
tf.Tensor(
[[2 7 6]
 [9 5 1]
 [4 3 8]], shape=(3, 3), dtype=int32)

同様に、tf.tensor_scatter_nd_sub を使用して、既存の値を持つテンソルから値を減算します。

# Convert the tensor into an identity matrix

t13 = tf.tensor_scatter_nd_sub(t11,
                               indices=[[0, 0], [0, 1], [1, 0], [1, 1], [1, 2], [2, 1], [2, 2]],
                               updates=[1, 7, 9, -1, 1, 3, 7])

print(t13)
tf.Tensor(
[[1 0 0]
 [0 1 0]
 [0 0 1]], shape=(3, 3), dtype=int32)

tf.tensor_scatter_nd_min を使用して、要素ごとの最小値をあるテンソルから別のテンソルにコピーします。

t14 = tf.constant([[-2, -7, 0],
                   [-9, 0, 1],
                   [0, -3, -8]])

t15 = tf.tensor_scatter_nd_min(t14,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[-6, -5, -4])

print(t15)
tf.Tensor(
[[-2 -7 -6]
 [-9 -5  1]
 [-4 -3 -8]], shape=(3, 3), dtype=int32)

同様に、tf.tensor_scatter_nd_max を使用して、要素ごとの最大値をあるテンソルから別のテンソルにコピーします。

t16 = tf.tensor_scatter_nd_max(t14,
                               indices=[[0, 2], [1, 1], [2, 0]],
                               updates=[6, 5, 4])

print(t16)
tf.Tensor(
[[-2 -7  6]
 [-9  5  1]
 [ 4 -3 -8]], shape=(3, 3), dtype=int32)

その他の資料とリソース

このガイドでは、TensorFlow で利用可能なテンソルスライス演算を使用して、テンソル内の要素をより詳細に制御する方法を学びました。