Kerasのコーディングではまったこと集

Kerasのsessionはきちんとclearさせてないとエラーがでます

Tensoflow + Keras のコードの実行で、

TypeError: 'NoneType' object is not callable

というエラーがでて原因がわからず少しはまりました。
どうやら、kerasのバックエンドのTensorFlowのsessionをclearしていないのが原因だったようです。
以下の記事を参考にしましたら、エラーが消えました。
keras+tensorflowで終了処理でエラーが発生する | CodeLab技術ブログ

ネットワークの可視化に関して

ネットワークを可視化したかったので、以下のドキュメントを参考にしました。
可視化 - Keras Documentation

from keras.utils import plot_model
plot_model(model, to_file='model.png')

たったこれだけなら簡単だと思ったのですが、必要なパッケージがインストールされていなくてそのままでは動かなかったです。

私の環境では、以下のようにすれば動作しました。

conda install graphviz
conda install pydot

さらに、以下のサイトから"Stable 2.38 Windows install packages"をダウンロードしインストールしました。
http://www.graphviz.org/download/
そして、Windows環境変数のPathに C:\Program Files (x86)\Graphviz2.38\bin を追加しました。
以上で無事、ネットワークのグラフが表示されました。

Google のTPU v3について

Google I/O 2018で発表された、機械学習を効率よく演算できる専用ASICチップのTPUについてです。
第3世代の発表が今回行われていたので、メモってみます。

彼らのアナウンスをまとめると:

TPUには4つのTPU演算ユニットが載っている。
TPU v2: 180Tera ops per second per one TPU chip which include 4 TPU units.
TPU v3は8倍?とアナウンスされているので、
TPU v3: 180 * 8 = 1.44Peta ops per second per one TPU chip which include 4 TPU units.
さらに TPU v3を束ねたサーバーは256 TPUs なので、
1.44Peta * 256TPU = 369Peta ops per second

という計算で、100Peta以上というアナウンスになっているのでしょうか。
8bit int の演算だと思っていましたが、100Peta flops と書いてあるし、floatの計算なのでしょうか。

よく読むと、Podが8倍の性能になって100kTeraFloposと書いてあり、チップの演算速度8倍になったとは言ってないですね。
逆算すると、
100Peta / 256 = 390 TeraFlops なので、チップそのものはv2 の2倍程度の速度向上のようです。

TensorflowのTutorial "Deep MNIST for Experts"を試した時のメモ

wshinya.hatenablog.com

前回は"MNIST For ML Beginners"の解説を読みプログラムを実行してみました。
今回は、以下のリンクから"Deep MNIST for Experts"の解説を読みプログラムを実行してみます。
Deep MNIST for Experts  |  TensorFlow

前回のBeginners編と今回のExperts編の一番大きな違いは、Beginners編では画像のローカル構造を無視してしまい、1次元のベクトルに展開してしまいましたが、Exprets編では2次元の画像の2次元のまま扱う手法としてCNNを用いているところです。
CNNを用いることで数字の形の特徴をとらえることができ、認識率が大きく向上することが期待されます。

  • 今回のネットワーク構成

畳み込み層
プーリング層
畳み込み層
プーリング層
全結合層
Softmax層

となっています。

2回の畳み込み層により画像のローカルな構造とよりグローバルな構造をとらえることができます。
そのあとは、多値分類問題として、全結合層+Softmax regressionという前回と同じような構造になっています。

まずはmnist_deep.py を実行してみました。
するとWARNINGがずらずらと表示されいますが、
"xxx is deprecated and will be removed in a future version."
という将来のバージョンでこのコマンドは使えなくなりますよという警告ですので、当面は無視しておいても問題なさそうです。
そして実際に学習が進み最終的には、
step 19900, training accuracy 1
test accuracy 0.9913
今度は、testデータで99%の精度を超えてきます。簡単なCNNですがかなりの精度がでますね。

1層目の畳み込み層の
W_conv1 = weight_variable([5, 5, 1, 32])
は、5x5x1(channel数、いまはgray scaleなので1)の畳み込みフィルターが32種類あるということを示しています。
2層目では、
W_conv2 = weight_variable([5, 5, 32, 64])
となっており、5x5x32のフィルターが64種類あることを意味しています。
ここでの32や64はネットワークの途中で学習して特徴量の数に対応しています。
また各層ごとに2x2でMax poolingしていますので,画像サイズは
28 x 28 -> 14 x 14 -> 7x7 と順次スケールされていきます。

