Welcome to Mashykom WebSite



TensorFlow 入門

 GoogleのTensorFlow開発チームは2019年10月1日、オープンソースの機械学習ライブラリ TensorFlow 2 を公開しました。これにより、TensorFlow が大幅に改訂されて、version 1.x からversion 2.xに変更されました。Keras がTensorFLowのモジュールに統合されました。そして、それに対応しての関係でしょうが、TensorFlow 1.xで使用されていたいくつかの重要なモジュールが廃止されました。とりわけ、TensorFlow 2で、tf.contribが廃止された影響は大きいです。また、Keras がTensorFLowのモジュールに統合されましたので、従来のKeras単体でのコードが正常に動作しません。

 このページでは、TensorFlow 2のインストール法と簡単な取扱説明を行います。TensorFlowの特徴はDefine and Run(静的計算グラフ)と呼ばれます。Define and Runではニューラルネットワークの計算方法をはじめに決めてしまうため、入力データの次元がデータごとに異なる状況に対応しづらいという特徴があります。Keras + Tensorflowは見やすく簡易で、非常に簡単にネットワークを作成できるので、人工知能の専門家以外の人たちにとって、使いやすい必須の道具となっています。一方で、、アップグレードが後方互換性を持たないという欠点と、動作が遅いという問題点もあります。

 Kerasを活用するための日本語版ドキュメントはこのサイトにあります。このKeras.ioのドキュメントには、活用できるexamplesが多数掲載されています。

 python関連のパッケージなどの環境はセットアップされているとします。Jupyter Notebookなどが必須なので、jupyter をインストールすることを推奨します。Anocandaをインストールしたときは、jupyter notebookは同時にインストールされます。anaconda3に付属するpythonの最新バージョンは 3.8.5です(Python3自体の最新バージョンは3.9.5です)。

 TensorFlow の公式ページにおけるインストール方法では、'virtualenv' を用いた 'Python virtual environments' を構築することが推奨されています。なぜなら、Anacondaでcondaコマンドを用いたTensorFlowのインストールでは、TensorFlowの最新バージョンがインストールできないからです。Anacondaで仮想環境を作成して、pipコマンドでインストールすることを勧めます。

 ここでは、GPUを搭載していないPCを前提にしているので、リアルタイムでの物体検出では、処理速度が遅く、画像の切り替わりがスムーズでないことはやむを得ません。MacOS Big Sur 11.3.1を前提にして記述していますが、Ubuntuでも正常に動作することは確認しています。TensorFlow がインストールされていれば、Windowsでも正常に作動すると思います。また、動作確認は以下に明記されたTensorflowやnumpyなどのバージョンで行います。

numpyのバージョンは1.19.2です
scipyのバージョンは1.5.2です
matplotlibのバージョンは3.3.2です
PIL(Pillow)のバージョンは8.0.1です
tensorflowのバージョンは2.4.1です

Last updated: 2021.5.14( First uploaded 2019.11.15)


Anaconda 環境でのTensorflow のインストール


 anaconda3をインストールすると、python3.8.5 のモジュール環境(Python 3.8.5本体, NumPy, SciPy, Matplotlib, Scikit-Learnなど )は自動的にセットアップされます。このとき、python3.8.5のパッケージ・モジュール(Python 3.8.5本体以外の, NumPy, SciPy, Matplotlib, Scikit-Learnなど )は ディレクトリ /anaconda3/lib/python3.8/site-packages/ にインストールされます。

 ここからは、anaconda3の(base)環境を使用する前提で説明を進めます。anaconda3がインストールされるときには、Pythonパスの設定は自動的に済んでいます。anaconda3 がインストールされているとき、シェルのプロンプトは


(base) $ 

となります。シェルプロンプトの prefix (base) はpython 3.8 に対応します。Python 3.8 を使用しないときは、$ conda deactivate と入力すれば、プロンプトは


$ #このシェルプロンプト状態ではインストールしたanaconda pythonは使用できません。

となります。通常のhomeディレクトリに戻ります。tensorflowを利用するときは必ず、$ conda activate を入力して、Pythonを使用可能な状態にします。

 anaconda で仮想環境を作成するときは、


(base)$ conda create -name 環境名 python=バージョン ライブラリ名=バージョン

とコマンドを入力します。具体的には、Tensorflowをインストールするための仮想環境なので、


(base)$ conda create -name tf_ai python=3.8.5 numpy jupyter

とします。これで仮想環境を作ることができたので、conda info -eで確認しましょう。


