Translate

2017年2月22日水曜日

旧バージョンのTensorFlowコードを 1.0 で動作するように変更する

TensorFlow Dockerコンテナを作り直したら
タグlatest-py3を指定していたため、
最新のTensorFlow 1.0に変わってしまった。

0.12で動いていたコードが動作しなくなった。

実際には、

TensorFlowのSeq2Seqモデルでチャットボットっぽいものを作ってみた
http://qiita.com/sanshirookazaki/items/128bf1b5a898ad5c18f1

をちょっと手直しして動かしていたのだけど..

・パッケージ移動
  tensorflow.models.rnn.rnn_cell → tensorflow.contrib.rnn.core_rnn_cell
 tensorflow.models.rnn.seq2seq → tensorflow.contrib.legacy_seq2seq

・シグニチャ変更
 legacy_seq2seq.model_with_buckets() の引数からボキャブラリサイズが消える。
 代わりにlegacy_seq2seq.embedding_attention_seq2seq() の引数にembedding_sizeを指定する型式に。


..っていうか、Attention付きSeqence-to-Sequnece がもはや legacy_seq2seq なの?!
ってほうに驚いたが、話を戻して..

TensorFlow 1.0 になったのが2月15日だから、いろんなところで「ギャッ!」と叫んでいてもおかしくないのに..みんな静かなのは何故だろう..

なんとか楽して修正したい..とおもって本家ページを覗いてみたら

Transitioning to TensorFlow 1.0
https://www.tensorflow.org/install/migration

なるページを見つけた。

以下、勝手翻訳の内容だ。
(At your own riskで参照のこと)
---------

TensorFlow 1.0 への移行


TensorFlow 1.0のAPIは、すべて後方互換性のある方法で変更されています。 つまり、TensorFlow 0.nで動作するTensorFlowプログラムは、必ずしもTensorFlow 1.0では動作しません。 私たちは内部的に一貫したAPIを保証するためにこのAPIを変更し、1.Nのライフサイクル全体にわたって後方修正の変更を行うつもりはありません。

このガイドでは、APIの主な変更点と、TensorFlow 1.0のプログラムを自動的にアップグレードする方法について説明します。 このガイドでは、変更の手順を説明するだけでなく、変更の理由を説明します。

アップグレードする方法


コードを1.0に自動的に移植したい場合は、tf_upgrade.py スクリプトを試してみてください。 このスクリプトは多くのケースを処理しますが、手動による変更が必要な場合もあります。 このスクリプトをGitHubツリーから入手してください。


1つの 0.n TensorFlow ソースファイルを 1.0 に変換するには、次の形式のコマンドを入力します。


$ python tf_upgrade.py --infile 入力ファイル --outfile 出力ファイル

たとえば、次のコマンドは、 test.py という名前の 0.10 TensorFlow プログラムを test_1.0.py という名前の 1.0 TensorFlow プログラムに変換します:

$ python tf_upgrade.py --infile test.py --outfile test_1.0.py

たとえば、次のコマンドは /home/user/cool ディレクトリにあるすべての 0.n TensorFlow プログラムを変換し、 /home/user/cool_1.0 ディレクトリに 1.0 コードを作成します。


$ python tf_upgrade.py --intree /home/user/cool --outtree /home/user/cool_1.0


制限事項


注意すべき制限事項がいくつかあります:
 

  • tf.reverse() インスタンスは手動で修正する必要があります。 tf_upgrade.py スクリプトは stdout report.txt ファイルの tf.reverse() について警告します。
  • 並べ替えられた引数では、 tf_upgrade.py はコードの最小限の再フォーマットを試みるため、実際の引数の順序を自動的に変更することはできません。 代わりに、 tf_upgrade.py は、キーワード引数を導入することによって、関数呼び出しを順序に依存しないようにします。
  • tf.get_variable_scope().reuse_variables() のような構築はうまくいかないでしょう。 これらの行を削除し、次のような行に置き換えることをお勧めします。
   with tf.variable_scope(tf.get_variable_scope(), reuse=True):
     ...
  • tf.pack および tf.unpack と同様に、 TensorArray.pack および TensorArray.unpack は、 TensorArray.stack および TensorArray.unstack に名前が変更されました。 しかし、 TensorArray.pack および TensorArray.unpack は、それらが tf 名前空間に間接的に関連しているので、語彙的に検出することはできません。 e.g. foo = tf.TensorArray(); foo.unpack()

コードを手動でアップグレード


tf_upgrade.py を実行する代わりに、コードを手動でアップグレードすることができます。 このドキュメントの残りの部分では、 TensorFlow 1.0 で行われた後方互換性のない変更の包括的な一覧を示します。

Variables


Variable 関数はより一貫性があり、混乱も少なくなっています。
 

  • tf.VARIABLES
  • tf.GLOBAL_VARIABLES に名前を変更する必要があります。
  • tf.all_variables
  • tf.global_variables に名前を変更する必要があります。
  • tf.initialize_all_variables
  • tf.global_variables_initializer に名前を変更する必要があります。
  • tf.initialize_local_variables
  • tf.local_variables_initializer に名前を変更する必要があります。
  • tf.initialize_variables 
  • tf.variables_initializer に名前を変更する必要があります。