2層目のmax poolingが終わった時点では7x7の画像が64枚出力されています。
これをreshapeして1次元ベクトルに変換しているのが
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
です。fully connected layerを構成するためのweight, W_fc1とバイアスb_fc1
をこれに作用させることで、全結合層計算ができます。
最後に活性化関数としてreluを適用してのが以下の行です.
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

このネットワークでは過学習を防止するためにdropout、つまり適当にネットワークの重みWをゼロにするという操作を行います。
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
初めの行はdropoutの際に接続が保持される確率を格納するためのplaceholderで学習時には0.5で推論時にはdropoutしないように1.0にセットしています。
最後に10種類の数値に対応するように単層のsoftmax回帰に相当する層を追加しています。

最適化は
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
とAdamを使用しています。

GradientDescentとAdamで結果がどれくらいちがうのかちょっと実験してみました。
学習率はどちらも0.0001
ADAM:
step 100, training accuracy 0.88
test accuracy 0.9195
SGD:
step 100, training accuracy 0.26
test accuracy 0.2062
まあ、予想通りですが、SGDに比べるとADAMの方がかなり収束が早いです。

TensorflowのTutorial "MNIST For ML Beginners"を試した時のメモ

Tensorflowを勉強するにはTensorflowのTutorialを自分で入力して実行しながら理解するのが一番手っ取り早いです。
特に初めてTensorflowを動かすときには、以下のリンク先のMNIST for ML BeginnersというTutorialがおすすめです。
MNIST For ML Beginners  |  TensorFlow

このチュートリアルは、単純な1層のネットワークで手書き文字を認識するというものです。
1層ですので、重みとバイアスも一つしかありませんが、それでもニューラルネットワークに必要な最小限の要素をすべて含んでいます。

TensorflowのtutorialにはMNISTの手書きデータを使うものはこのbiginner用とCNNを使ったものの2種類があります。
以下に、実際にコードを理解して実行したときの自分用のメモを残しておきます。

                  • -

mnist.train.images は [画像の数, 28x28=784] の shapeで値は0-1の画素の輝度
ラベルは 0~9 の数字でone-hot表現されています。
one-hot表現は例えば、
3 なら [0,0,0,1,0,0,0,0,0,0]
というふうに表現されます。
従ってラベルは
mnist.train.labels [画像の数, 10]というshapeで、値はfloatです。

> x = tf.placeholder(tf.float32, [None, 784])

xは学習データ(手書き数字の画像データを1次元にしたもの), Noneは画像の数は任意の長さを取りうることを意味する。
placeholderはこのように、学習データなどを入れる入れ物。

重みやバイアスは、実行時に随時更新されますので、tfのvariable変数として以下のように定義しています。
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

wは入力が784次元で出力が10次元なので[784, 10]となります。 
784列10行の行列と思えばいい。

ニューラルネットワークの計算のcoreの部分です。
> y = tf.nn.softmax(tf.matmul(x, W) + b)

tf.matmul(x, W)の部分ですが、データ数をNとすると
xは N x 784 の行列で, Wは 784 x 10の行列なので、結果のyはN行10列の行列です。
つまり各行にxの各行にたいする画像データを0から9のどの数値と予測したかの確率がyの各行に入ります。

この予想された出力yと正解とを使って表されたロス関数を最小化することで、適切なW,bを決めます。
従って正解も上記yと同じshapeである必要があるので、
> y_ = tf.placeholder(tf.float32, [None, 10])
というように、N行10列の行列としてplaceholderを用意しておきます。

多値分類問題なのでロス関数としてcross entropyを使用します。
> cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
tf.reduce_meanは指定されたshapeの成分についての和をとる関数で、今の場合は、reduction_indices=[1]となっているので
1番目の要素についての和をとります。
つまり、0から9の予想された数値の方向に和をとり、N個の要素をもつ1次元配列にします。
この1次元配列は、N個の学習データそれぞれに対するロス関数の値を格納しています。
最後に、tf.reduce_meanで、N個の学習データ(バッチ処理1回分)のそれぞれのロス関数すべての平均をとってこれを最適化関数として使用しています。

