FPGAの部屋

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

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。ご利用ください。 http://marsee101.web.fc2.com/index.html

2018年09月

ZYBOt のテスト用画像ファイルの作成(テスト・ファイルとラベル・ファイル)”の続き。

今まで作ってきたトレーニング・ファイルやラベル・ファイル、テスト・ファイルやラベル・ファイルを使用して、Keras で学習させた。

まずは、course_line というディレクトリを作成し、その下にJupyter Notebook のファイルが入る course_nn2_line ディレクトリを作成した。そして、 train_course_run_image と train_course_run_label 、test_course_run_image と test_course_run_label と画像ファイルをロードする「ゼロから作るDeep Learning」のPython ファイルを使用した course_dataset.py が入っている dataset_course ディレクトリを作成した。
612d35a0.png


今までと同じネットワークで学習した。
e92c342c.png


学習画像での精度は 99.0 % だが、テスト画像での精度は 92.1 % だった。かなり離れてしまっている。

Train on 55350 samples, validate on 55800 samples
Epoch 1/2
55350/55350 [==============================] - 8s 142us/step - loss: 0.2619 - acc: 0.8985 - val_loss: 0.3540 - val_acc: 0.9143
Epoch 2/2
55350/55350 [==============================] - 8s 151us/step - loss: 0.0416 - acc: 0.9900 - val_loss: 0.3693 - val_acc: 0.9206



グラフを示す。
ZYBOt_Keras_23_180930

モデルのサーマリを示す。

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_3 (Conv2D)            (None, 6, 52, 2)          52        
_________________________________________________________________
activation_7 (Activation)    (None, 6, 52, 2)          0         
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 3, 26, 2)          0         
_________________________________________________________________
flatten_3 (Flatten)          (None, 156)               0         
_________________________________________________________________
dense_5 (Dense)              (None, 100)               15700     
_________________________________________________________________
activation_8 (Activation)    (None, 100)               0         
_________________________________________________________________
dense_6 (Dense)              (None, 3)                 303       
_________________________________________________________________
activation_9 (Activation)    (None, 3)                 0         
=================================================================
Total params: 16,055
Trainable params: 16,055
Non-trainable params: 0


畳み込み層の統計情報を示す。

np.max(conv_layer_weight) = 0.6540467143058777
np.min(conv_layer_weight) = -0.6467538475990295
np.max(abs_conv_layer_weight) = 0.6540467143058777
np.min(abs_conv_layer_weight) = 0.015607763081789017
np.max(conv_layer_bias) = 0.08890005201101303
np.min(conv_layer_bias) = -0.29033342003822327
np.max(abs_conv_layer_bias) = 0.29033342003822327
np.min(abs_conv_layer_bias) = 0.08890005201101303
conv_output = (55800, 6, 52, 2)
np.std(conv_output) = 0.5240352153778076
np.max(conv_output) = 3.5787222385406494
np.min(conv_output) = -2.7464802265167236
np.max(abs_conv) = 3.5787222385406494
np.min(abs_conv) = 2.384185791015625e-07


畳み込み層の重みとバイアスのグラフを示す。
ZYBOt_Keras_24_180930

全結合層1層目の統計情報を示す。

np.max(dence_layer1_weight) = 0.4496344029903412
np.min(dence_layer1_weight) = -0.3555082380771637
np.max(abs_dence_layer1_weight) = 0.4496344029903412
np.min(abs_dence_layer1_weight) = 1.2449898349586874e-05
np.max(dence_layer1_bias) = 0.21790167689323425
np.min(dence_layer1_bias) = -0.16780713200569153
np.max(abs_dence_layer1_bias) = 0.21790167689323425
np.min(abs_dence_layer1_bias) = 5.26009825989604e-05
dence_layer1_output = (55800, 100)
np.std(dence_layer1_output) = 1.1125332117080688
np.max(dence_layer1_output) = 9.291604995727539
np.min(dence_layer1_output) = -10.281697273254395
np.max(abs_dence_layer1_output) = 10.281697273254395
np.min(abs_dence_layer1_output) = 2.682209014892578e-07


全結合層1層目の重みとバイアスのグラフを示す。
ZYBOt_Keras_25_180930

全結合2層目の統計情報を示す。