サマリ関数


サマリ関数は、 tf.summary 名前空間の下で統合されています。
 

  • tf.audio_summary
  • tf.summary.audio に名前を変更する必要があります。
  • tf.contrib.deprecated.histogram_summary
  • tf.summary.histogramに名前を変更する必要があります。
  • tf.contrib.deprecated.scalar_summary
  • tf.summary.scalarに名前を変更する必要があります。
  • tf.histogram_summary
  • tf.summary.histogramに名前を変更する必要があります。
  • tf.image_summary
  • tf.summary.imageに名前を変更する必要があります。
  • tf.merge_all_summaries
  • tf.summary.merge_allに名前を変更する必要があります。
  • tf.merge_summary
  • tf.summary.mergeに名前を変更する必要があります。
  • tf.scalar_summary
  • tf.summary.scalarに名前を変更する必要があります。
  • tf.train.SummaryWriter
  • tf.summary.FileWriterに名前を変更する必要があります。


数値の違い


整数除算と tf.floordiv はフローリングのセマンティクスを使用するようになりました。これは、 np.dividenp.mod の結果をそれぞれ tf.divide tf.mod と一致させるためです。さらに、 NumPy と一致させるために tf.round によって使用される丸めアルゴリズムを変更しました。

  • tf.div
  • tf.divide 除算のセマンティクスは、 Python セマンティクスに完全に一致するように変更されました。つまり、 Python3 の / と Python 2の将来の除算モードは常に浮動小数点数を生成し、 // は床除算を生成します。しかし、 tf.div でも整数床除算されます。 Cスタイルの切り捨てセマンティクスを強制するには、 tf.truncatediv を使用する必要があります。
  • プロモーションのためにPythonのセマンティクスに従った tf.divide を使用するようコードを変更することを検討してください。


  • tf.mod
  • tf.mod セマンティクスは Python セマンティクスに合わせて変更されました。特に、整数には床関数のセマンティクスが使用されます。 Cスタイルの切り捨て mod (剰余)を使いたい場合は、 tf.truncatemod を使います。

除算の古い動作と新しい動作は、以下の表のとおりです:
TF 0.11 (py2)TF 0.11 (py3)TF 1.0 (py2)TF 1.0 (py3)
tf.div(3,4)0000
tf.div(-3,4)00-1-1
tf.mod(-3,4)-3-311
-3/40-0.75-1-0.75
-3/4tf.divide(-3,4)N/AN/A-0.75-1


丸め演算(rounding)の古い動作と新しい動作は、以下の表のとおりです:

InputPythonNumPyC++ round()TensorFlow 0.11(floor(x+.5))TensorFlow 1.0
-3.5-4-4-4-3-4
-2.5-2-2-3-2-2
-1.5-2-2-2-1-2
-0.500-100
0.500110
1.522222
2.522332
3.544444

NumPyの名前マッチング


多くの関数が NumPy にマッチするように名前が変更されました。これは NumPy と TensorFlow の間の移行を可能な限り簡単にするために行われました。 関数が一致しない多くのケースがまだありますので、これは難しくて速いルールとは異なりますが、いくつかの共通の矛盾点を削除しました。
 

  • tf.inv
  • tf.reciprocal に名前を変更する必要があります。
  • これは、 NumPy の行列 inverse np.inv との混乱を避けるために行われました。

  • tf_list_diff
  • tf.setdiff1d に名前を変更する必要があります。

  • tf.listdiff
  • tf.setdiff1d に名前を変更する必要があります。

  • tf.mul
  • tf.multiply に名前を変更する必要があります。

  • tf.neg
  • tf.negative に名前を変更する必要があります。

  • tf.select
  • tf.where に名前を変更する必要があります。
  • tf.wherenp.where のように3つの引数または1つの引数をとるようになりました。

  • tf.sub
  • tf.subtractに名前を変更する必要があります。


NumPyの引数マッチング


