TensorFlow – tf.train.MonitoredTrainingSession

tf.train.MonitoredTrainingSessionを確認します。
訓練をモニターするのに特化したセッションという感じでしょうか?チュートリアルのコードでは下記のような使われ方をしています。

普通のセッションを使う代わりに使っています。

https://www.tensorflow.org/api_docs/python/train/distributed_execution#MonitoredTrainingSession

tf.train.MonitoredTrainingSession(master=”, is_chief=True, checkpoint_dir=None, scaffold=None, hooks=None, chief_only_hooks=None, save_checkpoint_secs=600, save_summaries_steps=100, config=None)

引数的に、勝手に変数の保存をしてくれたりするようです。

For a chief, this utility sets proper session initializer/restorer. It also creates hooks related to checkpoint and summary saving. For workers, this utility sets proper session creator which waits for the chief to inialize/restore.

引数は下記です。

  • master: String the TensorFlow master to use.
  • is_chief: If True, it will take care of initialization and recovery the
    underlying TensorFlow session. If False, it will wait on a chief to
    initialize or recover the TensorFlow session.
  • checkpoint_dir: A string. Optional path to a directory where to restore
    variables.
  • scaffold: A Scaffold used for gathering or building supportive ops. If
    not specified, a default one is created. It’s used to finalize the graph.
  • hooks: Optional list of SessionRunHook objects.
  • chief_only_hooks: list of SessionRunHook objects. Activate these hooks if
    is_chief==True, ignore otherwise.
  • save_checkpoint_secs: The frequency, in seconds, that a checkpoint is saved
    using a default checkpoint saver. If save_checkpoint_secs is set to
    None, then the default checkpoint saver isn’t used.
  • save_summaries_steps: The frequency, in number of global steps, that the
    summaries are written to disk using a default summary saver. If
    save_summaries_steps is set to None, then the default summary saver
    isn’t used.
  • config: an instance of tf.ConfigProto proto used to configure the session.
    It’s the config argument of constructor of tf.Session.

hookというのはコールバック的な感じで、session.runの前後に実行できるクラスらしい。これを紐づけることができて、リストで複数のhookを登録することができる。カスタマイズできるのが、SessionRunHookで、それ以外に用途が決まっているhookが複数事前に提供されているといったような感じのイメージを持った気がする。

class tf.train.SessionRunHook
class tf.train.StopAtStepHook
class tf.train.NanTensorHook

configは設定で、log_device_placementは、手動でデバイス指定してる場合にTrueにすると、手動設定したデバイスを選んでくれる的なやつっぽい。自分の非力な1体のPC環境ではあまり関係がないと思う。非力な1体のPC環境の場合、hookは自作する_LoggerHook()だけで、configは未設定でもよさそう。

引数でcheckpoint_dirを聞いてるくらいだから、tf.summary.FileWriter(‘.\logs’, sess.graph)みたいのを書かなくてもログが保存されるようになったりしてるのか試してみようと思います。

結果

そして、logsディレクトリにログファイルが登録されていて、TensorBoardでも見られた。
before_runのreturnで、tf.train.SessionRunArgs(add)とやると、after_runのrun_values.resultsに結果が入ってくる。

TensorFlow – Readerクラスでバッチ処理

参考:
TensorFlow : How To : データを読む
Inputs and Readers
TensorFlowチュートリアル – 畳み込みニューラルネットワーク(翻訳)

tf.train.shuffle_batchというのを使う。シャッフルが不要な時は、tf.train.batchを使う。

tf.train.shuffle_batch

tf.train.shuffle_batch(tensors, batch_size, capacity, min_after_dequeue, num_threads=1, seed=None, enqueue_many=False, shapes=None, allow_smaller_final_batch=False, shared_name=None, name=None)

# min_after_dequeue はバッファ、そこからランダムにサンプリングします、がどのくらい大きいかを定義します
# – 大きければより良いシャッフリング、しかし開始が遅くなりメモリがより多く使用されることを意味します。
# capacity は min_after_dequeue よりも大きくなければなりません。
# そして the amount larger は事前読み込みする最大値を決めます。
# 推奨:
# min_after_dequeue + (num_threads + 小さい安全マージン) * batch_size
min_after_dequeue = 10000
capacity = min_after_dequeue + 3 * batch_size
example_batch, label_batch = tf.train.shuffle_batch(
[example, label], batch_size=batch_size, capacity=capacity,
min_after_dequeue=min_after_dequeue)
return example_batch, label_batch