(base)$ conda info -e

 'base'と'tf_ai'が表示されます。仮想環境が切り替わっていませんので、tf_ai に切り替えます。


(base)$ activate tf_ai

---
結果

(tf_ai)$ 

 ターミナルを再起動すると、anacondaの(base)環境に戻ります。

 以後、(base)環境でのインストールを前提にします。Tensorflowのインストールをcondaコマンドを用いて実行すると、古いバージョンがダウンロードされるケースが多い。最新バージョンのインストールはpipコマンドを用いた方がベターです。ここでは、pipコマンドを使用するので


(base) $ pip install tensorflow # Current stable release for CPU and GPU

 とします。pipコマンドとcondaコマンドの混在を避けたい時は、これ以降のモジュールのインストールはすべてpipコマンドを使用する方がベターかもしれません。pipコマンドとcondaコマンドが混在しても、現在までのところ、致命的な問題は生じていません。

 インストールの確認は以下のコマンドを打ちます。


(base) $ python -c "import tensorflow as tf;print(tf.reduce_sum(tf.random.normal([1000, 1000])))"

This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
tf.Tensor(-1232.0776, shape=(), dtype=float32)

というテンソルが返れば、TensorFlow のインストールは成功です

 この入力で、TensorFlowのパッケージは /anaconda3/lib/python3.8/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

とインストールします。


Pyenv 環境でのTensorflow のインストール


 Mac OS にPyenv をインストールします。UbuntuでPyenvを利用する方法については、Ubuntu 20.04LTSでのPython環境構築のページを見てください。


$ brew update
$ brew install pyenv

 以下の警告が表示されます。取り敢えず、無視しましょう。

For compilers to find readline you may need to set:
  export LDFLAGS="-L/usr/local/opt/readline/lib"
  export CPPFLAGS="-I/usr/local/opt/readline/include"

For pkg-config to find readline you may need to set:
  export PKG_CONFIG_PATH="/usr/local/opt/

 .bash_profile に環境変数や init コマンドを追加します。


$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

ターミナルを再起動して動作確認します。


$ pyenv --version

pyenv 1.2.27

Python をインストールします。最新版の Python バージョンを調べて、以下のコマンドでインストールします。結構時間がかかります。

$ pyenv install --list

$ pyenv install 3.9.4

----
python-build: use openssl@1.1 from homebrew
python-build: use readline from homebrew
Downloading Python-3.9.4.tar.xz...
-> https://www.python.org/ftp/python/3.9.4/Python-3.9.4.tar.xz
Installing Python-3.9.4...
python-build: use readline from homebrew
python-build: use zlib from xcode sdk
Installed Python-3.9.4 to /Users/koichi/.pyenv/versions/3.9.4

インストールした Python をグローバルで使うように設定して、システムPythonとして使用できます。


$ pyenv global 3.9.4

 Pythonのバージョンを確認します。


$ pyenv versions

----
 system
* 3.9.4 (set by /Users/koichi/.pyenv/version)

システムPythonが変更されたか、バージョンの確認をしましょう。


$ python --version

----
Python 3.9.4

 システムのpythonが3.9.4バージョンに切り替わりました。

 以上で、Python環境の準備が完了したので、Tensorflowをインストールしましょう。以下のコマンド群を入力します。


$ pyenv shell 3.9.4
$ python -m pip install -U tensorflow
$ python -m pip install numpy scipy pillow pydot matplotlib seaborn scikit-learn scikit-image keras pandas opencv-python

 TensorFlow のバージョン確認をします。


$ python -c "import tensorflow as tf; print( tf.__version__ )"

 Python 開発環境で必須のモジュール群(JupyterLab, notebook, spyder)のインストールを行います。


$ python -m pip install -U jupyterlab jupyter jupyter-console  notebook  spyder

 Jupyter notebook の起動は,


$ jupyter notebook

 とします。

 また、Pyenv内にAnaconda パッケージをインストールすることができます。


$ pyenv install -l | grep anaconda

 というコマンドを入力して、インストールできるAnacondaのバージョンを確認します。最新のバージョンをインストールします。


$ pyenv install anaconda3-5.3.1

 この結果、anaconda3-5.3.1バージョンが、.pyenv/versions/内にインストールされます。'pyenv versions'というコマンドで確認します。


$ pyenv shell anaconda3-5.3.1

 と仮想環境を切り替えて、anaconda環境下のPythonを利用します。この後、Tensorflowをインストールします。


