コンテンツへスキップ

AlexeyAB/DarknetをNvidia Jetson Nanoにインストール

Raspberry Piとの一番の違いは、GPU対応で、Darknet・AlexeyABをシングルボードコンピューターにインストール出来ることが、大きな魅力となります。
しかも、インストールもWindows版よりも簡単だと思います。

参考記事:Windows10に AlexeyAB・Darknet・YOLO V3導入(Vestal Studio)

ライブラリーアップデート

  1. apt update
  2. apt upgrade -y

Cuda関係のパスを環境変数に登録

  1. export PATH=/usr/local/cuda-10.0/bin${PATH:+:${PATH}}
  2. export LD_LIBRARY_PATH=/usr/local/cuda-10.0/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

DarknetのダウンロードとYoloモデルのダウンロード

  1. git clone https://github.com/AlexeyAB/darknet
  2. cd darknet
  3. wget https://pjreddie.com/media/files/yolov3.weights
  4. wget https://pjreddie.com/media/files/yolov3-tiny.weights

MakeFileを変更しGPU、OPENCV対応へ

Makefileを変更し、GPU、CudaとOpencv対応となるようにコンパイルオプションを変更します。.

  1. sudo vi Makefile

MakeFile変更内容
GPU=1
CUDNN=1
OPENCV=1

Darknetをコンパイル

  1. make

以上でDarknetが利用可能となります。

darknetフォルダで、以下サンプルコマンドを実行し、動作を確認してください。

  1. cd darknet
  2. ./darknet detector test cfg/coco.data yolov3.cfg yolov3.weights -ext_output dog.jpg

Make時にエラーが出て、以下変更を加えました。

変更1

NVCC=nvcc 部分を
NVCC=/usr/local/cuda/bin/nvcc
に変更

変更2 ライブラリ追加

sudo apt install libopencv-dev

参考にさせて頂いたサイト

created by Rinker
NVIDIA
¥19,000 (2021/08/19 16:46:56時点 Amazon調べ-詳細)

WEBカメラ/USBカメラ

リアルタイム画像検出で大切な入力デバイスとなるカメラ、各種選択肢があります。画角、フォーカス、露出などを考えていくと悩むことがたくさんあります。
カメラの安定動作や設置時の物理的な安定性など、安定した画像検出には、場面場面に合わせたカメラが必要になります。

今回探したカメラの要件

  • ある程度物理的な設置位置がずれた際も、画像検出を続けたい
  • 暗闇以外、昼夜画像検出可能な範囲での撮影が可能
  • USB接続で安定動作

カメラの要求仕様

  • 画角が広い(ある程度の物理設置位置の変更に対応可能、そもそも多少の広角は必須)
  • ある程度自動での画質設定(朝日などが当たると、画質は一気に変わります)
  • オートフォーカス (こちらもあると安心)
  • 過度な高画質は不要(画像検出時に必要な画素数はHDで十分)
  • 音声は基本的に使わない(画像検出のみ)

一番の要件は、広角でした。広角対応のカメラは以下が候補となりました。

オートフォーカスで手頃なカメラだと、サンワサプライ オートフォーカスWEBカメラ CMS-V45Sなどが出来ていました。画角65度と通常のWEBカメラよりは広角。

通常のWEBカメラは、58度前後で60度以下となります。
最初にBUFFALOの広角カメラを導入したこともあり、60度以下の画角では今回は、そもそも画像検出対象の画角となりませんでした。
また、広角になるとオートフォーカスも難しいと思うので、広角+オートフォーカスを満たそうとすると、一気に対象製品を探すのが難しいです。

今回選んだカメラは、ロジクール ウェブカメラ C615 ブラック フルHD 1080Pとなります。

画角が78°でオートフォーカス。
近距離(最長7cm)対応、高速オートフォーカス、HD光補正。
一方、マイクはステレオ未対応のモノラル、画質(720p/30fps)となり、最新機種よりはスペックダウンします。(ここが、納得の価格で入手出来るポイントだと思います)

まだ、導入後1週間ですので、Jetson Nanoとの組み合わせで利用し、何かあれば、またレビューさせて頂きます。

created by Rinker
NVIDIA
¥19,000 (2021/08/19 16:46:56時点 Amazon調べ-詳細)

一つ前の関連記事:NVIDIA Jetson Nano vs Raspberry Pi with NCS2 (Movidius Neural Compute Stick 2)

全242回のめざましじゃんけん結果取得を通じて

