FC2カウンター FPGAの部屋 DNN

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

畳み込みニューラルネットワークのコードを書く時の検証方法

白線間走行用の畳み込みニューラルネットワーク(CNN)をVivado HLS で高位合成するために最適と思われるC ソースコードを書いたのだが、今回 Max Pooling のところでソースコードにバグがあった。
max_pooling.cpp が間違っていて、2 x 2 のウインドウでの最大値を取るはずが左上の値を取るコードになっていた。(”AXI4-Stream インターフェースのMax Pooling 1(ソースコード)”参照)
問題はどうやってソースコードが間違っているのか?を検証することだと思う。これほど間違っていても、最終的な出力では、最大 1.7 % 程度の精度の差があるだけである。(”AXI4-Stream インターフェースの畳み込みニューラルネットワーク5(モードの変更)”参照)

CNN をハードウェア化していなければ、TensorFlow やChairer などのフレームワークを使用していて、自分でプログラミングすることは無いと思われるので、コードを検証することは無いのだろうが、ハードウェアにする場合は、自分の書いたコードが正しいかどうかを常に確認する必要がある。特に、Vivado HLS に特化したソースコードを書くために複数の異なるコードを試すことはよくあるのだ。
TensorFlow やChairer などのフレームワークに重みとバイアスを変換して渡して推論させても、量子化出来なければ、値の比較はできない。
下の図で mp_fout[78][2] が量子化していない浮動小数点数の値で、mp_out[78][2] が量子化してある任意精度固定小数点データ型の値だ。2つの数には、1 以上の開きがある。これは、最初に畳み込み層の重みとバイアスを -1 ~ +1 までに量子化したためだ。
Max_Pooling_9_180225.pngMax_Pooling_10_180225.png

と言う訳で、任意精度で量子化できないと比較できない。(任意精度で量子化できるようだったら教えてください。特にTensorFlow はできるのかな?)

