|
TensorFlow が大幅に改訂されて、version 1.x からversion 2.0に変更されました。Keras がTensorFLowのモジュールに統合されました。そして、それに対応しての関係でしょうが、TensorFlow 1.xで使用されていたいくつかの重要なモジュールが廃止されました。とりわけ、TensorFlow 2.0で、tf.contribが廃止された影響は大きいです。この結果、TensorFlow 1.xで作成された機械学習プログラムの多くが TensorFlow 2.0 ではエラーが出て、正常に作動しません。また、Keras がTensorFLowのモジュールに統合されましたので、従来のKeras単体でのコードが正常に動作しません。
このページでは、TensorFlow 2.0のもとで正常に作動するDeep Learning(CNN)のPython実装の例を説明します。特に、画像識別や一般物体検出アルゴリズムをPythonでコード化したライブラリの代表的な事例を取り上げて、機械学習プログラムの実装と実行について説明します。
python関連のパッケージなどの環境はセットアップされているとします。Jupyter Notebookなどが必須なので、anaconda3をインストールすることを推奨します。anaconda3に付属するpythonの最新バージョンは 3.7です(Python3自体の最新バージョンは3.8.0です)。Mac OSでもUbuntuのどちらでも正常に動作することは確認しています。TensorFlow 2.0がインストールされていれば、Windowsでも正常に作動すると思います。TensorFlow の公式ページにおけるPython開発環境の設定では、'virtualenv' を用いた 'Python virtual environments' を構築することが推奨されています。
ここでは、GPUを搭載していないPCを前提にしているので、リアルタイムでの物体検出では、処理速度が遅く、画像の切り替わりがスムーズでないことはやむを得ません。また、動作確認は以下に明記されたTensorflowやKerasなどのバージョンで行っています。このページが書かれた時(2019年11月15日)のソフトウエ環境は
pythonのバージョンは3.7.4です numpyのバージョンは1.17.2です scipyのバージョンは1.3.1です matplotlibのバージョンは3.1.1です PIL(Pillow)のバージョンは6.2.0です kerasのバージョンは2.2.4です tensorflowのバージョンは2.0.0です。
Last updated: 2019.11.15
Tensorflow 2.0のインストール |
anaconda3をインストールすると、python3.7のモジュール環境(Python 3.7本体, NumPy, SciPy, Matplotlib, Scikit-Learnなど )は自動的にセットアップされます。このとき、python3.7のパッケージ環境(Python 3.7本体以外の, NumPy, SciPy, Matplotlib, Scikit-Learnなど )は ~/opt/anaconda3/lib/python3.7/site-packages/にインストールされます。
'virtualenv' を用いた 'Python virtual environments' を構築するときは、
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" $ export PATH="/usr/local/bin:/usr/local/sbin:$PATH" $ brew update $ brew install python # Python 3 $ sudo pip3 install -U virtualenv # system-wide install
で、'Virtualenv'をインストールします。その後、Pythonをインストールします。
$ virtualenv --system-site-packages -p python3 ./venv $ source ./venv/bin/activate # sh, bash, ksh, or zsh (venv) $ pip install --upgrade pip (venv) $ pip list # show packages installed within the virtual environment (venv) $ deactivate # don't exit until you're done using TensorFlow $ #このシェルプロンプト状態ではインストールしたPythonは使用できません。
シェルプロンプトの前に(venv)がついているときには、Pythonが作動します。deactivateした後は、Pythonがパスから消えますので、Tensorflowなどは使用できません。
ここからは、anaconda3がインストールされている前提で説明を進めます。anaconda3がインストールされるときには、Pythonパスの設定は自動的に済んでいます。anaconda3 がインストールされているとき、シェルのプロンプトは
(base) $
となります。シェルプロンプトの prefix (base) はpython 3.7 に対応します。Python 3.7 を使用しないときは、$ conda deactivate と入力すれば、プロンプトは
$ #このシェルプロンプト状態ではインストールしたanaconda pythonは使用できません。
となります。通常のhomeディレクトリに戻ります。tensorflowを利用するときは必ず、$ conda activate を入力して、Pythonが使用可能な状態にします。
以下のようなコマンドを入力してtensorflow 2.0 をインストールします。
(base) $ pip install tensorflow # virtualenvでは、(venv)$ pip install --upgrade tensorflow
この入力で、TensorFlowのパッケージは ~/opt/anaconda3/lib/python3.7/site-packages/tensorflow/にインストールされます。
kerasはtensorflowに統合されているので、kerasを単体でインストールする必要はないのですが、念のために、keras もインストールしておきましょう。
(base) $ conda install keras
kerasでモデルの保存を行うためにはHDF5が必要となるので、そのためのパッケージもインストールします。
(base) $ conda install h5py
さらに、構成したモデルを可視化して、そのグラフを描画するためには、graphvizとpydotを利用する必要があります。それらのパッケージは
(base) $ conda install graphviz (base) $ conda install pydot
とインストールします。
keras.Sequentialモデルを用いた手書き数値の識別 |
Tensorflowの公式サイトにあるtutorialsに沿って説明します。TensorFlowのモデルを構築し訓練するためのハイレベルのAPIである tf.kerasを使用します。tf.keras.Sequential モデルを用いた最も単純な例は以下のように書けます。第1行目の、
from __future__ import absolute_import, division, print_function, unicode_literals
はこうするのが慣例だと思って下さい。
from __future__ import absolute_import, division, print_function, unicode_literals from tensorflow.keras import datasets, layers, models mnist = datasets.mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train, x_test = x_train / 255.0, x_test / 255.0 model = models.Sequential() model.add(layers.Flatten(input_shape=(28, 28))) model.add(layers.Dense(128, activation='relu')) model.add(layers.Dropout(0.2)) model.add(layers.Dense(10, activation='softmax')) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) model.fit(x_train, y_train, epochs=5) model.evaluate(x_test, y_test, verbose=2)
ネットワークは4層のlayersから構成されます。model = Sequential()で、Sequentialモデルを用いた具体的なモデル名をmodelとします。簡単にネットワークのレイヤーを積み重ねて、モデルを構築します。Flatten(input_shape=(28, 28))は入力サイズが28✖️28の2次元データを1次元にフラットにします。Dense(128, activation='relu')は、128個のニューロンが隣接する層と全結合されたレイヤで、活性化関数がRelu関数であることを意味します。Dense(units=10, activation='softmax')は、追加される第4層が10個のニューロンからなる全結合層で、活性化関数がsoftmax関数であることを示します。Dropoutはディープラーニングの過学習を防ぐために行います。Dropoutは、隣接層のニューロンとのつながりをランダムに切断してあげることで、過学習を防ぎます。0.2という数字は、その切断するニューロンの割合を示しています。訓練時には、データが読み込まれるごとにニューロンはランダムに切断されます。
compile()で、以上で指定された4層のレイヤをもつニューラルネットワークに損失関数と学習方法を指定して、モデルを完成させ、このモデルを用いた訓練(学習)プロセスを設定します。損失関数は交差エントロピー、最適化手法はadamを指定しています。loss='mean_squared_error'と指定すると二乗和誤差関数を使用されます。この例で指定されている'categorical_crossentropy'を使用するためには、データ(x_train,y_train)を'to_categorical'でone-hot形式にする前処理が必要です。損失関数の最小点を検索するための最適化手法にはいくつかの種類があります。SGD(stochastic Gradient Descent)は最も単純なアルゴリズムで、RMSprop、Adagrad, Adadelta、Adamなどのアルゴリズムが利用可能です。これらの詳細については、ディープラーニングの参考書などを参照ください。
この後、fit()メソッドを用いて、epochs数とbatch_sizeの大きさを与えて、モデルのパラメータ値の訓練(学習)をします。訓練データは教師ラベル付きの(x_train,y_train)です。y_trainが教師ラベルです。mnistデータはmnist.load_data() で読み込んでいます。
上記のコードを実行すると、以下のように、エポックごとに学習の計算結果が表示されます。
Train on 60000 samples Epoch 1/5 60000/60000 [==============================] - 4s 73us/sample - loss: 0.2952 - accuracy: 0.9145 Epoch 2/5 60000/60000 [==============================] - 5s 82us/sample - loss: 0.1409 - accuracy: 0.9575 Epoch 3/5 60000/60000 [==============================] - 4s 66us/sample - loss: 0.1086 - accuracy: 0.9672 Epoch 4/5 60000/60000 [==============================] - 4s 72us/sample - loss: 0.0861 - accuracy: 0.9730 Epoch 5/5 60000/60000 [==============================] - 4s 72us/sample - loss: 0.0743 - accuracy: 0.9766 10000/1 - 0s - loss: 0.0415 - accuracy: 0.9761 [0.07995059116524644, 0.9761]
次に、MNIST データを用いて、手書き数値の分類をするための、上記のネットワークよりは少し高度な畳み込みニューラルネットワーク (CNN: Convolutional Neural Network) を用いた学習について説明します。このネットワークは MNIST テストセットにおいて、99%以上の精度を達成します。tf.Keras.Sequential APIを使用するため、ほんの数行のコードでモデルの作成と学習を行うことができます。以下にコードを紹介します。モデルは8層のネットワーク層から構成されています。
from __future__ import absolute_import, division, print_function, unicode_literals from tensorflow.keras import datasets, layers, models (train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data() train_images = train_images.reshape((60000, 28, 28, 1)) test_images = test_images.reshape((10000, 28, 28, 1)) # ピクセルの値を 0~1 の間に正規化 train_images, test_images = train_images / 255.0, test_images / 255.0 model = models.Sequential() model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1))) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.Flatten()) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(10, activation='softmax'))
ネットワーク層のモデルを完成するために、Conv2D(64, (3, 3), activation='relu'))層の後に、ネットワーク層が3層追加されています。(shape (3, 3, 64) の) 畳み込みの基礎部分からの最後の出力テンソルを、1つ以上の Dense レイヤーに入れて分類を実行します。現在の出力は 3D テンソルですが、Dense レイヤーは入力としてベクトル (1D) を取ります。まず、3D 出力を 1D に平滑化 (または展開) してから、最上部に1つ以上の Dense レイヤーを追加します。MNIST は 10 個の出力クラスを持ちます。そのため、我々は最後の Dense レイヤーの出力を 10 にし、softmax関数を使用します。
model.summary() Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 26, 26, 32) 320 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 11, 11, 64) 18496 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 3, 3, 64) 36928 _________________________________________________________________ flatten (Flatten) (None, 576) 0 _________________________________________________________________ dense (Dense) (None, 64) 36928 _________________________________________________________________ dense_1 (Dense) (None, 10) 650 ================================================================= Total params: 93,322 Trainable params: 93,322 Non-trainable params: 0 _________________________________________________________________
モデルの構造がよく理解できます。以下の通りに、モデルをコンパイルして、学習する。
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) model.fit(train_images, train_labels, epochs=5)
結果は次の通りです。
Train on 60000 samples Epoch 1/5 60000/60000 [==============================] - 39s 643us/sample - loss: 0.1437 - accuracy: 0.9553 Epoch 2/5 60000/60000 [==============================] - 43s 718us/sample - loss: 0.0470 - accuracy: 0.9851 Epoch 3/5 60000/60000 [==============================] - 48s 800us/sample - loss: 0.0334 - accuracy: 0.9897 Epoch 4/5 60000/60000 [==============================] - 47s 776us/sample - loss: 0.0257 - accuracy: 0.9920 Epoch 5/5 60000/60000 [==============================] - 44s 734us/sample - loss: 0.0209 - accuracy: 0.9932
シンプルなモデルですが、相当に正確な識別ができます。
keras.Sequentialモデルを用いた画像の識別 |
ここでは、tf.keras.Sequential modelを用いてイメージ画像から動物を識別する方法について説明します。 Convolutional Neural Network (CNN) を使用して、CIFAR images の分類問題を取り上げます。 CIFAR10 dataset は 10クラスに分類、各クラス当たり60,000 color images 画像があります。データセットは、 訓練用として 50,000 training images 、検証用とし 10,000 testing imagesが用意されています。Kerasにはこのデータセットを読み込むコードが付録しています
from __future__ import absolute_import, division, print_function, unicode_literals import tensorflow as tf from tensorflow.keras import datasets, layers, models import matplotlib.pyplot as plt (train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data() # Normalize pixel values to be between 0 and 1 train_images, test_images = train_images / 255.0, test_images / 255.0
と入力すると、cifar10のデータセットが読み込まれます。内容を見てみるために、以下のように入力します。
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'] plt.figure(figsize=(10,10)) for i in range(25): plt.subplot(5,5,i+1) plt.xticks([]) plt.yticks([]) plt.grid(False) plt.imshow(train_images[i], cmap=plt.cm.binary) # The CIFAR labels happen to be arrays, # which is why you need the extra index plt.xlabel(class_names[train_labels[i][0]]) plt.show()
25枚の画像が表示されます。画像はかなり不鮮明です。CNNモデルを作成し、学習するために、以下のコード作成します。cifarの画像のshapeは(32, 32, 3)です。
model = models.Sequential() model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3))) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (3, 3), activation='relu')) model.add(layers.Flatten()) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(10, activation='softmax')) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) history = model.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels))
Train on 50000 samples, validate on 10000 samples Epoch 1/10 50000/50000 [==============================] - 11s 222us/sample - loss: 1.5684 - accuracy: 0.4266 - val_loss: 1.2367 - val_accuracy: 0.5543 Epoch 2/10 50000/50000 [==============================] - 7s 130us/sample - loss: 1.1648 - accuracy: 0.5879 - val_loss: 1.1616 - val_accuracy: 0.5853 Epoch 3/10 50000/50000 [==============================] - 6s 130us/sample - loss: 1.0314 - accuracy: 0.6379 - val_loss: 1.0190 - val_accuracy: 0.6374 Epoch 4/10 50000/50000 [==============================] - 6s 129us/sample - loss: 0.9382 - accuracy: 0.6711 - val_loss: 0.9656 - val_accuracy: 0.6617 Epoch 5/10 50000/50000 [==============================] - 6s 129us/sample - loss: 0.8650 - accuracy: 0.6970 - val_loss: 0.9005 - val_accuracy: 0.6870 Epoch 6/10 50000/50000 [==============================] - 6s 129us/sample - loss: 0.8054 - accuracy: 0.7183 - val_loss: 0.9217 - val_accuracy: 0.6748 Epoch 7/10 50000/50000 [==============================] - 7s 131us/sample - loss: 0.7557 - accuracy: 0.7356 - val_loss: 0.9336 - val_accuracy: 0.6858 Epoch 8/10 50000/50000 [==============================] - 7s 132us/sample - loss: 0.7145 - accuracy: 0.7514 - val_loss: 0.9107 - val_accuracy: 0.6906 Epoch 9/10 50000/50000 [==============================] - 7s 134us/sample - loss: 0.6758 - accuracy: 0.7647 - val_loss: 0.8696 - val_accuracy: 0.7077 Epoch 10/10 50000/50000 [==============================] - 6s 130us/sample - loss: 0.6410 - accuracy: 0.7757 - val_loss: 0.8684 - val_accuracy: 0.7076
MNIST分類で採用した前項のモデルと同一ですが、学習の結果はそれほど高精度のモデルにはなっていません。MNISTのデータは白黒でしたので、このような結果となりました。
*** under construction ***
学習済みモデルを用いた画像からの物体の識別 |
通常のCPUを搭載したPCでは、正答率が90%を超えるまでニューラルネットワークの学習を行うためには、数時間から数日も必要とされます。Kerasには、学習済みモデルが用意されています。ImageNetで学習した重みをもつ画像分類のモデルとして、以下のものが用意されています。
Xception VGG16 VGG19 ResNet50 InceptionV3 InceptionResNetV2 MobileNet DenseNet NASNet
Object Detection APIを用いた物体検出 |
TensorFlow Object Detection API can be used to detect, with bounding boxes, objects in images and/or video using either some of the pre-trained models made available or through models you can train on your own (which the API also makes easier).
*** under construction ***