特定の TensorFlow 1.0 メソッドの引数は、特定の NumPy メソッドの引数と一致するようになりました。 これを達成するために、 TensorFlow 1.0 はキーワード引数を変更し、いくつかの議論を並べ替えました。 特に、 TensorFlow 1.0 は次元ではなく軸を使用するようになりました。 TensorFlow 1.0 は、テンソルを変更する操作で最初にテンソル引数を保持することを目的としています( tf.concat の変更を参照してください)。

  • tf.argmax キーワード引数の次元をaxisに変更する必要があります。

  • tf.argmin
  • キーワード引数の次元をaxisに変更する必要があります。

  • tf.concat 
  • キーワード引数concat_dimの名前をaxisに変更する必要があります。
  • 引数はtf.concat(value、axis、name = 'concat')に並べ替えられています。

  • tf.count_nonzero 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。

  • tf.expand_dims 
  • キーワード引数のdimaxisに変更する必要があります。 

  • tf.reduce_all 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。

  • tf.reduce_any 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。 

  • tf.reduce_join 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。

  • tf.reduce_logsumexp 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。

  • tf.reduce_max 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。

  • tf.reduce_mean 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。

  • tf.reduce_min 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。

  • tf.reduce_prod 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。

  • tf.reduce_sum 
  • キーワード引数reduction_indicesの名前をaxisに変更する必要があります。 

  • tf.reverse 
  • tf.reverseはどの次元が逆転したかを制御するために1Dブールテンソルをとるのに使われました。今度は軸インデックスのテンソルを使用します。
  • たとえば、tf.reverse(a、[True、False、True])tf.reverse(a、[0、2])でなければなりません。

  • tf.reverse_sequence 
  • キーワード引数batch_dimの名前をbatch_axisに変更する必要があります。
  • キーワード引数seq_dimの名前をseq_axisに変更する必要があります。

  • tf.sparse_concat 
  • キーワード引数concat_dimの名前をaxisに変更する必要があります。

  • tf.sparse_reduce_sum 
  • キーワード引数reduction_axesの名前をaxisに変更する必要があります。

  • tf.sparse_reduce_sum_sparse 
  • キーワード引数reduction_axesの名前をaxisに変更する必要があります。 

  • tf.sparse_split 
  • キーワード引数split_dimの名前をaxisに変更する必要があります。
  • 引数はtf.sparse_split(keyword_required = KeywordRequired()、sp_input = None、num_split = None、axis = None、name = None、split_dim = None)に並べ替えられています。 

  • tf.split 
  • キーワード引数split_dimの名前をaxisに変更する必要があります。
  • キーワード引数num_splitの名前をnum_or_size_splitsに変更する必要があります。
  • 引数はtf.split(value、num_or_size_splits、axis = 0、num = None、name = 'split')に並べ替えられています。 

  • tf.squeeze 
  • キーワード引数squeeze_dimsの名前をaxisに変更する必要があります。 

  • tf.svd 
  • 引数はtf.svd(tensor, full_matrices = False, compute_uv=True, name = None)に並べ替えられています。


簡略化された数学演算


バッチバージョンの数学演算は削除されました。今や機能はバッチ処理されていないバージョンに含まれています。同様に、 tf.complex_abs はその機能を tf.abs に移動しました。

  • tf.batch_band_part
  • tf.band_partに名前を変更する必要があります。

  • tf.batch_cholesky
  • tf.choleskyに名前を変更する必要があります。

  • tf.batch_cholesky_solve
  • tf.cholesky_solveに名前を変更する必要があります。

  • tf.batch_fft
  • tf.fftに名前を変更する必要があります。

  • tf.batch_fft3d
  • tf.fft3dに名前を変更する必要があります。

  • tf.batch_ifft
  • tf.ifftに名前を変更する必要があります。

  • tf.batch_ifft2d
  • tf.ifft2dに名前を変更する必要があります。

  • tf.batch_ifft3d
  • tf.ifft3dに名前を変更する必要があります。

  • tf.batch_matmul
  • tf.matmulに名前を変更する必要があります。

  • tf.batch_matrix_determinant
  • tf.matrix_determinantに名前を変更する必要があります。

  • tf.batch_matrix_diag
  • tf.matrix_diagに名前を変更する必要があります。

  • tf.batch_matrix_inverse
  • tf.matrix_inverseに名前を変更する必要があります。

  • tf.batch_matrix_solve
  • tf.matrix_solveに名前を変更する必要があります。

  • tf.batch_matrix_solve_ls
  • tf.matrix_solve_lsに名前を変更する必要があります。

  • tf.batch_matrix_transpose
  • tf.matrix_transposeに名前を変更する必要があります。

  • tf.batch_matrix_triangular_solve
  • tf.matrix_triangular_solveに名前を変更する必要があります。

  • tf.batch_self_adjoint_eig
  • tf.self_adjoint_eigに名前を変更する必要があります。

  • tf.batch_self_adjoint_eigvals
  • tf.self_adjoint_eigvalsに名前を変更する必要があります。

  • tf.batch_set_diag
  • tf.set_diagに名前を変更する必要があります。

  • tf.batch_svd
  • tf.svdに名前を変更する必要があります。

  • tf.complex_abs 
  • tf.absに名前を変更する必要があります。


その他の変更点


次のような変更が加えられました。



  • tf.image.per_image_whitening
  • tf.image.per_image_standardizationに名前を変更する必要があります。

  • tf.nn.sigmoid_cross_entropy_with_logits 
  • 引数はtf.nn.sigmoid_cross_entropy_with_logits(_sentinel = None、labels = None、logits = None、name = None)に並べ替えられています。

  • tf.nn.softmax_cross_entropy_with_logits 
  • 引数はtf.nn.softmax_cross_entropy_with_logits(_sentinel=None, labels=None, logits=None, dim=-1, name=None)に並べ替えられています。

  • tf.nn.sparse_softmax_cross_entropy_with_logits 
  • 引数はtf.nn.sparse_softmax_cross_entropy_with_logits(_sentinel = None、labels = None、logits = None、name = None)に並べ替えられています。

  • tf.ones_initializer 
  •  関数呼び出し、すなわちtf.ones_initializer()に変更する必要があります。

  • tf.pack
  • tf.stackに名前を変更する必要があります。

  • tf.round
  • tf.roundのセマンティクスは、Bankerの丸めと一致するようになりました。

  • tf.unpack
  • tf.unstackに名前を変更する必要があります。

  • tf.zeros_initializer 
  • 関数呼び出し、すなわちtf.zeros_initializer()に変更する必要があります。


