顔だけ認識したいという場合に顔の学習済みモデルが有れば
それを使用すれば済むんですが、いろいろ探したけど
見つからないか見つかったけどchainerで使える拡張子npzに
変換する時にエラーになったりして色々駄目だったので
試行錯誤しつつなんとか出来たのでその時の記録。

 

参考ページ
https://qiita.com/nakamura21/items/2b2ff6524710d167d618
いつもすいません。

 

■Ubuntuのインストール

 

 Ubuntu18.4.2Lをまっさらな状態でインストール
 & インストール中に最新化するか聞かれるので最新化する。

 マシンのスペック
  Intel(R) Core(TM) i5-4570 CPU @ 3.20GHz
  メモリ16Gバイト
  GeForce GT 1030

 

■ドライバーのインストール

 

 sudo ubuntu-drivers autoinstall
 sudo reboot

 

 なんかグラボを付けている状態で
  sudo ubuntu-drivers autoinstall ってすると
 自動でドライバーが入るそうで。なんかすげー
 っていうかWindowsではこれ常識か。

 

■グラボ認識しているか表示

 

 nvidia-smi

 

■CUDAのインストール

 

 sudo apt install nvidia-cuda-toolkit nvidia-driver-390
 sudo reboot

 

■cuDNNのダウンロードとインストール

 

 NVIDIAさんのページから持ってくる。
 アカウント作ってログインする必要がある。

 

 https://developer.nvidia.com/rdp/cudnn-archive

 

 参考ページではcuDNN v7.1.2 (Mar 21, 2018), for CUDA 9.1 & 9.2ってなっているけど
 mac用しかない。

 適当に入れるといつものように悪い事が起きそうなので
 nvcc -Vでcudaのバージョンを調べる

 

 nvcc -V
 nvcc: NVIDIA (R) Cuda compiler driver
 Copyright (c) 2005-2017 NVIDIA Corporation
 Built on Fri_Nov__3_21:07:56_CDT_2017
 Cuda compilation tools, release 9.1, V9.1.85

 

 ※ 9.1な模様 

 

 9.1対応のを探して
  Download cuDNN v7.1.3 (April 17, 2018), for CUDA 9.1
 の
  cuDNN v7.1.3 Library for Linux
 をダウンロード


 本当はUbuntu18.4用のを探したんだけどCuda9.1のはコレだったので。
 あとでdarknetコンパイルするときにMakefileを変更する必要がある。

 

□展開

 

 tar xzvf cudnn-9.1-linux-x64-v7.1.tgz

 

 展開後のファイルの構成


 cuda
 ├── NVIDIA_SLA_cuDNN_Support.txt
 ├── include
 │   └── cudnn.h
 └── lib64
     ├── libcudnn.so -> libcudnn.so.7
     ├── libcudnn.so.7 -> libcudnn.so.7.1.3
     ├── libcudnn.so.7.1.3
     └── libcudnn_static.a

 