一番のテーマは、信頼性の向上です。
「全部の回次を正しく結果取得」
1回1回の信頼性向上・・・まだ、道半ば。誤判定をなくす、(運用コストが低く)信頼性の高いH/Wの導入。そして、H/Wの冗長化
イレギュラー開催などへの対応
・・・見えていない部分もありますが、ダブルポイントなどへの対応、年末年始など、個別開催時間への対応など
信頼性を向上するうえで、システムの構成予想削減(よりシンプルに)、より高信頼なハードウェアで。
最近ホットな出来事は、USBカメラの画像が悪い時(太陽の高さなど、テレビの設置環境に依存)の画像検出率低下、さらには誤判定。
これらを回避する途中に、エッジコンピューティングでの画像検出エンジンの高速化が実現しました。
(高速化や信頼性を主テーマとすると、他の方式もありますが、あくまで気になる分野や楽しそうな技術の採用を優先させております)

  • Raspberry Pi単体での画像検出を断念 (Windowsメインマシンでのモデル実行)
  • Raspberry Pi with NCS2での画像検出へ移行
    世界最速めざましじゃんけん結果公開Neural Compute Stick 2 ( NCS )
    この時点でもすでに、エッジコンピューティングの凄さに感動しました。
  • NVIDIA Jetson Nanoを試行開始(Keras + YOLO)
  • NVIDIA Jetson Nanoでlibdarknet.so利用(NVIDIA CUDAの真髄)
    YOLO / Darknetを動かす上で、アーキテクチャ的には一番良い選択なのだと思います。それにしても、Keras(TensorFlow)と比べて、倍速になるとはびっくりしました。
今後、記事化予定ですが、DarknetのGitHubより配布されているPythonスクリプトもPython3対応版となっております。
Makefileを変更し「LIBSO=1」、Pythonスクリプトより、ctypes import *を用いて、lib = CDLL("libdarknet.so", RTLD_GLOBAL)ライブラリを取り込み、Python 3のwrapperとして利用出来ました。
Keras導入時点のWEB記事では、導入が難しそうな記事も散見され、深追いしておりませんでした。

NVIDIA CUDA Toolkit 10.0 に対応しcuDNN 7.3など、機械学習時にデファクトスタンダートとなっているライブラリやフレームワークが多く、システムアーキテクチャの選択肢が非常に多いです。
今回も他フレームワークも視野に入れ、比較検討することが出来ました。TensorFlow や PyTorch、Caffe、Keras、MXNet などの機械学習 (ML) フレームワークに対応しています。ネイティブにインストールすることができます。

NVIDIA Jetsonの情報収集

NVIDIAの社員や関係者が強力にサポート、情報発信。
さすが、大手。ハードの供給体制もRaspberry Pi と比べて力強さを感じます。開発コミュニティーへの社員の書き込みが、本当にすごい。
オープンコミュニティの新しい形にも見えました。ハードでビジネスは成立し、技術者が率先して、コミュニティに参加。これは、弱点と感じた部分を、むしろ強み(正しい情報、責任感ある素早い対応)にしております。
今回は、特にこれらを体感出来ました。

関連記事:

NVIDIA Jetson Nanoで機械学習(推論)

Movidius Neural Compute Stick2とRaspberry Pi 3B +も利用しておりますが、GPU/推論向けデバイスが一体化されており、少しサイズは大きいです。
USB3.0などI/Fに差分もあるので、Raspberry Pi 4Bと比較したほうが良いかもしれません。ただし、Raspberry Pi 4B と NCS2を同時導入すると考えると、Jetson Nanoのほうがコストパフォーマンスが良いと思いますし、便利なフレームワーク利用により、開発時の手間(コスト)も考えると、機械学習にはNVIDIA Jetson Nanoがベストな選択と思います。

Jetson Nano、Raspberry Pi 3B + with NCS2 速度比較

めざましじゃんけん時に取得したWEBカメラ画像を216枚で画像認識エンジンを動作させた際の性能比較です。
以前同じテストを用いて、NCS2(Movidius Neural Compute Stick 2)導入により十分高速化された結果となりました。今回は、その結果と比べても十分に魅力的なJetson Nanoの結果が出ました。

参考記事:ディープラーニング向けUSBアクセラレーターNeural Compute Stick 2ー

