2018年6月13日水曜日

ClojureでTensorFlowの物体判別プログラムを動かしてみた


背景

ClojureとはJavaの処理系で動作するLisp言語の一つです。
TensorFlowとは、Googleが開発している機械学習プログラムです。

TensorFlowがJava APIを提供しているので、Javaで書かれた物体認識プログラムをClojureに書き換えて動かしてみました。
書き換えに戸惑う部分があったので、動かし方と共に共有します。

使ったもの

cljコマンドが実行できる環境

cljプロジェクトを作成

この記事では~/gitprojectsというディレクトリの中にclj-tensorflow-practiceというプロジェクトを作り、そのプロジェクトで物体認識プログラムを動かします。
mkdir -p ~/gitprojects/clj-tensorflow-practice
cd ~/gitprojects/clj-tensorflow-practice

TensorFlowを利用できるように、下記のようなednファイルを作成します。
~/gitprojects/clj-tensorflow-practice/deps.edn
{:deps
 {org.tensorflow/tensorflow {:mvn/version "1.8.0"}}}

動作確認用プログラムを作成・実行

TensorFlow for Javaのインストール手順で紹介されているプログラムをClojureで書き換えて、TensorFlowが動いていることを確認しました。
~/gitprojects/clj-tensorflow-practice/src/hello_tf.clj
(ns hello-tf
  (:import [org.tensorflow Graph Session Tensor TensorFlow]))

(defn -main []
  (let [g (new Graph)
        value (str "Hello from " (TensorFlow/version))
        t (Tensor/create (byte-array (map byte value)))
        _ (-> (.opBuilder g "Const" "MyConst")
              (.setAttr "dtype" (.dataType t))
              (.setAttr "value" t)
              .build)
        output (-> (new Session g)
                .runner
                (.fetch "MyConst")
                .run
                (.get 0))]
    (prn (String. (.bytesValue output)))))

下記のようなコマンドで実行できました。
cd ~/gitprojects/clj-tensorflow-practice
clj -m hello-tf

学習済みデータをダウンロード

物体認識プログラムを動かす前に、Googleが提供している学銃済みデータをダウンロードします。
cd ~/gitprojects/clj-tensorflow-practice
mkdir data
cd data
wget https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip
unzip inception5h.zip

認識したい画像を配置

物体認識プログラムで認識させたい画像を配置します。
今回はOpenCVのサンプルプログラムで使われることが多いLenaさんの画像を利用しました。
cd ~/gitprojects/clj-tensorflow-practice
mkdir img
cd img
wget https://raw.githubusercontent.com/opencv/opencv/master/samples/data/lena.jpg

物体認識プログラムを作成・実行

TensorFlowのリポジトリで公開されている、Javaで書かれた物体認識プログラムをClojureで書き換えました。
プログラムは150行位あり、ところどころ修正するかもしれないので、リポジトリに公開しているファイル(下記のリンク)をご覧ください。

asukiaaa/clj-tensorflow-practice/src/main.clj

とりあえず動かしたい場合は、このようなコマンドでダウンロードできます。
cd ~/gitprojects/clj-tensorflow-practice/src
wget https://raw.githubusercontent.com/asukiaaa/clj-tensorflow-practice/master/src/main.clj

cljコマンドでmainを指定して実行できます。
cd ~/gitprojects/clj-tensorflow-practice
clj -m main

Lenaさんの画像にカウボーイハットがある可能性が高いと判定されました。


実装に時間がかかった部分を共有

main.cljを書く際に、時間を取られた部分を共有します。

型の変換

Clojureは、整数はlong、自然数はdoubleで値を保持しますが、TensorFlowではそれぞれIntとFloatで値を保持します。
TensorFlowのConstで値を作成する際に、それぞれ型を変換する必要があり、それに気づくのに時間を取られました。
(defn get-constant
  ([g name value type]
   (prn name value type)
   (let [t (Tensor/create value)]
     (-> (.opBuilder g "Const" name)
         (.setAttr "dtype" (DataType/fromClass type))
         (.setAttr "value" t)
         .build
         (.output 0))))
  ([g name value]
   (cond (integer? value) (get-constant g name (Integer. value) Integer)
         (float? value) (get-constant g name (Float. value) Float)
         (and (vector? value) (integer? (first value))) (get-constant g name (int-array value) Integer)
         :else (get-constant g name value String))))

多重配列の作成

Javaでも扱える多重配列をClojureで定義するには、make-arrayを使うと下記のように記述できます。
下記の記述では、2x100のFloat型の配列を定義しています。
(make-array Float/TYPE 1 100)

これは自分のClojureに対する経験不足のために時間を取られた件です。
良い学びになりました。

まとめ

ClojureでTensorFlowの画像認識プログラムを動かせました。
やりたかったことが出来て満足です。

共有したい情報は以上です。

参考

Installing TensorFlow for Java
Maven Repository: org.tensorflow

0 件のコメント :