$ pip install -U tensorflow

 Tensorflowを実行中に、モジュールが不足しているという警告が出るときは、適宜それらのモジュールをインストールしましょう。

 なお、Pyenvとは独立にAnacondaがインストールされているとき、PyenvのPython環境と衝突します。この時は、bash_profileファイル内 の1行

eval "$(pyenv init -)"

をコメントアウトします。こうすると、Pyenvとは独立にインストールしたAnaconda環境を使用できます。通常は、pyenvでAnacondaもインストールしますので、この問題は生じないと思います。

 PyenvのPython環境を使用するときは、ターミナルから、このコマンド(eval "$(pyenv init -)")を再度入力します。

 必要なくなったAnacondaをアンインストールしたい時、anacondaのディレクトリをそのまま,rmコマンドをしても,権限で削除できないので,sudoで実行します。


$ sudo rm -rf .pyenv/versions/anaconda3-5.3.1/

 Pyenv のアンインストールを実行したいときは、homebrew経由でインストールされている場合


$ brew uninstall pyenv

or

$ sudo rm -rf .pyenv

 とコマンドを打てば、アンインストールは完了します。pyenvをインストールしたときに、bash_profileにパスを設定しているので、その部分を削除します。


Virtualenv 環境でのTensorflow のインストール


 次に、'virtualenv' を用いた 'Python virtual environments' でTensorflowをインストールする方法を説明します。仮想環境を構築するために、


/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
export PATH="/usr/local/opt/python/libexec/bin:$PATH"
# if you are on macOS 10.12 (Sierra) use `export PATH="/usr/local/bin:/usr/local/sbin:$PATH"`
brew update
brew install python  # Python 3

で、'Virtualenv'をインストールします。その後、Pythonをインストールします。


$ virtualenv --system-site-packages -p python3 ./venv #name 'venv' is up to you 

$ 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は使用できません。

 Tensorflow をインストールします。


$ source ./venv/bin/activate
(venv)$ pip install --upgrade tensorflow

 インストールの確認は以下のコマンドを打ちます。


(venv)$ python -c "import tensorflow as tf;print(tf.reduce_sum(tf.random.normal([1000, 1000])))"

 tf.Tensor(-1232.0776, shape=(), dtype=float32)
というテンソルが返れば、TensorFlow のインストールは成功です

 シェルプロンプトの前に(venv)がついているときには、Pythonが作動します。deactivateした後は、Pythonがパスから消えますので、Tensorflowなどは使用できません。

 この入力で、TensorFlowのパッケージは ./venv/lib/python3/site-packages/tensorflow/にインストールされます。

 kerasはtensorflowに統合されているので、kerasを単体でインストールする必要はないのですが、念のために、keras もインストールしておきましょう。


(venv) $ pip install keras

 kerasでモデルの保存を行うためにはHDF5が必要となるので、そのためのパッケージもインストールします。


(venv) $ pip install h5py

 さらに、構成したモデルを可視化して、そのグラフを描画するためには、graphvizとpydotを利用する必要があります。それらのパッケージは


(venv) $ pip install graphviz
(venv) $ pip install pydot

とインストールします。


ニューラル・ネットワークの作成と学習


 ここからは、TensorFlowがインストールされていることを前提にして、Tensorflowの使用法について簡単に説明します。最初に、ニューラル・ネットワークの作成と学習について、Tensorflowの公式サイトにあるtutorialsに沿って説明します。TensorFlowのモデルを構築し訓練するために、通常、ハイレベルのAPIである tensorflow.kerasが使用されます。tensorflow.keras.Sequential モデルを用いた最も単純な例は以下のように書けます。

 層を積み重ねてネットワークモデルを構築します。


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))は入力サイズが28x28の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]


学習済みモデルを用いた画像分類


 通常のCPUを搭載したPCでは、正答率が90%を超えるまでニューラルネットワークの学習を行うためには、数時間から数日も必要とされます。Kerasには、学習済みモデルが用意されています。ImageNetで学習した重みをもつ画像分類のモデルとして、以下のものが用意されています。


