テンソルと演算

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

これは、下記の手法を示す TensorFlow の入門チュートリアルです。

  • 必要なパッケージのインポート
  • テンソルの作成と使用
  • GPU アクセラレーションの使用
  • tf.data.Dataset を使用してデータパイプラインを構築する

TensorFlowのインポート

始めるにはまず、tensorflow モジュールをインポートします。TensorFlow 2 の時点では、Eager execution はデフォルトでオンになっています。Eager execution では、TensorFlow のフロントエンドがよりインタラクティブになります。これについては、後で詳しく説明します。

import tensorflow as tf
2022-12-15 02:52:41.764436: 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-15 02:52:41.764552: 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-15 02:52:41.764564: 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.

テンソル

テンソルは多次元の配列です。NumPy の ndarray オブジェクトと同様に、tf.Tensor オブジェクトにはデータ型と形状があります。また、tf.Tensor はアクセラレータのメモリ(GPU など)に留まることができます。TensorFlow には、tf.Tensor を消費して生成する演算(tf.math.addtf.linalg.matmultf.linalg.inv など)が多数含まれたライブラリが用意されています。これらの演算によって、以下のように、組み込み Python 型が自動的に変換されます。

print(tf.math.add(1, 2))
print(tf.math.add([1, 2], [3, 4]))
print(tf.math.square(5))
print(tf.math.reduce_sum([1, 2, 3]))

# Operator overloading is also supported
print(tf.math.square(2) + tf.math.square(3))
tf.Tensor(3, shape=(), dtype=int32)
tf.Tensor([4 6], shape=(2,), dtype=int32)
tf.Tensor(25, shape=(), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(13, shape=(), dtype=int32)

それぞれのtf.Tensorには、形状とデータ型があります。

x = tf.linalg.matmul([[1]], [[2, 3]])
print(x)
print(x.shape)
print(x.dtype)
tf.Tensor([[2 3]], shape=(1, 2), dtype=int32)
(1, 2)
<dtype: 'int32'>

NumPy 配列と tf.Tensor の間のもっとも明確な違いは

  1. テンソルは( GPU や TPU などの)アクセラレータメモリを使用できる
  2. テンソルは変更不可

NumPy との互換性

TensorFlow tf.Tensor と NumPy ndarray の変換は簡単です。

  • TensorFlow の演算により NumPy の ndarray は自動的にテンソルに変換される
  • NumPy の演算によりテンソルは自動的に NumPy の ndarray に変換される

テンソルは .numpy() メソッドを使って明示的に NumPy の ndarray に変換されます。NumPy のndarray と tf.Tensor はその下敷きとなるメモリ上の表現が、できるかぎり共通化されているので、通常この変換のコストは小さいです。しかし、NumPy 配列はホスト側のメモリに置かれる一方、tf.Tensor はGPU のメモリに置かれる可能性もあるため、下層の表現をいつも共通化できるとは限りません。また、変換にはGPU からホスト側メモリへのコピーも関わってきます。

import numpy as np

ndarray = np.ones([3, 3])

print("TensorFlow operations convert numpy arrays to Tensors automatically")
tensor = tf.math.multiply(ndarray, 42)
print(tensor)


print("And NumPy operations convert Tensors to NumPy arrays automatically")
print(np.add(tensor, 1))

print("The .numpy() method explicitly converts a Tensor to a numpy array")
print(tensor.numpy())
TensorFlow operations convert numpy arrays to Tensors automatically
tf.Tensor(
[[42. 42. 42.]
 [42. 42. 42.]
 [42. 42. 42.]], shape=(3, 3), dtype=float64)
And NumPy operations convert Tensors to NumPy arrays automatically
[[43. 43. 43.]
 [43. 43. 43.]
 [43. 43. 43.]]
The .numpy() method explicitly converts a Tensor to a numpy array
[[42. 42. 42.]
 [42. 42. 42.]
 [42. 42. 42.]]

GPU による高速化

多くの TensorFlow 演算の計算速度は、GPU を使って高速化されています。TensorFlow はアノテーションを使用せずに、GPU または CPU を演算に使用するかどうかを決定し、必要であれば CPU と GPU メモリ間でテンソルをコピーします。演算によって生成されたテンソルは、通常、演算が実行されたデバイスのメモリによってバックアップされます。以下に例を示します。

x = tf.random.uniform([3, 3])

print("Is there a GPU available: "),
print(tf.config.list_physical_devices("GPU"))

print("Is the Tensor on GPU #0:  "),
print(x.device.endswith('GPU:0'))
Is there a GPU available: 
[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:1', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:2', device_type='GPU'), PhysicalDevice(name='/physical_device:GPU:3', device_type='GPU')]
Is the Tensor on GPU #0:  
True

