サイトアイコン sciencompass

Jetson ~Hello AI World~ -画像認識のプログラムをPythonで作る-

NVIDIAが公開しているJetson-InferenceのチュートリアルであるHello AI Worldを勝手に日本語訳しています。
今回は、画像認識のプログラムをPythonで書くチュートリアルページを日本語訳します。

元ページはこちら
https://github.com/dusty-nv/jetson-inference/blob/master/docs/imagenet-example-python-2.md

ここでは、my-recognition.pyという名前で画像認識のプログラムをPythonで作成します。このプログラムは、ハードディスク内の任意の画像を読み込むことができ、imageNetオブジェクトを使って画像のクラス分類をします。

このページで紹介するプログラムは、Jetson Nanoのpython/examples/my-recognition.pyに保存されているので、いつでも参考にすることが出来ます。また、プログラムはユーザーのホームディレクトリ、または任意のディレクトリに保存することもできます。

プログラム作成の準備

プログラムは好きなところに保存することができますが、ここでは簡単のためにホームディレクトリにmy-recognition-pythonというディレクトリを作ります。そのディレクトリの中にプログラムと画像認識に使用する画像を保存することにします。

次のコマンドをターミナルで実行して、必要なディレクトリとファイルを準備します。

$ cd ~/
$ mkdir my-recognition-python
$ cd my-recognition-python
$ touch my-recognition.py
$ chmod +x my-recognition.py
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/black_bear.jpg
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/brown_bear.jpg
$ wget https://github.com/dusty-nv/jetson-inference/raw/master/data/images/polar_bear.jpg

最後の三行ではテスト用の画像をwgetコマンドによってダウンロードしています。

続いて、ここで作成した空のソースファイルにPythonプログラムを書いていきます。

・touch

指定したファイルのタイムスタンプを更新するコマンドであるが、存在しないファイル名を指定すると、その名前でファイルを新規作成する。
これを利用して、まずはファイル作成をしているのが今回の例である。

より詳細は、こちら。
https://eng-entrance.com/linux-command-touch

・chmod

ファイルやディレクトリの編集権限を編集するコマンド。ここでは、作成した”my-recognition.py”に編集する権限を与えている。
“+”が権限の追加を表しており、”x”が実行可能な権限を表す。
“x”の代わりに”r”だと読み込み可能、”w”だと書き込み可能を表す。
また、”+”の代わりに”-“だと権限の削除、”=”だとその後ろの記号の状態に変化させる。すなわち、
“=r”とすれば読み込みだけ可能、”=rwx”とすれば読み込み、書き込み、実行、すべて可能となる。

より詳細は、こちら。
https://eng-entrance.com/linux-command-chmod

・wget

URLを指定して、ファイルをダウンロードするコマンド。オプションについてはこちら。

https://www.atmarkit.co.jp/ait/articles/1606/20/news024.html

ソースコード作成

まず、my-recognition.pyを編集ソフトで開きます。
特に好みの編集ソフトを使用していないのであれば、gedit my-recognition.pyを入力し、geditで編集してもよいです。

まず最初に、Shebang(シバンまたはシェバン)を書き、ファイルに書かれたプログラム分をPythonを使って実行するように指定します。

#!/usr/bin/python

続いて、スクリプトの中で使用するモジュールをインポートします。


Shebangはいつも書く定型文になっているため、英語では”boilerplate code”と言われています。”boilerplate”は鋳型の意味で、転じてニュースで繰り返し出てくる記事や定型文のことを言います。判で押したように同じもののことを言います。Shebangはそれこそハンコで押すように毎回同じことを書くので、”boilerplate code”と表現されているようです。

モジュールのインポート

画像認識を行うためにjetson.inferenceモジュールを、画像を読み込むためにjetson.unitsモジュールをインポートします。また、コマンドラインをパースするためにargparseパッケージもインポートします。それらを書くと次のようになります。

import jetson.inference
import jetson.utils

import argparse

※これらのjetsonモジュールはjetson nanoをセットアップする段階ですでにインストールされているものとしています。
もし、インストールされていない場合、このチュートリアルで作成するプログラムを実行した際に、モジュールが見つかりませんというエラーが発生します。

コマンドライン引数の解析

コマンドライン引数の解析をするためにいくつかの定型文を追加します。
これによって、画像のファイル名を引数に追加し、オプションで画像認識にしようするネットワークを –networkパラメータで指定できるようにします。

# parse the command line
parser = argparse.ArgumentParser()
parser.add_argument("filename", type=str, help="filename of the image to process")
parser.add_argument("--network", type=str, default="googlenet", help="model to use, can be: googlenet, resnet-18, ect. (see --help for others)")
opt = parser.parse_args()

このチュートリアルで作成するプログラムは、指定した画像ファイルを読み込み、分類します。実行するには、次のようにターミナルに入力します。

$ ./my-recognition.py my_image.jpg