Xception
VGG16
VGG19
ResNet50
InceptionV3
InceptionResNetV2
MobileNet
DenseNet
NASNet


 ここでは、ディープラーニングでよく使用されるニューラルネットワークであるVGGモデルを使用します。VGGは、畳み込み層とプーリング層から構成される基本的なCNNです。畳み込み層と全結合層を全部で16もしくは19層にしてディープにしています。前者をVGG16、後者をVGG19と呼びます。VGGは、2014年に開催された大規模画像認識のコンペILSVRC(ImageNet Large Scale Visual Recognition Challenge)で2位の成績に終わりましたが、シンプルな構成なので応用面ではよく使用されます。(ちなみに、優勝者はGoogLeNetでした)VGGは3x3のフィルターによる畳み込み層を2回から4回連続して、プーリング層でサイズを半分にするという処理を繰り返します。

 ResNetは2015年Microsoftのチームによって開発されたニューラルネットワークです。その特徴は、層を深くしすぎると過学習などの問題が起きるのを回避するために、スキップ構造(ショートカット)と呼ばる概念を導入した点です。ResNetは、VGGのネットワークをベースにして、スキップ構造を取り入れて、層を深くしています。具体的には、畳み込み層を2層おきにスキップしてつなぎ、層を150層以上まで深くしています。ILSVRCのコンペでは、誤認識率が3.5%という驚異的な成果を出しています。

 上で触れたとおり、VGG16は2014年のILSVRCで提案された畳み込み13層とフル結合3層の計16層から成る畳み込みニューラルネットワークです。層の数が多いだけで一般的な畳み込みニューラルネットと大きな違いはなく、同時期に提案されたGoogLeNetに比べるとシンプルでわかりやすい。VGG16の出力層は1000ユニットあり、ImageNetの1000クラスを分類するニューラルネットです。

 ImageNetと呼ばれる大規模な画像データセットを使って訓練した学習済みモデルを使用します。tensorflowではVGG16モデルがkeras.applications.vgg16モジュールに実装されているため簡単に使えます。ImageNetの大規模画像セットで学習済みのモデルなので自分で画像を集めて学習する必要がなくて、簡単に利用できて便利です。

学習済みモデルVGG16を用いた画像識別のコードは以下のようになります。


from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.vgg16 import preprocess_input, decode_predictions
import numpy as np

model = VGG16(include_top=True, weights='imagenet', input_tensor=None, input_shape=None)

img_path = 'images/elephant.jpg'
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)

model.summary()

preds = model.predict(x)

# decode the results into a list of tuples (class, description, probability)
# (one such list for each sample in the batch)


print('Predicted:', decode_predictions(preds, top=3)[0])

 一般的に、VGG16クラス、VGG16(include_top=True, weights='imagenet', input_tensor=None, input_shape=None)は4つの引数を取ります。include_topはVGG16のトップにある1000クラス分類するフル結合層(FC)を含むか含まないかを指定します。ここでは画像分類を行いたいためFCを含んだ状態で使いますので、Trueがデフォルトです。weightsはVGG16の重みの種類を指定します。VGG16は単にモデル構造であるため必ずしもImageNetを使って学習しなければいけないわけではありません。しかし、現状ではImageNetで学習した重みしか提供されていないので、これを採用します。input_tensorは自分でモデルに画像を入力したいときに使うので、ここでは必要ありませんので、デフォルトでいいです。input_shapeは入力画像の形状を指定します。include_top=Trueにして画像分類器として使う場合は 、デフォルトにしておきます。このとき、入力のshapeは(224, 224, 3) ('channels_last'データフォーマットのとき) または (3, 224, 224) ('channels_first'データフォーマットのとき)となっています。

 この例では以下にある像の画像'elephant.jpg'を用いています。

elephant.jpg

 この画像はホームディレクトリに作成されたimagesという名前のディレクトリの下に配置されています。model.summary()するとモデル構造が見られます。このコードを実行すると、


Model: "vgg16"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         [(None, 224, 224, 3)]     0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 224, 224, 64)      1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 224, 224, 64)      36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 112, 112, 64)      0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 112, 112, 128)     73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 112, 112, 128)     147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 56, 56, 128)       0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 56, 56, 256)       295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 56, 56, 256)       590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 56, 56, 256)       590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 28, 28, 256)       0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 28, 28, 512)       1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 28, 28, 512)       2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 28, 28, 512)       2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 14, 14, 512)       0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 14, 14, 512)       2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 7, 7, 512)         0         
_________________________________________________________________
flatten (Flatten)            (None, 25088)             0         
_________________________________________________________________
fc1 (Dense)                  (None, 4096)              102764544 
_________________________________________________________________
fc2 (Dense)                  (None, 4096)              16781312  
_________________________________________________________________
predictions (Dense)          (None, 1000)              4097000   
=================================================================
Total params: 138,357,544
Trainable params: 138,357,544
Non-trainable params: 0
_________________________________________________________________
Predicted: [('n02504458', 'African_elephant', 0.7639979), ('n01871265', 'tusker', 0.17359596), ('n02504013', 'Indian_elephant', 0.062363148)]