以上

------

なるほど、tf_upgrade.py っていうツールを用意していたのね。
でも、それだけじゃ直しきらないからその分はココにある通り直してね..
か..

まあないよりましか。

ついでに tf_upgrade.py のありか

TensorFlow Python API Upgrade Utility
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/tools/compatibility

のトップページだけ翻訳したのが、以下の内容。
(こちらも at your own risk でお願いします)
------

TensorFlow Python APIアップグレードユーティリティ


このツールを使用すると、既存の TensorFlow Python スクリプトをアップグレードできます。このスクリプトは単一の Python ファイルで実行できます:

$ tf_upgrade.py --infile foo.py --outfile foo-upgraded.py


修正できないエラーのリストを出力します。ディレクトリツリー上で実行することもできます。

$ tf_upgrade.py --intree coolcode --outtree coolcode-upgraded


いずれの場合も、レポートを破棄する。変更の詳細は次のようになります。

third_party/tensorflow/tools/compatibility/test_file_v0.11.py Line 125

Renamed keyword argument from `dim` to `axis`
Renamed keyword argument from `squeeze_dims` to `axis`

    Old:                   [[1, 2, 3]], dim=1), squeeze_dims=[1]).eval(),
                                        ~~~~    ~~~~~~~~~~~~~
    New:                   [[1, 2, 3]], axis=1), axis=[1]).eval(),
                                        ~~~~~    ~~~~~

警告


このスクリプトを実行する前に、コードの一部を手動で更新しないでください。特に、 tf.concat tf.split のような引数を並べ替えた関数は、引数に不一致を示すキーワード引数をスクリプトが誤って追加する原因になります。

このスクリプトは実際に引数を並べ替えません。その代わりに、スクリプトは、引数が並べ替えられた関数にキーワード引数を追加します。

このスクリプトは、すべての機能をアップグレードすることはできません。 1つの顕著な例は tf.reverse() であり、テンソルの bool ではなくインデックスのリストを取るように変更されています。スクリプトがこれを検出すると、これを stdout(およびレポート)に報告し、手動で修正することができます。たとえば、 tf.reverse(a, [False, True, True]) がある場合は、手動で tf.reverse(a, [1, 2]) に変更する必要があります。

このスクリプトは標準の Python パッケージのみを使用するように設計されているため、このスクリプトでは扱えない構文もあります。スクリプトが「必要なキーワード引数を挿入できませんでした。(A necessary keyword argument failed to be inserted.)」で失敗した場合または 「辞書検索でキーワードを見つけることができませんでした。手動で修正してください。(Failed to find keyword lexicographically. Fix manually.)}で失敗した場合、 @machrisaa's fork of this script を試してみてください。@machrisaaRedBaron Pythonリファクタリングエンジン を使用しています。このエンジンは、このスクリプトがベースになっている組み込みの @ast@ モジュールより構文要素をより確実にローカライズできます。

以上

---------

なるほど..

でも、さっきのコードは自前で直しちゃったしな..

次の機会にでも使ってみるか..




でも、TensorFlowを去年からやってる人は
Python2 → Python3 にいつ代えるか問題
という大問題をかかえてるし..

なんたってサンプルがpython2 前提が多かったもんだから
python2 ではじめた人が以外に多くって、
CentOSやUbuntuのデフォルトも python3 へうつってきているのだけど
Python2 と Python3 は文字コードの処理で動きが違うんだよなあ..
asciiコードでなんとかなる欧米人は良いだろうけど、
日本語データをコーパスにしている日本人にはキツイのよ..

でもDockerHub側も tensorflow/tensorflow に移動になったタイミングかはわからないけど、
Python3のコンテナも登場したしなあ..

しかも先日のDev Summitでしれっと、こんなのだしてたし..



これって、つまりcontribからcoreのほうへパッケージ大移動が今後も続くってことじゃん..


..やっぱKerasとEstimatorだな..

2017年2月17日金曜日

TensorFlow for Java の README.md を翻訳してみて、邪推が外れたことを知る

 前々々日(2017/2/15)にGoogleがTensorFlow1.0をリリースしたと発表した。

Google、機械学習ライブラリ「TensorFlow 1.0」正式版を初リリース
http://cloud.watch.impress.co.jp/docs/news/1044644.html


でも先週末ころに TensorFlow の Java リンクがGitHubに変わっていたので
なんとなく
そろそろ1.0くるな
でJava実装もお披露目かな、と
わかってはいたのだけど..

ということで、

[GitHub] TensorFlow for Java
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/java/README.md

を翻訳してみた。

参照する場合は at your own risk でお願いします。


----------

TensorFlow for Java


TensorFlowライブラリのJavaバインディングです。