□インストール

 

 sudo cp -a cuda/include/* /usr/lib/cuda/include/
 sudo cp -a cuda/lib64/* /usr/lib/cuda/lib64/

 

 vi ~/.bashrc

 以下を追加


 ## CUDA and cuDNN paths
 export PATH=/usr/lib/cuda/bin:${PATH}
 export LD_LIBRARY_PATH=/usr/lib/cuda/lib64:${LD_LIBRARY_PATH}

 

□後片付け
 
 sudo apt autoremove
 sudo apt clean

 

□.bashrcを変更したのでterminalに反映

 ここで今までっ使っていたterminalを閉じて
 新しいterminalを起動

 

■DARKNETの入手とインストール

 

□gitをインストール

 

 sudo apt install git

 

□DARKNETをインストール

 

 git clone https://github.com/AlexeyAB/darknet.git

 cd darknet

 

■DARKNETのコンパイル


 vi Makefile
 以下の箇所を修正


  GPU=1
  CUDNN=1

 

 make

 

 →エラーになる

 

□Makefileをubuntuに合わせて変更

 

 COMMON+= -DGPU -I/usr/local/cuda/include/
   ↓
 COMMON+= -DGPU -I/usr/lib/cuda/include
 
 LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand
   ↓
 LDFLAGS+= -L/usr/lib/cuda/lib64 -lcuda -lcudart -lcublas -lcurand
 
 CFLAGS+= -DCUDNN -I/usr/local/cudnn/include
   ↓
 CFLAGS+= -DCUDNN -I/usr/lib/cuda/include
 
 LDFLAGS+= -L/usr/local/cudnn/lib64 -lcudnn
   ↓
 LDFLAGS+= -L/usr/lib/cuda/lib64 -lcudnn
 
 make
 
 今度はうまく行ったっぽい。
 
□DARKNETの起動を確認
 
 ./darknet 
 usage: ./darknet <function>

 

 よしよし。
 ここまでOKか

 

■学習用のデータセットの準備

 

ここで再度先日の参考ページ登場
https://qiita.com/ha9kberry/items/1bc113cfcd9892a9ddbd
ほんと助かっています。


前回は01のデータセット準備までは出来ているはずなので。
と思ったんだけど。
圧縮ファイルがぶっ壊れてた。涙;;
 →やり直す。やり直し部分も含めて以下へ記載しています。

 

■顔の学習の元になる顔の写真と顔の座標のファイルを整備

 

学習させるには顔の写真と、その写真の中の何処が顔なのかを入力する必要があり。
その元になるファイルはいろんなサイトで公開してもらっているようなので
これを使用する。

 

□顔の学習のもとになる顔の写真と顔の座標のファイルをダウンロード

 

http://mmlab.ie.cuhk.edu.hk/projects/WIDERFace/

 

WIDER Face Training Images
 と
Face annotations


をダウンロードして解凍する

こんな感じで展開されます
.
├── WIDER_train
│   └── images
│       ├── 0--Parade
│       │   ├── 0_Parade_Parade_0_1014.jpg
│       │   ├── 0_Parade_Parade_0_1019.jpg
│       │   ├── 0_Parade_Parade_0_1040.jpg
│       │   ├── 0_Parade_Parade_0_1041.jpg
  省略
│       ├── 1--Handshaking
│       │   ├── 1_Handshaking_Handshaking_1_102.jpg
│       │   ├── 1_Handshaking_Handshaking_1_105.jpg
│       │   ├── 1_Handshaking_Handshaking_1_113.jpg
 省略
│           ├── 9_Press_Conference_Press_Conference_9_944.jpg
│           ├── 9_Press_Conference_Press_Conference_9_946.jpg
│           └── 9_Press_Conference_Press_Conference_9_97.jpg
├── wider_face_split
    ├── readme.txt
    ├── wider_face_test.mat
    ├── wider_face_test_filelist.txt
    ├── wider_face_train.mat
    ├── wider_face_train_bbx_gt.txt
    ├── wider_face_val.mat
    └── wider_face_val_bbx_gt.txt

 

中を見ると集合写真とかのjpgが沢山と
 wider_face_train_bbx_gt.txtが顔の座標が入っている模様。

 

□Annotationファイル作成の環境整備

 

参考ページの人はJupyter Notebookを使用しているようなんですが
自分は違うので自分で環境整備します。

 

sudo apt install python3
sudo apt install python3-pip
pip3 install opencv-python

 

□Annotationファイルを作成する前にファイルを整理する

 

vi generator.py
以下の内容で作成

 

import os
import cv2
import math
import random

txt_file = 'wider_face_split/wider_face_train_bbx_gt.txt'
with open(txt_file) as f:
    num = f.read().count('jpg')
print('number of images:',num)

 

そのまま実行すると


python3 generator.py 
number of images: 12880


となるんです。参考ページの結果は5451。

 

参考ページによるとなんでかはわかりませんけど
「予め0--Parade?20--Family_Groupのみ抽出」となっていますんで

 

wider_face_train_bbx_gt.txtを開いて
0--Parade?20--Family_Groupだけ残す。

 

ちなみに、このファイルの番号が曲者で
普通に20--Family_Groupの後ろを削除すればOKと思うじゃないですか?
しかーし、よく見ると
20--Family_Groupのあとには21--Festival/21_Festival_Festival_21_14.jpgが有って
その後ろは22→23→・・・・と続きますが
29の次が3--Riot/3_Riot_Riot_3_189.jpgになるので注意です。

 

それと、もう一つ。
Ubuntuに最初から入っていたテキストエディターなんですが、
これでやると、セーブしたときにファイルが崩れます。
適当に他の行とくっついて以下のような行が発生して後ろの工程でエラーになりますので注意です。
「264--Dancing/4_Dancing_Dancing_4_71.jpg」

 

もう一回実行

 

python3 generator.py
number of images: 5451

 

参考ページと同じでok

 

□解説 Annotationファイルの構成

 

0_Parade_marchingband_1_45.txt


0 0.68017578125 0.9162995594713657 0.0400390625 0.07342143906020558
0 0.02978515625 0.8127753303964758 0.0185546875 0.027900146842878122

 

- 各バウンディングボックスごとにクラス x座標 y座標 ボックス幅 ボックス高さ
- 座標はバウンディングボックスの中心座標
- 座標、幅・高さともに、画像の幅・高さに対する相対値
- Annotationファイルは、画像ファイルと同じディレクトリ内に保存

 

上記の形式になるように変換する。

その為のプログラムは参考ページを参考に作成する。

 

□変換プログラム

vi generator2.py

以下の内容で作成

 

import cv2

def generator():
    num = 5451
    with open("wider_face_train_bbx_gt.txt") as f:
        img_paths=[]

        for i in range(num):
            # 両端の空白や改行を除去して1行ずつ読み込む
            img_path=f.readline().strip()
            # 画像パス一覧取得
            img_paths.append(img_path)
            # 画像を読み込み幅・高さ取得
            im = cv2.imread(img_path)
            im_h, im_w, im_c = im.shape
            # '/'で分割
            split=img_path.split('/')
            # Annotationファイルを格納するディレクトリ取得
            dir_name=split[0]
            # Annotationファイル名作成
            file_name=split[1].replace('.jpg', '.txt')
            # ボックス数取得
            count = int(f.readline())
            readline=[]
            readlines=[]

            for j in range(count):
                readline=f.readline().split()
                # ボックスの左上座標を取得
                xmin=int(readline[0])
                ymin=int(readline[1])
                # ボックスの幅・高さを取得
                w=int(readline[2])
                h=int(readline[3])
                # ボックスの中央座標(相対値)を作成
                xcenter=str((xmin+w/2)/im_w)
                ycenter=str((ymin+h/2)/im_h)
                # ボックスの幅・高さを相対値に変換
                w=str(w/im_w)
                h=str(h/im_h)

                class_num='0'
                # クラス x座標 y座標 ボックス幅 ボックス高さを半角スペースで結合
                string=' '.join([class_num, xcenter, ycenter, w, h])
                readlines.append(string)
            # 改行で結合    
            readlines_str='¥n'.join(readlines)
            # 該当するディレクトリ内にAnnotationファイルを保存
            with open(dir_name+'/'+file_name, 'w') as j:
                j.write(readlines_str)

    # 画像パス一覧を出力
    return img_paths

img_paths = generator()

 

これを動かすのにディレクトリ構成を以下のように変更

.
├── 0--Parade
│   ├── 0_Parade_Parade_0_1014.jpg
│   ├── 0_Parade_Parade_0_1019.jpg
│   ├── 0_Parade_Parade_0_1040.jpg
 省略
├── 1--Handshaking
│   ├── 1_Handshaking_Handshaking_1_102.jpg
│   ├── 1_Handshaking_Handshaking_1_105.jpg
│   ├── 1_Handshaking_Handshaking_1_113.jpg
 省略
│   ├── 9_Press_Conference_Press_Conference_9_946.jpg
│   └── 9_Press_Conference_Press_Conference_9_97.jpg
├── generator2.py
└── wider_face_train_bbx_gt.txt

 

そこで
python3 generator2.py を実行。

 

実行すると、jpgファイルと同じディレクトリにjpg部分をtxtにしたファイルが作成される

 

.
├── 0--Parade
│   ├── 0_Parade_Parade_0_1014.jpg
│   ├── 0_Parade_Parade_0_1014.txt
│   ├── 0_Parade_Parade_0_1019.jpg
│   ├── 0_Parade_Parade_0_1019.txt
│   ├── 0_Parade_Parade_0_1040.jpg
│   ├── 0_Parade_Parade_0_1040.txt
 省略
├── 1--Handshaking
│   ├── 1_Handshaking_Handshaking_1_102.jpg
│   ├── 1_Handshaking_Handshaking_1_102.txt
│   ├── 1_Handshaking_Handshaking_1_105.jpg
│   ├── 1_Handshaking_Handshaking_1_105.txt
│   ├── 1_Handshaking_Handshaking_1_113.jpg
│   ├── 1_Handshaking_Handshaking_1_113.txt
 省略
│   ├── 9_Press_Conference_Press_Conference_9_946.jpg
│   ├── 9_Press_Conference_Press_Conference_9_946.txt
│   ├── 9_Press_Conference_Press_Conference_9_97.jpg
│   └── 9_Press_Conference_Press_Conference_9_97.txt
├── generator2.py
└── wider_face_train_bbx_gt.txt


□trainデータ、testデータそれぞれで使う画像のパス一覧テキストファイルを作成

 

プログラムを見るとfaceというディレクトリの中のファイル一覧を取ってくるようになっているようなのと、
0--Parade?20--Family_Group以外が有るとうまく行かないようなんで
以下の構成に変更
 21--Festival以降のフォルダーは削除

.
├── face
│   ├── 0--Parade
│   │   ├── 0_Parade_Parade_0_1014.jpg
│   │   ├── 0_Parade_Parade_0_1014.txt
│   │   ├── 0_Parade_Parade_0_1019.jpg
│   │   ├── 0_Parade_Parade_0_1019.txt
 省略
│   ├── 1--Handshaking
│   │   ├── 1_Handshaking_Handshaking_1_102.jpg
│   │   ├── 1_Handshaking_Handshaking_1_102.txt
│   │   ├── 1_Handshaking_Handshaking_1_105.jpg
│   │   ├── 1_Handshaking_Handshaking_1_105.txt
 省略
│       ├── 9_Press_Conference_Press_Conference_9_97.jpg
│       └── 9_Press_Conference_Press_Conference_9_97.txt
├── generator3.py
└── wider_face_split
    └── wider_face_train_bbx_gt.txt

 

・trainingとtestに分けるプログラム

 

vi generate3.py
以下の内容で作成

 

import math
import glob

num = 5451
# testデータの比率
test_size=0.1
test_num=math.floor(num*test_size)
train_num=num-test_num
print('number of train images:', train_num)
print('number of test images:', test_num)

# 画像データを格納しているディレクトリ
img_paths=glob.glob("face/*/*.jpg")