Windows(GPU未使用)
Core i7 6700/(Skylake) クロック周波数:3.4GHz
15秒 opencv.dnn
Raspberry Pi 3
Model B+
ARM Cortex-A53 1.4GHz
785秒 opencv.dnn
Raspberry Pi 3
Model B+
ARM Cortex-A53 1.4GHz
+  Movidius Vision Processing Unit(Myriad 2)
105秒 opencv.dnn
NVIDIA Jetson Nano
Quad-core ARM A57 @ 1.43 GHz
109秒 opencv.dnn
NVIDIA Jetson Nano
Quad-core ARM A57 @ 1.43 GHz
+ 128-core Maxwell
46秒 Keras-YOLO
NVIDIA Jetson Nano
Quad-core ARM A57 @ 1.43 GHz
+ 128-core Maxwell
20秒 libdarknet.so (ctypes)
2019-08-14 20:34:48,460:202:INFO:ループ開始:D:\pic4ml\Janken_Target_Test\20190806_055717_102196_1.jpg 処理回数:1
2019-08-14 20:35:03,389:256:INFO:ジャンケン結果判定 Len(total_results): 3 List Values: 0,2,5
019-08-14 20:35:03,390:289:INFO:ジャンケン結果:Chokiを出してLose、相手はGoo
2019-08-15 12:11:10,292:202:INFO:ループ開始:/home/miki/cronScript/Janken_Target_Test/20190806_055717_102196_1.jpg 処理回数:1
2019-08-15 12:24:15,786:256:INFO:ジャンケン結果判定 Len(total_results): 3 List Values: 0,2,5
2019-08-15 12:24:15,787:289:INFO:ジャンケン結果:Chokiを出してLose、相手はGoo
2019-08-24 12:16:09,419:202:INFO:ループ開始:/home/miki/cronScript/Janken_Target_Test/20190806_055717_102196_1.jpg 処理回数:1
2019-08-24 12:17:54,200:256:INFO:ジャンケン結果判定 Len(total_results): 3 List Values: 0,2,5
2019-08-24 12:17:54,201:289:INFO:ジャンケン結果:Chokiを出してLose、相手はGoo
2019-10-05 11:01:36,900:4:INFO:ループ開始:/home/miki/hdd/cronScript/Janken_Target_Test/20190806_055717_102196_1.jpg 処理回数:1
2019-10-05 11:02:22,651:7:INFO:ジャンケン結果判定 Len(total_results): 3 List Values: 0,2,5
2019-10-05 11:02:22,701:30:INFO:ジャンケン結果:Chokiを出してLose、相手はGoo
2019-10-12 15:36:23,341:164:INFO:ループ開始:/home/miki/hdd/cronScript/Janken_Target_Test/20190806_055717_102196_1.jpg 処理回数:1
2019-10-12 15:36:43,531:210:INFO:ジャンケン結果判定 Len(total_results): 3 List Values: 0,2,5
2019-10-12 15:36:43,532:247:INFO:ジャンケン結果:Chokiを出してLose、相手はGoo
created by Rinker
NVIDIA
¥19,000 (2021/08/19 16:46:56時点 Amazon調べ-詳細)

関連記事:NVIDIA JETSON NANO

Intel Neural Compute Stick 2

2

機械学習のトレーニング時に悩まされるメモリー不足

2019年8月個人向け深層学習・機械学習向けGPUの購入を考えたり、AlexeyAB / Darknet で独自学習(YOLO3 ,Tiny – YOLO 3)でもトレーニングパラメーターを調整したりして、メモリ不足を回避し学習を実施する必要があります。
Chainer利用時に、メモリ不足に困ったのですが、Unified Memoryという、CPUとGPUで共通のメモリ空間(=GPUメモリ+CPUメモリ)を使う方法です。
以下のパラメーターでOut of MemoryでNGとなった場合を考えると。
INPUT_WIDTH = 128
INPUT_HEIGHT = 128
GPU_ID = 0
BATCH_SIZE = 64
MAX_EPOCH = 20
BATCHI_SIZEを小さくして、Out of Memoryを回避して学習をすすめることも出来ます。
INPUT_WIDTH = 128
INPUT_HEIGHT = 128
GPU_ID = 0
BATCH_SIZE = 32
MAX_EPOCH = 20
または、GPUを利用せずにCPUで学習を進めることも出来ます。GPUを導入しているパソコンだと、メインメモリはそれなりの容量搭載されていると思います。
INPUT_WIDTH = 128
INPUT_HEIGHT = 128
GPU_ID = -1
BATCH_SIZE = 64
MAX_EPOCH = 20
#model.to_gpu(GPU_ID)

CPUとGPUメモリを合わせて利用 Unified Memory for CUDA

参考URL:
import cupy as cp

pool = cp.cuda.MemoryPool(cp.cuda.malloc_managed)