TensorFlowのcifar10のチュートリアルのコード(cifar10_input.py)に下記のように使われている。

上記コードのmin_after_dequeue(min_queue_examples)は、下記のように取得されている。

上記のNUM_EXAMPLES_PER_EPOCH_FOR_TRAINは下記のように設定されている。

バッチもシャッフルしてくれる。シャッフルするために、事前にデータを何個か読み込んでおいて、その中からシャッフルしてくれる。事前読み込み数がmin_after_dequeueで、これが多いと沢山の中からシャッフルできるからシャッフルされ具合がいい感じになる。でも読み込み数が多いからその分遅くなる。でも途中からは裏で読み込んでおいてくれるので遅くならない。ただメモリ使用量は増える。って感じすか??上記事例だとエポック当たり5万件のデータがある場合、それに0.4をかけた数をmin_after_dequeueにしている。そして推奨値の数式に従って、capacityは、min_after_dequeue + 3 * バッチサイズにしている。

バッチ処理してみる

コードサンプル
下記のfile0.csvとfile1.csvはここで使ったものと同じ内容。

結果

TensorFlow – 学習精度を上げるために画像加工して増やす

参考:Images
上記を見ると色々な加工関数があるんですね。デコードエンコードも色々便利そうなのがあるんですね。

TensorFlowのチュートリアル「Convolutional Neural Networks」で、cifar10の画像を学習精度を上げるために画像を色々加工して増やしています。何をしていて、どうやればいいのか確認します。ソースコードはここです。

Readクラスでファイルから画像・ラベルデータを取り出した後に下記をしています。この5つの関数達を試していこうと思います。

すでに同じことをやってるサイトを発見しました。
参考:画像の水増し方法をTensorFlowのコードから学ぶ

なんか、上記5つの関数のうち最後の1つが参考サイトだと違う。参考サイトだとホワイトニングしている。参考サイトのおかげで答えが分かりましたが、一応自分でも試しておきます。

tf.random_crop

コード

結果

seek設定してないけどランダムになった。seekを明示した場合、seekが同じだと同じ結果になるってことらしい。

tf.image.per_image_standardization

これが参考サイトにない。その代りホワイトニングがなくなっている。
コード

結果は恐ろしい色合いになった。

こんな恐ろしい画像から学習しているんだなー。

チュートリアルの5関数を適用してみる

コード

結果

TensorFlow – 画像ファイルをReaderクラスで読み込む

参考:TensorFlowのReaderクラスを使ってみる

こんな風にしたら単一ファイルを読み込めるらしい。

コード

結果

TensorFlow – Readerクラスでデータを読み込んでみる

参考:TensorFlow : How To : データを読む

ファイルからデータを読む場合の処理の流れ

・ファイルパスのリストを、tf.train.string_input_producer 関数に渡す(shuffle=Trueにしたらepochでファイル名をシャッフルする)
・読み込むデータに合わせてreaderを選択する。
・ファイル名キューをreaderのreadメソッドに渡す。readメソッドは、ファイルとレコード識別キーと、スカラ文字列値を返す。
・スカラ文字列を、サンプルを構成するテンソルに変換するためにデコーダと変換 OPs の一つ(あるいはそれ以上)を利用します。

csvファイルを読んでみる

上記コードの動きを色々なパターンでチェックしてみまっす

ちなみに、csvファイルは、下記です。

file0.csv

file1.csv

下記を試してみます。コードは基本上記と同じですが、exmapleとlabelを3回表示させています。結果は、file0.csvとfile1.csvのどちらかの1~3行目を順番に取得していることが分かりました。ファイルから取り出すのは1行目から順番ですが、取り出すファイル自体は勝手にランダムな感じにしてくれてるっぽいです。

結果(下記のときと、file1.csvの内容の時がランダムに変わる)

epochでファイルが変わるか確認する

tf.train.string_input_producerの引数にshuffle=Trueを渡すと、epochでファイル名をシャッフルすると書いてありますので、それも試してみようと思います。まずは、shuffle=Trueを設定しない場合。

結果
下記のようになりました。file0と1だけだと、シャッフルしてるか分かりづらいですね。。とりあえずこれはシャッフルはしてないです。何回かやってみます。

同じコードをもう一度実行したら下記になりました。これぞまさにシャッフルですね。ということは、デフォルトでshuffle=Trueが設定されているようです。