np.max(dence_layer2_weight) = 0.6938429474830627
np.min(dence_layer2_weight) = -0.8714218139648438
np.max(abs_dence_layer2_weight) = 0.8714218139648438
np.min(abs_dence_layer2_weight) = 0.0005191437667235732
np.max(dence_layer2_bias) = 0.04392116516828537
np.min(dence_layer2_bias) = -0.030551407486200333
np.max(abs_dence_layer2_bias) = 0.04392116516828537
np.min(abs_dence_layer2_bias) = 0.009192205034196377
dence_layer2_output = (55800, 3)
np.std(dence_layer2_output) = 7.362751007080078
np.max(dence_layer2_output) = 29.604900360107422
np.min(dence_layer2_output) = -32.173988342285156
np.max(abs_dence_layer2_output) = 32.173988342285156
np.min(abs_dence_layer2_output) = 0.0001368783414363861


全結合2層目の重みとバイアスのグラフを示す。
ZYBOt_Keras_26_180930

各層の重みやバイアスの C ヘッダ・ファイルを出力し、1000個のテスト画像を出力した C ヘッダ・ファイル course_line_data.h を出力した。
32498004.png

icrawler で学習用画像を収集する”で icrawler はなんとか pip でインストール出来たのだが、ZYBOt のKeras での学習が出来なかったので、仕方が無いので Anaconda をインストールすることにした。

Ubuntuを初めて触るド素人がAnacondaを入れてみた”を参考にして、Anaconda のサイトから Anaconda3-5.2.0-Linux-x86_64.sh をダウンロードしてインストールした。
4cf75c78.png


インストール後に .bashrc を反映した。
source .bashrc

Anaconda に keras をインストールした。
conda install -c conda-forge keras
4bd767b4.png


Anaconda に icrawler をインストールした。
conda install -c hellock icrawler
e7c3dd2a.png


jupyter notebook &
でJupyter Notebook を立ち上げた。

icrawler が動作した。
abbe7acf.png


Keras の学習も問題ない。
718cd595.png

機械学習用の画像を集めるのにicrawlerが便利だった”で icrawler を使って学習用画像を収集していたが、なかなかうまく行かなかったので、顛末を書く。

icrawler のインストールはAnaconda の場合は、conda でインストール出来て、そちらはWindows だったが、動作して問題なかった。
pip の場合は、
pip install icrawler
でインストールを行った。
071fddf7.png

cf7b3a7e.png


機械学習用の画像を集めるのにicrawlerが便利だった”のコードを少し変えて試してみたが、"Couldn't find a tree builder with the features you requested: lxml."というエラーだった。
1c0168a9.png


色々と調べたところ、”BeautifulSoup4でlxmlが使えない”で、

lxmlのバージョンを3.7.3まで下げるとエラーは消えます。(3.8.0だとNG)

ということだったので、lxml の 3.7.3 をインストールした。
sudo pip install 'lxml==3.7.3'
94c5aa76.png


51b56098.png


これで、icrawler を動作させると動いた。
e4c8373b.png


もう一度、
sudo pip install 'lxml==4.2.5'
で戻しても動作したのはなぜだろうか?

icrawler でグーグルを使って収集した猫の写真を示す。
df6330f1.png

ZYBOt の学習用画像のトレーニング・ファイルのチェック”の続き。

前回までで学習用画像ファイルの用意が出来たので、今回は、テスト用画像ファイルのテスト・ファイルとラベル・ファイルを作成する。

テスト・ファイルの名前は、test_course_run_image で、ラベル・ファイルの名前は、test_course_run_label とした。
Vivado 2018.2 の course_test_dataset プロジェクトを作成し、course_test_dataset.cpp を作成した。
b8eca84c.png


C シミュレーションを行った。
a91e56e3.png


test_course_run_image と test_course_run_label が出来ている。
course_test_dataset/solution1/csim/build/ ディレクトリを見ると test_course_run_image が 31.2 MB で test_course_run_label が 55.8 kB だった。

test_course_run_image をバイナリ・エディタの GHex で開いた。
3583af56.png


データ数が 0xD9F8 = 55800 個であることが分かる。

test_course_run_label をバイナリ・エディタの GHex で開いた。
4cbfca41.png


こちらのデータ数も 0xD9F8 = 55800 個であることが分かった。

最後に course_test_dataset.cpp を示す。

// course_test_dataset.cpp
// 2018/09/29 by marsee
//

#include <iostream>
#include "hls_opencv.h"
#include <arpa/inet.h>
#include <stdio.h>
#include <dirent.h>
#include "hls_video.h"

#define BMP_HEIGHT    600
#define BMP_WIDTH    800

#define REDUCTION_RATIO 0.075   // 1/13.3333... 60x45

#define DATASET_HEIGHT  10
#define DATASET_WIDTH   56

const char LEFT_PIC_DIR[] = "test/left_test";
const char RIGHT_PIC_DIR[] = "test/right_test";
const char STRAIGHT_PIC_DIR[] = "test/straight_test";
const char CUR_DIR[] = ".";
const char PAR_DIR[] = "..";