cp.cuda.set_allocator(pool.malloc)
Unified Memoryとは、CPUとGPUで共通のメモリ空間(=GPUメモリ+CPUメモリ)を使う方法となります。
以下、エラーメッセージの例となります。
Exception in main training loop: out of memory to allocate 134217728 bytes (total 816308736 bytes)
Traceback (most recent call last):
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\training\trainer.py", line 315, in run
    update()
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\training\updaters\standard_updater.py", line 165, in update
    self.update_core()
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\training\updaters\standard_updater.py", line 177, in update_core
    optimizer.update(loss_func, *in_arrays)
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\optimizer.py", line 685, in update
    loss.backward(loss_scale=self._loss_scale)
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\variable.py", line 981, in backward
    self._backward_main(retain_grad, loss_scale)
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\variable.py", line 1061, in _backward_main
    func, target_input_indexes, out_grad, in_grad)
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\_backprop_utils.py", line 109, in backprop_step
    target_input_indexes, grad_outputs)
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\functions\activation\relu.py", line 75, in backward
    return ReLUGrad2(y).apply((gy,))
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\function_node.py", line 263, in apply
    outputs = self.forward(in_data)
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\function_node.py", line 369, in forward
    return self.forward_gpu(inputs)
  File "C:\Users\user\Anaconda3\envs\Own-Project\lib\site-packages\chainer\functions\activation\relu.py", line 103, in forward_gpu
    gx = _relu_grad2_kernel(self.b, inputs[0])
  File "cupy\core\_kernel.pyx", line 547, in cupy.core._kernel.ElementwiseKernel.__call__
  File "cupy\core\_kernel.pyx", line 369, in cupy.core._kernel._get_out_args_with_params
  File "cupy\core\core.pyx", line 134, in cupy.core.core.ndarray.__init__
  File "cupy\cuda\memory.pyx", line 518, in cupy.cuda.memory.alloc
  File "cupy\cuda\memory.pyx", line 1085, in cupy.cuda.memory.MemoryPool.malloc
  File "cupy\cuda\memory.pyx", line 1106, in cupy.cuda.memory.MemoryPool.malloc
  File "cupy\cuda\memory.pyx", line 934, in cupy.cuda.memory.SingleDeviceMemoryPool.malloc
  File "cupy\cuda\memory.pyx", line 949, in cupy.cuda.memory.SingleDeviceMemoryPool._malloc
  File "cupy\cuda\memory.pyx", line 697, in cupy.cuda.memory._try_malloc
Will finalize trainer extensions and updater before reraising the exception.
---------------------------------------------------------------------------
OutOfMemoryError                          Traceback (most recent call last)
<ipython-input-24-041e2033e90a> in <module>
----> 1 trainer.run()

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\training\trainer.py in run(self, show_loop_exception_msg)
    327                 f.write('Will finalize trainer extensions and updater before '
    328                         'reraising the exception.\n')
--> 329             six.reraise(*sys.exc_info())
    330         finally:
    331             for _, entry in extensions:

~\Anaconda3\envs\Own-Project\lib\site-packages\six.py in reraise(tp, value, tb)
    691             if value.__traceback__ is not tb:
    692                 raise value.with_traceback(tb)
--> 693             raise value
    694         finally:
    695             value = None

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\training\trainer.py in run(self, show_loop_exception_msg)
    313                 self.observation = {}
    314                 with reporter.scope(self.observation):
--> 315                     update()
    316                     for name, entry in extensions:
    317                         if entry.trigger(self):

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\training\updaters\standard_updater.py in update(self)
    163 
    164         """
--> 165         self.update_core()
    166         self.iteration += 1
    167 

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\training\updaters\standard_updater.py in update_core(self)
    175 
    176         if isinstance(in_arrays, tuple):
--> 177             optimizer.update(loss_func, *in_arrays)
    178         elif isinstance(in_arrays, dict):
    179             optimizer.update(loss_func, **in_arrays)

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\optimizer.py in update(self, lossfun, *args, **kwds)
    683             else:
    684                 self.target.zerograds()
--> 685             loss.backward(loss_scale=self._loss_scale)
    686             del loss
    687 

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\variable.py in backward(self, retain_grad, enable_double_backprop, loss_scale)
    979         """
    980         with chainer.using_config('enable_backprop', enable_double_backprop):