注意: TensorFlow Java APIは不完全で実験的なものであり、予告なく変更することがあります。 Issue #5 で進展を確認することができます。それまでは、TensorFlowをAndroidで使用するには、 contrib/ android 、 makefile または/もしくはAndroidのカメラデモを参照してください。

前提条件

  • bazel
  • TensorFlowをソースコードから構築するための環境(LinuxまたはMac OS X)。これらの詳細を読み飛ばしてGPUサポートを気にしない場合は、次のようにしてください:
# On Linux
sudo apt-get install python swig python-numpy

# On Mac OS X with homebrew
brew install swig

インストール


Javaアーカイブ(JAR)とネイティブライブラリを設定してビルドする:
# ビルドを設定します(e.g. GPUサポートなど)
# https://www.tensorflow.org/get_started/os_setup#configure_the_installation
./configure

# JARおよびネイティブライブラリをビルドします
bazel build --config opt \
  //tensorflow/java:tensorflow \
  //tensorflow/java:libtensorflow_jni

Maven


外部Javaプロジェクトでライブラリを使うためには、Mavenリポジトリに公開します。たとえば、 mvm ツール(別途インストール)を使用してライブラリをローカルの Maven リポジトリへ公開します:
bazel build -c opt //tensorflow/java:pom
mvn install:install-file \
  -Dfile=../../bazel-bin/tensorflow/java/libtensorflow.jar \
  -DpomFile=../../bazel-bin/tensorflow/java/pom.xml

Maven座標を使用してライブラリを参照してください。 たとえば、Mavenを使用している場合は、この依存関係を pom.xml ファイルに置きます(使用する TensorFlow ランタイムのバージョンで文字列 0.12.head を置き換えます)。
<dependency>
  <groupId>org.tensorflow</groupId>
  <artifactId>libtensorflow</artifactId>
  <version>0.12.head</version>
</dependency>

サンプル

bazel 使用

//tensorflow/java:tensorflow への依存関係を java_binary または java_library ルールに追加します。例えば:
bazel run -c opt //tensorflow/java/src/main/java/org/tensorflow/examples:label_image

javac 使用


コンパイルのためにクラスパスに libtensorflow.jar を追加してください。たとえば:
javac \
      -cp ../../bazel-bin/tensorflow/java/libtensorflow.jar \
      ./src/main/java/org/tensorflow/examples/LabelImage.java

実行中 libtensorflow.jar および libtensorflow_jni.so(OS Xの libtensorflow_jni.dylib )を使用可能にします。 例えば:
java \
      -Djava.library.path=../../bazel-bin/tensorflow/java \
      -cp ../../bazel-bin/tensorflow/java/libtensorflow.jar:./src/main/java \
      org.tensorflow.examples.LabelImage

以上
---------


TensorFlowの本質はPythonではなくC++ライブラリの方なので、
Javaからは直接C++ライブラリをJNIで活用する仕組みになっている。

主要なクラスは、以下の通り。

Graph クラス: 
TensorFlow計算を表すデータフローグラフ。

Operation クラス:
Tensorsで計算を実行するグラフノード。

OperationBuilder クラス:
グラフ操作のためのビルダクラス。

Output クラス:
Operationクラスによって生成されたテンソルのシンボリックハンドル。

Session クラス:
Graph 実行のためのドライバ。

Session.Run クラス:
セッション実行の際に得られるテンソルとメタデータを内包。

Session.Runner クラス:
Operation を実行し、 Tensor を評価する。

Shape クラス;
操作によって生成されるテンソルの部分的に既知である型式。

Tensor クラス:
多次元配列の型。

TensorFlow クラス:
TensorFlow実行状態を記述する静的ユーティリティメソッド。

あと、列挙型と例外クラスが1つづつ。

列挙型 DataType :
Tensorの要素タイプ。

例外クラス TensorFlowException :
TensorFlowグラフ実行中にスローされる、チェックされていない例外。



GitHubにサンプルコードが1つだけはいっていたので
のぞいてみると、
TensorFlow計算グラフをビルドするところは
GraphインスタンスをGraphBuilderクラスで定義するようで
ちょうどStringBuilderで文字列をがしがしつないでいくところと同じ感じで実装するようだ。
ただ、つくるのはGraphインスタンスではなく
Outputクラスというグラフの結果をもらう部分である。
注意するのはこのGraphBuilderクラスはTensorFlow側ライブラリのクラスではなく
このクラスのインナークラスになっていて中身はGraphインスタンスから
OperationBuilderインスタンスを取ってきてOperationつまりノードを定義していく。

..なんだかなあ..サンプルでそうしてるんなら、ライブラリ設計の時
もうちょっと頑張ってよ..

ならkerasのクラスをそのままJavaクラス化すればいいのに
それをしないのはKeras←→TensorFlowで書かれているPythonコードをJava化しないと
いけないからだろうなあ..


TensorFlow計算グラフ(Graphインスタンス)を実行するには、
Pythonと同じで、
Sessionインスタンスをnew して、Session.Runner インスタンスをもらい実行するのだけど
Pythonから予測するとその際にOperationインスタンスを指定するのだけど、
さきほどのOutputインスタンスからとってくるらしい。