# trainファイル作成
train_list=img_paths[:train_num]
train_str='¥n'.join(train_list)
with open('train.txt', 'w') as f:
    f.write(train_str)

# testファイル作成
test_list=img_paths[train_num:]
test_str='¥n'.join(test_list)
with open('test.txt', 'w') as f:
    f.write(test_str)

 

・実行


 python generator3.py

 

以下の様にtest.txtファイルとtrain.txtファイルができる

 

test.txt
内容は以下の通り


face/2--Demonstration/2_Demonstration_Demonstration_Or_Protest_2_485.jpg
face/2--Demonstration/2_Demonstration_Political_Rally_2_190.jpg
face/2--Demonstration/2_Demonstration_Protesters_2_14.jpg
face/2--Demonstration/2_Demonstration_Political_Rally_2_469.jpg
省略

 

train.txt
内容は以下の通り


face/16--Award_Ceremony/16_Award_Ceremony_Awards_Ceremony_16_325.jpg
face/16--Award_Ceremony/16_Award_Ceremony_Awards_Ceremony_16_82.jpg
face/16--Award_Ceremony/16_Award_Ceremony_Awards_Ceremony_16_538.jpg
face/16--Award_Ceremony/16_Award_Ceremony_Awards_Ceremony_16_41.jpg
省略

 