int data_write(char *bmp_file, uint8_t label, FILE *ftin, FILE *ftln){
    uint8_t bufchar[100];

    cv::Mat pict_img = cv::imread(bmp_file,1);
    if(pict_img.empty()){
        fprintf(stderr,"Error: %s\n", bmp_file);
        return(-1);
    }
    cv::Mat reduct_img(pict_img.rows*0.075, pict_img.cols*0.075, pict_img.type());
    cv::resize(pict_img, reduct_img, reduct_img.size(), cv::INTER_LINEAR);
    cv::Mat gray_img;
    cv::cvtColor(reduct_img, gray_img, CV_BGR2GRAY);

    //sprintf(bmp_file, "%s_RED%d.bmp", straight_fn, i);
    //cv::imwrite(bmp_file, gray_img);

    for(int y=0; y<5; y++){
        for(int x=0; x<5; x++){
            cv::Rect rect_center(x, 30+y, 56, 10);
            cv::Mat img_rect(gray_img, rect_center);
            //sprintf(bmp_file, "%s_RED_rect%d_%d%d.bmp", straight_fn, i, y, x);
            //cv::imwrite(bmp_file, img_rect);

            for(int iy=0; iy<img_rect.rows; iy++){
                for(int ix=0; ix<img_rect.cols; ix++){
                    bufchar[ix] = img_rect.at<uchar>(iy, ix);
                }
                fwrite(bufchar, sizeof(uint8_t), img_rect.cols, ftin); // image write
            }
            bufchar[0] = label;
            fwrite(bufchar, sizeof(uint8_t), 1, ftln); // label write
        }
    }
    return(0);
}

int main(){
    char bmp_file[256];
    FILE *ftin, *ftln;
    char train_image_name[] = "test_course_run_image";
    char train_label_name[] = "test_course_run_label";
    uint32_t buf[5];

    DIR *ldir, *rdir, *sdir;
    struct dirent *ldp, *rdp, *sdp;
    int lnum=0, rnum=0, snum=0;
    int max_num;
    int lcnt=0, rcnt=0, scnt=0;

    // Open a train file and a test file
    if ((ftin = fopen(train_image_name, "wb")) == NULL){
        fprintf(stderr, "Can't open %s\n", train_image_name);
        exit(1);
    }
    if ((ftln = fopen(train_label_name, "wb")) == NULL){
        fprintf(stderr, "Can't open %s\n", train_label_name);
        exit(1);
    }

    // Open folder of each files
    if((ldir=opendir(LEFT_PIC_DIR)) == NULL){
        fprintf(stderr, "LEFT_PIC_DIR Open Error\n");
        exit(1);
    }
    if((rdir=opendir(RIGHT_PIC_DIR)) == NULL){
        fprintf(stderr, "RIGHT_PIC_DIR Open Error\n");
        exit(1);
    }
    if((sdir=opendir(STRAIGHT_PIC_DIR)) == NULL){
        fprintf(stderr, "STRAIGHT Open Error\n");
        exit(1);
    }

    // Count the number of files in each folder
    for(ldp=readdir(ldir); ldp != NULL; ldp=readdir(ldir)){
        lnum++;
    }
    for(rdp=readdir(rdir); rdp != NULL; rdp=readdir(rdir)){
        rnum++;
    }
    for(sdp=readdir(sdir); sdp != NULL; sdp=readdir(sdir)){
        snum++;
    }

    // Find the maximum value
    if(lnum > rnum && lnum > snum)
        max_num = lnum;
    else if(rnum > lnum && rnum > snum)
        max_num = rnum;
    else
        max_num = snum;

    printf("lnum = %d, rnum = %d, snum = %d, max_num = %d\n", lnum, rnum, snum, max_num);

    // Close
    closedir(ldir);
    closedir(rdir);
    closedir(sdir);

    // Writed header
    buf[0] = htonl(0x803); // magic number
    buf[1] = htonl((lnum-2+rnum-2+snum-2)*25); // number of image
    buf[2] = htonl(10); // number of rows (10)
    buf[3] = htonl(56); // number of columns (56)
    fwrite(buf, sizeof(uint32_t), 4, ftin);

    buf[0] = htonl(0x801); // magic number
    buf[1] = htonl((lnum-2+rnum-2+snum-2)*25); // number of image
    fwrite(buf, sizeof(uint32_t), 2, ftln);

    // refereed to http://opencv.jp/cookbook/opencv_img.html
    // Reopen folder of each file
    if((ldir=opendir(LEFT_PIC_DIR)) == NULL){
        fprintf(stderr, "LEFT_PIC_DIR Open Error\n");
        exit(1);
    }
    if((rdir=opendir(RIGHT_PIC_DIR)) == NULL){
        fprintf(stderr, "RIGHT_PIC_DIR Open Error\n");
        exit(1);
    }
    if((sdir=opendir(STRAIGHT_PIC_DIR)) == NULL){
        fprintf(stderr, "STRAIGHT Open Error\n");
        exit(1);
    }

    // read file name and write image data
    for(int i=1; i <= max_num; i++){
        if(i <= lnum){
            ldp = readdir(ldir);
            if(strcmp(CUR_DIR, ldp->d_name)!=0 && strcmp(PAR_DIR, ldp->d_name)!=0){
                sprintf(bmp_file, "%s/%s", LEFT_PIC_DIR, ldp->d_name);
                data_write(bmp_file, 0, ftin, ftln);
            }
        }
        if(i <= rnum){
            rdp = readdir(rdir);
            if(strcmp(CUR_DIR, rdp->d_name)!=0 && strcmp(PAR_DIR, rdp->d_name)!=0){
                sprintf(bmp_file, "%s/%s", RIGHT_PIC_DIR, rdp->d_name);
                data_write(bmp_file, 0x2, ftin, ftln);
            }
        }
        if(i <= snum){
            sdp = readdir(sdir);
            if(strcmp(CUR_DIR, sdp->d_name)!=0 && strcmp(PAR_DIR, sdp->d_name)!=0){
                sprintf(bmp_file, "%s/%s", STRAIGHT_PIC_DIR, sdp->d_name);
                data_write(bmp_file, 0x1, ftin, ftln);
            }
        }
    }
    fclose(ftin);
    fclose(ftln);

    return(0);
}


