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が多数掲載されています。

 Jupyter Notebookなどが必須なので、jupyter をインストールすることを推奨します。Anocandaをインストールしたときは、jupyter notebookは同時にインストールされます。2022年2月時点で、anaconda3に付属するpythonの最新バージョンは 3.9です(Python3自体の最新バージョンは3.10です)。

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

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

numpyのバージョンは1.20.3です
scipyのバージョンは1.6.3です
matplotlibのバージョンは3.4.2です
PIL(Pillow)のバージョンは8.2.0です
kerasのバージョンは2.8.0です
tensorflowのバージョンは2.8.0です
pandasのバージョンは1.2.4です
sklearnのバージョンは0.24.2です

Last updated: 2022.2.20( First uploaded 2019.11.15)


システム Python での Tensorflow のインストール


 システム Python または Anaconda に梱包されている python バージョンを使用するときの、 Tensorflow のインストールについて説明します。Python 公式版をインストールすることを推奨します。Python 公式版のインストールはpython 情報サイトのページに説明があります。Windows、 macOS、 Ubuntu などのOSに対応したインストーラーが準備されています。こららを利用して、各自のPCに必要な Python のバージョンをインストールできます。Tensorflow は Python 3.9 以下のバージョンをサポートします。

 macOS の場合、Homebrew が利用できます。Homebrew を使用しないときは、パスの設定が必要です。


$ brew install python3
$ which python3
$ python3 --version 
$ pip3 --version

 Python 3 を実行するとき、python3 と入力しないと、Python 2 バージョンが起動します。

 brew install で Python 10 がインストールされてしまったら(2022年8月以降、python10 になります)、Tensorflow 用に Python 3.9 以下のバージョンをインストールする必要があります。以下のようにします。


$ brew install python@3.9 #python@3.9のインストール
$ which python3
$ python3 --version

 この場合、Python3.9を実行する python3.9 コマンドは、/usr/local/bin ディレクトリに登録されないので、次のように手動で登録しておきます。


$ ln -s /usr/local/opt/python@3.9/bin/python3.9 /usr/local/bin/python3.9

 複数バージョンのPython3をインストールしている場合は、python3.9、python3.10 のように、コマンドファイル名で使い分けるようにします。

 以下のようなコマンドを入力してtensorflow 2 をインストールします。


$ pip3 install --user --upgrade tensorflow # install in $HOME

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


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

2022-09-19 09:13:06.180403: I tensorflow/core/platform/cpu_feature_guard.cc:151] 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(1223.3867, shape=(), dtype=float32)

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

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


$ pip3 install --user --upgrade tensorflow # install in $HOME

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


$ pip3 install h5py

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


$ pip3 install graphviz
$ pip3 install pydot

とインストールします。


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


 Tensorflow のインストールでは、Python の仮想環境を構築することが推奨されているので、仮想環境の作成の仕方を説明します。Python の仮想環境を構築する方法は複数あります。venv と pyenv が代表的な仮想環境の作成手法だと思います。更に高度なことができる pipenv というツールもあります。ここでは、pyenv を用いた仮想環境を作成します。pyenvは、システムPython とは別の Python をインストールするのに便利なツールです。ここでは、Pyenv を用いた手続きについて説明します。Ubuntu での仮想環境の構築については、PyenvによるPython環境の構築のページを参照ください。

 既にインストールされている pyenv を消去しておきます。


$ rm -rf ~/.pyenv

 pyenv のダウンロードと更新をします。仮想環境を ~/.pyenv 以下に作成します。


$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
$ cd ~/.pyenv
$ git pull

 git pull はpyenvのアップデートをするためです。名称 pyenv は任意ですが、通常、この通りにします。Mac では brew コマンドでも「$ brew install pyenv」としてダウンロードできます。Windows PC でのインストールについては公式サイトを参照ください。

 pyenv がインストールできたら、パス設定をします。bashrc あるいは bash_profile ファイルに以下のパス設定を追加します。


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

 ここで、pyenv を使用して、システム Python とは別に Python 3.9.x をインストールします。Tensorflow は Python 3.9 以下をサポートしてます。(2022年9月現在)新しく端末を開いて、システム python のバージョンを確認してみる。


$ which python3
$ python3 --version 

インストールできる Python 3.9 のバージョンの確認をします。


$ pyenv install -l | grep 3.9

 Python 3.9.4 をインストールします。


$ pyenv install 3.9.4

 Python のパッケージが .pyenv/versions/3.9.4 ディレクトリにインストールされます。仮想環境 3.9.4 にpip, setuptools をインストールします。「pyenv shell 3.9.4」コマンドで仮想環境3.9.4に切り替えます。