・結果的に以下のディレクトリ構成になる
.
├── face
│   ├── 0--Parade
│   ├── 0--Parade
│   │   ├── 0_Parade_Parade_0_1014.jpg
│   │   ├── 0_Parade_Parade_0_1014.txt
│   │   ├── 0_Parade_Parade_0_1019.jpg
│   │   ├── 0_Parade_Parade_0_1019.txt
 省略
│   │   ├── 9_Press_Conference_Press_Conference_9_946.jpg
│   │   ├── 9_Press_Conference_Press_Conference_9_946.txt
│   │   ├── 9_Press_Conference_Press_Conference_9_97.jpg
│   │   └── 9_Press_Conference_Press_Conference_9_97.txt
 省略
├── generator3.py
├── test.txt
├── train.txt
└── wider_face_split
    └── wider_face_train_bbx_gt.txt

 

■02.Darknetで学習を実施。

 

参考ページ
https://qiita.com/ha9kberry/items/e7c822dd0874e5a24639
ほんといつも助かっています。

 

ここまでの操作でダークネットのインストールとコンパイルで成功しているので
その続きから行う。

 

□weightをダウンロード

 

wget https://pjreddie.com/media/files/darknet53.conv.74


□設定ファイル作成

 

vi cfg/obj.data
以下の内容で作成

 

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

 

vi cfg/obj.name
以下の内容で作成

 

face

 

□設定ファイルの編集

 

yolov3.cfg編集

vi cfg/yolov3.cfg


Line 3:コメントアウト
Line 4:コメントアウト
Line 6:batch=24に設定
Line 7:subdivisions=8に設定

※変更箇所は「→」の所
      1 [net]
      2 # Testing
→    3 #batch=1
→    4 #subdivisions=1
      5 # Training
→    6 batch=24
→    7 subdivisions=8
      8 width=416
      9 height=416
     10 channels=3
     11 momentum=0.9

filters=(classes+5)*3
Line 603:filters=18に設定
Line 610:classes=1に設定
Line 689:filters=18に設定
Line 696:classes=1に設定
Line 776:filters=18に設定
Line 783:classes=1に設定

    599 [convolutional]
    600 size=1
    601 stride=1
    602 pad=1
→  603 filters=18
    604 activation=linear
    605 
    606 
    607 [yolo]
    608 mask = 6,7,8
    609 anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
→  610 classes=1
    611 num=9
    612 jitter=.3
    613 ignore_thresh = .7
    614 truth_thresh = 1
    615 random=1


    685 [convolutional]
    686 size=1
    687 stride=1
    688 pad=1
→  689 filters=18
    690 activation=linear
    691 
    692 
    693 [yolo]
    694 mask = 3,4,5
    695 anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