--> 981             self._backward_main(retain_grad, loss_scale)
    982 
    983     def _backward_main(self, retain_grad, loss_scale):

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\variable.py in _backward_main(self, retain_grad, loss_scale)
   1059 
   1060                 _backprop_utils.backprop_step(
-> 1061                     func, target_input_indexes, out_grad, in_grad)
   1062 
   1063                 for hook in hooks:

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\_backprop_utils.py in backprop_step(func, target_input_indexes, grad_outputs, grad_inputs)
    107     else:  # otherwise, backward should be overridden
    108         gxs = func.backward(
--> 109             target_input_indexes, grad_outputs)
    110 
    111         if is_debug:

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\functions\activation\relu.py in backward(self, indexes, grad_outputs)
     73             return ReLUGradCudnn(x, y).apply((gy,))
     74         # Generic implementation
---> 75         return ReLUGrad2(y).apply((gy,))
     76 
     77 

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\function_node.py in apply(self, inputs)
    261                 outputs = static_forward_optimizations(self, in_data)
    262             else:
--> 263                 outputs = self.forward(in_data)
    264 
    265         # Check for output array types

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\function_node.py in forward(self, inputs)
    367         assert len(inputs) > 0
    368         if isinstance(inputs[0], cuda.ndarray):
--> 369             return self.forward_gpu(inputs)
    370         return self.forward_cpu(inputs)
    371 

~\Anaconda3\envs\Own-Project\lib\site-packages\chainer\functions\activation\relu.py in forward_gpu(self, inputs)
    101 
    102     def forward_gpu(self, inputs):
--> 103         gx = _relu_grad2_kernel(self.b, inputs[0])
    104         return gx,
    105 

cupy\core\_kernel.pyx in cupy.core._kernel.ElementwiseKernel.__call__()

cupy\core\_kernel.pyx in cupy.core._kernel._get_out_args_with_params()

cupy\core\core.pyx in cupy.core.core.ndarray.__init__()

cupy\cuda\memory.pyx in cupy.cuda.memory.alloc()

cupy\cuda\memory.pyx in cupy.cuda.memory.MemoryPool.malloc()

cupy\cuda\memory.pyx in cupy.cuda.memory.MemoryPool.malloc()

cupy\cuda\memory.pyx in cupy.cuda.memory.SingleDeviceMemoryPool.malloc()

cupy\cuda\memory.pyx in cupy.cuda.memory.SingleDeviceMemoryPool._malloc()

cupy\cuda\memory.pyx in cupy.cuda.memory._try_malloc()

OutOfMemoryError: out of memory to allocate 134217728 bytes (total 816308736 bytes)

Tensorflowのインストール

Tensorflowは、Kerasのバックエンドに使われていたり、各種機械学習のフレームワークを利用する際に、よく出てきます。
個人的には、GPU対応パッケージが準備されており、そのサポート範囲が広いので重宝しております。

使用できるパッケージ

  • tensorflow - 最新の安定版リリース、CPU のみ(Ubuntu、Windows 用)
  • tensorflow-gpu - 最新の安定版リリース、GPU サポートを含む(Ubuntu、Windows 用)
  • tf-nightly - ナイトリー ビルドのプレビュー、CPU のみ(不安定)
  • tf-nightly-gpu - ナイトリー ビルドのプレビュー、GPU サポートを含む(不安定、Ubuntu と Windows 用)

Pip/Pip3コマンドでTensorFlow/TnesorFlow-GPUをインストール

インストールコマンドのサンプルを記載しておきます。

# Current stable release for CPU-only
pip3 install tensorflow

# Preview nightly build for CPU-only (unstable)
pip3 install tf-nightly

# Install TensorFlow 2.0 Beta
pip3 install tensorflow==2.0.0-beta0

以下が、Windows環境にGPU対応版をインストールした場合です。

@windows>pip3 install tensorflow-gpu
...
Successfully installed setuptools-41.0.1 tensorflow-gpu-1.14.0

参考にさせて頂いたサイト

pip での TensorFlow のインストール

NVIDIA Jetson Nano

NVIDIA CUDA Toolkit 10.0 に対応しcuDNN 7.3など、機械学習時にデファクトスタンダートとなっているライブラリやフレームワークが、利用可能になっています。
TensorFlow や PyTorch、Caffe、Keras、MXNet などの機械学習 (ML) フレームワークに対応しています。ネイティブにインストールすることができます。

Raspberry Pi with NCS2 VS Jetson

導入時に気になったのは、開発者コミュニティーです。
Raspberry Piは、歴史もあり、世界中の方々が同じような悩みを持ち、各種解決策がWEBに公開されています。一方で、NVIDIA Jetson Nanoは、どの程度このようなコアユーザーによる情報公開などがされているのか気になりました。