という結果が表示されます。重み(#Param)がある層を数えていくと全部で16個あることがわかります。include_top=Trueなのでfc1、fc2、predictionsという層が追加されているのが確認できます。また、最後のpredictions層の形状が (None, 1000) で1000クラスの分類であることもわかります。Noneはサイズが決まっていないことを意味し、ここでは入力サンプル数を意味します。

 load_img()でロードした画像は (rows, cols, channels) の3Dテンソルなので、これにサンプル数 samples を追加した4Dテンソルに変換する必要があります。img_to_array()でPIL形式の画像をNumPy array形式に変換して、np.expand_dimsで4次元に変換します。

 クラスの予測はpredict()で行います。VGG16用の平均を引く前処理 preprocess_input() を通した4Dテンソルを入力データとします。predict()の戻り値は、1000クラスの確率値です。VGG16用のdecode_predictions()を使うと確率値が高い順にクラス名を出力してくれます。

  確率76.39%で画像が'African_elephant'の画像であると識別しました。このケースは正答率が比較的高く出る画像です。画像を色々と変えて試して見てください。例えば、以下のひまわりの画像を用いてください。

flower.jpg

 手元に画像がないときは、ImageNetを検索して、そこからダウンロードしてください。ImageNetとはスタンフォード大学がインターネット上から画像を集め分類したデータセットのことです。一般画像認識用に用いられる。ImageNetを利用して画像検出・識別精度を競うILSVRCなどコンテストも開かれています。ダウンロードできる画像は、著作権フリーというのではないので、自己学習用のものです。学習済みモデルを用いた画像分類の詳細については、keras + Tensorflowを用いた画像分類のページを参照してください。


Object Detection APIを用いた物体検出


TensorFlow Object Detection API を活用すると、学習済みモデルを用いた画像からの物体検出およびライブ映像からの物体検出が容易に実行できます。Object Detection APIで使用できる学習済みモデルについては、detection_model_zooに記述されています。これらのモデルはthe COCO dataset、 the Kitti dataset、 the Open Images dataset、 the AVA v2.1 dataset または the iNaturalist Species Detection Datasetで学習済みです。 COCO データセットで学習されたモデルの代表的なものは以下の通りです。


ssd_mobilenet_v1_coco
ssd_mobilenet_v2_coco
ssd_inception_v2_coco
faster_rcnn_inception_v2_coco
faster_rcnn_resnet50_coco
mask_rcnn_inception_v2_coco

TensorFlow Object Detection APIを利用するために、モジュールをこのサイトからダウンロードして下さい。


$ mkdir Tensorflow
$ cd Tensorflow
$ git clone https://github.com/tensorflow/models.git

 modelsという名前で展開されますので、tensorflow/modelsという名前のディレクトリに保存されます。ここで説明するObject Detection APIのノートブックは、Googole Colab で実行できます。以下の説明は、TensorFlowのGitHubのrepoをダウンロードして、利用する際に必要な手続きです。Google Colab を活用するときは、無視してください。

Tensorflow Object Detection API は configure model and training parametersの過程でProtobufs を使用しますので、Protobuf librariesをコンパイルする必要があります。 tensorflow/models/research/ ディレクトリで、ターミナルから


$ cd models/research

# Compile protos.
$ protoc object_detection/protos/*.proto --python_out=.

# Install TensorFlow Object Detection API.
$ cp object_detection/packages/tf2/setup.py .
$ python -m pip install --use-feature=2020-resolver .

と入力します。エラーが表示されるときは、Object Detection API Demo に記載されているthe installation instructionsを参照して下さい。

Cocoapiを使用するときは、 pycocotools subfolder を tensorflow/models/research ディレクトリにコピーする必要があります。以下のように入力します。


$ git clone https://github.com/cocodataset/cocoapi.git
$ cd cocoapi/PythonAPI
$ make
$ cp -r pycocotools tensorflow/models/research/

次に、 Jupyter Notebookを用いて、 tensorflow/models/research/object_detection/colab_tutorials/ ディレクトリに行って、object_detection_tutorial.ipynb を開いて下さい。Object Detection API Demoというノートブックが表示されます。以下にその内容を示します。


import os
import pathlib

if "models" in pathlib.Path.cwd().parts:
  while "models" in pathlib.Path.cwd().parts:
    os.chdir('..')
elif not pathlib.Path('models').exists():
  !git clone --depth 1 https://github.com/tensorflow/models

!cd models/research/

import numpy as np
import os
import six.moves.urllib as urllib
import sys
import tarfile
import tensorflow as tf
import zipfile

from collections import defaultdict
from io import StringIO
from matplotlib import pyplot as plt
from PIL import Image
from IPython.display import display

from object_detection.utils import ops as utils_ops
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_util

# patch tf1 into `utils.ops`
utils_ops.tf = tf.compat.v1

# Patch the location of gfile
tf.gfile = tf.io.gfile

def load_model(model_name):
  base_url = 'http://download.tensorflow.org/models/object_detection/'
  model_file = model_name + '.tar.gz'
  model_dir = tf.keras.utils.get_file(
    fname=model_name, 
    origin=base_url + model_file,
    untar=True)

  model_dir = pathlib.Path(model_dir)/"saved_model"

  model = tf.saved_model.load(str(model_dir))
  model = model.signatures['serving_default']

  return model

# List of the strings that is used to add correct label for each box.
PATH_TO_LABELS = 'models/research/object_detection/data/mscoco_label_map.pbtxt'
category_index = label_map_util.create_category_index_from_labelmap(PATH_TO_LABELS, use_display_name=True)

# If you want to test the code with your images, just add path to the images to the TEST_IMAGE_PATHS.
PATH_TO_TEST_IMAGES_DIR = pathlib.Path('models/research/object_detection/test_images')
TEST_IMAGE_PATHS = sorted(list(PATH_TO_TEST_IMAGES_DIR.glob("*.jpg")))

 上記のコードは Jupyter Notebook にコピペして、実行して下さい。以下同様です。次に、モデルをロードし、画像から検出を行ます。ここで使用される学習済みモデルは、 'ssd_mobilenet_v1_coco_2017_11_17' です。


model_name = 'ssd_mobilenet_v1_coco_2017_11_17'
detection_model = load_model(model_name)

print(detection_model.inputs)

detection_model.output_dtypes
detection_model.output_shapes

def run_inference_for_single_image(model, image):
  image = np.asarray(image)
  # The input needs to be a tensor, convert it using `tf.convert_to_tensor`.
  input_tensor = tf.convert_to_tensor(image)
  # The model expects a batch of images, so add an axis with `tf.newaxis`.
  input_tensor = input_tensor[tf.newaxis,...]

  # Run inference
  output_dict = model(input_tensor)

  # All outputs are batches tensors.
  # Convert to numpy arrays, and take index [0] to remove the batch dimension.
  # We're only interested in the first num_detections.
  num_detections = int(output_dict.pop('num_detections'))
  output_dict = {key:value[0, :num_detections].numpy() 
                 for key,value in output_dict.items()}
  output_dict['num_detections'] = num_detections

  # detection_classes should be ints.
  output_dict['detection_classes'] = output_dict['detection_classes'].astype(np.int64)
   
  # Handle models with masks:
  if 'detection_masks' in output_dict:
    # Reframe the the bbox mask to the image size.
    detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks(
              output_dict['detection_masks'], output_dict['detection_boxes'],
               image.shape[0], image.shape[1])      
    detection_masks_reframed = tf.cast(detection_masks_reframed > 0.5,
                                       tf.uint8)
    output_dict['detection_masks_reframed'] = detection_masks_reframed.numpy()
    
  return output_dict

def show_inference(model, image_path):
  # the array based representation of the image will be used later in order to prepare the
  # result image with boxes and labels on it.
  image_np = np.array(Image.open(image_path))
  # Actual detection.
  output_dict = run_inference_for_single_image(model, image_np)
  # Visualization of the results of a detection.
  vis_util.visualize_boxes_and_labels_on_image_array(
      image_np,
      output_dict['detection_boxes'],
      output_dict['detection_classes'],
      output_dict['detection_scores'],
      category_index,
      instance_masks=output_dict.get('detection_masks_reframed', None),
      use_normalized_coordinates=True,
      line_thickness=8)

  display(Image.fromarray(image_np))

for image_path in TEST_IMAGE_PATHS:
  show_inference(detection_model, image_path)

検出結果は以下のような表示となります。

object_detection_1.png

object_detection_2.png


Tensorflow で Object Detection のページに行く

このページの先頭に戻る