TensorFlow for Goを使ってみた

はじめに

TensorFlowをGo言語で動かしてみました。

環境構築

TensorFlow for GoはWindowsに対応していないため、Ubuntu環境にインストールします。

Go言語のインストール

sudo apt install golang-go

TensorFlow for C のインストール

TensorFlow for Cのライブラリをダウンロードしたものを/usr/localに置いて、以下のコマンドを実行します。 (ファイル名はダウンロードしたファイルによって変わります。)

sudo tar -C /usr/local -xzf /usr/local/libtensorflow-cpu-linux-x86_64-1.13.1.tar.gz
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/lib
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

以下の動作確認用のサンプルプログラムを「hello_tf.c」という名前で保存します。

#include <stdio.h>
#include <tensorflow/c/c_api.h>

int main() {
  printf("Hello from TensorFlow C library version %s\n", TF_Version());
  return 0;
}

サンプルプログラムをビルドして、実行します。

gcc hello_tf.c -ltensorflow -o hello_tf
./hello_tf
Hello from TensorFlow C library version 1.13.1

上記のように出力されればTensorFlow for Cのインストールは成功です。

TensorFlow for Go のインストール

パッケージをインストールします。

go get github.com/tensorflow/tensorflow/tensorflow/go

以下のコマンドを入力します。

go test github.com/tensorflow/tensorflow/tensorflow/go

こんな感じの結果が返ってきます。

ok      github.com/tensorflow/tensorflow/tensorflow/go  1.166s

以下の動作確認用のサンプルプログラムを「hello_tf.go」という名前で保存します。

package main

import (
    tf "github.com/tensorflow/tensorflow/tensorflow/go"
    "github.com/tensorflow/tensorflow/tensorflow/go/op"
    "fmt"
)

func main() {
    // Construct a graph with an operation that produces a string constant.
    s := op.NewScope()
    c := op.Const(s, "Hello from TensorFlow version " + tf.Version())
    graph, err := s.Finalize()
    if err != nil {
        panic(err)
    }

    // Execute the graph in a session.
    sess, err := tf.NewSession(graph, nil)
    if err != nil {
        panic(err)
    }
    output, err := sess.Run(nil, []tf.Output{c}, nil)
    if err != nil {
        panic(err)
    }
    fmt.Println(output[0].Value())
}

サンプルプログラムを実行します。

go run hello_tf.go

こんな感じの結果が返ってきたら成功です。

Hello from TensorFlow version 1.13.1

Protocol Buffers形式への変換

Tenforflow for Goの場合、hdf5ではなく、ProtocolBuffersの形式である必要があります。
この記事を公開した時点では、tensorflow 1.15.0で作成したpbファイルはTensorFlow for Goで読み取る事ができませんでした。
そのため1.13.2にバージョンを下げて実行しました。

import tensorflow as tf
from keras import backend as K
from keras.models import load_model
from tensorflow.python.saved_model import builder as saved_model_builder
from tensorflow.python.saved_model.signature_def_utils import predict_signature_def
from tensorflow.python.saved_model import tag_constants

def export_h5_to_pb(path_to_h5, export_path):
    sess = tf.Session()
    K.set_session(sess)
    K.set_learning_phase(0)

    keras_model = load_model(path_to_h5)

    builder = saved_model_builder.SavedModelBuilder(export_path)

    signature = predict_signature_def(inputs={"images": keras_model.input},
                                      outputs={"scores": keras_model.output})
    with K.get_session() as sess:
        print(sess)
        # Save the meta graph and the variables
        builder.add_meta_graph_and_variables(sess, tags=[tag_constants.SERVING], signature_def_map={"predict": signature})
    builder.save()

path_to_h5 = 'something.h5'
export_path = 'models'
export_h5_to_pb(path_to_h5, export_path)

実行すると、modelsフォルダが作成され、その中に「saved_model.pb」が作成されます。

推定

pb形式に変換したモデルが出力されたら、このモデルを使用して推定してみます。

model, err := tensorflow.LoadSavedModel("models", []string{"serve"}, nil)

まずはモデルを読み込みます。 「models」がフォルダ名で、「serve」が「builder.add_meta_graph_and_variables」の「tags」に渡した値になります。

result, err := model.Session.Run(
    map[tensorflow.Output]*tensorflow.Tensor{
        model.Graph.Operation("input_1").Output(0): tensor,
    },
    []tensorflow.Output{
        model.Graph.Operation("dense_2/Softmax").Output(0),
    },
    nil,
)

推定結果がresultに格納されます。
「model.Graph.Operation」の箇所は上がinputで、下がoutputになります。
このブログの方法でmodelを作成した場合、inputは「input_1」になるみたいです。
outputについては、今回Softmaxを使用したのでこの指定になっており、使用する関数に応じて変更が必要になります。

未分類

Posted by ababa