2019年7月10日水曜日

Neural NetworkのRuntimeを作る

.xlsxのファイルを表計算ソフトで開けばいろいろな計算ができるように、.onnxのファイルをNeural NetworkのRuntimeで開けばディープラーニングができるそうです。
なんかめちゃくちゃ簡単そうじゃん。
これならおじさんもできる!

ということで本日はNeural NetworkのRuntimeを作って遊ぶがテーマです。
といっても先日、ブログでPose Estimationを行ったときに、副産物でOpenCVのNeural NetworkのRuntimeもできてしまったので、本日はこれを使って.onnxファイルを読み込んで、ディープラーニングをしてみたいと思います。


まず、昨日作ったもののソース。
https://drive.google.com/file/d/1P4VC3_gZXwANeL0yup-5Ni56IFyvs_VM/view?usp=sharingminoipencv


次に、MNISTの.onnxファイルのダウンロード方法とサンプルコード
https://algorithm.joho.info/programming/python/cv2-dnn-readnetfromonnx-py/


Net net = readNetFromONNX();
net.setInput(inpBlob);
Mat output = net.forward();

上記のように3行書くだけでディープラーニングができるようです。
すごいね。ファイルを読んで、データをセットして、再生の関数を呼ぶだけ。

Pythonが気に入らないので、MNISTをいつものようにC++で書き直します。

-------------------------
#include<stdio.h>
#include<iostream>
#include<string>
#include<vector>

#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION


#include "opencv2_core.hpp"
#include "opencv2_imgproc.hpp"
#include "opencv2_imgproc_imgproc_c.h"
#include "opencv2_dnn.hpp"

#include "stb_image.h"
#include "stb_image_write.h"

void changeb_g(unsigned char* p, int x, int y, int c)
{
int ct = x*y;
int i;
unsigned char t;
for (i = 0; i < ct; i++) {
t = p[0];
p[0] = p[2];
p[2] = t;
p[3] = 255;
p += c;
}
}


int main()
{
unsigned char* p;
int x=-1, y=-1, n=-1;

//
p = stbi_load("tegaki5.png", &x, &y, &n, 4);
if (p == NULL || x < 1 || y < 1)return 1;
changeb_g(p, x, y, 4);
cv::Mat color = cv::Mat(y, x, CV_8UC4);
memcpy(color.data, p, x * 4 * y);
stbi_image_free(p);

//
cv::Mat img;
cv::cvtColor(color, img, CV_BGRA2GRAY);
cv::resize(img, img, cv::Size(28, 28));
img = ~img;


//std::cout << "img = " << std::endl << " " << img  << std::endl << std::endl;

cv::Mat inpBlob = cv::dnn::blobFromImage(img);
cv::dnn::Net net = cv::dnn::readNetFromONNX("mnist_model.onnx");

net.setInput(inpBlob);
cv::Mat output = net.forward();

//std::cout << "output = " << std::endl << " " << output  << std::endl << std::endl;

int i;
for (i = 0; i < 10; i++) {
printf("%d : %f \n",i,output.at<float>(i));
}

return 0;
}

-------------------------

OpenCVでONNXを使えるようになったのは最近なので仕様がどんどん変わっています。
そもそも入力画像はこれでよいのでしょうか?
blobFromImage()が勝手に正規化するようなこと書いてあるんですが、本当でしょうか?
戻り値は0から9の判別結果って書いてあるんですが、数値の範囲ってどうなっているのでしょう???
このONNX系のドキュメントが本当になくて全くわかりません。
本当にこのコード正しいのでしょうか?

とりあえず、以下の画像で実験。


結果
-------------------------
0 : -4.652389
1 : -9.075597
2 : -6.733267
3 : 3.908587
4 : -7.073473
5 : 17.678633
6 : 3.654180
7 : -3.370771
8 : -0.516723
9 : 0.264699
-------------------------

とりあえず確かに「5」と認識しているっぽいです。
おじさん、調子に乗ってResNetのONNXファイルもダウンロードしてやってみたのですが、うまくいかず。
なんかまだバグがたくさんあるっぽいです。

0 件のコメント:

コメントを投稿