もしあなたが機械学習エンジニア、データサイエンティスト、または趣味で時々機械学習モデルを開発しているのであれば、Tensorflowをご存知でしょう。
Tensorflowは、Google Brain Teamによって開発された、Python、C++、CUDAで記述されたオープンソースかつ無償のフレームワークである。機械学習モデルの開発、テスト、デプロイに使用されます。
当初、Tensoflowは複数のプラットフォームやプログラミング言語を完全にサポートしておらず、機械学習モデルのトレーニングもあまり高速かつ効率的ではありませんでしたが、時間の経過といくつかのアップデートを経て、Tensorflowは現在、機械学習モデルの開発、トレーニング、デプロイのための主要フレームワークと見なされています。
Tensorflow 1.x
Tensorflow 1.xは、このフレームワークにとって大きな飛躍となった。多くの新機能が導入され、パフォーマンスが向上し、オープンソースの貢献が行われた。TensorFlowのハイレベルなAPIが導入され、プロトタイプをすぐに構築することが非常に容易になった。
Kerasと互換性を持たせた。しかし、開発者を苛立たせた大きな点は、TensorFlowを使うときにPythonのシンプルさを生かす感じがしないことだった。
TensorFlowでは、すべてのモデルがグラフで表現され、ノードがグラフ内の計算を表す。これは「記号的プログラミング」の一例であり、Pythonが「命令的プログラミング」言語であるのに対して、TensorFlowは「記号的プログラミング」の一例です。
この記事の範囲外なので、あまり詳しくは説明しません。しかし、ここで重要なのは、PyTorch(Imperative Programmingをより指向し、Pythonの動的挙動を利用する)のリリースに伴い、初心者や研究者はTensorflowよりもPyTorchの方が理解しやすく学びやすいと感じ、瞬く間にPyTorchが人気を博し始めたことです。
Tensorflowの開発者は皆、TensorflowとGoogle Brain Teamに同じことを要求していたのです。さらに、TensorFlow 1.xでは多くのAPI、すなわちtf.lays, tf.contrib.layers, tf.keras
が開発され、開発者は多くの選択肢から選ぶことになり、その結果コンフリクトが発生したのです。
Tensorflow 2.0の発表
Tensorflowチームがこれらの問題に対処しなければならないことは明らかだったので、彼らはTensorflow 2.0を発表した。
すべての問題に対処するために、彼らは大きな変更を加えなければならなかったので、これは大きなステップであった。多くの人が再学習に直面しましたが、改善されたことで再学習する価値が生まれました。
トレーニング段階では、tf.data
とDatasetsが紹介され、データのインポートと処理を簡単に行うことができるようになった。そして、複数のCPU、GPU、TPUを使った分散学習が紹介されています。シリアライズには、SavedModel
を使用して、TensorFlow Hubや、TensorFlow Serving、TensorFlow Lite、TensorFlow.JSなどのサービスにデプロイすることが可能です。
出典:blog.tensorflow.org
Tensorflow 2.0 の新機能。
Tensorflow 2で行われた最も重要なアップデートを簡単に説明します。
1. 複数のプラットフォームでのモデルのデプロイ
Tensorflow は常に実運用に非常に適していましたが、Tensorflow 2 では複数のプラットフォームでの互換性と同等性が改善されました。
Tensorflowのモデルを保存するための SavedModel
フォーマットの新しいプラットフォームサポートが導入されたのです。保存したモデルは、Tensorflow Liteを使えばモバイルやIoTデバイスに、Tensorflow.jsを使えばNode.jsに、どのプラットフォームでもデプロイできるのが新しいところです。また、Tensorflow Servingを使えば、本番環境で利用することも可能です。
それでは、コンパイルしたモデルを保存する方法について説明します。
import os
import tensorflow as tf
# Building the Model
model = tf.keras.Sequential([
tf.keras.layers.Dense(5,actiavtion='relu',input_shape=(16,)),
tf.keras.layers.Dense(1,activation='sigmoid')])
# Compiling the Model
model.compile(loss='binary_crossentropy',optimizer='adam')
# Saving the Model
save_path = path + "/version_number/"
save_path = os.path.join
tf.saved_model.save(model, save_path)
これで完了です。これで、前述のどのサービスでもデプロイできるようになりました。
2. イージーエクスキューション
Tensorflow 2以前は、モデルを実行するためにセッションを作成する必要がありました。実際、デバッグのために変数の値を表示したい場合、まずセッションを作成し、そのセッションの中でprint文を書く必要があった。
入力データをモデルに与えるために、遅くて無駄なプレースホルダーを作らなければならなかったのです。基本的に、Tensorflow 1.xでは、実行中にグラフを構築するのではなく、まずグラフ全体を構築してから実行することになっていました。
特に、実行中に動的なグラフを作成できるPyTorchとは対照的に、これは静的で不格好に感じられました。
ありがたいことに、Tensorflow 2.0ではこの点が改善され、イーガー実行が導入されました。Tensorflow 1.xと2.0では、どのようにグラフを構築していたのか見てみましょう。
import tensorflow as tf
"""Creating the Graph"""
# Tensorflow 1.x
# Defining two Tensorflow variables
a = tf.Variable(4)
b = tf.Variable(5)
result = tf.multiply(a,b)
ここで、変数 result
にアクセスするために、グラフをセッションで実行する必要があります。
# Creating a session
with tf.Session() as sess:
# Initializing all the Variables
sess.run(tf.global_variables_initializer())
print(sess.run(result))
今はその代わりに、直接アクセスできる。
import tensorflow as tf
# Tensorflow 2.0
a = tf.Variable(4)
b = tf.Variable(5)
# No need to create a session
print(float(a*b))
3. KerasとTensorflowの統合
KerasはTensorflowの上に構築されたNeural NetとDeep LearningのAPIです。
ほとんどの人は、TensorflowやPyTorchに移行する前にKerasから始めます。ディープニューラルネットを高速に実験するために設計されたため、よりシンプルになっています。
Tensorflow 2.0以前は、ライブラリでサポートされていましたが、統合されてはいませんでした。現在は、公式に高レベルのAPIとして提供されています。明示的にインストールする必要はなく、Tensorflowに同梱され、tf.keras
からアクセスできるようになった。
その結果、APIが整理され、tf.contrib.lays
tf.layers
等が削除されました。現在では、tf.keras
がAPIとして使用されています。tf.contrib.layers
と tf.layers
の両方が同じことをやっていたのです。そして tf.keras
は tf.keras.layers
モジュールを含んでいるので、三重の冗長性がある。
また、Tensorflow 1.xからTensorflow 2.0にアップグレードするためのガイドも提供されました。
4. tf.function デコレータ
これはTensorflow 2の最もエキサイティングな機能の1つである。@tf.function
デコレーターは、Python関数を自動的にTensorflow Graphsに変換してくれるのである。
グラフベースの実行の利点はそのままに、重たいセッションベースのプログラミングから解放される。以下のような関数に @tf.function
デコレータを適用することで、Tensorflow のグラフに変換することができます。
@tf.function
def multiply(a, b):
return a * b
multiply(tf.ones([2, 2]), tf.ones([2, 2]))
因みに、これはAutographによって自動的に補完されます。装飾した関数と全く同じ効果を持つグラフが生成されるのです。
5. 分散コンピューティングを用いたトレーニング
Tensorflow 2.0では、GPUを使用したトレーニングのパフォーマンスが向上しています。チームによると、このバージョンはTensorflow 1.xよりも3倍高速だそうです。
そして現在のところ、TensorflowはTPUとも連携できる。実際、複数のTPUやGPUと分散コンピューティングのアプローチで作業することができます。
これについては、公式ガイドで詳しく説明されています。
6. tf.dataとデータセット
tf.dataを使うと、カスタムデータパイプラインを非常に簡単に構築することができるようになった。feeded_dict
を使用する必要はない。tf.data
は、テキスト、画像、ビデオ、時系列など、様々な種類の入力フォーマットをサポートしています。
また、非常にクリーンで効率的な入力パイプラインを提供します。例えば、前処理された単語を含むテキストファイルをインポートして、モデルで使用したいとします。ほとんどの自然言語処理問題で行われている古典的な前処理をやってみよう。
まず、ファイルを読んで、すべての単語を小文字に変換して、リストに分割します。
import numpy as np
text_file = "file.txt"
text = open(text_file,'r').read()
text = text.lower()
text = text.split()
次に、重複する単語をすべて削除します。これは、単語を Set
にまとめて、それを List
に変換し、ソートすれば簡単にできます。
words = sorted(list(set(text)))
さて、ユニークな単語を並べ替えたので、それらを語彙にしましょう。各単語にはユニークな数字の識別子が割り当てられています。
vocab_to_int = {word:index for index, word in enumerate(words)}
int_to_vocab = np.array(words)
ここで、単語を表す整数の配列を Tensorflow データセットに変換するために、 tf.data.Dataset
が提供する from_tensor_slices()
関数を使用します。
words_dataset = tf.data.Dataset.from_tensor_slices(words_as_int)
これで、このデータセットに対して、より小さなシーケンスにバッチングするなどの操作を実行できるようになります。
seq_len = 50
sequences = words_dataset.batch(seq_len+1,drop_remainder=True)
これで、学習時にDatasetオブジェクトから簡単にバッチを取得できるようになりました。
for (batch_n,inp) in enumerate(dataset):
また、既存のデータセットを直接 Dataset
オブジェクトにロードすることもできます。
import tensorflow_datasets as tfds
mnist_data = tfds.load("mnist")
mnist_train, mnist_test = mnist_data["train"], mnist_data["test"]
7. tf.keras.Model
keras.Model`クラスをサブクラス化することで、独自のカスタムモデルを定義することができます。
PyTorchはカスタムクラスを使用してモデルを作成することができます(Layer
を形成するクラスをカスタマイズし、モデルの構造を変更する)。
Tensorflow 1.0のように、Sequential
モデルを作ってみましょう。
# Creating a Model
model = tf.keras.Sequential([
tf.keras.layers.Dense(512,activation='relu',input_shape=(784,)),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(512,activation='relu'),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10,activation='softmax')
])
今度は、Sequential
モデルを使うのではなく、keras.Model
クラスをサブクラス化して独自のモデルを作ってみましょう。
# Creating a Model
class mnist_model(tf.keras.Model):
def __init__(self):
super(mnist_model,self).__init__()
self.dense1 = tf.keras.layers.Dense(512)
self.drop1 = tf.keras.layers.Dropout(0.2)
self.dense2 = tf.keras.layers.Dense(512)
self.drop2 = tf.keras.layers.Dropout(0.2)
self.dense3 = tf.keras.layers.Dense(10)
def call(self,x):
x = tf.nn.relu(self.dense1(x))
x = self.drop1(x)
x = tf.nn.relu(self.dense2(x))
x = self.drop2(x)
x = tf.nn.softmax(self.dense3(x))
return x
この方法でも同じモデルを作成することができますが、この方法では、必要に応じて完全にカスタマイズしてモデルを作成することができます。
8. tf.GradientTape
tf.GradientTape
を使用すると、自動的にグラデーションを計算することができます。これは、カスタムの学習ループを使用する場合に便利です。
model.fit`を呼び出すのではなく、カスタムのトレーニングループを使ってモデルをトレーニングすることができます。これにより、学習プロセスを微調整したい場合に、よりコントロールしやすくなります。
tf.GradientTapeによるカスタムトレーニングループと
keras.Model` によるカスタムモデルを組み合わせることで、今までにないモデルやトレーニングのコントロールが可能になります。
これらはすぐにコミュニティでとても愛されるようになった機能です。ここでは、装飾された関数とカスタムトレーニングループでカスタムモデルを作成する方法を紹介します。
"""Note: We'll be using the model created in the previous section."""
# Creating the model
model = mnist_model()
# Defining the optimizer and the loss
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
loss_object = tf.keras.losses.CategoricalCrossentropy(from_logits=False)
@tf.function
def step(model,x,y):
"""
model: in this case the mnist_model
x: input data in batches
y: True labels """
# Use GradientTape to monitor trainable variables
with tf.GradientTape() as tape:
# Computing predictions
predictions = model(x)
# Calculating Loss
loss = loss_object(y,predictions)
# Extracting all the trainable variables
trainable_variables = model.trainable_variables()
# Computing derivative of loss w.r.t variables/weights
gradients = tape.gradient(loss,trainable_variables)
# Updating the weights
optimizer.apply_gradients(zip(gradients,trainable_variables))
return loss
ループを使ってモデルと学習データを一括して渡すことで、step()
関数を呼び出すだけでよいのです。
結論
Tensorflow 2.0の登場により、多くの挫折がやり直された。システムサポートの多様化や新サービスから、カスタムモデルやトレーニングループまで、Tensorflow 2.0はベテランプラクティショナーにとっても新しい学習体験を導入しているのです。