そこで、現在のソースコードはHLSストリームに最適化されているのだが、CNN を分割せずにソースコードを見たときに分かりやすいコードで書いたプログラムがあるので、それをHLSストリーム対応に変更し、各層に分割して比較してみようと思っている。(”カーブ、直線用白線間走行用畳み込みニューラルネットワーク13(AXI4 Stream版CNN IP 1”参照)

これで検証の方針は決まったのだが、CNN は多少コードを間違っていても、大した影響はない。ということは、ポイントを外さなければハードウェアに都合の良いように途中のアルゴリズムを変更しても、それほどの問題はないということかもしれない?それをおいおい確かめてみようと思う。

ちなみになぜ面倒に各層をHLSストリームでつないでいるのか?というと、自由に各層をつなげて、いろいろな層構成を書くことが簡単に行えるようにするためである。つまり、各層を部品として使えるようにするためだ。
  1. 2018年04月23日 05:06 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

「第45回 コンピュータビジョン勉強会@関東」で発表してきました

昨日、「第45回 コンピュータビジョン勉強会@関東」で「FPGAに実装したCNNを使用して白線間を走行するミニ・ロボットカーの製作」という題で発表してきました。

他の発表を聞いていたのですが、いろいろと面白いのがありました。ここにまとめサイトがあります。

2番目のお話は、ホットドッグ検出器でした。ホットドッグがあると白黒画面がホットドッグのところだけ色が付きます。資料にはないですが、会場で TensorFlow.js を使ってデモしていました。

Androidだけでもアリシアちゃんになれちゃうアプリを作った話@第45回 コンピュータビジョン勉強会」はモバイル端末上で動く画像のポーズを3Dキャラクタに追従させるアプリでした。資料 17 ページを見ると分かりますが、Chairer から ONNX を通して、TensorFlow にモデルを送っています。これは良いですね。。。

後、「SSDで道路の傷検出」とかいろいろとためになるお話が聞けました。楽しかったです。
  1. 2018年04月22日 05:07 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

HLSストレーム・インターフェースのReLU2(C ソースコード)

HLSストレーム・インターフェースのReLU1”の続き。

前回は、HLSストリーム・インターフェースでReLU を作成した。今回はその C ソースコードを貼っておく。

その前に、C コードの合成で生成された relu.vhd の entity 部分を貼っておく。

entity relu is
port (
    ap_clk : IN STD_LOGIC;
    ap_rst : IN STD_LOGIC;
    ap_start : IN STD_LOGIC;
    ap_done : OUT STD_LOGIC;
    ap_idle : OUT STD_LOGIC;
    ap_ready : OUT STD_LOGIC;
    ins_V_dout : IN STD_LOGIC_VECTOR (33 downto 0);
    ins_V_empty_n : IN STD_LOGIC;
    ins_V_read : OUT STD_LOGIC;
    outs_V_din : OUT STD_LOGIC_VECTOR (33 downto 0);
    outs_V_full_n : IN STD_LOGIC;
    outs_V_write : OUT STD_LOGIC;
    ap_return : OUT STD_LOGIC_VECTOR (31 downto 0) );
end;


すべての層で使う予定のHLS ストリームのテンプレートを書いた layer_general.h は、”HLSストレーム・インターフェースの畳み込み層1(Cソースコード、C コードの合成、Export RTL)”を参照のこと。

relu.h を示す。

// relu.h
// 2018/02/20 by marsee
//

#ifndef __RELU_H__
#define __RELU_H__

static const size_t HORIZONTAL_PIXEL_WIDTH = 52;
static const size_t VERTICAL_PIXEL_WIDTH = 6;
static const size_t ALL_PIXELS = HORIZONTAL_PIXEL_WIDTH * VERTICAL_PIXEL_WIDTH;

static const size_t NUMBER_OF_KERNEL = 2;
static const size_t ARRAY_SIZE = 2;
static const size_t W = 16;
static const size_t I = 6;

typedef ap_fixed<166, AP_TRN, AP_WRAP> conv_type;

#endif


relu.cpp を示す。

// relu.cpp
// 2018/04/15 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "layer_general.h"
#include "relu.h"

int relu(hls::stream<ap_fixed_axis<W,I,NUMBER_OF_KERNEL,1> >& ins,
        hls::stream<ap_fixed_axis<W,I,NUMBER_OF_KERNEL,1> >& outs){
#pragma HLS DATA_PACK variable=outs
#pragma HLS DATA_PACK variable=ins

    ap_fixed_axis<W,I,NUMBER_OF_KERNEL,1> pix;

    do {
#pragma HLS PIPELINE II=1
#pragma HLS LOOP_TRIPCOUNT min=1 max=1 avg=1
    // user が 1になった時にフレームがスタートする
        ins >> pix;
    } while(pix.user == 0);

    Loop1: for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        Loop2: for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS PIPELINE II=1
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> pix;    // AXI4-Stream からの入力

            for(int i=0; i<NUMBER_OF_KERNEL; i++){                
                if (pix.data[i] < conv_type(0.0)) // データが 0 以下だったら 0 にする
                    pix.data[i] = conv_type(0.0);
            }

             outs << pix;
        }
    }

    return(0);
}


relu_tb.cpp を示す。

// relu_tb.cpp
// 2018/02/20 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <math.h>
#include <ap_axi_sdata.h>
#include <hls_video.h>

#include "layer_general.h"
#include "relu.h"
#include "conv_layer_output.h"

int relu(hls::stream<ap_fixed_axis<W,I,NUMBER_OF_KERNEL,1> >& ins,
        hls::stream<ap_fixed_axis<W,I,NUMBER_OF_KERNEL,1> >& outs);

int relu_soft( hls::stream<float_axis<NUMBER_OF_KERNEL,1> >& ins,
         hls::stream<float_axis<NUMBER_OF_KERNEL,1> >& outs);

