読者です 読者をやめる 読者になる 読者になる

CentOSにRuby版TensorFlowをインストールする

Ruby版のTensorFlowであるtensorflow.rbをCentOS 7にインストールしてみました。

github.com

GPUないのでCPUだけ使う版です。

大まかに

  • TensorFlowをコンパイルするためのツールbazelをインストール
  • bazelでTensorFlowをコンパイルしてシェアードライブラリをインストール
  • tensorflow.rbのgemをインストール

といった流れになります。

bazelをインストール

$ sudo yum install gcc-c++ java-1.8.0-openjdk-devel
$ git clone https://github.com/bazelbuild/bazel.git
$ export JAVA_HOME=/usr/lib/jvm/java
$ cd bazel
$ ./compile.sh
...
$ cp output/bazel ~/bin 

TensorFlowをコンパイルしてシェアードライブラリをインストール

$ sudo yum install swig python-devel python-setuptools numpy
$ git clone https://github.com/tensorflow/tensorflow.git
$ cd tensorflow
$ ./configure

./configureするとPythonのパスやらいろいろ聞いくるので答えます。大抵、デフォルトのままリターン押すだけで良いはず。

$ bazel build //tensorflow:libtensorflow.so
$ sudo cp bazel-bin/tensorflow/libtensorflow.so /usr/lib

tensorflow.rbをインストール

$ sudo yum install ruby-devel
$ sudo gem install bundler
$ git clone https://github.com/somaticio/tensorflow.rb.git
$ cd tensorflow.rb/ext/sciruby/tensorflow_c
$ ruby extconf.rb
$ make
$ sudo make install
$ cd ./../../..
$ bundle install
$ bundle exec rake install

サンプルの実行

以下のサンプルプログラムを実行してみます。

require 'tensorflow'
graph = Tensorflow::Graph.new
input1 = graph.placeholder('input1', Tensorflow::TF_DOUBLE, [2,3])
input2 = graph.placeholder('input2', Tensorflow::TF_DOUBLE, [2,3])
graph.define_op("Add", 'output', [input1, input2], "",nil)

session = Tensorflow::Session.new
session.extend_graph(graph)

input1 = Tensorflow::Tensor.new([[1.0,3.0, 5.0],[2.0,4.0, 7.0]])
input2 = Tensorflow::Tensor.new([[-5.0,1.2,4.5],[8.0,2.3, 3.1]])
result = session.run({"input1" => input1.tensor, "input2" => input2.tensor},["output"],nil)
print result[0], "\n"

実行して以下のような結果になればOK。

[[-4.0, 4.2, 9.5], [10.0, 6.3, 10.1]]

GoでGlusterFSのlibgfapiを使う

分散ファイルシステムGlusterFSのlibgfapiをGoから使うには、gogfapiというものがあるのでそれを使う。

gogfapi - Gluster Community Forge

例えば、GlusterFSのボリューム上にあるファイルを読み出すプログラム gfcat.go は以下のようになる。

package main

import (
    "os"

    "forge.gluster.org/gogfapi/gogfapi.git/gfapi"
)

func main() {
    if len(os.Args) < 3 {
        os.Exit(1)
    }
    volname := os.Args[1]
    path := os.Args[2]

    vol := new(gfapi.Volume)
    ret := vol.Init("localhost", volname)
    if ret != 0 {
        panic("failed to init volume")
    }
    ret = vol.Mount()
    if ret != 0 {
        panic("failed to mount volume")
    }

    f, err := vol.Open(path)
    if err != nil {
        panic(err)
    }
    b := make([]byte, 4096)

    for {
        n, err := f.Read(b)
        if n == 0 || err != nil {
            break
        }
        os.Stdout.Write(b)
    }
}

使い方は

go build gfcat.go
sudo gfcat VOLNAME path

のように、root権限で実行し、引数としてボリューム名とパスを指定する。root権限が必要なのはlibgfapiの仕様である。 接続先ホストはlocalhost決めうちになっているので、ボリュームを構成するノード上で実行しなければいけない。

プログラムとしては、ボリュームの初期化と仮想的なマウントが入る以外は、Goのosパッケージのファイル操作に近い。 ただ、上記でも使っているRead関数は、ファイルの終端に達してもEOFを返してくれないようであるので注意。よって上記のプログラムでは、読み込んだバイト数が0かどうかで終わりを判定している。