結論からするとNVIDIAの社員や関係者が協力にサポート、情報発信。
さすが、大手ですね、ハードの共有体制もRaspberry Pi と比べて感心しましたが、開発コミュニティーへの社員の書き込みが、本当にすごい。
オープンコミュニティの新しい形にも見えました。ハードでビジネスは成立し、技術者が率先して、コミュニティに参加。これは、弱点と感じた部分を、むしろ強み(正しい情報、責任感ある素早い対応)にしております。
あとは、ケースやファンなど、市場の大きさに合わせて、周辺のアクセサリーメーカーが追従してくれば、IoTにおけるローエンドエッジデバイスの筆頭になりそうです。
個人的には、Intel NCS2も引き続き注目して行きます。OpenCVのDNNに対応していたりと、まだまだ一長一短があるように感じます。
ただし、機械学習や推論を目的としたIoTデバイスの本命は、Jetson Nanoになりそうです。IntelのNCSはベアボーン系のミニPCかな。

関連記事:

NVIDIA Jetson Nanoで機械学習(推論)

Movidius Neural Compute Stick2とRaspberry Pi 3B +も利用しておりますが、GPU/推論向けデバイスが一体化されており、少しサイズは大きいです。
USB3.0などI/Fに差分もあるので、Raspberry Pi 4Bと比較したほうが良いかもしれません。ただし、Raspberry Pi 4B と NCS2を同時導入すると考えると、Jetson Nanoのほうがコストパフォーマンスが良いと思いますし、便利なフレームワーク利用により、開発時の手間(コスト)も考えると、機械学習にはNVIDIA Jetson Nanoがベストな選択と思います。NVIDIAですから。

Jetson Nano、Raspberry Pi 3B + with NCS2 速度比較

めざましじゃんけん時に取得したWEBカメラ画像を216枚で画像認識エンジンを動作させた際の性能比較です。
以前同じテストを用いて、NCS2(Movidius Neural Compute Stick 2)導入により十分高速化された結果となりました。今回は、その結果と比べても十分に魅力的なJetson Nanoの結果が出ました。

参考記事:ディープラーニング向けUSBアクセラレーターNeural Compute Stick 2ー

Windows(GPU未使用)
Core i7 6700/(Skylake) クロック周波数:3.4GHz
15秒 opencv.dnn
Raspberry Pi 3
Model B+
ARM Cortex-A53 1.4GHz
785秒 opencv.dnn
Raspberry Pi 3
Model B+
ARM Cortex-A53 1.4GHz
+  Movidius Vision Processing Unit(Myriad 2)
105秒 opencv.dnn
NVIDIA Jetson Nano
Quad-core ARM A57 @ 1.43 GHz
109秒 opencv.dnn
NVIDIA Jetson Nano
Quad-core ARM A57 @ 1.43 GHz
+ 128-core Maxwell
46秒 Keras-YOLO
2019-08-14 20:34:48,460:202:INFO:ループ開始:D:\pic4ml\Janken_Target_Test\20190806_055717_102196_1.jpg 処理回数:1
2019-08-14 20:35:03,389:256:INFO:ジャンケン結果判定 Len(total_results): 3 List Values: 0,2,5
019-08-14 20:35:03,390:289:INFO:ジャンケン結果:Chokiを出してLose、相手はGoo
2019-08-15 12:11:10,292:202:INFO:ループ開始:/home/miki/cronScript/Janken_Target_Test/20190806_055717_102196_1.jpg 処理回数:1
2019-08-15 12:24:15,786:256:INFO:ジャンケン結果判定 Len(total_results): 3 List Values: 0,2,5
2019-08-15 12:24:15,787:289:INFO:ジャンケン結果:Chokiを出してLose、相手はGoo
2019-08-24 12:16:09,419:202:INFO:ループ開始:/home/miki/cronScript/Janken_Target_Test/20190806_055717_102196_1.jpg 処理回数:1
2019-08-24 12:17:54,200:256:INFO:ジャンケン結果判定 Len(total_results): 3 List Values: 0,2,5
2019-08-24 12:17:54,201:289:INFO:ジャンケン結果:Chokiを出してLose、相手はGoo
created by Rinker
NVIDIA
¥19,000 (2021/08/19 16:46:56時点 Amazon調べ-詳細)

関連記事:NVIDIA JETSON NANO

Intel Neural Compute Stick 2

じゃんけん予想とじゃんけん結果

めざましじゃんけん 広場

