はじめに
TensorFlowのHaskell用バインディングがリリースされています。
本格的に使用する場合はコンパイル方式を用いると思いますが、本記事では、環境に慣れるために対話的に使用する方法について簡単に紹介します。
以下では、Linux(ubuntu 16.04LTS 18.04LTS)を用いた例を紹介します。 なお、Dockerはインストール済みであることを前提としています。
本記事は、2017年8月時点 2018年8月時点の内容です。TensorFlowのHaskell用バインディングは開発中のため、今後、使い勝手が変わると思いますので注意してください。
以下は参考資料です。
環境の準備
1. stackコマンドのインストール
stackをインストールします。 既にインストールされている場合はこの手順は不要です。
こちらの公式情報に従って、インストールしていきます。
以下のコマンドにより、グローバル環境(/usr/bin)にstackコマンドがインストールされます。
$ curl -sSL https://get.haskellstack.org/ | sh
インストールできたか確認してみましょう。
$ stack --version
Version 1.7.1, ...
インストールできています。
2. TensorFlow/haskellバインディングのインストール
つぎに、TensorFlowのHaskellバインディングをインストールしていきます。
こちらの公式情報に従って、インストールしていきます。
まず以下のように、githubからソースを取得(git clone)してから、dockerイメージを作成(docker build)します。
$ git clone --recursive https://github.com/tensorflow/haskell.git tensorflow-haskell
$ cd tensorflow-haskell
$ IMAGE_NAME=tensorflow/haskell:v0
$ docker build -t $IMAGE_NAME docker
これで、dockerイメージが作成されました。 確認してみましょう。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tensorflow/haskell v0 af52250c4a2b xx minutes ago 1.46GB
tensorflow/tensorflow 1.9.0 caab7ec02690 xx weeks ago 1.25GB
dockerイメージ(tensorflow/haskell)を用意できました。(あわせて、tensorflow/tensorflowのイメージも取得されています。)
次に、dockerイメージから生成するdockerコンテナ内で、stackの環境を構築(stack setup)します。
$ stack --docker --docker-image=$IMAGE_NAME setup
上記のコマンドで、dockerコンテナ内からも利用できる~/.stack以下に、GHC(Haskellコンパイラ)がインストールされました。
次に、TensorFlowのHaskellバインディングのソースをビルドします。
以下のコマンドで、カレントディレクトリ(tensorflow-haskell)以下のHaskellソース群がビルドされ、ローカルのディレクトリ下(./.stack-work)にインストールされます。 stackのtestコマンドを使ってビルドしています。
(環境により数十分かかりますが、最初に一度行うのみです。)
$ stack --docker --docker-image=$IMAGE_NAME test
以上で、TensorFlowのHaskellバインディング環境のインストールは完了です。
TensorFlowを対話的に試してみる
1. stack --docker環境で bashを対話的に起動する
ここからが本番です。
通常の使い方であれば、stack build
コマンドでソースをビルドしてから、stack exec
コマンドで生成されたバイナリを実行する手順になると思います。
ですが、ここでは、試行錯誤的な作業を行いやすいように、対話環境を起動してみます。
具体的には、以下のコマンドで、まず、dockerコンテナ内でbashを起動します。
$ stack --docker --docker-image=$IMAGE_NAME exec -- bash
これで、ほどよいstack環境が整備されたdockerコンテナ内で、対話的に作業を行えます。
以下のコマンドなどで、環境の確認をしてみましょう。
stack$ pwd
stack$ which ghc
stack$ ghc --version
さらに、TensorFlowのHaskellバインディングを、パッケージとして認識できているかを、ghc-pkg
コマンドで確認してみましょう。
stack$ ghc-pkg list
/home/my/.stack/programs/x86_64-linux-dkd1ce2ff9c9560b648268df668d177711/ghc-8.2.2/lib/ghc-8.2.2/package.conf.d
Cabal-2.0.1.0
array-0.5.2.0
base-4.10.1.0
:
/home/my/.stack/snapshots/x86_64-linux-dkd1ce2ff9c9560b648268df668d177711/lts-11.9/8.2.2/pkgdb
Cabal-2.0.1.1
HTTP-4000.3.11
HUnit-1.6.0.0
QuickCheck-2.10.1
ansi-terminal-0.8.0.4
:
/home/my/tensorflow-haskell/.stack-work/install/x86_64-linux-dkd1ce2ff9c9560b648268df668d177711/lts-11.9/8.2.2/pkgdb
haskell-src-exts-1.19.1
proto-lens-protobuf-types-0.2.2.0
proto-lens-protoc-0.2.2.3
snappy-0.2.0.2
snappy-framing-0.1.1
tensorflow-0.2.0.0
tensorflow-core-ops-0.2.0.0
tensorflow-logging-0.2.0.0
tensorflow-mnist-0.1.0.0
:
このように、ローカルディレクトリ以下の./.stack-work/install/...
以下に、TensorFlow/Haskellバインディングのパッケージが正しく入っています。
2. dockerコンテナ内で、ghci を対話的に起動する
さて、ようやく本題です。
dockerコンテナ内で、GHCの対話環境(REPL)である、ghciを起動しましょう。
stack$ ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
Prelude>
正しく動くか確認しましょう。
Prelude> 1+2
3
OKですね。
では、TensorFlowを試していきます。
そのまえに、importによってghciのプロンプトが長くなって見づらくなるのを避けるために、プロンプトの設定を行います(必須ではありません。)
Prelude> :set prompt "ghci> "
ghci> :set prompt-cont "ghci| "
3. ghci 上で、TensorFlowを対話的に試す
いよいよ、TensorFlowのコードを試します。
以下では、 こちらのコード例を試してみます。
このコード例では、リスト記法を便利にするGHCの言語拡張(OverloadedLists)を設定します。
gchi> :set -XOverloadedLists
次に、必要なパッケージをimportします。
ghci> import Data.Vector (Vector)
ghci> import TensorFlow.Ops (constant, add)
ghci> import TensorFlow.Session (runSession, run)
続いて、TensorFlowでグラフ(ネットワーク)を定義します。ここでは単純な加算グラフを定義してみます。
ghci> :{
ghci| runSimple :: IO (Vector Float)
ghci| runSimple = runSession $ do
ghci| let node1 = constant [1] [3 :: Float]
ghci| let node2 = constant [1] [4 :: Float]
ghci| let additionNode = node1 `add` node2
ghci| run additionNode
ghci| :}
最後に、TensorFlowのグラフ(ネットワーク)の計算を実行します。
ghci> runSimple
[7.0]
素直に実行できました!
このように、TensorFlowを対話的、試行錯誤的に試せます。
ghciを終了するには以下のようにします。
ghci> :q
Leaving GHCi.
dockerコンテナ内のbashを終了するには、exit
を実行しましょう。
なお、TensorFlowが整備されたdockerコンテナ内のbashを再び起動するには、以下のコマンドから始めればOKです。
$ IMAGE_NAME=tensorflow/haskell:v0
$ stack --docker --docker-image=$IMAGE_NAME exec -- bash
では、Haskell & TensorFlowを、気軽にenjoy!
補足
runghcも使えます
dockerコンテナ内でbashを立ち上げられるので、ghciだけでなく、runghcなども使用できます。
例えば、以下のようにファイルを準備して、
$ cat test1.hs
{-# LANGUAGE OverloadedLists #-}
import Data.Vector (Vector)
import TensorFlow.Ops (constant, add)
import TensorFlow.Session (runSession, run)
runSimple :: IO (Vector Float)
runSimple = runSession $ do
let node1 = constant [1] [3 :: Float]
let node2 = constant [1] [4 :: Float]
let additionNode = node1 `add` node2
run additionNode
main :: IO ()
main = do
result <- runSimple
print result
以下のように、runghcで実行することができます。
$ runghc test1.hs
[7.0]
このように、runghcやghciを使って、試行錯誤的に手軽にTensorFlow/Haskellを試せます。
stackとdockerについて少し
うまく作られているstackとdockerの連携について、関係を少しだけ補足します。
- docker buildでビルドしたdockerイメージは、stack --dockerコマンドにより使い回される
- そのdockerイメージをもとに、stack --dockerコマンドにより生成されるdockerコンテナは、毎回使い捨てられる
- 但し、それらのdockerコンテナはローカルディレクトリやホームディレクトリをマウントするので、ファイルの更新内容は以降のdockerコンテナに引き継がれる
- また、ホストOSとdockerコンテナ間で、ファイルは読み書き可能に共有される
よく出来てますね。
参考リンク
参考となるリンクをいくつか挙げます。
以上です。