int main(){
    using namespace std;

    hls::stream<ap_fixed_axis<W,I,NUMBER_OF_KERNEL,1> > ins;
    hls::stream<float_axis<NUMBER_OF_KERNEL,1> > ins_soft;
    hls::stream<ap_fixed_axis<W,I,NUMBER_OF_KERNEL,1> > outs;
    hls::stream<float_axis<NUMBER_OF_KERNEL,1> > outs_soft;

    float relu_fout[ALL_PIXELS][NUMBER_OF_KERNEL];
    conv_type relu_out[ALL_PIXELS][NUMBER_OF_KERNEL];

    ap_fixed_axis<W,I,NUMBER_OF_KERNEL,1> pix;
    float_axis<NUMBER_OF_KERNEL,1> fpix;

    // ins に入力データを用意する
    for(int i=0; i<5; i++){    // dummy data
        pix.user = 0;
        for(int j=0; j<NUMBER_OF_KERNEL; j++){
            pix.data[j] = (conv_type)i;
        }
        ins << pix;
        fpix.user = 0;
        for(int j=0; j<NUMBER_OF_KERNEL; j++){
            fpix.data[j] = (float)i;
        }
        ins_soft << fpix;
    }

    // 1 画面分のデータを ins、ins_soft に入力する
    for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
        for(int i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
            for(int k=0; k<NUMBER_OF_KERNEL; k++){
                pix.data[k] = conv_layer_out[j*HORIZONTAL_PIXEL_WIDTH+i][k];
                fpix.data[k] = conv_layer_fout[j*HORIZONTAL_PIXEL_WIDTH+i][k];
            }

            if (j==0 && i==0){    // 最初のデータの時に TUSER を 1 にする
                pix.user = 1;
                fpix.user = 1;
            } else {
                pix.user = 0;
                fpix.user = 0;
            }

            if (i == HORIZONTAL_PIXEL_WIDTH-1){ // 行の最後でTLASTをアサートする
                pix.last = 1;
                fpix.last = 1;
            } else {
                pix.last = 0;
                fpix.last = 0;
            }

            ins << pix;
            ins_soft << fpix;
        }
    }

    relu(ins, outs);
    relu_soft(ins_soft, outs_soft);

    // outs, outs_soft を relu_out[][], relu_fout[][] に出力する
    int errcnt=0;
    for(int j=0; j < VERTICAL_PIXEL_WIDTH; j++){
        for(int i=0; i < HORIZONTAL_PIXEL_WIDTH; i++){
            outs >> pix;
            outs_soft >> fpix;

            for(int k=0; k<NUMBER_OF_KERNEL; k++){
                relu_out[j*HORIZONTAL_PIXEL_WIDTH+i][k] = pix.data[k];
                relu_fout[j*HORIZONTAL_PIXEL_WIDTH+i][k] = fpix.data[k];
                if ((double)pow((double)pix.data[k]-(double)fpix.data[k],(double)2) > 4){ // 2乗誤差が4よりも大きい
                    printf("ERROR HW and SW results mismatch i = %d, j = %d, HW[%d] = %f, SW[%d] = %f\n", i, j, k, (float)pix.data[k], k, fpix.data[k]);
                    errcnt++;
                    return(1);
                }
                printf("HW and SW results i = %d, j = %d, HW[%d] = %f, SW[%d] = %f\n", i, j, k, (float)pix.data[k], k, fpix.data[k]);
            }
        }
    }
    cout << "Error Count = " << errcnt << endl;
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    // ReLU の結果をヘッダファイルに出力
    ofstream OH("relu_output.h");
    OH << "// relu_output.h" << endl;
    time_t now = time(0);
    struct tm* localNow = localtime(&now);
    OH << "// " << localNow->tm_year+1900 << "/" << localNow->tm_mon+1 << "/" << localNow->tm_mday;
    OH << " " << setw(2) << setfill('0') << localNow->tm_hour << ":" << localNow->tm_min << ":" << localNow->tm_sec << " by marsee" << endl;
    OH << "//" << endl;
    OH << endl;
    OH << "#ifndef __RELU_OUTPUT_H__" << endl;
    OH << "#define __RELU_OUTPUT_H__" << endl;
    OH << endl;
    OH << "const float relu_fout[" << VERTICAL_PIXEL_WIDTH*HORIZONTAL_PIXEL_WIDTH  << "][" << NUMBER_OF_KERNEL << "] = {" << endl;
    for (int y=0; y<VERTICAL_PIXEL_WIDTH ; y++){
        for (int x=0; x<HORIZONTAL_PIXEL_WIDTH ; x++){
            OH << "    {" << fixed << setprecision(12) << relu_fout[HORIZONTAL_PIXEL_WIDTH*y+x][0];
            for(int i=1; i<NUMBER_OF_KERNEL; i++){
                OH << ", " << relu_fout[HORIZONTAL_PIXEL_WIDTH*y+x][i];
            }
            OH << "}";
            
            if (y==VERTICAL_PIXEL_WIDTH-1 && x==HORIZONTAL_PIXEL_WIDTH-1)
                OH << endl;
            else
                OH << "," << endl;
        }
    }
    OH << "};" << endl << endl;

    OH << "const ap_fixed<16, 6, AP_TRN, AP_WRAP> relu_out[" << VERTICAL_PIXEL_WIDTH*HORIZONTAL_PIXEL_WIDTH  << "][" << NUMBER_OF_KERNEL << "] = {" << endl;
    for (int y=0; y<VERTICAL_PIXEL_WIDTH ; y++){
        for (int x=0; x<HORIZONTAL_PIXEL_WIDTH ; x++){
            OH << "    {" << (float)relu_out[HORIZONTAL_PIXEL_WIDTH*y+x][0];
            for(int i=1; i<NUMBER_OF_KERNEL; i++){
                OH << ", " <<  (float)relu_out[HORIZONTAL_PIXEL_WIDTH*y+x][1];
            }
            OH << "}";

            if (y==VERTICAL_PIXEL_WIDTH -1 && x==HORIZONTAL_PIXEL_WIDTH -1)
                OH << endl;
            else
                OH << "," << endl;
        }
    }
    OH << "};" << endl << endl;
    OH << "#endif" << endl;

    return(0);
}    