このサンプルは学習済みInceptionモデルを復元して使っているようで
肝心のバッチを作って訓練する所がない..

TensorFlow for Java の設計は
 おそらくJavaを知っている人ではなく、
確実にTensorFlow/Pythonを知っているけどJavaはそれほど知らない人じゃないかな..

そうでないとこんなJDBCみたいなAPIつくらんでしょ..

Kerasのようなライブラリが
ぜったいJavaのAPIになるとおもっていたのだけど、
Oracleがハンドルし始めて黄昏を迎えているJava
コミュニティはもうとっくの昔に何処かへちっていってしまったのだろうか..

2017年2月3日金曜日

IBM Watson NLC と TensorFlow で実装した簡単なCNN モデルを比較してみた


IBM Watson の NLC は
1000文字までの文章と分類名のペア
を学習データとして投入した分類器を作成できる
サービスだ。

最近は日本語書籍も出ており、
Watson Toolkitという
curlを打てなくても使えるお手軽さ
はよくできているとおもう。

NLCの裏側はオープンになっていないので
どんなアルゴリズムでどんな事前学習が行われているかは
APIを活用するユーザ側にはさっぱりわからない。

巷の評価は、いわゆるオープンなデータセットをつかっていて
それを元に比較しているので、
どうも

「催眠術師の仲間から選んだ人に催眠術を書ける術士」

みたいで眉唾だ..

ということで、
データセットをコッチで用意した。

某テキストの文章を1文づつ切り出し、
その文章の分類名を、全セクション134で切り分けてみた。

学習データ(X_train, y_train):2000件
バッチ用テストデータ(X_test, y_test):140件
評価用データ(X_eval, y_eval):55件

とかなり少ないが、
実際にNLCと
データ編集が比較的近くてやりやすい
https://github.com/tkengo/tf/tree/master/cnn_text_classification
のサンプルコードを使って
評価用データの

・正解率
 最も頻度が高い分類が合致した件数を、全質問数う(55)で割ったもの

・正解選択ヒット率
 トップ10までにある場合は、荷重づけした特点を
 F1の1位から10位までのポイント制で1を按分した数加えたスコアを、
 全質問数(55)でわったもの。

の二つを出してみた。




..正直、おはなしにならんくらい独自実装のほうが使い物にならん

どうもこのデータセットだと
分類種類の多さにくらべデータ件数が少なすぎるようで
ちっとも学習できていない..

これじゃIBM社員を、ますまずその気にさせてしまう..


でも..
箸にも某にもつかないダメデータセットでも
それなりの成績を出すNLCの事前学習度合いが
箱入り娘級の調教具合..

有償サービスにするにはこれより良い成績ださないと
話にならないか...

2017年1月19日木曜日

Keras の概要を読んで、邪推する

TensofFlowを勉強している私に
簡単にコードが書ける Kersa というものがあり、
TensorFlowをラップしているらしいよ
と教えてくれる人がいたので
Kerasの概要を勉強してみた。

TensorFlow のときとは違って既に日本語化ドキュメントが
用意されており、
6~7割TensorFlowサイトをGoogle翻訳して読んでいたので
サクリと読むことができた。

TensorFlowのAPIをラップしたライブラリなので
基本機械学習フレームワークであるのだけど、
たしかに

むっちゃ簡単

なのである。

何が簡単かというと、なによりコードが読みやすい


TensorFlowは設計者の意図を理解するまで
なかなか把握しにくいAPIになっている。

高速なC/C++実装をPythonコードでモデル記述し、セッションを実行するため、
TensorFlow は上から下に必ずしも処理されない。

しかもPython上のリテラルをC/C++実装上の変数・配列格納領域へrunする時に渡す
というところが、ベタ読みする開発者にとって無駄としか思えない。


だが Kerss のライブラリは、
オブジェクト指向
設計を行っている。


Modelをインスタンス化して、
シーケンシャルな多層パーセプトロンの場合
順番にインスタンス化したLayerインスタンスadd()していき、
できあがったModelインスタンスに対して、
compile()/fit()で学習、evaluate()で評価する。

上から下に読めば簡単に理解できる

Layerは独自のものも作れるコンポジットな設計だし、
add()して一気に処理するアタリはApplet/Swingなどの設計と同じだ。



IBMやSBのWatsonや
Google API、
Microsoft Cognitive APIなどの他力を嫌う
オンプレミス至上主義の多い日本企業では
機械学習の独自実装はじつは喉から手が出るほど欲しい


で TensorFlow をためそうとするのだけど、
先程書いたとおり
コードの可読性が極めて悪い

しかもキチンと機械学習を理解していないと
何をインプットにして、何をアウトプットにすれば良いのか
どのパターンでどういうモデルを使い分ければ良いのかすら
わからない..

勉強するには TensorFlowのチュートリアルコード
読まないといけないのだけど、
TensorFlowはガンガンバージョンアップして
チュートリアルコードがdeprecatedされた関数で
動かないものも少なくない。