ここが少し混乱しやすいのですが、実際のtutorialのコードでは上記の部分が以下のようにsoftmax_cross_entropy_with_logitsという関数で書かれています。
>cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))
解説を読むと、前者の書き方のほうが数値的に不安定するそうです。

実施のコードで試してみると、前者の場合の精度は私の実行環境では、約0.92、後者では、0.91でほぼ同じ結果になりました。
実行時間は前者では約0.77sec, 後者では0.90secでlogits関数の計算の分だけ速度が落ちているようです。
(実際のコードを一番最後に添付しておきます)

logits関数とは、L = log(p/(1-p)) のことで変形するとp= 1/(1+exp(-L))で、p=0.5の時0,P>0.5のときL>0, p<0.5のときL<0となる関数。
確率p [0, 1.0] -> [-inf, inf]にマップする。
softmaxで確率[0, 1.0]の出力を得て、それをlogitsに通すことで正解の確率が大きければ値はより大きくなる。マイナスが掛かっているのでloss関数としては値が小さくなるということです。
確率が0や1に近い時に勾配が数値的に消失したり不安定にあったりするのを防ぐ効果があります。
stackoverflow.com


最適化はGradientDescentで学習率は0.5に設定しています。
>train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

学習結果の評価
>correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
tf.argmaxは引数の配列の中で一番値の高いもののindexを返す。yは[教師データの数, 正解の確率]という配列になっているので、
1番目の要素(数値の0から9のそれぞれの予測確率)から一番高いもの一つが選ばれます。
tf.equalで教師データと一致しているときにTrue, 異なっているときにFalseをセットします。

# 精度の計算
>accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.castはTrue, Falseを以下のように数値に変換
[True, False, True, True] -> [1,0,1,1]
tf.reduce_meanでこの1,0,1,1,・・・の平均をとり結果を全体の精度とする。

今回試してみた実際のコードは以下のようになります。

import tensorflow as tf
import time

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

start_time = time.time()

x = tf.placeholder(tf.float32, [None, 784])

W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

y = tf.nn.softmax(tf.matmul(x, W) + b)

y_ = tf.placeholder(tf.float32, [None, 10])
#cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y))

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
# interactiveSessionでtfのsessionを作成
sess = tf.InteractiveSession()
# global変数の初期化
tf.global_variables_initializer().run()

print ("--- start training ---")
for _ in range(1000): # 1000ステップの学習を行う
    # 1 batch = 100個のデータでbatch学習を行う
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
print ("--- finish training ---")

# 予測yと正解ラベルy_が同じ値であればTrue、ことなればFalseがセットされる
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
# 精度の計算
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print("精度:")
print( sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

end_time = time.time()
print ("time: " + str(end_time - start_time) + "sec")

深層学習でよく使われる学習用データセットまとめ

追記:
せっかくまとめましたが、arXivTimesに素晴らしいまとめがありますのでそれで十分ですね。
github.com

MNIST:

手書き文字認識学習用データ
28pixel x 28pixel x 1channel
60000枚:training用
10000枚:test用
クラス: 10個の数字

機械学習におけるHello World的なデータ
ちなみに、MNISTとはMixed National Institute of Standard Technologyの省略形で、日本語に訳せば"国立標準技術研究所"でしょうか。
日本では旧通産省工業技術院、今の産業技術研究所に相当するアメリカの研究機関です。

CIFAR-10:

一般物体認識のベンチマークとしてよく使われている写真データ
32pixel x 32pixel x 3channel
50000枚:training用
10000枚:test用

画像は10種類にラベル付けされている
クラス:airplane, automobile, bird, cat, deer, dog, frog, horse, ship, truck

AlexNet(SuperVision)のAlex Krizhevskyさんが整備
(AlexさんはILSVRC2012で優勝)
以下のサイトに詳しく解説されています
aidiary.hatenablog.com

CIFAR-100:
CIFAR-10の100種類のクラス分け版
qiita.com

Microsoft COCO ( MS COCO ):

画像と、画像の認識、セグメンテーション、画像を説明する短いキャプションがセットになったデータ
以下の解説を参照のこと
qiita.com

Imagenet:

ダウンロードできるのは学術関係者に限定される
ImageNetとはスタンフォード大学がインターネット上から画像を集め分類したデータセット。一般画像認識用に用いられる。ImageNetを利用して画像検出・識別精度を競うThe ImageNet Large Scale Visual Recognition Challenge(ILSVRC)などコンテストも開かれる
現在、1400万枚以上のデータが集まり、2万クラス以上あるらしい
ネット上の画像を集めてきているので結構リンク切れがあったりするらしい。

GoogleのOpen Image Dataset v4

Googleが用意した1,540万のバウンディングボックス含む190万画像600カテゴリのデータセット
Open Images Dataset V4
ai.googleblog.com
ダウンロードは以下のサイトから
github.com

Caltech101

101個にカテゴリー分類されたデータ.
画像の品質がいい。
Caltech101

The PASCAL Visual Object Classes Homepage

Yoloの学習済みモデルが公開されている.
http://host.robots.ox.ac.uk/pascal/VOC/

              • -

他のデータセットもKerasのドキュメントで解説されています
データセット - Keras Documentation

Kerasを使っていてPILが必要になったときの対処法

conda install PILとやったらpythonのversionが3.5だと怒られてしまいます。
PILの代わりに、

conda install Pillow

とすればいいようです。

以下のサイトを参考にしました。
qiita.com

Pillowについては以下を参照
qiita.com

Tensorflow GPU版 + Keras + OpenCV ver3.0の環境構築

最近TF1.7もリリースされ、そろそろCUDA9.0にアップデートしないといけないと思っていたので、復習も兼ねてTensorflowの環境構築方法をまとめました。(2018年4月現在の情報)

OS: Windows10Pro, 64bit

1) Tensorflow GPU版のためのCUDA環境の構築

