TensorFlow: Save and Restore Graph/Variable
TensorflowのSaverでsave/restoreされるのは,MetaGarph/Variableなどの情報.graphだけを永続化したい場合は,tf.train.write_graph/tf.import_graph_defを使う.
同じグラフを常に使う場合,単なるチェックポイントからの復帰は,これのみで可能.
Save and Restore Graph/Variable
元のグラフ,変数を保存後,別のグラフにimportして,RestoreしたVariableにアクセスするサンプル.
- Variableを作って
- Default Graphに Opを追加
- VariableをCollectionに追加しておいて,Restore後にアクセスしやすくしておく
- tf.train.Saver.saveでsave
- tf.Graphで別のグラフを作って,graph.as_default()でコンテキストをつくり
- saver.restore()
- ユーザ定義のcollectionへアクセスして,変数へアクセス
#!/usr/bin/env python import tensorflow as tf import datetime def main(): # Varialbes initial_v1 = tf.truncated_normal((10, 5), mean=0, stddev=0.1) #v1 = tf.Variable(initial_v1, name="v1") v1 = tf.get_variable("v1", initializer=initial_v1) initial_v2 = tf.truncated_normal((5, 3), mean=0, stddev=0.1) #v2 = tf.Variable(initial_v2, name="v2") v2 = tf.get_variable("v2", initializer=initial_v2) tf.add_to_collection("v2", v2) # Ops op_name = "prod" prod = tf.matmul(v1, v2, name=op_name) init_op = tf.initialize_all_variables() # Saver saver = tf.train.Saver([v1, v2]) #saver = tf.train.Saver() with tf.Session() as sess: # Init variables sess.run(init_op) # Compute result0 = sess.run(prod) print result0 print "" # Save variables now = datetime.datetime.now() save_path = "/tmp/{}-{}.ckpt".format(__file__, now) saver.save(sess, save_path, write_meta_graph=True) print "Model saved in {}".format(save_path) print "" # Restore graph to another graph (not default graph) and variables graph = tf.Graph() with graph.as_default(): saver = tf.train.import_meta_graph("{}.meta".format(save_path)) with tf.Session() as sess: saver.restore(sess, save_path) print "Variables restored" print "" print [var.name for var in tf.get_collection(tf.GraphKeys.VARIABLES)] print [var.eval() for var in tf.get_collection(tf.GraphKeys.VARIABLES)] print tf.get_collection("v2")[0].eval() #print tf.get_variable("v2:0") can NOT get print "" if __name__ == '__main__': main()
正直,save/restore APIが使いにくいので,そのうち変更されるかもしれない... これのようにハックしている人もいる.
参考
- http://stackoverflow.com/questions/33759623/tensorflow-how-to-restore-a-previously-saved-model-python
- https://www.tensorflow.org/versions/r0.8/how_tos/variables/index.html#saving-and-restoring
- https://gist.github.com/nikitakit/6ef3b72be67b86cb7868
- https://www.tensorflow.org/versions/master/how_tos/meta_graph/index.html
Docker Engine
今更ながら,Dockerを触ってみた.
なぜDockerなのか
一言で言うと,CI/CD (継続的インテグ/継続的ディリバリ)が簡単になるため.
Getting Started
やっぱり本家のGetting Startedをやるのが,基本を理解するのに一番わかり易い.
ここでやるのは,Machine, Swarm, Composeではない,Engineのみ.
Getting Startedをやる.
Installation
$ curl -fsSL https://get.docker.com/ | sh
- in case of over-proxy
$ curl -fsSL https://get.docker.com/gpg | sudo apt-key add -
userをdokcer groupに登録して,デーモン登録してから
$ sudo usermod -aG docker $USER $ sudo sysv-rc-conf --level 456 docker on
logout or reboot
Run whalesay image
$ docker run docker/whalesay cowsay boo $ docker run docker/whalesay cowsay boo-boo $ docker run docker/whalesay ls / $ docker run docker/whalesay ls
Build your own image
以下の手順で作る
1. create directory
2. create/write Dockerfile in the diretory
3. build image from the Dockerfile
- (push the image to DockerHub)
- (run the image as a container)
Dockerfile
FROM docker/whalesay:latest # ベースとなるimage RUN apt-get -y update && apt-get install -y fortunes # commitされるコマンド CMD /usr/games/fortune -a | cowsay # default action, 1つだけ,複数あると最後のみ有効
を作って
docker build -t docker-whale ${Created Directory}
でimageができる.
確認
docker images
Create Docker Hub account & repository
dokcer hubにアクセスして作成すればいい.
Tag and Push your image
docker-whaleという名前のレポジトリができているので,namspace = docker hub accountをつける
docoker tag ${image id} ${namespace}/docker-whale:latest
pushする
$ dokcer login --username=${your account} $ docker push ${your account}/docker-whale:latest
pullする前に,rmi
$ docker rmi docker-whale ${your account}/docker-whale
pullする
$ docker pull ${your account}/docker-whale
確認
$ dokcer images
基本の理解を深める
Docker ハンズオンをみて,一部やってみるのがいい.
所感
git likeに使えていい.Dockerfileはgitで管理すればいいし,imageはDokcer Hubで管理すればいい.LXCよりは断然dokcerだと感じた.
あとは,公式Referenceを見ながらやるのがいいと思う.
ちょっと古いが,知らぬはエンジニアの恥。今さら聞けない【コンテナ/仮想化技術】11選に,この手の技術の表面的な説明が網羅されているので,参考になる.
用語
参考
- https://docs.docker.com/linux
- http://www.slideshare.net/zembutsu/introduction-to-docker-management-and-operations-basic
- http://qiita.com/kiida/items/059e34ea53c16e6bc9ec
- https://docs.docker.com/
- https://docs.docker.com/engine/reference/
- http://qiita.com/hihihiroro/items/6dda871dc2566801a6da
- http://paiza.hatenablog.com/entry/2014/10/21/%E7%9F%A5%E3%82%89%E3%81%AC%E3%81%AF%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E3%81%AE%E6%81%A5%E3%80%82%E4%BB%8A%E3%81%95%E3%82%89%E8%81%9E%E3%81%91%E3%81%AA%E3%81%84%E3%80%90%E3%82%B3%E3%83%B3
Computational Graphの実装概要
TF, CNTK, Theano, Caffe, Chainer等,巷にDNNライブラリはあふれている.DNNライブラリとはいかないまでも,自分でComputational Graphを実装してみたいと前から思っていたので,書いてみた.インターフェイスとしてすら,まだ全部出来ているわけではない.
概要
3つのクラス
- ComputationalGraph
- Vertex
- Edge
がある.
設計思想
こんな感じに積み木を積み上げるように使いたい.
v_in = Vertex("x") v1 = Edge(name="e0")(v_in) v2 = Edge(name="e1")(v1) v3 = Edge(name="e2")(v2, v1) # fork and concate v4 = Edge(name="e3")(v3) v5 = Edge(name="e4")(v4) ... v_in.forward() v_out.backward()
学習パラメータとグラフは分離させたいので,EdgeについてるパララメータもVertexとして扱いたい.すなわち,Edgeにパラメータを持たせないことで,グラフとパラメータの分離ができて,グラフを動的に構築しながら,foward/backwardができる.
DAGのSourcesでfowardってやって,DAGのDistinationsでbackwardてやると,それぞれ,inference, backpropをしてくれるようにしたい.
すなわち,v.foward() -> e.foward() -> v.forward() -> e.foward() ... な感じで連鎖的に,自分のfowardを呼んで,子供のfowardを呼んで,その子供のfowardを呼んで,というようにしたい.backwardはその逆で,自分のbackwardを呼んで,親のbackwordを呼んでといった感じ.
ComputationalGraph
Directed Acyclic Graphそののもで, G=(V, E), VertexとEdgeを持つ
Vertex
Edgeを通る前,および,通った後の入れ物として機能するコンテナ
Edge
任意のVertciesを受け取って,何かしらの操作をして,Vertexを返す
制約
- DAGである
- Edgeの入力/出力はVertex, Vetexの入力/出力はEdge
- Multi Graphでない, 複数Edgeが同じVertex間に存在してはならない
- Edgeは,複数のvertexを入力として良いが,出力vertexは1つ. すなわち,Edgeにおける,入力Vertex:出力Vertex=1-n:1
- Vertexは,複数のEdgeに入ってい良いし,全く入らなくても良い (=Distination). すなわち,Vertexにおける,入力Edge:出力Edge=1:0-n
- forward時,Edgeに複数入力がある場合は,全部の入力が揃うまで,子供Veretexのfowardは呼べない.
- backward時,Vertexに複数入力がある場合は,全部の入力が揃うまで,親Edgeののbackwardは呼べない.
残件 (順不同)
これ以上やらないと思うが,
- Activationの実装
- Convolutionの実装
- Computational Graph上にヘルパー関数forward/backwardの実装
- Optimizerの実装
- ComputatinalGraph上のグラフ操作系のヘルパー関数いろいろ
コード
Computational Graphにある.
サンプルは,ここにある.
所感
思ったより,Fork/Concateがややこしく,Edge.foward, Vertex.backwardがややこしくなっている.この実装がベストプラクティスなのか不明.現状,1 processで1graphが制約になっているのも不満.
mコマンドを触ってみた
mコマンド(mcmd)というものが耳に入ったのでひと通り触ってみた.
数億件くらいのCSVデータを効率的に集計処理できる
mコマンドとは
- join, uniq, sort, count, sum, aveなどの集計処理に使える
- in/outのフォーマットはCSV
- パイプが使えるので,他のunixコマンドと組み合わせられる
- 1台の標準PCでも数億件行のデータを効率よく処理できる
NYSOL
大規模データの解析に関する様々な大学やプロジェクトでの研究成果を
広く産業界に還元する目的で構築されたソフトウェアツールの総称およびそのプロジェクト活動である。
の元で配布しているらしいので,日本人くらいしか使っていないかもしれないことに注意.
インストール (Ubuntu14.04)
依存関連で足りなかったもの(他にもg++とかあるが)
- ruby-dev
- libboost
実際のインストールは,Donwloadから最新版を持ってきて,
$ ./configure
$ make
$ sudo make install
laptopで,1.0hrくらいかかった.この記事を書いている時点での最新版は,2.4.
shared libraryを認識させる
$ sudo ldconfig
注意点
CSVは
- 全行同じフィールド数
- 1行の最大バイト数はデフォルト,1MB (10MBまで拡張可能)
- 最終レコードでも改行は必要
- カンマを含むデータはダブルクオーツで囲む
- ダブルクオーツを含むデータは,ダブルクオーツで囲む,かつデータ中のダブルクオーツにダブルクオーツをつける
- 改行を含むデータもダブルクオーツで囲む
mchkcsvコマンドでチェック可能.
データ型
まとめるより,これを見る.インプットの全てのデータは文字列で表現されていることに注意.
項目指定
いろいろある.直感にあっているので,まとめるよりこれを見る.
パラメータ指定
まとめるより,これを見る.結構直感的.
- i: input file
- o: output file
- f: field for in:out
- s: sort key
- k: key of "group by"
コマンド例
- mcmdは,mxxxというコマンド郡の総称.mxxxがいっぱいある.
- サンプルデータは,DLしたtar.gzの中のdatasetディレクトリに入っている
ここで紹介されているコマンドを練習として扱う.
sort
$ msortf i=uci/iris.csv f=SepalLength
cut
$ mcut i=uci/iris.csv f=SepalLength,SepalWidth,Species
cut, uniq, then cal length
$ mcut i=uci/iris.csv f=Species | muniq k=Species | mcal c='length($s{Species})' a=Species_len o=uci/Species_len.csv
join
$ mjoin i=uci/iris.csv m=uci/Species_len.csv k=Species f=Species_len
cut, then count
$ mcut i=uci/iris.csv f=Species | mcount k=Species a=count_Species
select with condition
$ msel i=uci/iris.csv c='$s{Species}=="setosa" || $s{Species}=="versicolor"' $ msel i=uci/iris.csv c='$s{Species}=="setosa" && ${SepalLength}>5'
所感
実験結果をCSV形式で吐いて,それを解析するときに,grep, cut, sort, uniq, awk, sedとかのコマンドの組み合わせで処理するよりは便利かもしれない.ただし,全行同じフィールド数って言うのが結構辛い制約なので,正直,書捨て集計をする場合は,grep, cut, sort, uniq, awk, sedに慣れていたら,必要ないと思ってしまった.
「そんなことはない!こういうユースケースでは超使える」という意見がある人は,教えてくださいm(_ _ )m.
中規模データでロジックが必要な場合はnumpy, scipy, pandas使えばいいし,大規模データでロジックが必要な場合はSpark使えば良い.
個人的には,引き出しの一つとしてとっておく.
参考
- http://www.nysol.jp/
- http://www.nysol.sakura.ne.jp/mcmd2/jp/index.html
- http://www.nysol.jp/install
- http://www.nysol.sakura.ne.jp/mcmd2/jp/sect-datatype.html
- http://www.nysol.sakura.ne.jp/mcmd2/jp/sect-csv.html
- http://www.nysol.sakura.ne.jp/mcmd2/jp/sect-fieldname.html
- http://nakapara.jp/practice/about_mcmd
- http://www.slideshare.net/weda654/m-40991284
Dygraphs メモ
基本
Tutorialに書いてあることがすべて
- html
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/dygraph/1.1.1/dygraph-combined.js"></script>
- js
g2 = new Dygraph( document.getElementById("graphdiv2"), "temperatures.csv", // CSV 形式ならfileでなくてもOK {} // options );
TensorFlow: Sequence-to-Sequence Models
sequence 2 sequenceの学習の話.この記事を書いている時点で,TFのversionは,0.6.
データのダウンロード
cd tensorflow/models/rnn/translate python translate.py --data_dir [your_data_directory]
で,English to Frenchのデータセットのダウンロードが始まる.20GBくらいある.
seq2seqのライブラリは,ここにある.ただし実態は,こっち.
Sequence-to-Sequence Basics
まずは,RNN Encoder-Decoderの話から.RNN Encoder-Decoderは,Encoder (RNN)でインプットをEncodeし,fixed-length vectorにして,それをDecoder (RNN)のインプットにする.DecoderもRNNであって,そのfixed-length vectorをRNNのセルがいつも見に行く.たぶん,一番シンプルなAttentionと考えることもできると思う.しかし,fixed-length vectorしか見ないので,Input Vecotr SequenceのどこがOutput Vector Sequenceに効くのかよく分わからないので,Attentionの概念がでてくるのだと思う.EncoderとDecoderでは,パラメータをシェアしていてもいいし,一般的には,違うセル(異なるパラメータセット)を使ってもいい.
Attentionの細かい説明は,Bahdanu et al., 2014に書いてある.簡単にいうと,AttentionはRNN Encoder-Decoderにおいて,Decoderが,ステップの度に,Encoderの出力を覗き見ること.Bahdanu et al., 2014では,sequenceのannotationを覗き見ている.annotationは,forward hidden stateとbackward hidden stateを結合したものと定義している.そうすることで,word_iの周辺情報をみることができるので良いとのこと(BiRNNだと思う).
言語に限らず,画像関連でも使用される.これでは,フィルターを使ってどこを見るかをシークエンシャルに決めることで,Attention.これもAttentionで,次にどこみるかを決める.
これによると,RNNの次(というか延長でもう来ている)は,Attention!
Attentionのコード自体は,これの431行目あたりに書いてあって,decoder inputの度に呼ばれて,結合されている(ここの456行目からあたり).
TensorFlow seq2seq Library
基本これ.
outputs, states = basic_rnn_seq2seq(encoder_inputs, decoder_inputs, cell)
encoder_inputs, decoder_inputs, およびrnn cellを受け取って,decoderにおけるすべての,output, stateを返す.
Decoderのインプットは,普通,教師を使うのだが,学習時でもモデルをロバストにする目的やシークエンスの生成時には,Decoderの前のアウトプットを現在のインプットに使用する.
シンボルがin/outの場合は,embeddingが用意されている.
outputs, states = embedding_rnn_seq2seq(
encoder_inputs, decoder_inputs, cell,
num_encoder_symbols, num_decoder_symbols,
output_projection=None, feed_previous=False)
言語処理のように,symbolが非常に多い場合は,Sampled Softmaxを使う.それも用意されていて,ouput_projectionに (W, b)を入れればいい.
Neural Translation Model
Sampled softmax and output projection
Sampled Softmaxの話.num_symbolが512(default value)を超えない場合は,普通のSoftmaxを使った方が良いという話.
Bucketing and padding
Sequencesはそれぞれ,長さが異なるので,理想的には,すべての長さに対応するgraphを作りたいが,それは非効率的.長さが違う場合は,paddingをしたりするが,一番長いsequenceに合わせると,短いsequenceは過度にpaddingされてしまう.なので,妥協案として,bucketing and paddingをする.
これの766行目あたりからをみるとbucket毎に,モデルを作っている様に見える.これらをこれの161行目あたりで,bucket毎(モデル毎)でlossのgradとっている.(全データが全部のバケットに入っている様に見えるのは気のせいだろうか...)
Let's Run It
取り敢えず動かしたいなら,DLが終わった後,
python translate.py \ --data_dir [your_data_directory] --train_dir [checkpoints_directory] \ --en_vocab_size=40000 --fr_vocab_size=40000 \
代替,batch-size 64で,340K steps くらいすると,bucket0, bucket1はperplexity的にいい感じになってきて,予測ができる.
python translate.py \ --data_dir [your_data_directory] --train_dir [checkpoints_directory] \ --size=256 --num_layers=2 --steps_per_checkpoint=50 \ Reading model parameters from /tmp/translate.ckpt-340000 > Who is the president of the United States? Qui est le président des États-Unis ?
What Next?
上記はseq2seqだったけど,同じモデルが,seq2treeのようにparserとしても使える.Vinyals & Kaiser et al., 2015は,それ系のタスクでstate-of-the-artらしい.
参考
- https://www.tensorflow.org/versions/v0.6.0/tutorials/seq2seq/index.html#sequence-to-sequence-models
- http://arxiv.org/pdf/1409.0473v6.pdf
- http://arxiv.org/pdf/1502.04623.pdf
- http://arxiv.org/pdf/1406.6247v1.pdf
- http://colah.github.io/posts/2015-08-Understanding-LSTMs
- http://www.statmt.org/wmt15/translation-task.html
TensorFlow: Python API: Transformation
記事を書いている時点では,v6.0なので注意
Casting
- tf.string_to_number
- tf.to_double
- tf.to_float
- tf.to_bfloat16
- tf.to_int32
- tf.to_int64
- tf.cast
特に言及なし.
Shapes and Shaping
- tf.shape
- tf.size
- tf.rank
- tf.reshape
- tf.squeeze
- tf.expand_dims
rankはTensorの次元数を返す
squeezeは,dim=1のテンソルの次元を削除.
expand_dimsは,dim=1のテンソルの次元を追加. batchsize=1のサンプルを作るのによく使用される.
Slicing and Joining
- tf.slice
- tf.split
- tf.tile
- tf.pad
- tf.concat
- tf.pack
- tf.unpack
- tf.reverse_sequence
- tf.reverse
- tf.transpose
- tf.gather
- tf.dynamic_partition
- tf.dynamic_stitch
reverse_sequenceは,逆向きにデータを突っ込むorBiRNNのために用意されているような感じを受ける.サンプル(sequenceとなっている前提)毎に,sequcneを反転させる.
gatherは,もともとのtensorから必要なindeciesのみ集める.
dynamic_stitchは,n個のTensorを指定したindicesでつなぎ合わせる感じ.
indiciesが2d-tensorの場合は,
merged[indices[m][i], ...] = data[m][i, ...]
のようになるので,
- len(data) = indices.shape[0]
- data[j][0] = indices.shape[1] for any j
- indicesのエレメントは,0: len(data) * len(data[j].shape[0])で, uniqueな値を取る
が条件のようではある.