しかもGoogleの提供するTensorFlowサイトは
機械学習に関する知識ベースで解説を組んでいて
こまかいどの変数がどういう意味を持ってここで加算してるのかとか
ちくちく説明してくれていない..


そこでこのKeras
そらみんな飛びつくよなあ..



個人的には TensorFlow の Java実装になってくれないか..

!そうか
Kerasの狙いは

Java機械学習標準ライブラリ狙い

か!


..ありうる話だ。


という与太話で記事を終えるのも申し訳ないので
KerasサンプルコードのGitてっぺんにある README.mdを翻訳した
以下にリストを残しておく。

参照の際は、
At your own riskでお願いします。
----

Keras サンプルディレクトリ


[addition_rnn.py]
2つの(文字列としての)数値の加算実行によるSequence-to-Sequence 実装の学習

[antirectifier.py]
Kerasにおけるカスタムレイヤの記述方法のデモ

[babi_memnn.py]
文章読解のための、bABlデータセット上のメモリネットワークのトレーニング


[babi_rnn.py]
文章読解のための、bAbIデータセット上の 2 分岐 recurrent networkのトレーニング

[cifar10_cnn.py]
CIFAR10の小さな画像データセットを使った、シンプルなディープCNNのトレーニング

[conv_filter_visualization.py]
入力スペースの勾配降下法によるVGG16フィルタの可視化

[conv_lstm.py]
畳み込みLSTMネットワークを使ったデモ

[deep_dream.py]
Kerasの深い夢(実行例)

[image_ocr.py]
畳み込みスタックとそれに続く反復スタックとCTCログ損失機能をトレーニングすることによる光学式文字認識(OCR)の実行

[imdb_bidirectional_lstm.py]
IMDBセンチメント分類タスク上において双方向LSTMをトレーニング

[imdb_cnn.py]
Convolution1Dをテキスト分類に使用するデモ

[imdb_cnn_lstm.py]
IMDBセンチメント分類タスクにおいてrecurrent stack networkが後続する畳み込みスタックのトレーニング

[imdb_fasttext.py]
IMDBセンチメント分類タスクにおけるFastTextモデルのトレーニング

[imdb_lstm.py]
IMDBセンチメント分類タスクにおけるLSTMをトレーニング

[lstm_benchmark.py]
IMDBセンチメント分類タスクにおいて異なるLSTM実装を比較

[lstm_text_generation.py]
ニーチェの著作からテキストを生成

[mnist_acgan.py]
MNISTデータセットにおけるAC-GAN(Auxiliary Classifier GAN)の実装

[mnist_cnn.py]
MNISTデータセットを使った簡単なconvnetの作成

[mnist_hierarchical_rnn.py]
MNIST数字分類において階層型RNN(HRNN)をトレーニング

[mnist_irnn.py]
Le氏ほかによる論文「整流化された線形単位の再帰的ネットワークを初期化する方法」における pixcel-by-pixcel のシーケンシャルなMNIST実験の再現

[mnist_mlp.py]
MNISTデータセットにおける単純なディープな多層パーセプトロンのトレーニング

[mnist_net2net.py]
「Net2Net:知識移転による加速学習」におけるMNISTによるNet2Net実験の再現

[mnist_siamese_graph.py]
MNISTデータセットからの数字のペアを入力とした Siamese(シャム人の) 多層パーセプトロンをトレーニング

[mnist_sklearn_wrapper.py]
sklearnラッパ使用方法のデモ

[mnist_swwae.py]
MNISTデータセットの残りのブロックに基づいた スタックされたWhat-Where AutoEncoderのトレーニング

[mnist_transfer_cnn.py]
翻訳学習玩具の例

[neural_doodle.py]
ニューラルいたずら書き

[neural_style_transfer.py]
ニューラルスタイル変換

[pretrained_word_embeddings.py]
凍結したKeras 埋め込みレイヤに事前トレーニング済みの単語埋め込み(GloVe埋め込み)をロードし、20 ニュースグループデータセット上のテキスト分類モデルの訓練への使用

[reuters_mlp.py]
ロイターニュースワイヤトピック分類タスクにおける簡単なMLPのトレーニングと評価

[stateful_lstm.py]
stateful RNNsを使った長いシーケンスを効率的にモデル化する方法のデモ

[variational_autoencoder.py]
variational autoencoder 構築方法のデモ

[variational_autoencoder_deconv.py]
Kerasにおけるデコンボリューションレイヤを使ったvariational autoencoderの構築方法のデモ

-------


p.s.

映画「君の名は。
を見た人はほぼ100%
売れるニオイしかしない
と思ったはずだと思うけど、

TensorFlowをかじった人が
この
Kerasを読んだら
きっとTensorFlowより
流行るニオイしかしない
と思うはず..

2017年1月18日水曜日

TensorFlow の tf.strided_slice() を調べる

TensorFlow の チュートリアル RNN サンプルである ptb_word_lm.py を動かしてみたのだけど、

TypeError: strided_slice() missing 1 required positional argument: 'strides'

というエラーメッセージが表示され動作しない..

で、調べてみると..

strided_slice() missing 1 required positional argument: 'strides' #752

