オッサンはDesktopが好き

自作PCや機械学習、自転車のことを脈絡無く書きます

Lenux + tensorflowで作ったDeep Learningの学習済みネットワークを,Windowsに移植して推論する (3)

少し時間が空いてしまいましたが,3回目です.
1回目*1に失敗レポートを書くと宣言してましたが,,,なんと,解決して出来るようになりました!!!
せっかくなので,成功レポート:Lenuxで作った学習モデルをWindowsに移植してC言語で推論する方法を書きます.
前回までとはLenux側のソースが完全に変わってしまっています.
大変恐縮ですが,前回からの続きという読み方は避けて下さい.

0. PC環境

改めてPC環境を確認しておきます.
実は2回目を書いた後でLenuxが壊れ,環境を作り直しました.
ですので,OSやPythonのver.が変わっています.

Lenux

  • Ubuntu 18.04 LTS
  • python 3.6.9
  • tensorflow-gpu 1.14.0
  • keras 2.3.1
  • nvidia driver 440.82
  • CUDA 10.0
  • cudnn 7.4.2

WIndows

1. Windows側のTensorflow環境

(1) ここ*2からC言語用のdllをダウンロード
Lenux用*3も必要になるので,併せてダウンロードします.

(2) 下記のディレクトリを作成し,ここにWindows用のzipを展開

C:\Tool\tensorflow_for_c_1.14.0

※ 以後では,このパスに環境を作るものとします.

(3) Lenux用のzipを適当な場所に展開し,includeフォルダの中にある下記の2つをコピー

  • コピーするファイル
c_api_experimental.h
tf_attrtype.h
  • コピー先
C:\Tool\tensorflow_for_c_1.14.0\include\tensorflow\c

////////////////////////////////////////////////////
ちなみに,失敗レポートを書くつもりだったやり方はC++用のTensorflowビルド*4を使っていました.
成功している方*5もいらっしゃる様ですが,僕が使おうとしたtensorflow 1.14.0のビルドはかなりrawな状態でアップロードされている様です.
リンクしようするとlibが不足してしましました.
////////////////////////////////////////////////////

2. Lenux側でpbファイルを作成

(1) 学習モデルの作成
今回から唐突にkerasを使い始めました.
特に理由は無く,何となくです.
Windows移植に成功した理由が,kerasの導入では無いと思っています.
確かめていませんが,結果オーライですので.

(2) kerasモデルをpbファイルに変換
前回はTensorflowのチェックポイントからpbを作ってましたが,今回はkerasのh5から作りました.

def convert_keras_to_tensorflow(keras_model_filename, tf_model_filename):
    model = load_model(keras_model_filename)
    model.summary()
    frozen_graph = freeze_session(K.get_session(), output_names=[out.op.name for out in model.outputs])
    tf.train.write_graph(frozen_graph, './', tf_model_filename, as_text=False)
    tf.train.write_graph(frozen_graph, './', tf_model_filename + '.txt', as_text=True)

if __name__ == '__main__':
    # convert
    keras_model_filename = './model.h5'
    tf_model_filename = './frozen_graph.pb'
    convert_keras_to_tensorflow(keras_model_filename, tf_model_filename)

3. Windows側で推論処理を構築

(1) Visual Studioc++コンソールアプリケーションを作成

(2) Tensorflowを使うための設定

C:\Tool\tensorflow_for_c_1.14.0\include
C:\Tool\tensorflow_for_c_1.14.0\lib
  • 追加の依存ファイル
tensorflow.lib
  • 実行フォルダにコピー
tensorflow.dll
frozen_model.pb    ※ Lenux側で作った学習済みネットワーク
testImage.txt      ※ Lenux側でも使ったテスト画像

(3) 推論処理の実行
この方のソース*6を参考にさせていただきました.
実際の画像(png)ではなく,Lenux側でテスト用に配列したテキストを読み込んでいます.

  • 画像の読み込み
char image_path[512];
strcpy(image_path, directory);
strcat(image_path, "\\testImage.txt");
std::vector<std::vector<float>> images(DATA_SIZE, std::vector<float>(IMG_SIZE, 0.0));
if (!readImage(image_path, images))
{
    std::cout << "Cannot read images" << std::endl;
    return -1;
}
  • モデルの読み込み
/* get graph info */
char model_path[512];
strcpy(model_path, directory);
strcat(model_path, "\\frozen_graph.pb");
displayGraphInfo(model_path);

(4) ノード名のチェック
Pythonからpbファイルを使う場合*7と同じで,入力と出力のノード名を正確に指定することがポイントになります.
上記のdsipplayGraphInfoを実行するとコンソールで見れますので,ソースに反映します.

f:id:changlikesdesktop:20200418164651p:plain:w400 f:id:changlikesdesktop:20200418164705p:plain:w400

  • 入力ノードを指定
/* prepare input tensor */
TF_Output input_op = { TF_GraphOperationByName(graph, "conv2d_1_input"), 0 };
if (input_op.oper == nullptr) {
    std::cout << "Can't init input_op" << std::endl;
    return 2;
}
  • 出力ノードを指定
/* prepare output tensor */
TF_Output out_op = { TF_GraphOperationByName(graph, "dense_2/Softmax"), 0 };
if (out_op.oper == nullptr) {
    std::cout << "Can't init out_op" << std::endl;
    return 3;
}

(5) 実行

f:id:changlikesdesktop:20200418163002p:plain:w400

こんな感じでできました!!!

4. 結び

前からやりたかった事が出来て嬉しいです.
Lenux + Pythonで解析結果を出すだけだと,何となく学生時代の研究みたいな感じがしてしまうんですが,,,具体的なアプリケーション適用が現実的になってきました(^_^)

この記事はコロナショックの真っ只中で書いています.
大変な思いをされている方が大勢いらっしゃることかと思います.
私も在宅勤務を余儀なくされました.
不謹慎ですが,私の場合は在宅勤務になって通勤時間が無くなり,ソースを書いたり,研究をする時間が増えました.
今は,世の中に平穏が戻ったときのために,知力と体力を蓄えるときなのだと思っています.

今回書いたソースはここ*8です.