$ pyenv shell 3.9.4
$ python -m pip install -U pip setuptools

 Python 環境の切り替えは次のようなコマンドで行います。


$ pyenv shell system (システムPythonに切り替え)

$ pyenv shell 3.9.4  (.pyenvのPython 3.9.4 に切り替え) 

$ pyenv global 3.9.4 (PC 全体でPython 3.9.4を使用するとき)

 デフォルトで pyenv 環境下の Python 3.9.4 を使いたいときは, 次のように設定します。


$ echo 'pyenv shell 3.9.4' >> ~/.bash_profile
$ exec $SHELL -l

 この設定をすると、ターミナルの起動後に システム Python ではなく、pyenvのpython3.9.4 が起動可能になります。

 Python 3.9.4 を起動してみよう。pyenv 環境下で Python 3.9.4 に切り替えてから、python を起動します。


$ pyenv shell 3.9.4
$ python

Python 3.9.4 (default, May 15 2021, 14:49:04) 
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 

 以上で、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 pandas opencv-python

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


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

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


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

2022-09-19 09:13:06.180403: I tensorflow/core/platform/cpu_feature_guard.cc:151] 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(1223.3867, shape=(), dtype=float32)

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

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


$ python -m pip install -U jupyterlab jupyter 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もインストールしますので、この問題は生じないと思います。

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


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


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


 MacOS には Python 3.x がプリインストールされているので、venv を用いた 仮想環境を構築するために、


$ python3 -m venv .venv 

 と入力して、仮想環境を .venv 内に作成します。このコマンドは、指定したディレクトリ ~/.venv に仮想環境を作成します。仮想環境のディレクトリ名は、 .venv 以外でも、好きな名前をつけても大丈夫です。 日本語のPython 情報サイトの Virtualenv を用いた 仮想環境構築のページに説明があります。

 作成した仮想環境 .venv ディレクトリにある bin/activate を、. または source コマンドで実行して、仮想環境に切り替えます。


$ source .venv/bin/activate  # sh, bash, ksh, or zsh
(venv) $ 

 コマンド プロンプトの先頭に (venv) と表示され、仮想環境で実行中であることがわかります。pip をアップグレードするときは、以下のように打ちます。その後、仮想環境用の Python モジュールをインストールします。 pip list は site-packages にインストールされたモジュールの一覧を表示します。


(venv) $ python3 -m pip install --upgrade pip

(venv) $ pip list  # show packages installed within the virtual environment

 仮想環境からシステム Python を使用する通常の状態に切り替えるときは、deactivate コマンドを実行します。


(venv) $ deactivate  # don't exit until you're done using TensorFlow

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

 Python のモジュールをインストールするときは、以下のようにします。


$ source .venv/bin/activate
(venv)$ python3 -m pip install numpy scipy pillow pydot matplotlib seaborn scikit-learn scikit-image keras pandas opencv-python

 機械学習で必要とされる主要なパッケージが仮想環境下にインストールされます。

 続けて、Python を起動して、NumPy のバージョンの確認をします。


(venv)$ python3
Python 3.9.4 (default, May 15 2021, 14:49:04)
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> np.__version__
'1.20.3'
>>> quit()
(venv)$

 複数のバージョンのシステムPython をインストールしている環境では、使用する Python を指定して仮想環境を作成できます。

 Python 3.7とPython 3.8がインストールされた環境で、Python 3.7の仮想環境を作成する場合は、python3.7 を使って次のように指定します。ここでは、仮想環境をディレクトリ py37env に作成します。


$ python3.7 -m venv py37env

 ここで作成した py37env を使用すると、python 3.7の仮想環境に切り替わります。

 以上で、複数種類の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を単体でインストールする必要はないのです。

 さらに、構成したモデルを可視化して、そのグラフを描画するためには、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() で読み込んでいます。

  jupyter notebook を起動して、新規ノートブックを作成して、上記のコードをそのセルにコピペして実行すると、以下のように、エポックごとに学習の計算結果が表示されます。


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]

 ここまで出来たら Tensorflow 入門の最初のステップは終了です。


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


 通常の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を用いた画像分類のページを参照してください。

 上記のコードをjupyter notebook を用いて実行してみて下さい。このコードが正常に作動できれば、Tensorflow の入門編の第2ステップは終了です。


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 を活用するときは、無視してください。

 tf_slim と pycocotools がインストールされていないときは、インストールします。


$ pip install tf_slim
$ pip install pycocotools

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 に記載されている 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というノートブックが表示されます。このノートブックはColab で実行することを前提に編集されています。自身のPCで実行する時は、修正を加えた以下のコードを使用して下さい。その内容を示します。


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 API を利用した物体検出が理解できました。


このページの先頭に戻る

TensorFlow を用いた画像分類のページに行く

GitHub Web ページへ