実際には、”my_image.jpg”を読み込みたい画像のファイル名に書き換えて実行します。また、オプションとして、–networkパラメータで画像の分類に使うネットワークを変更することが出来ます。デフォルトでは、GoogleNetに指定されています。

$ ./my-recognition.py --network=resnet-18 my_image.jpg

他の分類モデルを使いたい場合、こちらのページにネットワークのダウンロード方法が書かれています。
https://github.com/dusty-nv/jetson-inference/blob/master/docs/imagenet-console-2.md#downloading-other-classification-models
このページの日本語訳はこちらです。
2019/11 作成中

画像ファイルの読み込み

ハードディスクからGPUメモリへloadImageRGBA()関数を使って画像を読み込みます。JPG, PNG, TGA, BMP形式のファイルを読み込むことが出来ます。

コマンドラインで指定されたファイルを読み込むために、次の行をソースファイルに追加します。

img, width, height = jetson.utils.loadImageRGBA(opt.filename)

読み込まれた画像は、CPUとGPUの共有メモリに保存されます。JetsonのCPUとGPUは同じ物理メモリを共有しているので、メモリのコピー(すなわち cudaMemcpy())は必要ありません。

※画像は float4の色情報、RGBA形式で読み込まれ、ピクセルは0から255の範囲になります。

・RGBA形式

RGBA形式は、RGBのRed・Green・Blueに、alphaという値を加えた色を表すモデルです。ここで、 alphaは色の透明度を表します。
RGBA形式で色を指定する際には、RGBの色を指定した後に、透明度を指定します。
RGBの色は0-255、透明度は、0-1の数値で指定します。
透明度は0が不透明、1が完全に透明になります。

画像認識ネットワークの読み込み

imageNetオブジェクトを使って、次のコードはTensorRTと所望の認識モデルを読み込みます。認識に使われるネットワークは、–networkフラグで指定しない限り、デフォルトのGoogleNetが使われます。

使用することのできる認識モデルは、ImageNet ILSVRCデータセットですでに学習済みのモデルになります。これらのモデルは1000種類の分類が可能で、果物や野菜、動物の種類の分類や、車、家具、スポーツ用品といった日常品の分類をすることが出来ます。

# load the recognition network
net = jetson.inference.imageNet(opt.network)

画像認識

続いて、imageNet.Classify()関数で、認識ネットワークを使って画像の分類をしてみましょう。

# classify the image
class_idx, confidence = net.Classify(img, width, height)

iamgeNet.Classify()は画像ファイルを受け取り、TensorRTを使って推論します。

推論の結果はタプルで返されます。タプルには物体のクラスが整数で、結果の正しい確率を浮動小数点の数字で含まれています。

結果の解釈

最後に、画像認識によってどのような結果が得られたのかを取得します。

# find the object description
class_desc = net.GetClassDesc(class_idx)

# print out the result
print("image is recognized as '{:s}' (class #{:d}) with {:f}% confidence".format(class_desc, class_idx, confidence * 100))

imageNet.Classify()は認識したオブジェクトのインデックスを整数で返します。ILSVRCで学習したモデルは0から999までの整数で表されます。クラスのインデックスをimageNet.GetClassDesc()関数に渡すことで、クラスの分類がテキストで返ってきます。この分類はilsvrc12_synset_words.txtから自動的に呼び出されます。

これで、画像認識のPythonコードが完成です!

ソースコード全文

ソースコードの全文を記して終わりにします。

#!/usr/bin/python

import jetson.inference
import jetson.utils

import argparse

# parse the command line
parser = argparse.ArgumentParser()
parser.add_argument("filename", type=str, help="filename of the image to process")
parser.add_argument("--network", type=str, default="googlenet", help="model to use, can be: googlenet, resnet-18, ect. (see --help for others)")
opt = parser.parse_args()

# load an image (into shared CPU/GPU memory)
img, width, height = jetson.utils.loadImageRGBA(opt.filename)

# load the recognition network
net = jetson.inference.imageNet(opt.network)

# classify the image
class_idx, confidence = net.Classify(img, width, height)

# find the object description
class_desc = net.GetClassDesc(class_idx)

# print out the result
print("image is recognized as '{:s}' (class #{:d}) with {:f}% confidence".format(class_desc, class_idx, confidence * 100))

実行例

テスト画像を使って画像認識をしてみましょう。次のような結果が得られます。


$ ./my-recognition.py polar_bear.jpg
image is recognized as 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus' (class #296) with 99.999878% confidence

$ ./my-recognition brown_bear.jpg
image is recognized as 'brown bear, bruin, Ursus arctos' (class #294) with 99.928925% confidence

$ ./my-recognition.py black_bear.jpg
image is recognized as 'American black bear, black bear, Ursus americanus, Euarctos americanus' (class #295) with 98.898628% confidence

画像の認識に使うモデルを変更することもでき、そのような場合の実行例は次のようになります。


$ ./my-recognition.py --network=resnet-18 polar_bear.jpg
image is recognized as 'ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus' (class #296) with 99.743396% confidence

 

モバイルバージョンを終了