まずは、NVIDIAのサイトからインストールガイドを表示して熟読する
インストールガイドは以下のcudnnのダウンロードサイトからcuDNN Install Guideをクリックすることで閲覧できる
https://developer.nvidia.com/rdp/cudnn-download

GPUドライバーを最新のものに更新
http://www.nvidia.co.jp/Download/index.aspx?lang=jp

CUDA Toolkit 9.0 Downloads のイントール
最新は9.1だが以下のサイトから9.0をダウンロード
https://developer.nvidia.com/cuda-toolkit-archive
Patch 1 (Released Jan 25, 2018)
Patch 2 (Released Mar 5, 2018)
を順にあてる
nvcc --version
で確認
Cuda compilation tools, release 9.0, V9.0.176
となっているので成功していることがわかる

cuDNNのダウンロードとインストール
cuDNN v7.0.5 (Dec 5, 2017), for CUDA 9.0を選択
https://developer.nvidia.com/rdp/cudnn-download
ダウンロードしたcudnn-9.0-windows10-x64-v7.zipを解凍してインストールガイド通りにファイルをコピーしました.

2) anacondaの仮想環境を構築
> conda create -n tensorflowGPUKerasOpneCV python=3.5 anaconda
pythonのバージョンを3.5にした理由はopenCVが3.5にしか対応していないからです。

3) opneCV ver.3.0のインストール
> conda install -c menpo opencv3

4) Gpu版tensorflowのインストール
> pip install tensorflow-gpu
 tensorflow GPU版 ver. 1.7.0のインストール

5) その他必要なモジュールのインストール
> conda install h5py
> conda install matplotlib
> conda install scikit-learn

6) Kerasのインストール
pip install keras


7) 正しくインストールできたかどうかのテスト

tensorflowを実行すると
ー> "could not create cudnn handle: CUDNN_STATUS_ALLOC_FAILED"
が出たのでcuDNNのバージョンを変えてみる
Download cuDNN v7.0.4 (Nov 13, 2017), for CUDA 9.0
だめなのでもう一度
pip install --ignore-installed --upgrade tensorflow-gpu
をやってみたら問題は解決しました。

ちなみにCPU版では

1) conda create -n tensorflowCPUKerasOpneCV python=3.5 anaconda
2) conda install -c menpo opencv3
3) pip install tensorflow
4) pip install keras
5) その他必要なモジュールのインストール
> conda install h5py
> conda install matplotlib
> conda install scikit-learn

juypter notebookを使うときは
> conda install jupyter notebook
も忘れないように

(参考)
OSError: Unable to open file (unable to open file: name =
というエラーが出るとき、
C:\Users\username\.keras\datasets に残っている以前ダウンロードしたデータをいったん消去すれば解決することがあるようです