全く勝率が上がらない。ゆっくりですが、データを集めて、勝率を上げてゆきたいです。
AIや機械学習を扱ったことがある方は、是非、参加してください!
運営が見えないと、こういうシステムにも参加しにくいですよね。一般企業の会社員です。仕事は、機械学習どころか、プログラムなんかも見ることもありません。
学生時代より独自ドメイン・自宅サーバ・簡単なプログラムを趣味程度に楽しんでおりました。
画像分析でもないので、是非、時系列データの将来予測に参加してください!!

AI Janken

それなりの期間、動作させてきました。
弱いハード・ソフトライブラリ部分のエラー、少なからず入る人間による入力部。(実は、一番苦労しているのは、明日のじゃんけん参加者のTwitter取得と文字列処理)

まだまだ、手放しに安定稼働とならないのですが、今まで動作してきた稼動ログを公開します。画像検出の精度が上がってます。

めざましじゃんけん結果画像検出システム

Darknet導入や機械学習など、各種記事を記載して来ました。
最初の全体像を記載した投稿に、各記事へのリンクを増やしております。

フジテレビ|めざましじゃんけん結果画像検出システム

気の向くままに、記載していたのですが、一番内容が薄そうな内容が未だに残ってました。
今回のタイトルの通り、WindowsへOpenCVをインストールです。

特に、独自でコンパイルなどは、実施しておらず、pip3やAnaconndaで導入します。

pip install opencv-python

以上です。簡単で良いですね。
OpenCVも奥が深いライブラリです。

いずれ、今までの学習履歴も記載したいですが、以下書籍は分かりやすかったです。機械学習やOpenCVぐらい大きなライブラリーは、書籍で全体像を勉強し、細部をWEBで調べる方法で習得を勧めてます。今まで、購入した技術書でハズレはないかな。

created by Rinker
¥3,630 (2024/12/22 20:40:16時点 Amazon調べ-詳細)

Yolo3、Tiny-Yolo3での独自学習モデルをPythonに実装

画像検出に向けて、AlexeyAB Darknetを用いて、YOLO3、Tiny-YOLO3で作成した、独自学習モデルをPythonで実装します。

前提条件

YOLO2 Tiny-YOLO2 YOLO3 Tiny-YOLO3 をPythonで実装

学習済みモデル(weightsファイル)とコンフィグファイル(cfgファイル)

「darknet\build\darknet\x64\cfg\obj.data」ファイルのbackupに指定したフォルダに、学習モデル(weightsファイル)が出力されます。

classes = 7
train = train.txt
valid = test.txt
names = cfg/obj.names
backup = backup/

独自学習に用いたコンフィグファイルは、「darknet\build\darknet\x64\cfg\」フォルダ内で作成していると思いますので、独自学習時に用いたcfgファイルとなります。

これらのファイルを、画像検出を実施するRaspberry PiやサーバーのPythonファイルが読み込み可能な場所にコピーします。

Python3での実装

  • net = cv.dnn.readNetFromDarknet(CFG, MODEL)
    • CFG:学習モデル(weightsファイル)
    • MODEL:独自学習時に用いたcfgファイル
  • net.setPreferableTarget
    • net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
      Raspberry PiやWindowsなどで動作させる際のTarget指定。
      現時点では、OpenCVのYOLO向けDNNでは、GPUはサポートされておりません。
    • net.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)
      Intel Movidius Neural Compute Stick 2 (NCS2)を利用する際は、TargetにNCS2を指定することが出来ます。Raspberry Pi 3B +で動作確認済みとなります。

参考記事:Movidius Neural Compute Stick 2、OpenVINO™ toolkit for Raspbian* OS導入

Python3 ソースコード

サンプルスクリプトを掲載しておきます。

#!/usr/bin/env python
# coding: utf-8

target_model = "yolov3-tiny-janken_final.weights"
target_config = "yolov3-tiny-janken.cfg"

import cv2 as cv
import numpy as np

MODEL = "./janken_cfg/" + target_model
CFG = "./janken_cfg/" + target_config
SCALE = 0.00392   ##1/255
INP_SHAPE = (416, 416) #input size
MEAN = 0
RGB = True

# Load a network
net = cv.dnn.readNetFromDarknet(CFG, MODEL)
net.setPreferableBackend(cv.dnn.DNN_BACKEND_DEFAULT)
##net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)
net.setPreferableTarget(cv.dnn.DNN_TARGET_MYRIAD)

confThreshold = 0.8 # Confidence threshold
nmsThreshold = 0.8  # Non-maximum supression threshold