それでは、shuffle=False設定にしてみます。
コードで変更するのは下記だけです。

結果
何回やっても下記になりました。shffle=Falseにすると、最初に取得するファイルも、tf.train.string_input_producerに渡した順番通りで固定のようです。

何をしたらエラーになるか確認してみる

上記のコードで、csvファイルの1行当たりのカラム数が5より大きい場合はエラーになりました。

カラム数が5より小さくてもエラーになりました。

record_defaultsを下記のように変えたらエラーになりました。record_defaultsの形状をみて、想定しているデータの個数やデータ型を想定しているようです。それと合わないデータが入ってたらエラーを出すようです。

エラー

record_defaultsを下記のように変えたらエラーになりました。shapeのランクが1じゃないといけないらしいです。shapeが(5, 0)になるからダメで、(5, 1)になるようにしないといけないってことかな?

エラー

record_defaultsを下記にしたら、エラーになりました。numpyの配列だとダメっぽいです。

エラー

これだとOKでした。

固定長バイナリデータファイルを読み込む

各レコードがバイトの固定数である、バイナリ・ファイルを読むためには、 tf.decode_raw 演算とともに tf.FixedLengthRecordReader を使用します。decode_raw 演算は文字列から uint8 テンソルに変換します。

例えば、CIFAR-10 データセット は、各レコードがバイトの固定長を使用して表される、ファイルフォーマットを使用します: ラベルのための1 バイト、続いて 3072 バイトの画像データです。ひとたび uint8 テンソルを持てば、標準操作で各部分をスライスし必要に応じて再フォーマットすることができます。CIFAR-10 については、どのように読みデコードするかを tensorflow/models/image/cifar10/cifar10_input.py で見ることができ、このチュートリアル で説明されています。

コードサンプル

結果

これで、cifar10のデータを読み込めました。

TensorFlow – tf.strided_slice関数を調べる

tf.strided_sliceを調べます。TensorFlowのGithubにのってる説明ページはこれです。

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は終了位置、stridesは間隔のようです。以前はstridesを指定しない場合、デフォルトでstridesを1とみなしていたようですが、最近のtensorflowのアップデートで、stridesも明示しないとエラーになるようになったようです。ちなみに、終了位置は普通の配列のスライスと同じで、指定したインデックスのひとつ前までになります。

これだけなら簡単なのですが、他にも色々引数があるし、inputもbeginも多次元配列に対応しているようです。

コード

結果

begin、end、stridesはnumpyのshapeのような感じで入れていくようです。コードだとbeginは[0, 5]ですが、これは1次元目は0から始まり、2次元目は5から始まるということになるようです。

Python3 – cifar10をダウンロードして画像を表示させてみる

参考:
Convolutional Neural Networks
https://github.com/tensorflow/models/tree/master/tutorials/image/cifar10/

上記githubに実際のコードがあります。
Cifar10というのは、10種類のカラー画像が沢山入ってるやつで、機械学習によく使われるようです。場所は下記です。
http://www.cs.toronto.edu/~kriz/cifar.html
Cifar100というのもあるようです。

データは、pythonバージョンとかバイナリバージョンとかありますが、TensorFlowが使ってるのは、バイナリバージョンです。バイナリバージョンの説明として、上記本家サイトに下記のように書いてあります。

The binary version contains the files data_batch_1.bin, data_batch_2.bin, …, data_batch_5.bin, as well as test_batch.bin. Each of these files is formatted as follows:
<1 x label><3072 x pixel>

<1 x label><3072 x pixel>
In other words, the first byte is the label of the first image, which is a number in the range 0-9. The next 3072 bytes are the values of the pixels of the image. The first 1024 bytes are the red channel values, the next 1024 the green, and the final 1024 the blue. The values are stored in row-major order, so the first 32 bytes are the red channel values of the first row of the image.

Each file contains 10000 such 3073-byte “rows” of images, although there is nothing delimiting the rows. Therefore each file should be exactly 30730000 bytes long.

There is another file, called batches.meta.txt. This is an ASCII file that maps numeric labels in the range 0-9 to meaningful class names. It is merely a list of the 10 class names, one per row. The class name on row i corresponds to numeric label i.

ダウンロード&展開

ここにダウンロードのコードをいくつか書きました。ここではTensorFlowのコードサンプルと同じくurllib.request.urlretrieveを使います。