→  696 classes=1
    697 num=9
    698 jitter=.3
    699 ignore_thresh = .7
    700 truth_thresh = 1
    701 random=1

    772 [convolutional]
    773 size=1
    774 stride=1
    775 pad=1
→  776 filters=18
    777 activation=linear


    780 [yolo]
    781 mask = 0,1,2
    782 anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
→  783 classes=1

 

□darknetディレクトリの構成

 

darknet/
  ├ backup/
  ├ cfg/
  │  ├ yolov3.cfg
  │  ├ obj.data
  │  ├ obj.name
 省略
  ├ face/
  │  ├ test.txt
  │  ├ train.txt
  │  ├0--Parade
  │  ├2--Demonstration
 省略
  ├ darknet
  ├ Makefile
  ├ darknet53.conv.74
 省略

 

■学習実行

 

./darknet detector train cfg/obj.data cfg/yolov3.cfg darknet53.conv.74

 

エラーになる。


yolov3
layer     filters    size              input                output
   0 conv     32  3 x 3 / 1   416 x 416 x   3   ->   416 x 416 x  32 0.299 BF
   1 conv     64  3 x 3 / 2   416 x 416 x  32   ->   208 x 208 x  64 1.595 BF
  省略
  35 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  36 Shortcut Layer: 33
  37  Try to set subdivisions=64 in your cfg-file. 