デバイス名

Tensor.device プロパティにより、そのテンソルの内容を保持しているデバイスの完全な名前文字列を得ることができます。この名前には、プログラムを実行中のホストのネットワークアドレスや、ホスト上のデバイスについての詳細がエンコードされています。この情報は、TensorFlow プログラムの分散実行に必要なものです。テンソルがホスト上の N 番目のGPUにある場合、文字列の最後は GPU:<N> となります。

明示的なデバイスの配置

TensorFlow における「配置」とは、個々の演算を実行するデバイスの割り当てを指します。前述のとおり、明示的に指定されていない場合、TensorFlow は演算を実行するデバイスを自動的に決定し、必要であれば、そのデバイスにテンソルをコピーします。

ただし、TensorFlow 演算は、tf.device コンテキストマネージャーを使用して、特定のデバイスに明示的に配置することが可能です。以下に例を示します。

import time

def time_matmul(x):
  start = time.time()
  for loop in range(10):
    tf.linalg.matmul(x, x)

  result = time.time()-start

  print("10 loops: {:0.2f}ms".format(1000*result))

# Force execution on CPU
print("On CPU:")
with tf.device("CPU:0"):
  x = tf.random.uniform([1000, 1000])
  assert x.device.endswith("CPU:0")
  time_matmul(x)

# Force execution on GPU #0 if available
if tf.config.list_physical_devices("GPU"):
  print("On GPU:")
  with tf.device("GPU:0"): # Or GPU:1 for the 2nd GPU, GPU:2 for the 3rd etc.
    x = tf.random.uniform([1000, 1000])
    assert x.device.endswith("GPU:0")
    time_matmul(x)
On CPU:
10 loops: 49.58ms
On GPU:
10 loops: 343.95ms

データセット

このセクションでは、tf.data.Dataset API を使用して、モデルにデータを提供するためのパイプラインを構築しています。tf.data.Dataset は、パフォーマンスの高い複雑な入力パイプラインを、モデルのトレーニングまたは評価ループを提供する単純で再利用可能なピースから構築するために使用されます。(詳細については、tf.data: TensorFlow 入力パイプラインを構築するガイドをご覧ください。)

ソースDatasetの作成

ソース Dataset を作成するには、tf.data.Dataset.from_tensorstf.data.Dataset.from_tensor_slices などのファクトリー関数を使用して、またはファイルから読み取る tf.data.TextLineDatasettf.data.TFRecordDataset などのオブジェクトを使用します。詳細については、tf.data: TensorFlow 入力パイプラインを構築するガイドの「入力データを読み取る」セクションをご覧ください。

ds_tensors = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5, 6])

# Create a CSV file
import tempfile
_, filename = tempfile.mkstemp()

with open(filename, 'w') as f:
  f.write("""Line 1
Line 2
Line 3
  """)

ds_file = tf.data.TextLineDataset(filename)

変換の適用

tf.data.Dataset.maptf.data.Dataset.batchtf.data.Dataset.shuffle などの変換関数を使用して、データセットのレコードに変換を適用します。

ds_tensors = ds_tensors.map(tf.math.square).shuffle(2).batch(2)

ds_file = ds_file.batch(2)

イテレート

tf.data.Dataset オブジェクトは、中のレコードを繰り返し利用するためのイテレーションをサポートします。

print('Elements of ds_tensors:')
for x in ds_tensors:
  print(x)

print('\nElements in ds_file:')
for x in ds_file:
  print(x)
Elements of ds_tensors:
tf.Tensor([1 9], shape=(2,), dtype=int32)
tf.Tensor([ 4 16], shape=(2,), dtype=int32)
tf.Tensor([25 36], shape=(2,), dtype=int32)

Elements in ds_file:
tf.Tensor([b'Line 1' b'Line 2'], shape=(2,), dtype=string)
tf.Tensor([b'Line 3' b'  '], shape=(2,), dtype=string)