class_names = ['active', 'goo', 'choki', 'pa', 'won', 'lose', 'draw']

def getOutputsNames(net):
    layersNames = net.getLayerNames()
    return [layersNames[i[0] - 1] for i in net.getUnconnectedOutLayers()]

def postprocess(frame, outs):
    frameHeight = frame.shape[0]
    frameWidth = frame.shape[1]

    def drawPred(classId, conf, left, top, right, bottom):
        left = int(left)
        top = int(top)
        right = int(right)
        bottom = int(bottom)
        # Draw a bounding box.
        cv.rectangle(frame, (left, top), (right, bottom), (0, 255, 0))

        label = class_names[classId] + '_%.2f' % conf

        labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)
        top = max(top, labelSize[1])
        cv.rectangle(frame, (left, top - labelSize[1]), (left + labelSize[0], top + baseLine), (255, 255, 255), cv.FILLED)
        cv.putText(frame, label, (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))

    layerNames = net.getLayerNames()
    lastLayerId = net.getLayerId(layerNames[-1])
    lastLayer = net.getLayer(lastLayerId)

    classIds = []
    confidences = []
    boxes = []

    if lastLayer.type == 'Region':
        classIds = []
        confidences = []
        boxes = []
        for out in outs:
            for detection in out:
                scores = detection[5:]
                classId = np.argmax(scores)
                confidence = scores[classId]
                if confidence > confThreshold:
                    center_x = int(detection[0] * frameWidth)
                    center_y = int(detection[1] * frameHeight)
                    width = int(detection[2] * frameWidth)
                    height = int(detection[3] * frameHeight)
                    left = center_x - width / 2
                    top = center_y - height / 2
                    classIds.append(classId)
                    confidences.append(float(confidence))
                    boxes.append([left, top, width, height])
    else:
        print('Unknown output layer type: ' + lastLayer.type)
        exit()

    indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold)
    for i in indices:
        i = i[0]
        box = boxes[i]
        left = box[0]
        top = box[1]
        width = box[2]
        height = box[3]
        drawPred(classIds[i], confidences[i], left, top, left + width, top + height)

c = cv.VideoCapture(0)
c.set(cv.CAP_PROP_FRAME_WIDTH, 640) # カメラ画像の横幅を1280に設定
c.set(cv.CAP_PROP_FRAME_HEIGHT, 480) # カメラ画像の縦幅を720に設定
c.read()

r, frame = c.read()

frameHeight = frame.shape[0]
frameWidth = frame.shape[1]
# Create a 4D blob from a frame.
inpWidth = INP_SHAPE[0]
inpHeight = INP_SHAPE[1]
blob = cv.dnn.blobFromImage(frame, SCALE, (inpWidth, inpHeight), MEAN, RGB, crop=False)
   
# Run a model
net.setInput(blob)
outs = net.forward(getOutputsNames(net))
   
##print(outs)
postprocess(frame, outs)
# Put efficiency information.
t, _ = net.getPerfProfile()
label = 'Inference time: %.2f ms' % (t * 1000.0 / cv.getTickFrequency())
cv.putText(frame, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0))
#対象ファイルコピー保存
target_filepath = './result.jpg'
cv.imwrite(target_filepath, frame)

関連記事

Movidius Neural Compute Stick 2(NCS2)ヒートシンク

予想通り、NCS2の発熱量は大きいです。特に、連続稼働させている状況では、手で触ると、長時間は触り続けられない程高温になっております。
最低限、USBの延長ケーブルで、Raspberry Piやパソコンより距離をとって、設置することは必須となります。

今回、細かなヒートシンク10個入りを購入し、写真のように片面3個、先端部に1個の計7個のヒートシンクを導入しました。
コストをかけずにすぐに導入できる熱対策なのでおすすめです。

導入後、USB接続部分より本体を触っても、触り続けられる温度へと下がっております。

USB接続外部ディスクへヒートシンク

SSD、HDDの発熱は大きいです。物理デバイスであり、高温による機器の寿命など気になります。PCや専用のNAS BOXならば熱処理も施されておりますが、Raspberry PiにSATAとUSBの変換ケースを用いて、利用する際には、この高音となるUSB接続のケースが気になります。
こちらもヒートシンクを導入し、熱対策を行います。
ヒートシンクを貼り付けたのみですが、温度変化を実感出来ます。

導入したヒートシンク(本記事で掲載している商品)

Movidius Neural Compute Stick 2向け2.5インチ外付けUSB
Intel Neural Compute Stick 2