ZYBOt の学習用画像ファイルの作成(トレーニング・ファイルとラベル・ファイル)”の続き。

前回は、学習用画像ファイルを使用して、MNISTデータセットと同じフォーマットでトレーニング・ファイルとラベル・ファイルを生成した。今回は、その内のトレーニング・ファイルが正しいかどうか?を確かめてみよう。

元ネタのFPGAの部屋のブログの記事は、”白線追従走行用畳み込みニューラルネットワークの製作4(トレーニング・ファイルのチェック)

Vivado HLS 2018.2 の course_dataset_check プロジェクトを作成して、トレーニング・ファイルを読み出して、画像ファイルに変換するソフトウェアのcourse_dataset_check.cpp を作成した。
16dccb07.png


C シミュレーションを行った。
d6f02f0e.png


course_data_check/solution1/csim/build に output25.png から output99.png ファイルが生成された。
3ba83fb6.png


output25.png から output49.png までは右旋回の学習用画像となっている。横 5 ピクセルずらして、また縦 5 ピクセルづつずらして学習用画像を作成しているので、下の図の様になる。output50.png から 25 枚は直進の学習用画像となる。
e8c56143.png


問題なくトレーニング・ファイルが作成されているようだ。
最後に、course_dataset_check.cpp を貼っておく。

// course_dataset_check.cpp
// 2018/09/27 by marsee
//

#include <iostream>
#include "hls_opencv.h"

#define DATASET_HEIGHT  10
#define DATASET_WIDTH   56

#define IMAGE_START_NUMBER  25
#define IMAGE_DISP_LENGTH   75

int main(){
    FILE *ftin, *ftln;
    char train_image_name[] = "train_course_run_image";
    uint8_t buf[600];
    char png_file[100];

    if ((ftin = fopen(train_image_name, "rb")) == NULL){
        fprintf(stderr, "Can't open %s\n", train_image_name);
        exit(1);
    }

    fread(buf, sizeof(uint32_t), 4, ftin); // header read

    for(int i=0; i<IMAGE_START_NUMBER; i++){
        fread(buf, sizeof(uint8_t), DATASET_HEIGHT*DATASET_WIDTH, ftin);
    }

    cv::Mat wlt_img(cv::Size(56, 10), CV_8UC1);

    for (int i=0; i<IMAGE_DISP_LENGTH; i++){
        fread(buf, sizeof(uint8_t), DATASET_HEIGHT*DATASET_WIDTH, ftin);

        for (int y = 0; y < wlt_img.rows; y++) {
            for (int x = 0; x < wlt_img.cols; x++) {
                wlt_img.at<uchar>(y, x) = buf[y*DATASET_WIDTH+x];
            }
        }
        sprintf(png_file, "output%d.png", i+IMAGE_START_NUMBER);
        cv::imwrite(png_file, wlt_img);
    }

    fclose(ftin);

    return(0);
}


↑このページのトップヘ