CUDA status Error: file: ./src/cuda.c : () : line: 213 : build time: Mar  9 2019 - 09:54:27 
CUDA Error: out of memory
CUDA Error: out of memory: File exists
darknet: ./src/utils.c:281: error: Assertion `0' failed.
中止 (コアダンプ)

 

 

メモリが足りないってよ。
GT1030の搭載メモリは2Gバイト

ここで試行錯誤。
      6 batch=24
      7 subdivisions=8
の数字をいろいろイジっても駄目で。


google先生に聞いてみた。

 

先人の声
「私はあなたのGPUのメモリが不足していると思います。 
 Yolov3が完全にGPUにロードされたとき、
 それは私のコンピュータ上でデフォルト設定(416 * 416)と
 プラス表示および他のアプリケーションから
 300ish MiBで約1600MBのメモリを必要とします。 
 より大きなメモリを搭載したGPUで実行するか、
 cfgファイルの幅と高さの設定を減らしてみてください
 (サイズを小さくすると、検出結果に影響が出る可能性があります)。」
 
と仰っております。
画面フレーム?のサイズを減らすと検出結果に影響が出るよ。
と言っておられますがGT1030しか持っていないのでしょうがないよねー
「ふん。働いてお金を沢山貯めてもっと良いのを買うんだ!!」
しかし画面フレーム?のサイズを減らせばGPUのメモリ消費が少ないとの事なので
半分ぐらいにして再度実行

 →まだエラーになる。
では元の数字の4分の1ぐらいで実行。なんかうまく行くっぽい。

 

追加の変更は以下の通り。

 

vi cfg/yolov3.cfg


Line 8:width=128に設定
Line 9:height=128に設定

      1 [net]
      2 # Testing
      3 # batch=1    ←コメントにした
      4 # subdivisions=1 ←コメントにした
      5 # Training
      6 batch=24     ←コメントを外して24にした
      7 subdivisions=8  ←コメントを外して8にした
      8 width=128   ←128にした
      9 height=128  ←128にした
     10 channels=3
     11 momentum=0.9

 

後ろの方のfiltersとclassesはそのまま同じ


Line 603:filters=18に設定
Line 610:classes=1に設定
Line 689:filters=18に設定
Line 696:classes=1に設定
Line 776:filters=18に設定
Line 783:classes=1に設定

 

□学習の様子

 

 136: 103.537476, 132.362717 avg loss, 0.000000 rate, 1.965623 seconds, 3264 images
Loaded: 0.000034 seconds
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.510125, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.442774, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.137911, Class: 0.430334, Obj: 0.358204, No Obj: 0.337541, .5R: 0.031250, .75R: 0.000000,  count: 32
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.511793, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.444947, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.050849, Class: 0.419898, Obj: 0.387084, No Obj: 0.337189, .5R: 0.000000, .75R: 0.000000,  count: 69
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.507179, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.442994, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.038144, Class: 0.419298, Obj: 0.349665, No Obj: 0.337408, .5R: 0.000000, .75R: 0.000000,  count: 64
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.508707, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.442302, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.320144, Class: 0.395719, Obj: 0.325046, No Obj: 0.337644, .5R: 0.250000, .75R: 0.250000,  count: 4
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.513188, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.444114, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.062433, Class: 0.457910, Obj: 0.391780, No Obj: 0.337275, .5R: 0.000000, .75R: 0.000000,  count: 44
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.507034, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.443162, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.150425, Class: 0.570029, Obj: 0.337372, No Obj: 0.337979, .5R: 0.000000, .75R: 0.000000,  count: 7
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.512920, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.443773, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.057833, Class: 0.500358, Obj: 0.431524, No Obj: 0.336149, .5R: 0.000000, .75R: 0.000000,  count: 57
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.512746, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.444053, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.366167, Class: 0.522596, Obj: 0.302629, No Obj: 0.339804, .5R: 0.000000, .75R: 0.000000,  count: 7


nvidia-smi -l で見ていると


GPUの使用率はほぼ100%に張り付き
メモリーが1992Mしか搭載していないところ
  1658Mバイト使用している。

 

Sat Mar  9 16:33:12 2019       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.116                Driver Version: 390.116                   |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GT 1030     Off  | 00000000:01:00.0  On |                  N/A |
| 57%   61C    P0    N/A /  30W |   1658MiB /  1992MiB |     97%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0       861      G   /usr/lib/xorg/Xorg                           152MiB |
|    0      1005      G   /usr/bin/gnome-shell                         117MiB |
|    0      9839      G   ...uest-channel-token=11718656754115347387    27MiB |
|    0     17442      C   ./darknet                                   1349MiB |
+-----------------------------------------------------------------------------+


うまく行く予感しかしない。
ちなみにCPUの使用率はほぼぼ0でした。


procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 241176 315680 10381696    0    0     0     0 1049 1705 21  5 74  0  0
 0  0      0 241476 315680 10381696    0    0     0     0  396 1413  2  3 94  0  0
 1  0      0 241352 315680 10381696    0    0     0     0  441 1783  3  3 94  0  0
 1  0      0 241352 315680 10381696    0    0     0     0 1078 1552 22  2 75  0  0
 0  0      0 241104 315680 10381696    0    0     0     0  449 1676  4  2 94  0  0
 0  0      0 241228 315680 10381696    0    0     0     0 1043 1937 21  4 75  0  0


CPUも使ったほうが、もう少しは早いかもと思ったりとか、
  実はGPU無しでも結構行けるのでは?
などと思うのは無謀なのだろうか?

 

これで終わるまで待つ。
いやいや、参考ページによると「avg lossに変化が見られなくなったので強制終了」となっているので
時々avg lossの数字を確認する必要がありそうです。
最初が340ぐらい。

これで一晩放置プレー。おれは酒を飲む。そして寝る。zzzz..

 

そして朝。

さて、avg lossの数字を確認する。
4.32とかになっております。

これで行けそうな気がするので

 

darknet/backupフォルダーを確認すると
-rw-r--r-- 1 miha miha 246305388  3月  9 17:14 yolov3_1000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 17:57 yolov3_2000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 18:39 yolov3_3000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 19:22 yolov3_4000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 20:05 yolov3_5000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 20:46 yolov3_6000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 21:28 yolov3_7000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 22:10 yolov3_8000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 22:52 yolov3_9000.weights
-rw-r--r-- 1 miha miha 246305388  3月  9 23:34 yolov3_10000.weights
-rw-r--r-- 1 miha miha 246305388  3月 10 00:17 yolov3_11000.weights
-rw-r--r-- 1 miha miha 246305388  3月 10 01:00 yolov3_12000.weights
-rw-r--r-- 1 miha miha 246305388  3月 10 01:41 yolov3_13000.weights
-rw-r--r-- 1 miha miha 246305388  3月 10 02:22 yolov3_14000.weights
-rw-r--r-- 1 miha miha 246305388  3月 10 03:03 yolov3_15000.weights
-rw-r--r-- 1 miha miha 246305388  3月 10 03:45 yolov3_16000.weights
-rw-r--r-- 1 miha miha 246305388  3月 10 04:05 yolov3_last.weights

 

とファイルが出来ております。なんかすごく早起きしちゃいました。11時間経過ぐらいでしょうか?
ファイル名を見ると、40分おきぐらいに1000づつ数字が加算されていますね。
これは学習回数との事。

 

これの最後のlastをいつものWindowsのchainer+yoloの環境に持っていって顔を認識できるか試す。

 

■chainer+yolo3で顔認識

 

□chainerで読み込めるnpzの形式に変更する

 

copy yolov3_last.weights yolo3-face_final.weights
python darknet2npz.py --model yolo_v3 --n-fg-class 1 yolo3-face_final.weights yolo3-face_final.weights.npz

 

□classの一覧ファイルの作成

 

yolo3-face.list
以下の内容で作成

 

face

 

□実行!!

 

python yolo3.py --pretrained-model yolo3-face_final.weights.npz --class_num 1 --class_list yolo3-face.list 0

 

最後のパラメーター0はビデオストリーミングの0からリアルタイム

その代わりにファイル名を指定すればファイルに対して処理を行う。

 

□実行結果

 

python yolo3.py --pretrained-model yolo3-face_final.weights.npz --class_num 1 --class_list yolo3-face.list face.jpg

 

python yolo3.py --pretrained-model yolo3-face_final.weights.npz --class_num 1 --class_list yolo3-face.list face2.jpg

□プログラムは前と同じ

 

import time
import argparse
import matplotlib.pyplot as plt
import cv2
import numpy as np
from timeit import default_timer as timer
import chainer
from chainercv.datasets import voc_bbox_label_names
from chainercv.datasets import coco_bbox_label_names
from chainercv.links import YOLOv3

#色のテーブル 150まで対応
label_colors = (
    (120, 120, 120),
    (180, 120, 120),
    (6, 230, 230),
    (80, 50, 50),
    (4, 200, 3),
    (120, 120, 80),
    (140, 140, 140),
    (204, 5, 255),
    (230, 230, 230),
    (4, 250, 7),
    (224, 5, 255),
    (235, 255, 7),
    (150, 5, 61),
    (120, 120, 70),
    (8, 255, 51),
    (255, 6, 82),
    (143, 255, 140),
    (204, 255, 4),
    (255, 51, 7),
    (204, 70, 3),
    (0, 102, 200),
    (61, 230, 250),
    (255, 6, 51),
    (11, 102, 255),
    (255, 7, 71),
    (255, 9, 224),
    (9, 7, 230),
    (220, 220, 220),
    (255, 9, 92),
    (112, 9, 255),
    (8, 255, 214),
    (7, 255, 224),
    (255, 184, 6),
    (10, 255, 71),
    (255, 41, 10),
    (7, 255, 255),
    (224, 255, 8),
    (102, 8, 255),
    (255, 61, 6),
    (255, 194, 7),
    (255, 122, 8),
    (0, 255, 20),
    (255, 8, 41),
    (255, 5, 153),
    (6, 51, 255),
    (235, 12, 255),
    (160, 150, 20),
    (0, 163, 255),
    (140, 140, 140),
    (250, 10, 15),
    (20, 255, 0),
    (31, 255, 0),
    (255, 31, 0),
    (255, 224, 0),
    (153, 255, 0),
    (0, 0, 255),
    (255, 71, 0),
    (0, 235, 255),
    (0, 173, 255),
    (31, 0, 255),
    (11, 200, 200),
    (255, 82, 0),
    (0, 255, 245),
    (0, 61, 255),
    (0, 255, 112),
    (0, 255, 133),
    (255, 0, 0),
    (255, 163, 0),
    (255, 102, 0),
    (194, 255, 0),
    (0, 143, 255),
    (51, 255, 0),
    (0, 82, 255),
    (0, 255, 41),
    (0, 255, 173),
    (10, 0, 255),
    (173, 255, 0),
    (0, 255, 153),
    (255, 92, 0),
    (255, 0, 255),
    (255, 0, 245),
    (255, 0, 102),
    (255, 173, 0),
    (255, 0, 20),
    (255, 184, 184),
    (0, 31, 255),
    (0, 255, 61),
    (0, 71, 255),
    (255, 0, 204),
    (0, 255, 194),
    (0, 255, 82),
    (0, 10, 255),
    (0, 112, 255),
    (51, 0, 255),
    (0, 194, 255),
    (0, 122, 255),
    (0, 255, 163),
    (255, 153, 0),
    (0, 255, 10),
    (255, 112, 0),
    (143, 255, 0),
    (82, 0, 255),
    (163, 255, 0),
    (255, 235, 0),
    (8, 184, 170),
    (133, 0, 255),
    (0, 255, 92),
    (184, 0, 255),
    (255, 0, 31),
    (0, 184, 255),
    (0, 214, 255),
    (255, 0, 112),
    (92, 255, 0),
    (0, 224, 255),
    (112, 224, 255),
    (70, 184, 160),
    (163, 0, 255),
    (153, 0, 255),
    (71, 255, 0),
    (255, 0, 163),
    (255, 204, 0),
    (255, 0, 143),
    (0, 255, 235),
    (133, 255, 0),
    (255, 0, 235),
    (245, 0, 255),
    (255, 0, 122),
    (255, 245, 0),
    (10, 190, 212),
    (214, 255, 0),
    (0, 204, 255),
    (20, 0, 255),
    (255, 255, 0),
    (0, 153, 255),
    (0, 41, 255),
    (0, 255, 204),
    (41, 0, 255),
    (41, 255, 0),
    (173, 0, 255),
    (0, 245, 255),
    (71, 0, 255),
    (122, 0, 255),
    (0, 255, 184),
    (0, 92, 255),
    (184, 255, 0),
    (0, 133, 255),
    (255, 214, 0),
    (25, 194, 194),
    (102, 255, 0),
    (92, 0, 255),
    (0, 0, 0)
)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--gpu', type=int, default=-1)
    parser.add_argument('--pretrained-model', default='voc0712')
    parser.add_argument('--class_num', default=20)
    parser.add_argument('--class_list', default=0)
    parser.add_argument('video')
    args = parser.parse_args()

    #
    #パラメータ解析
    # python yolo3.py 0
    #    デフォルトではvoc0712のモデルをダウンロードして来ます。認識できるのは20種類
    #
    # python yolo3.py --pretrained-model yolov3.weights.npz --class_num 80 --class_list yolov3.list 0
    #  --pretrained-model 
    #    darknet2npz.pyで変換した学習済みモデルyolov3.weights.npzを指定
    #  --class_num
    #    上記学習済みモデルのクラス数
    #  --class_list
    #    上記学習済みモデルのクラス名一覧 1行に1クラス
    #  ビデオ
    #    WEBカメラの場合は0
    #    動画ファイルの場合はファイル名
    #
    if args.pretrained_model=='voc0712' :
      label_names = voc_bbox_label_names
      model = YOLOv3(20, 'voc0712')
    else :
      print(args.class_list)
      if args.class_list==0 : 
        label_names = coco_bbox_label_names
      else:
        f = open(args.class_list, "r")
        name_list = []
        for line in f:
          line = line.strip()
          name_list.append(line)
        f.close()
        label_names = name_list
      
      model = YOLOv3(n_fg_class=int(args.class_num), pretrained_model=args.pretrained_model)
    
    #GPU対応
    #  CPUなら省略
    #  GPUなら0
    if args.gpu >= 0:
        chainer.cuda.get_device_from_id(args.gpu).use()
        model.to_gpu()
    #
    #対応しているクラス名一覧を表示する
    #
    for name in label_names:
      print(name)
    #
    #WEBカメラまたは動画ファイルを開く
    #
    if args.video == "0":
        vid = cv2.VideoCapture(0)
    else:
        vid = cv2.VideoCapture(args.video)
    if not vid.isOpened():
        raise ImportError("Couldn't open video file or webcam.")

    
    # Compute aspect ratio of video
    vidw = vid.get(cv2.CAP_PROP_FRAME_WIDTH)
    vidh = vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
    # vidar = vidw / vidh
    print(vidw)
    print(vidh)

    accum_time = 0
    curr_fps = 0
    fps = "FPS: ??"
    prev_time = timer()

    frame_count = 1
    while True:
        ret, frame = vid.read()
        if ret == False:
            time.sleep(5)
            print("Done!")
            return

        # BGR -> RGB
        rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        # Result image
        result = frame.copy()

        # (H, W, C) -> (C, H, W)
        img = np.asarray(rgb, dtype = np.float32).transpose((2, 0, 1))

        # Object Detection
        bboxes, labels, scores = model.predict([img])
        bbox, label, score = bboxes[0], labels[0], scores[0]

        print("----------")
        nPerson = 0
        nBottle = 0
        if len(bbox) != 0:
            for i, bb in enumerate(bbox):
                # print(i)
                lb = label[i]
                conf = score[i].tolist()
                ymin = int(bb[0])
                xmin = int(bb[1])
                ymax = int(bb[2])
                xmax = int(bb[3])

                class_num = int(lb)

                # Draw box 1
                cv2.rectangle(result, (xmin, ymin), (xmax, ymax),
                label_colors[class_num], 2)

                # Draw box 2
                # cv2.rectangle(result, (xmin, ymin), (xmax, ymax), (0,255,0), 2)

                #text = label_names[class_num] + " " + ('%.2f' % conf)
                text = label_names[class_num] + " " + ('%.2f' % conf)
                print(text)
                if(label_names[class_num] == 'person'):
                  nPerson = nPerson + 1
                if(label_names[class_num] == 'bottle'):
                  nBottle = nBottle + 1
                
                text_top = (xmin, ymin - 10)
                text_bot = (xmin + 80, ymin + 5)
                text_pos = (xmin + 5, ymin)

                # Draw label 1
                cv2.rectangle(result, text_top, text_bot, 
                label_colors[class_num], -1)
                cv2.putText(result, text, text_pos, 
                cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 0), 1)

                # Draw label 2
                # cv2.rectangle(result, text_top, text_bot, (255,255,255), -1)
                # cv2.putText(result, text, text_pos, 
                # cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 0), 1)
            print("==========")
            print("Number of people : " + str(nPerson))
            print("Number of bottle : " + str(nBottle))
        # Calculate FPS
        curr_time = timer()
        exec_time = curr_time - prev_time
        prev_time = curr_time
        accum_time = accum_time + exec_time
        curr_fps = curr_fps + 1
        if accum_time > 1:
            accum_time = accum_time - 1
            fps = "FPS:" + str(curr_fps)
            curr_fps = 0