TensorFlowは、機械学習アプリケーションのためのオープンソースライブラリです。
Google Brainの第2世代システムで、クローズドソースのDistBeliefを置き換えた後、Googleが研究用と生産用の両方のアプリケーションに使用しています。
TensorFlowのアプリケーションは、いくつかの言語で書くことができる。
この記事では、そのPython版について、ライブラリのインストール、基本的な低レベルコンポーネント、実際のデータセットで学習を実行するためのフィードフォワードニューラルネットワークをゼロから構築することについて見ています。
深層学習ニューラルネットワークの学習期間は、より複雑なシナリオにおいてしばしばボトルネックとなります。
ニューラルネットワークだけでなく、他のMLアルゴリズムもほとんどが行列の乗算で動作するため、標準的なCPU(Central Processing Units)ではなく、GPU(Graphical Processing Units)で実行した方がはるかに速いのです。
TensorFlowはCPUとGPUの両方をサポートしており、GoogleはTensor Processing Unit(TPU)と呼ばれる、異なる処理ユニットの中で最高のパフォーマンスを生み出す、クラウドでの計算のための独自の専用ハードウェアも製造しています。
インストール
TPUはクラウドでのみ利用可能ですが、TensorFlowのローカルコンピュータへのインストールは、CPUとGPUの両方の処理アーキテクチャをターゲットにできます。
GPU版を利用するには、NVIDIAのグラフィックカードが必要であり、さらにいくつかの要件を満たす必要があります。
基本的に、virtualenv、pip、Docker、Anaconda、ソースからのインストールの少なくとも5つのオプションがあります。
- virtualenvとDockerを使ったインストールでは、TensorFlowを他のPythonライブラリから分離した環境にインストールすることが可能です。
- Anacondaは、TensorFlowを含む科学計算用ライブラリの大規模なセットを含むPythonディストリビューションです。
- pipはPythonパッケージの “ネイティブ “なインストーラーと見なされており、個別の環境を使用することはありません。
- 最後に、ソースからのインストールはGitを経由し、特定のソフトウェアのバージョンを選択するのに最適な方法であり、TensorFlowの現在の安定バージョンはr1.4(この記事を書いている時点)です。
最も一般的で簡単なインストール方法は、virtualenvとpipを使用する方法です。
Pythonを使ったことがある人であれば、pipは知っていると思います。
ここでは、Ubuntuマシンでの入手方法を説明します。
# Install pip
sudo apt-get install python-pip python-dev # Python 2.7
sudo apt-get install python3-pip python3-dev # Python 3.x
UbuntuとMac OSXのマシンにTensorFlowをインストールする方法は、以下の通りです。
# CPU support
pip install tensorflow # Python 2.7
pip3 install tensorflow # Python 3.x
# GPU support
pip install tensorflow-gpu # Python 2.7
pip3 install tensorflow-gpu # Python 3.x
上記のコマンドはWindowsマシンでも動作しますが、Python 3.5.xと3.6.xのバージョンのみが対象となります。
TensorFlowを別の環境にインストールするには、virtualenvまたはconda(Anacondaの一部)を使用します。
一般的な手順は上記と同じですが、今回はまず、新しい環境を作成し、有効化する必要があります。
virtualenv --system-site-packages ~/tensorflow
source ~/tensorflow/bin/activate
これにより、必要なパッケージはすべて、あなたのシステム上にグローバルにインストールされているものとは別に保持されます。
コアAPIコンポーネント
TensorFlowをプログラムするために、様々なAPIが用意されています。
最下層のものはCoreと呼ばれ、基本的なコンポーネントと連携する。
Tensor、Graphs、Sessions といった基本的なコンポーネントを扱う。
上位のAPIである tf.estimator
は、ワークフローを簡略化し、データセット管理、学習、評価などの処理を自動化するために構築されている。
いずれにせよ、ライブラリのCore機能を知ることは、最先端の学習アプリケーションを構築する上で極めて重要である。
Core APIの要点は、一連の操作をノードのグラフに配置した計算グラフを構築することである。
各ノードは複数のテンソル(基本データ構造)を入力として持ち、それに対して演算を行って出力を計算し、それが後に多層ネットワークの他のノードへの入力を表すことがある。
このようなアーキテクチャは、ニューラルネットワークのような機械学習アプリケーションに適している。
テンソル
テンソルはTensorFlowの基本的なデータ構造であり、NumPyの多次元配列のように任意の次元のデータを格納することができる。
テンソルには、定数、変数、プレースホルダーの3つのタイプがある。
- 定数は不変のテンソルである。定数は不変のテンソルであり、入力を持たず、内部に保存された単一の値を出力するノードとみなすことができる。
- 変数は,グラフの実行中に値が変化するミュータブルなテンソルである.MLアプリケーションでは,変数に最適化すべきパラメータを格納します(例: ニューラルネットワークのノード間の重さ).変数は,グラフを実行する前に,特別な操作を明示的に呼び出して初期化する必要がある.
- Placeholdersは外部ソースからのデータを格納するテンソルである。グラフの実行時に値が提供されるという「約束」を表す.MLアプリケーションでは,通常,学習モデルへのデータ入力にプレースホルダを用 います.
以下の数行は、3つのテンソルタイプの例を示している。
import tensorflow as tf
tf.reset_default_graph()
# Define a placeholder
a = tf.placeholder("float", name='pholdA')
print("a:", a)
# Define a variable
b = tf.Variable(2.0, name='varB')
print("b:", b)
# Define a constant
c = tf.constant([1., 2., 3., 4.], name='consC')
print("c:", c)
a: Tensor("pholdA:0", dtype=float32)
b: <tf.variable 'varb:0'="" dtype="float32_ref" shape="()">
c: Tensor("consC:0", shape=(4,), dtype=float32)
テンソルはこの時点では値を持たず、その値はグラフがSessionで実行されるときにのみ利用可能であることに注意してください。
グラフ
この時点では、グラフは接続されていない木のテンソルだけを保持している。
このテンソルに対していくつかの操作を行ってみよう。
d = a * b + c
d
<tf.tensor 'add:0'="" shape="<unknown"> dtype=float32>
結果は’add’という名前のテンソルであり、モデルは下図のようになる。
TensorFlowのビルトイン機能であるTensorBoardを使って、グラフや他のパラメータを探索することができる。
図1:乗算と加算からなるTensorFlowのグラフ
また、グラフを探索するのに便利なのが、グラフ内の全ての演算を出力する以下のようなツールです。
# call the default graph
graph = tf.get_default_graph()
# print operations in the graph
for op in graph.get_operations():
print(op.name)
pholdA
varB/initial_value
varB
varB/Assign
varB/read
consC
mul
add
セッション
最後に、このグラフはセッションの中で実行される必要がある。
変数はあらかじめ初期化されており、プレースホルダーテンソルは feed_dict
属性を通して具体的な値を受け取ることに注意してください。
# Initialize variables
init = tf.global_variables_initializer()
# Run a session and calculate d
sess = tf.Session()
sess.run(init)
print(sess.run(d, feed_dict={a: [[0.5], [2], [3]]}))
sess.close()
[[ 2. 3. 4. 5.]
[ 5. 6. 7. 8.]
[ 7. 8. 9. 10.]]
上記の例は、学習モデルをかなり単純化したものである。
いずれにせよ、基本的な tf
コンポーネントをグラフで組み合わせて、セッションで実行できることを示した。
また、異なる形状のテンソルに対してどのような演算が実行されるかを示した。
次の節では、Core API を使って実際のデータに対して機械学習のためのニューラルネットワークを構築する。
ニューラルネットワークモデル
このパートでは、TensorFlowのCoreコンポーネントを使用してフィードフォワードニューラルネットワークをゼロから構築します。
1つの隠れ層のノード数によって異なる、3つのニューラルネットワークのアーキテクチャを比較します。
アイリスデータセット
Irisデータセットは、150の植物の例からなり、それぞれ4次元(入力特徴として使用)とタイプ(予測する必要のある出力値)が与えられています。
植物は3つのタイプ(setosa, virginica, versicolor)のいずれかに属することができる。
まず、TensorFlowのウェブサイトからデータをダウンロードしましょう。
これは、120と30の例からなるトレーニングサブセットとテストサブセットに分割されています。
# Import the needed libraries
import numpy as np
import pandas as pd
import tensorflow as tf
import urllib.request as request
import matplotlib.pyplot as plt
# Download dataset
IRIS_TRAIN_URL = "http://download.tensorflow.org/data/iris_training.csv"
IRIS_TEST_URL = "http://download.tensorflow.org/data/iris_test.csv"
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'species']
train = pd.read_csv(IRIS_TRAIN_URL, names=names, skiprows=1)
test = pd.read_csv(IRIS_TEST_URL, names=names, skiprows=1)
# Train and test input data
Xtrain = train.drop("species", axis=1)
Xtest = test.drop("species", axis=1)
# Encode target values into binary ('one-hot' style) representation
ytrain = pd.get_dummies(train.species)
ytest = pd.get_dummies(test.species)
モデル・学習
すなわち、入力層は4つの入力特徴を表す4つのニューロンを含み、出力層は植物種をワンショットで符号化するのに使われる3ビットのために3つのニューロンを含むことになる。
例えば、「セトーサ」種はベクトル [1, 0, 0] で、「バージニカ」は [0, 1, 0] で符号化されるなど。
隠れ層のニューロン数として3つの値を選択する。
その結果、ネットワークのサイズは(4-5-3)、(4-10-3)、(4-20-3)となる。
つまり、最初のネットワークは、例えば、4つの入力ニューロン、5つの「隠れ」ニューロン、3つの出力ニューロンを持つことになる。
図2:3層構造のフィードフォワードニューラルネットワーク
以下のコードでは、モデルを作成し、最小化すべき損失関数を定義し、最適な重み W_1
と W_2
を学習するために2000回反復するセッションを実行する関数を定義しています。
前述したように、入力行列と出力行列は tf.placeholder
テンソルに与え、重みは各反復で値が変化するため変数として表現される。
損失関数は予測値 y_est
と実際の種族タイプ y
の平均二乗誤差として定義され、使用する活性化関数はシグモイドである。
関数 create_train_model
は学習した重みを返し、損失関数の最終的な値を出力する。
# Create and train a tensorflow model of a neural network
def create_train_model(hidden_nodes, num_iters):
# Reset the graph
tf.reset_default_graph()
# Placeholders for input and output data
X = tf.placeholder(shape=(120, 4), dtype=tf.float64, name='X')
y = tf.placeholder(shape=(120, 3), dtype=tf.float64, name='y')
# Variables for two group of weights between the three layers of the network
W1 = tf.Variable(np.random.rand(4, hidden_nodes), dtype=tf.float64)
W2 = tf.Variable(np.random.rand(hidden_nodes, 3), dtype=tf.float64)
# Create the neural net graph
A1 = tf.sigmoid(tf.matmul(X, W1))
y_est = tf.sigmoid(tf.matmul(A1, W2))
# Define a loss function
deltas = tf.square(y_est - y)
loss = tf.reduce_sum(deltas)
# Define a train operation to minimize the loss
optimizer = tf.train.GradientDescentOptimizer(0.005)
train = optimizer.minimize(loss)
# Initialize variables and run session
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
# Go through num_iters iterations
for i in range(num_iters):
sess.run(train, feed_dict={X: Xtrain, y: ytrain})
loss_plot[hidden_nodes].append(sess.run(loss, feed_dict={X: Xtrain.as_matrix(), y: ytrain.as_matrix()}))
weights1 = sess.run(W1)
weights2 = sess.run(W2)
print("loss (hidden nodes: %d, iterations: %d): %.2f" % (hidden_nodes, num_iters, loss_plot[hidden_nodes][-1]))
sess.close()
return weights1, weights2
それでは、3つのネットワークアーキテクチャを作成し、損失関数を繰り返しプロットしてみましょう。
# Run the training for 3 different network architectures: (4-5-3) (4-10-3) (4-20-3)
# Plot the loss function over iterations
num_hidden_nodes = [5, 10, 20]
loss_plot = {5: [], 10: [], 20: []}
weights1 = {5: None, 10: None, 20: None}
weights2 = {5: None, 10: None, 20: None}
num_iters = 2000
plt.figure(figsize=(12,8))
for hidden_nodes in num_hidden_nodes:
weights1[hidden_nodes], weights2[hidden_nodes] = create_train_model(hidden_nodes, num_iters)
plt.plot(range(num_iters), loss_plot[hidden_nodes], label="nn: 4-%d-3" % hidden_nodes)
plt.xlabel('Iteration', fontsize=12)
plt.ylabel('Loss', fontsize=12)
plt.legend(fontsize=12)
loss (hidden nodes: 5, iterations: 2000): 31.82
loss (hidden nodes: 10, iterations: 2000): 5.90
loss (hidden nodes: 20, iterations: 2000): 5.61
<matplotlib.legend.legend 0x123b157f0="" at="">
図3:異なるネットワークアーキテクチャの2000回の反復における損失関数。
20個の隠れニューロンを持つネットワークは、最小値に到達するまでに多くの時間を要することがわかるが、これはその複雑さによるものである。
5個の隠れニューロンを持つネットワークはローカルミニマムから抜け出せず、良い結果を得ることができない。
いずれにせよ、Irisのような単純なデータセットでは、5個の隠れニューロンを持つ小さなネットワークでも良いモデルを学習することができるはずである。
今回のケースでは、モデルがローカルミニマムにはまり込んでしまったのは単なるランダムな出来事であり、何度もコードを実行すれば、そうそう起こることではありません。
モデル評価
最後に、モデルの評価をしてみましょう。
学習した重み W_1
と W_2
を用いて、テストセットの例を順伝播させる。
精度指標は正しく予測された例の割合として定義される。
# Evaluate models on the test set
X = tf.placeholder(shape=(30, 4), dtype=tf.float64, name='X')
y = tf.placeholder(shape=(30, 3), dtype=tf.float64, name='y')
for hidden_nodes in num_hidden_nodes:
# Forward propagation
W1 = tf.Variable(weights1[hidden_nodes])
W2 = tf.Variable(weights2[hidden_nodes])
A1 = tf.sigmoid(tf.matmul(X, W1))
y_est = tf.sigmoid(tf.matmul(A1, W2))
# Calculate the predicted outputs
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
y_est_np = sess.run(y_est, feed_dict={X: Xtest, y: ytest})
# Calculate the prediction accuracy
correct = [estimate.argmax(axis=0) == target.argmax(axis=0)
for estimate, target in zip(y_est_np, ytest.as_matrix())]
accuracy = 100 * sum(correct) / len(correct)
print('Network architecture 4-%d-3, accuracy: %.2f%%' % (hidden_nodes, accuracy))
Network architecture 4-5-3, accuracy: 90.00%
Network architecture 4-10-3, accuracy: 96.67%
Network architecture 4-20-3, accuracy: 96.67%
全体として、我々は単純なフィードフォワードニューラルネットでかなり高い精度を達成することができました。
これは、かなり小さなデータセットを使って特に驚くべきことです。
TensorFlowの高レベルAPIを使ったもっとシンプルな例はこちらで見ることができます。
リソース
このチュートリアルでは、TensorFlow でできることのほんの一部しかカバーしていません。
TensorFlow と一般的な深層学習についてもっと学ぶための素晴らしいリソースをいくつか紹介します。
- TensorFlowによるディープラーニング
- PythonによるディープラーニングのためのTensorFlow完全ガイド
- データサイエンス。Pythonによるディープラーニング
- TensorFlow.org
結論
この記事では、機械学習のためのTensorFlowライブラリを紹介し、インストールのための簡単なガイドを提供し、TensorFlowの低レベルCore APIの基本コンポーネントを紹介しました。
Tensors、Graphs、Sessionsを紹介し、最後にIrisデータセットの実データを分類するためのニューラルネットワークモデルを構築しました。
一般に、TensorFlowは記号的なライブラリなので、そのコーディング哲学を理解するのに時間がかかるかもしれませんが、Coreコンポーネントに慣れれば、機械学習アプリを作るのにかなり便利になります。
この記事では、基本的なコンポーネントを表示してモデルを完全に制御するために低レベルのCore APIを使用しましたが、通常は tf.estimator
などの高レベルのAPIや、Kerasなどの外部ライブラリを使用する方がはるかにシンプルです。
となります。