展開された内容

最初の1バッチがラベル、その次からは赤、緑、青の順で1024バイトずつ入ってる。画像の大きさは32 x 32(=1024)。画像は各ファイルに1万枚分ある。
(1024 x 3 + 1) x 10000 = 30,730,000(bytes)

試しに画像を表示させてみる

試しにdata_batch_1.binから1枚分取得して表示させてみます。下記のreshapeとかtransposeで頭がこんがらがったのでここテストして頭を整理しました。

10枚取得してラベルもあわせて表示してみる

コードサンプル

結果

Python3 – PIL.Imageで画像を合体してテキストを書く

コードサンプル

結果

Numpy – 配列の形を変えるテスト

TensorFlowでは頻繁に配列の形を変換しますが、結構混乱して理解するのに時間がかかります。Numpy.reshapeとかNumpy.transposeの動きをシンプルな配列で確認してみます。

これから操作する配列は、下記のようなCifar10の画像データの構造をイメージしてます。
最初の4個は赤。次の4個は緑、最後の4個は青。
最初は上記が一次元の配列に格納されている状態にして、最終的にはこれを下記の並びにしたいです。縦、横、チャンネルの3次元配列にしたいということです。

4個ずつ赤・緑・青があるとういことは、2×2の画像サイズになります。よって、配列のshapeは、[2, 2, 3]になることを想定しております。このshapeになりつつ、配列データの構造に不整合がなければ形の変換が成功したことになります。

コード

結果

Python3 – Clint (コマンドライン入出力を色々できるモジュール)

面白そうだからやってみる。
参考:https://github.com/kennethreitz/clint/tree/master/examples
参考:PythonのコマンドラインツールClintを試す

インストール

文字に色つける

コードサンプル

プログレスバー

コードサンプル

Python3 – ファイルのダウンロード

urllib.request.urlretrieveを使うとできます。本家の説明ページはここです。なんか廃止されるかもしれないとか書いてあるけど。他にはRequestsパッケージを使う方法もあります。

urllib.request.urlretrieveを使う

圧縮ファイルをダウンロードして展開する

ダウンロード中に進捗を表示する

Requestsパッケージを使う

画像ファイルをダウンロードして表示する

コードサンプル

圧縮ファイルをダウンロードして展開する

ダウンロード中に進捗を表示する

TensorFlow – tf.gfile.Exists

tf.gfile.Existsを調べます。

コード例

サンプルコード

hogeディレクトリがない状態で実行すると、hogeディレクトリが作られる。
空のhogeディレクトリがある状態で実行すると、hogeディレクトリが削除されて、また作られる。
適当なファイルやディレクトリを入れたhogeディレクトリがある状態で実行すると、hogeディレクトリが削除されて、また作られる。

なんかただディレクトリあったら消してつくってるだけで、何か特別なファイルがあったらそのファイルだけ消すとかそういう特別なことしてるわけじゃないっぽい。なんでわざわざこれ使うのかな?

Python3 – if __name__ == ‘__main__’:

参考:Python – if __name__ == ‘__main__’: の意味

コマンドラインからスクリプトファイルを指定してPythonインタプリタを起動すると、指定されたファイルは、__main__という名前のモジュールとしてPythonに読み込まれる。実行中スクリプトのモジュールの名前は、__name__という名前の変数に設定されているため、この値を参照して、ファイルがコマンドラインから実行されたのか、それともimport文でインポートされたのかを識別できる。

__name__は、モジュール名で、コマンドラインから実行するとそのファイルのモジュール名は、__main__になる。importすると、そのファイルのモジュール名は、hoge.pyだったらhogeになる。(importするときもimport hoge.pyじゃなくて、import hogeとする)

コードサンプル
test.py

test2.py

実行

結果

TensorFlow – tf.app.flags.FLAGS(ファイル実行時にパラメタを付与できるようにする)

tf.app.flags.FLAGSを使うと、TensorFlowのPythonファイルを実行する際にパラメタを付与できるようになる。

下記のようにすると、パラメタ付与が可能になり、デフォルト値やヘルプ画面の説明文を登録できる。tf.app.flags.DEFINE_stringは、String型用で、他にtf.app.flags.DEFINE_boolean、tf.app.flags.DEFINE_integer等を型に合わせて使う。

コードサンプル (test.py)

ヘルプを表示する

結果

実行例

結果