int relu_soft(hls::stream<float_axis<2,1> >& ins,
        hls::stream<float_axis<2,1> >& outs){

    float_axis<2,1> fpix;

    do {
    // user が 1になった時にフレームがスタートする
        ins >> fpix;
    } while(fpix.user == 0);

    Loop1: for (int y=0; y<VERTICAL_PIXEL_WIDTH; y++){
        Loop2: for (int x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (!(x==0 && y==0))    // 最初の入力はすでに入力されている
                ins >> fpix;    // AXI4-Stream からの入力
            
            for(int i=0; i<NUMBER_OF_KERNEL; i++){
                if (fpix.data[i] < 0.0// データが 0 以下だったら 0 にする
                    fpix.data[i] = 0.0;
            }

            outs << fpix;
        }
    }

    return(0);
}


  1. 2018年04月20日 04:32 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

HLSストレーム・インターフェースのReLU1

HLSストリームの畳み込み層に続き、HLSストリームのReLU を実装して行こう。

まずは、relu プロジェクトを作成した。
hls_relu_1_180419.png

C シミュレーションを行った。結果を示す。
hls_relu_2_180419.png

C シミュレーションでの ReLU の出力結果は relu_output.h に記録された。
hls_relu_12_180419.png

C コードの合成を行った。結果を示す。
hls_relu_3_180419.png

Estmated は 8.72 ns で問題ない。
Latency は 321 クロックだった。これもほとんど 1 クロックで 1 ピクセルを処理できているので問題ないはず。。。
リソース使用量は、FF が 251 個、LUT が 791 個だった。

C/RTL 協調シミュレーションを行った。結果を示す。
hls_relu_4_180419.png

Latency は 351 クロックだった。

C/RTL 協調シミュレーションの波形を示す。
hls_relu_5_180419.png

ins_V_empty_n の前の部分が間が空いているのが分かる。これは、user 信号が 1 にアサートされたときがスタートなのだが、それを待っている do while() 文のLatency が長いことが原因のようだ。
その部分を拡大してみよう。

hls_relu_6_180419.png

1 にアサートされる間隔は、60 ns で 6 クロック分に当たる。

解決策としては、その do while() 文にPIPELINE指示子を入れてみよう。
hls_relu_7_180419.png

これで、再度 C コードの合成を行った。結果を示す。
hls_relu_8_180419.png

Estmated は 6.77 ns となった。
Latency は、317 クロックと 321 クロックから 4 クロック改善している。
リソース使用量は、FF が 165 個で、LUT が 360 個だった。FF、LUT 共に少なくなっている。

もう一度、C/RTL 協調シミュレーションを行った。結果を示す。
hls_relu_9_180419.png

Latency は 322 クロックで、前回の 351 クロックより 29 クロック少なくなっている。

C/RTL 協調シミュレーションの波形を示す。
hls_relu_10_180419.png

do while() 文と次の for() 文の間が 3 クロック間が空いているだけで、他はWait 無しに処理できているようだ。

Vivado synthesis, place and route にチェックを入れて Export RTL を行った。結果を示す。
hls_relu_11_180419.png

SLICE は 48 個使用している。
LUT は 119 個、FF は 132 個使用している。
CP achieved post-implementation は 5.008 ns で問題なさそうだ。
  1. 2018年04月19日 05:04 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

HLSストレーム・インターフェースの畳み込み層3(Windows 10 のVivado HLS 使用)

HLSストレーム・インターフェースの畳み込み層2(C シミュレーション、C/RTL 協調シミュレーション)”の続き。

Linux 版の Vivado HLS 2017.4 では(正確にいうと SDx 2017.4 のVivado HLS )では、HLSストレーム・インターフェース版畳み込み層のC/RTL 協調シミュレーションがエラーになってしまった。そこで、Windows 10 のVivado HLS 2017.4 (こちらも SDx がインストールしたVivado HLS)で試してみようと思う。なお、ソースコードは同一のコードを使用している。

一通りやることにして、最初は C シミュレーションからやってみよう。
hlsw_conv_layer_5_180418.png

C シミュレーションはLinux との違いは無いようだ。

次に、C コードの合成を行った。結果を示す。
hlsw_conv_layer_1_180418.png

Latency もリソース使用量もLinux と同一だった。

次に問題のC/RTL 協調シミュレーションを行った。成功した。Windows 10 だとうまく行くようだ。
hlsw_conv_layer_2_180418.png

Latency は 581 クロックだった。
C/RTL 協調シミュレーションの波形を示す。
hlsw_conv_layer_3_180418.png

ins_TRADY と ins_TVALID がほとんど 1 でスループットが最大になっているのが分かる。
outs_V_write を見ると、後ろの方に 6 個の 1 の部分があって、その 1 の部分が平らになっている。
問題無いようだ。

最後に、Vivado synthesis, place and route にチェックを入れて Export RTL を行った。結果を示す。なお、左が Windows 10 で右hがLinux の Export RTL の結果だ。
hlsw_conv_layer_4_180418.pnghls_conv_layer_4_180413.png

Resource Usage の SLICE がWindows 10 版と Linux 版で違っているのが分かる。Windows 10 版が 284 個で Linux 版が 268 個だった。その他の Resource Usage の値は一緒だった。
タイミングでも、CP achieved post-synthesis の値は一緒だったが、CP achieved post-implementation の値が違っている。Windows 10 版は 9.173 ns で Linux 版は 8.703 ns だった。

C/RTL 協調シミュレーションが Linux ではうまく行かないので、Windows 10 で開発を進めていこう。
  1. 2018年04月18日 05:08 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

darknet で画像認識をやってみる2(Tiny Darknet)

darknet で画像認識をやってみる1(ImageNet Classification)”の続き。

前回の extraction は 27 層だったが、今回は、更に層数の少ない 22 層の Tiny Darknet をやってみることにした。

darknet の Tiny Darknet をやってみる。
まずは、重み(tiny.weights)をダウンロードしよう。
wget https://pjreddie.com/media/files/tiny.weights
YOLOv3_32_180416.png

実行してみよう。
./darknet classify cfg/tiny.cfg tiny.weights data/dog.jpg
YOLOv3_38_180417.jpg
YOLOv3_39_180417.jpg

結果をテキストで示す。

masaaki@masaaki-H110M4-M01:~/DNN/darknet$ ./darknet classify cfg/tiny.cfg tiny.weights data/dog.jpg
layer     filters    size              input                output
    0 conv     16  3 x 3 / 1   224 x 224 x   3   ->   224 x 224 x  16  0.043 BFLOPs
    1 max          2 x 2 / 2   224 x 224 x  16   ->   112 x 112 x  16
    2 conv     32  3 x 3 / 1   112 x 112 x  16   ->   112 x 112 x  32  0.116 BFLOPs
    3 max          2 x 2 / 2   112 x 112 x  32   ->    56 x  56 x  32
    4 conv     16  1 x 1 / 1    56 x  56 x  32   ->    56 x  56 x  16  0.003 BFLOPs
    5 conv    128  3 x 3 / 1    56 x  56 x  16   ->    56 x  56 x 128  0.116 BFLOPs
    6 conv     16  1 x 1 / 1    56 x  56 x 128   ->    56 x  56 x  16  0.013 BFLOPs
    7 conv    128  3 x 3 / 1    56 x  56 x  16   ->    56 x  56 x 128  0.116 BFLOPs
    8 max          2 x 2 / 2    56 x  56 x 128   ->    28 x  28 x 128
    9 conv     32  1 x 1 / 1    28 x  28 x 128   ->    28 x  28 x  32  0.006 BFLOPs
   10 conv    256  3 x 3 / 1    28 x  28 x  32   ->    28 x  28 x 256  0.116 BFLOPs
   11 conv     32  1 x 1 / 1    28 x  28 x 256   ->    28 x  28 x  32  0.013 BFLOPs
   12 conv    256  3 x 3 / 1    28 x  28 x  32   ->    28 x  28 x 256  0.116 BFLOPs
   13 max          2 x 2 / 2    28 x  28 x 256   ->    14 x  14 x 256
   14 conv     64  1 x 1 / 1    14 x  14 x 256   ->    14 x  14 x  64  0.006 BFLOPs
   15 conv    512  3 x 3 / 1    14 x  14 x  64   ->    14 x  14 x 512  0.116 BFLOPs
   16 conv     64  1 x 1 / 1    14 x  14 x 512   ->    14 x  14 x  64  0.013 BFLOPs
   17 conv    512  3 x 3 / 1    14 x  14 x  64   ->    14 x  14 x 512  0.116 BFLOPs
   18 conv    128  1 x 1 / 1    14 x  14 x 512   ->    14 x  14 x 128  0.026 BFLOPs
   19 conv   1000  1 x 1 / 1    14 x  14 x 128   ->    14 x  14 x1000  0.050 BFLOPs
   20 avg                       14 x  14 x1000   ->  1000
   21 softmax                                        1000
   22 cost                                           1000
Loading weights from tiny.weights...Done!
data/dog.jpg: Predicted in 0.388883 seconds.
14.51%: malamute
 6.09%: Newfoundland
 5.59%: dogsled
 4.55%: standard schnauzer
 4.05%: Eskimo dog



やはり、前回と一緒で、一番確率の高いのは malamute のようだ。しかも 14.51% で、前回の 12.77% よりも確率は上がっている。
darknet から dog.jpg の画像を引用する。
YOLOv3_35_180416.jpg

次に data/eagle.jpg をやってみよう。
./darknet classify cfg/tiny.cfg tiny.weights data/eagle.jpg
YOLOv3_40_180417.jpg

data/eagle.jpg: Predicted in 0.384116 seconds.
54.11%: bald eagle
12.01%: ruddy turnstone
11.61%: kite
8.80%: hen
4.15%: vulture


やはり、一番確率の高いのは、bald eagle でハクトウワシだそうだ。こちらは、前回の 61.74% よりも 54.11% で確率は下がっている。
eagle.jpg をdarknet から引用する。
YOLOv3_36_180416.jpg

最後に giraffe.jpg をやってみる。
giraffe.jpg を darknet から引用する。
YOLOv3_37_180416.jpg

キリンとシマウマが写っている画像だ。
./darknet classify cfg/tiny.cfg tiny.weights data/giraffe.jpg
YOLOv3_41_180417.jpg

data/giraffe.jpg: Predicted in 0.378156 seconds.
29.71%: zebra
8.75%: tiger cat
7.81%: great grey owl
6.33%: prairie chicken
4.63%: bustard


やはり、シマウマが認識されているがキリンは項目が見当たらない。zebra の認識率は、前回は 28.03% で、今回は 29.71% だった。
  1. 2018年04月17日 04:06 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0

darknet で画像認識をやってみる1(ImageNet Classification)

4月7日の”組込みDL 体験コース”は面白かった。パソナテックさんありがとうございました。層構成のレポートがわかるようになったし、とても参考になった。
しかし、テキストがYOLOv3 以前のdarknet で書かれているので、サイトが変わってしまったようだ。重みをダウンロードしようとしたらできなかった。
今回は、darknet の Classification(画像認識)をやってみようと思う。

darknet の ImageNet Classification をやってみよう。
まずは、重み(extraction.weights)をダウンロードしよう。
wget https://pjreddie.com/media/files/extraction.weights
YOLOv3_30_180416.png

コアダンプされたが、extraction.weights はダウンロードできているようだ。
実行してみよう。実行するときに detect ではなく、classifier を指定すれば良いようだ。
./darknet classifier predict cfg/imagenet1k.data cfg/extraction.cfg extraction.weights data/dog.jpg
YOLOv3_31_180416.png

masaaki@masaaki-H110M4-M01:~/DNN/darknet$ ./darknet classifier predict cfg/imagenet1k.data cfg/extraction.cfg extraction.weights data/dog.jpg
layer     filters    size              input                output
    0 conv     64  7 x 7 / 2   224 x 224 x   3   ->   112 x 112 x  64  0.236 BFLOPs
    1 max          2 x 2 / 2   112 x 112 x  64   ->    56 x  56 x  64
    2 conv    192  3 x 3 / 1    56 x  56 x  64   ->    56 x  56 x 192  0.694 BFLOPs
    3 max          2 x 2 / 2    56 x  56 x 192   ->    28 x  28 x 192
    4 conv    128  1 x 1 / 1    28 x  28 x 192   ->    28 x  28 x 128  0.039 BFLOPs
    5 conv    256  3 x 3 / 1    28 x  28 x 128   ->    28 x  28 x 256  0.462 BFLOPs
    6 conv    256  1 x 1 / 1    28 x  28 x 256   ->    28 x  28 x 256  0.103 BFLOPs
    7 conv    512  3 x 3 / 1    28 x  28 x 256   ->    28 x  28 x 512  1.850 BFLOPs
    8 max          2 x 2 / 2    28 x  28 x 512   ->    14 x  14 x 512
    9 conv    256  1 x 1 / 1    14 x  14 x 512   ->    14 x  14 x 256  0.051 BFLOPs
   10 conv    512  3 x 3 / 1    14 x  14 x 256   ->    14 x  14 x 512  0.462 BFLOPs
   11 conv    256  1 x 1 / 1    14 x  14 x 512   ->    14 x  14 x 256  0.051 BFLOPs
   12 conv    512  3 x 3 / 1    14 x  14 x 256   ->    14 x  14 x 512  0.462 BFLOPs
   13 conv    256  1 x 1 / 1    14 x  14 x 512   ->    14 x  14 x 256  0.051 BFLOPs
   14 conv    512  3 x 3 / 1    14 x  14 x 256   ->    14 x  14 x 512  0.462 BFLOPs
   15 conv    256  1 x 1 / 1    14 x  14 x 512   ->    14 x  14 x 256  0.051 BFLOPs
   16 conv    512  3 x 3 / 1    14 x  14 x 256   ->    14 x  14 x 512  0.462 BFLOPs
   17 conv    512  1 x 1 / 1    14 x  14 x 512   ->    14 x  14 x 512  0.103 BFLOPs
   18 conv   1024  3 x 3 / 1    14 x  14 x 512   ->    14 x  14 x1024  1.850 BFLOPs
   19 max          2 x 2 / 2    14 x  14 x1024   ->     7 x   7 x1024
   20 conv    512  1 x 1 / 1     7 x   7 x1024   ->     7 x   7 x 512  0.051 BFLOPs
   21 conv   1024  3 x 3 / 1     7 x   7 x 512   ->     7 x   7 x1024  0.462 BFLOPs
   22 conv    512  1 x 1 / 1     7 x   7 x1024   ->     7 x   7 x 512  0.051 BFLOPs
   23 conv   1024  3 x 3 / 1     7 x   7 x 512   ->     7 x   7 x1024  0.462 BFLOPs
   24 conv   1000  1 x 1 / 1     7 x   7 x1024   ->     7 x   7 x1000  0.100 BFLOPs
   25 avg                        7 x   7 x1000   ->  1000
   26 softmax                                        1000
   27 cost                                           1000
Loading weights from extraction.weights...Done!
data/dog.jpg: Predicted in 2.876122 seconds.
12.77%: malamute
10.03%: Siberian husky
 7.23%: Eskimo dog
 4.91%: miniature schnauzer
 4.88%: Afghan hound


一番確率の高いのは malamute で犬の一種のようだ。
darknet から dog.jpg の画像を引用する。
YOLOv3_35_180416.jpg

次に data/eagle.jpg をやってみよう。
./darknet classifier predict cfg/imagenet1k.data cfg/extraction.cfg extraction.weights data/eagle.jpg
YOLOv3_33_180416.png

Loading weights from extraction.weights...Done!
data/eagle.jpg: Predicted in 2.890507 seconds.
61.74%: bald eagle
36.86%: kite
0.48%: vulture
0.19%: ptarmigan
0.14%: hen


一番確率の高いのは、bald eagle でハクトウワシだそうだ。
eagle.jpg をdarknet から引用する。
YOLOv3_36_180416.jpg

最後に giraffe.jpg をやってみる。
giraffe.jpg を darknet から引用する。
YOLOv3_37_180416.jpg

キリンとシマウマが1頭ずついるので、何を認識するか興味のあるところだ。
./darknet classifier predict cfg/imagenet1k.data cfg/extraction.cfg extraction.weights data/giraffe.jpg
YOLOv3_34_180416.png

Loading weights from extraction.weights...Done!
data/giraffe.jpg: Predicted in 2.897918 seconds.
28.03%: zebra
14.40%: bustard
11.90%: gazelle
6.38%: cheetah
5.97%: impala


シマウマが認識されているがキリンは項目が見当たらない。
  1. 2018年04月16日 05:36 |
  2. DNN
  3. | トラックバック:0
  4. | コメント:0
»