で読む限り、どうも tensorFlow 0.12になってから stride_slice()の引数strideを指定しないと動かないらしい..

ほかにも、困ってる人がいるみたい..

tensorflow0.12でcifar10を動かす時のエラー

CIFARのサンプルにも影響でてるのか..

tf.slided_slice() は多次元テンソルデータを矩形(?)に切り出す関数らしく、
下手にstrideを指定すると間違えるおそれがある..

ということで、TensorFlowの tf.stlide_slice()のドキュメントを勝手訳してみた。
----
tf.strided_slice(input_, begin, end, strides=None, begin_mask=0, end_mask=0, ellipsis_mask=0, new_axis_mask=0, shrink_axis_mask=0, var=None, name=None) {#strided_slice}


テンソルから、ストライドされたスライスを抽出します。

最初の順番では、この操作はテンソル `input` の `begin` から始まる位置から、サイズ `end - begin` のスライスを抽出します。スライス抽出は、すべての次元が `end`より小さくなるまで、` begin`インデックスに `stride` を追加することによって継続されます。ストライドのコンポーネントは負の値にすることができ、これは逆のスライスを引き起こすことに注意してください。

この操作は、numpyスタイルのスライスされた範囲のエンコーディングと考えることができます。Pythonスライス input[、...、] が与えられた場合、この関数は次のように呼び出されます。

`begin`、` end`、 `strides`はすべて長さ n になります。 n は一般に `input`と同じ次元ではありません。

i番目の仕様では、 `begin_mask`、` end_mask`、`ellipsis_mask`、` new_axis_mask`、`shrink_axis_mask`は、i番目の仕様に対応するi番目のビットを持ちます。

`begin_mask`のi番目のビットがゼロでない場合、` begin [i] `は無視され、そのディメンション内の可能な最大範囲が代わりに使用されます。
`end_mask`は、終了範囲を除いて同様に機能します。

7 x 8 x 9 型テンソルの `foo [5:、:、::3]`は `foo [5:7,0:8,0:3]`と同じです。
`foo [:: - 1]`は8のテンソルを逆転させます。

`ellipsis_mask`のi番目のビットが必要ならば、指定されていない次元数だけ他の次元の間に挿入されます。 `ellipsis_mask`には1つの非ゼロビットだけが許されます。

たとえば、 10 x 3 x 3 x 10 型テンソルの形の `foo [3:5, ...,4:5]``foo [3:5, :, :4:5]`と `foo [3:5, ...] `は` foo [3:5, :, :, :]]` と等価です。

`new_axis_mask`のi番目のビットが 1 の場合、` begin`、 `end`、` stride`は無視され、出力テンソルのこの時点で新しい長さ 1 次元が追加されます。

たとえば、 10 x 8 型テンソルの `foo [3:5,4]` は 2 型テンソルの形状を生成し、 `foo [3:5,4:5]` は `shrink_mask` が `1 << 1 == 2` の 2 x 1 型テンソルを生成します。

`shrink_axis_mask`のi番目のビットが 1 ならば、適切な次元でスライスを実行するために `begin` 、 `end [i]` 、 `stride [i]` が使われますが、出力テンソルは次元が 1 つ小さくなります。 これは、slice [i]i番目のエントリ== 1の場合にのみ有効です。


注: `begin`と` end` はゼロインデックス化されています。 `strides`エントリはゼロでなければなりません。


```python
# 'input' は [[[1, 1, 1], [2, 2, 2]],
#             [[3, 3, 3], [4, 4, 4]],
#             [[5, 5, 5], [6, 6, 6]]]
tf.strided_slice(input, [1, 0, 0], [2, 1, 3], [1, 1, 1]) ==> [[[3, 3, 3]]]
tf.strided_slice(input, [1, 0, 0], [2, 2, 3], [1, 1, 1]) ==> [[[3, 3, 3],
                                                               [4, 4, 4]]]
tf.strided_slice(input, [1, 1, 0], [2, -1, 3], [1, -1, 1]) ==>[[[4, 4, 4],
                                                                [3, 3, 3]]]

引数:



*  `input_`: `Tensor`.
*  `begin`: `int32` もしくは `int64` の `Tensor` 。
*  `end`:  `int32` もしくは `int64` の `Tensor` 。
*  `strides`: `int32` もしくは `int64` の `Tensor` 。
*  `begin_mask`: `int32` のマスク値。
*  `end_mask`: An `int32` のマスク値。
*  `ellipsis_mask`: `int32` のマスク値。
*  `new_axis_mask`: `int32` のマスク値。
*  `_masshrink_axisk`: `int32` のマスク値。
*  `var`: `input_` に関連する変数、もしくは None
*  `name`: operation (操作)名 (オプション)。


戻り値:


 `input`と同じ型の `Tensor` 。

Google Colab相当の環境をローカルPC上のDocker Composeで実現する

 Docker Composeの有料版に、お金を払いたくない ^H^Hが使えない ため古いゲーミングPC(GeForce3080)にDocker Composeを入れてその上のコンテナでGoogle Colab相当のノート操作ができないかためしてみた: コンテナイメージとして a...