これなら分かる!Deep Learningの学び始め方
まえおき
仕事半分趣味半分として独学でDeep Learningを学び始めて早3ヶ月が経ちました.
CNNの亜種とかを論文片手に構築したりするレベルです.
(だいたいはCNN先生で良いんじゃない?と思ったりしますが,しょうがない...)
ただ,未だにDeep Learningは極力使いたくないというか,勾配ブースティングやSVMで問題ないなら使いませんし,機械学習とか使わなくても良い優れたアルゴリズムがあれば,そちらを使うようにしてます.
(保守の問題とかあるので,専門性の高い技術は使わないようにしてます.ヘタレエンジニアです.はい.)
ただ,精度だったり速度だったり諸々に問題があって,どうしても最先端の手法にすがりつきたくなる場合があったりします.(はい.泥沼です)
そういうときの奥の手のひとつとしてDeep Learningがあるのかなーというのが現状の認識だったりします.
おすすめ資料
それはさておき,今思えば最初はここから手をつけとけばよかったなと思う資料について,個人的主観で記載します.
ロジスティック回帰やニューラルネットなど機械学習入門的な内容を分かりやすく記載されていますので,CNNを学び始める前段階として読んでおいたほうが無難な気がします.
- ニューラルネットワークと深層学習
http://nnadl-ja.github.io/nnadl_site_ja/
ニューラルネットについて非常に分かりやすく,また何故こういう方法を採用しているのか記載されています.
TensorFlowの内部処理をブラックボックスとして使いたいけど,そうは言ってられなくなった時に重宝しました.
今にしてみれば,ChainerやTensorFlowとか使う前に,自前で一度は作っといたほうが良かったと思ってます.
- TensorFlow - チュートリアル
https://www.tensorflow.org/versions/r0.7/tutorials/index.html
Google謹製のライブラリTensorFlowのチュートリアルです.これでもかってぐらい分かりやすく説明してくださっています.
- ADAM: A METHOD FOR STOCHASTIC OPTIMIZATION
http://arxiv.org/pdf/1412.6980v8.pdf
Adamの論文です.何の気なしにAdamOptimizerとか使ってるけど,これなんぞ...と思った時に役立ちます.
なんでReLU使ってんの?なんでシグモイドじゃダメなの?って思った時に見つけた記事です.ちょっと幸せになれました.
- Distinctive Image Features from Scale-Invariant Keypoints
https://www.cs.ubc.ca/~lowe/papers/ijcv04.pdf
SIFTの論文です.なんでプーリングとかやってんの?この人達...とか思った時に何となく役にたった論文です.
コンピュータビジョンは一般教養として知っとかないとダメだったなーと思った記憶があります.
機械学習の大会を開いているサイトです.理論的な話とかじゃなくて,もうちょい泥臭い部分が知りたいのです...とか思った時にForum読んで幸せになってます.
たぶんLSTMの記事で一番わかりやすいです.
片っ端から論文読んでいくと,今どういった方法が主流なのかがわかって幸せになれます.
AlphaGo vs. イ・セドルの第四局の感想
第四局の72手目からAlphaGoが崩れ始めたのは以下の理由だと思う.
AlphaGoもモンテカルロ碁ベースでできているので,下記A),B)のいずれかの手が採択されるようになっていると考えられます.
- A). 勝率から考えて有望そうな手
- B). 詰碁や手筋のような正解となる手順は少ないが,正しく読みきれるなら有望な手
B).で実際に読み切るためには,
- 普通は考えない手は無視して探索領域を狭められるか,
- 手数が短い
のいづれかの条件を満たす必要があります.今回の第四局のキリは上記のA), B)いづれの条件も満たさなかったので見破れなかったのではないかと考えられます.つまり,
- ほぼ盤面全体を見ないと解けない広範囲な探索領域から見つける必要があったので,B).で正解を得ることが難しかった.
- 勝率から考えると正解は1パターンしか存在しないので,A)でコンピュータが考慮することはまずない.
それ以降,コンピュータが無茶な手を打ち始めたのは,
上記の72手目を読みきれず形勢が悪くなり,勝率を上げるための無理手で挽回しようとしたため,初級者のような手を乱発したのだと考えられます.
このように考えると,
- 右側での助からない黒石が逃げていったのも,
- 左下の割り込みも,
万一相手がミスってくれたら逆転できるため,つまり,ミスって勝利となる確率の方が通常の手を打って挽回するより逆転しやすいため(上記のA.に相当),ああいった手を打ってしまったのではないかと考えられます.
あと,第二局15手目のノゾキは,将棋でおなじみのフレーム問題が発生しているためなんじゃないかと考えられます.
15手目のノゾキはAlphaGoの権利といった手で,いつでも打つことができるので,
人間だとコウ材や局面の切り替えに使ったりするのが普通と考えられています.
じゃあ,結局いつ打つのかというのを,上記のA).やB).では解決できないので,
AlphaGoは不確定な要素をなるだけ除外するべく,十数手先の盤面の中では最も有望そうな手になるノゾきを打ったのではないかと思う.
そう考えると,コウが対局中現れづらいのもある程度納得いきますし.
今回の対局を見た限りでは,直感的に有望そうといった問題はコンピュータにお株を奪われていくかもしれないが,
直線的だけど深い読みが必要そうといった問題の解決には,まだ何かが必要そうな印象を受けました.
さておき,AlphaGoによって今後様々な定石が登場しそうで楽しみです.
TensorFlow - 画像を加工してみる.
TensorFlowには画像を加工するための様々な関数が用意されています.
CIFAR-10のチュートリアルでも色々と適用しているので画像加工部分のみ切り出してみました.
tensorflow/models/image/cifar10/cifar10_input.py - tensorflow - Git at Google
加えた処理
- 画像の切り取り(ランダムに適用)
- 明るさの変更(ランダムに適用)
- コントラストの変更(ランダムに適用)
- 白色化
コード
#!/usr/bin/env python # -*- coding: utf-8 -*- from sklearn.datasets import load_sample_images import matplotlib.pyplot as plt import tensorflow as tf def main(args): original_image = load_sample_images().images[0] / 255.0 img = tf.placeholder(tf.float32, shape=[427, 640, 3]) # 画像の切り取り height, width = 400, 400 crop_img = tf.image.random_crop(img, [height, width]) # 明るさをランダムに変更 brightness_img = tf.image.random_brightness(img, max_delta=63) # コントラストをランダムに変更 contrast_img = tf.image.random_contrast(img, lower=0.2, upper=1.8) # 白色化 whitening_img = tf.image.per_image_whitening(img) with tf.Session() as sess: imgs = [original_image] + sess.run([crop_img, brightness_img, contrast_img, whitening_img], feed_dict={img: original_image}) for i, (image, title) in enumerate(zip(imgs, ["original", "crop", "brightness", "contrast", "whitening"])): plt.subplot(231 + i) plt.imshow(image) plt.title(title) plt.show() if __name__ == "__main__": tf.app.run()
結果
GPUを使ってTensorFlowで遊んでみる.
EC2でGPUを使えるようにするために,以下の設定を行いました.
1. AMIの選択: "Ubuntu Server 14.04 LTS (HVM), SSD Volume Type - ami-9abea4fb"を選択
2. インスタンスタイプの選択: "g2.2xlarge"を選択
3. ストレージの追加: 64GBに増やす.
4. あとは下記URLの方の通りに設定する.(助かりました m(_ _)m)
http://www.sekailab.com/wp/2015/11/18/setup-tensorflow-gpu-ec2/
http://askubuntu.com/questions/183867/how-do-i-update-oracle-java-7-jdk-and-jre
- tensorflow-0.5.0-py2-none-any.whlの代わりにtensorflow-0.6.0-py2-none-any.whlを使用する.
$ cd ~/tensorflow/tensorflow/models/image/mnist $ time python convolutional.py ... Step 8500 (epoch 9.89), 25.8 ms Minibatch loss: 1.601, learning rate: 0.006302 Minibatch error: 0.0% Validation error: 0.9% Test error: 0.8% real 3m44.491s user 2m46.346s sys 1m23.404s
sklearn風にTensorFlowを使えるライブラリskflowを使ってみる.
TensorFlowをsklearn風に使えるライブラリskflowを発見.
インストール方法
pip install git+git://github.com/tensorflow/skflow.git
サンプル
skflow/examples at master · tensorflow/skflow · GitHub
iris(アヤメ)の線形分類
ロジスティック回帰を用いてアヤメを分類
- コード
import skflow from sklearn import datasets, metrics iris = datasets.load_iris() classifier = skflow.TensorFlowLinearClassifier(n_classes=len(set(iris.target))) classifier.fit(iris.data, iris.target) score = metrics.accuracy_score(iris.target, classifier.predict(iris.data)) print("Accuracy: %f" % score)
- 実行結果
I tensorflow/core/common_runtime/local_device.cc:40] Local device intra op parallelism threads: 4 I tensorflow/core/common_runtime/direct_session.cc:58] Direct session inter op parallelism threads: 4 Step #1, avg. loss: 5.27594 Step #21, epoch #4, avg. loss: 1.46109 Step #41, epoch #8, avg. loss: 0.80689 Step #61, epoch #12, avg. loss: 0.61384 Step #81, epoch #16, avg. loss: 0.52919 Step #101, epoch #20, avg. loss: 0.46205 Step #121, epoch #24, avg. loss: 0.63972 Step #141, epoch #28, avg. loss: 0.36715 Step #161, epoch #32, avg. loss: 0.48894 Step #181, epoch #36, avg. loss: 0.32878 Accuracy: 0.886667 real 0m3.050s user 0m2.123s sys 0m0.554s
bostonの線形回帰
最小二乗誤差を用いてボストンの物件価格を推定.
- コード
import skflow from sklearn import datasets, metrics, preprocessing boston = datasets.load_boston() X = preprocessing.StandardScaler().fit_transform(boston.data) regressor = skflow.TensorFlowLinearRegressor() regressor.fit(X, boston.target) score = metrics.mean_squared_error(regressor.predict(X), boston.target) print ("MSE: %f" % score)
- 実行結果
I tensorflow/core/common_runtime/local_device.cc:40] Local device intra op parallelism threads: 4 I tensorflow/core/common_runtime/direct_session.cc:58] Direct session inter op parallelism threads: 4 Step #1, avg. loss: 477.46436 Step #21, epoch #1, avg. loss: 392.31329 Step #41, epoch #2, avg. loss: 150.05814 Step #61, epoch #3, avg. loss: 33.18234 Step #81, epoch #5, avg. loss: 25.03089 Step #101, epoch #6, avg. loss: 22.11081 Step #121, epoch #7, avg. loss: 26.25769 Step #141, epoch #8, avg. loss: 24.56068 Step #161, epoch #10, avg. loss: 21.69363 Step #181, epoch #11, avg. loss: 23.11506 MSE: 22.851618 real 0m3.734s user 0m2.203s sys 0m0.632s
iris(アヤメ)の分類
隠れ層が[10,20,10]となるDNNを用いてアヤメの分類
- コード
import skflow from sklearn import datasets, metrics iris = datasets.load_iris() classifier = skflow.TensorFlowDNNClassifier(hidden_units=[10, 20, 10], n_classes=len(set(iris.target))) classifier.fit(iris.data, iris.target) score = metrics.accuracy_score(iris.target, classifier.predict(iris.data)) print("Accuracy: %f" % score)
- 実行結果
I tensorflow/core/common_runtime/local_device.cc:40] Local device intra op parallelism threads: 4 I tensorflow/core/common_runtime/direct_session.cc:58] Direct session inter op parallelism threads: 4 Step #1, avg. loss: 1.75397 Step #21, epoch #4, avg. loss: 0.88171 Step #41, epoch #8, avg. loss: 0.71925 Step #61, epoch #12, avg. loss: 0.56106 Step #81, epoch #16, avg. loss: 0.49119 Step #101, epoch #20, avg. loss: 0.42057 Step #121, epoch #24, avg. loss: 0.45917 Step #141, epoch #28, avg. loss: 0.36405 Step #161, epoch #32, avg. loss: 0.40900 Step #181, epoch #36, avg. loss: 0.30453 Accuracy: 0.920000 real 0m5.406s user 0m2.905s sys 0m1.039s
TensorFlow - CIFA10のチュートリアルを試してみる
- 原文
- 翻訳
http://qiita.com/KojiOhki/items/e218f36840df10ae358d
所感
注意点
実験結果
$ wget https://tensorflow.googlesource.com/tensorflow/+archive/0.6.0/tensorflow/models/image/cifar10.tar.gz $ tar xzvf cifar10.tar.gz $ python cifar10_train.py # 時間がかかるので同ファイルのmax_stepの値を下げたほうが無難かも. $ python cifar10_eval.py
チュートリアルを実行するだけなら上のコマンドで大丈夫です.(最新版だとcifar10_eval.pyで下記のエラーを吐くのでv0.6.0を利用しています.)
AttributeError: 'ExponentialMovingAverage' object has no attribute 'variables_to_restore'
cifar10_train.pyではモデルの評価をしないので,分類精度を知りたい場合はcifar10_eval.pyを実行する必要があります.
cifar10_train.pyでは反復処理1000回ごとに一度,モデルの全パラメータを保存したcheckpointを生成してくれるので,3000回程度反復させてから精度を調べてみると良いかもしれません.
コード
あとMNISTのチュートリアルのコードを基に,保存処理や視覚化,GPU演算などを取り払ってチュートリアルの訓練部分を書き直してみたのが下記コードとなります..
# cifar10_train.py import os import tensorflow as tf import cPickle import numpy as np import cv2 import time IMAGE_SIZE = 24 NUM_CLASSES = 10 def unpickle(filename): with open(filename, 'rb') as fp: return cPickle.load(fp) def maybe_download(): if not os.path.exists("cifar-10-batches-py"): os.system("curl http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz -o cifar-10-python.tar.gz") os.system("tar xzvf cifar-10-python.tar.gz") def shuffle(images, labels): perm = np.arange(len(labels)) np.random.shuffle(perm) return np.array(images)[perm], np.array(labels)[perm] def dense_to_one_hot(labels_dense, num_classes=10): num_labels = labels_dense.shape[0] index_offset = np.arange(num_labels) * num_classes labels_one_hot = np.zeros((num_labels, num_classes)) labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1 return labels_one_hot def crop_to_bounding_box(image, offset_height, offset_width, target_height, target_width): return image[offset_width:offset_width+target_width, offset_height:offset_height+target_height] def random_contrast(image, lower, upper, seed=None): contrast_factor = np.random.uniform(lower, upper) avg = np.mean(image) return (image - avg) * contrast_factor + avg def random_brightness(image, max_delta, seed=None): delta = np.random.randint(-max_delta, max_delta) return image - delta def per_image_whitening(image): return (image - np.mean(image)) / np.std(image) def random_flip_left_right(image): if np.random.random() < 0.5: image = cv2.flip(image, 1) return image def random_crop(image, size): W, H, D = image.shape w, h, d = size left, top = np.random.randint(W - w + 1), np.random.randint(H - h + 1) return image[left:left+w, top:top+h] def distort(images, is_train=True): for i, image in enumerate(images): image = np.array(image) image = image.astype(float) if is_train: image = random_crop(image, (24, 24, 3)) image = random_flip_left_right(image) image = random_brightness(image, max_delta=63) image = random_contrast(image, lower=0.2, upper=1.8) else: image = crop_to_bounding_box(image, 4, 4, 24, 24) images[i] = per_image_whitening(image) return images def load(is_train=True): images, labels = [], [] if is_train: for j in range(1, 6): cifar10 = unpickle("cifar-10-batches-py/data_batch_%d" % j) for i in range(len(cifar10["labels"])): image = np.reshape(cifar10["data"][i], (3, 32, 32)) image = np.transpose(image, (1, 2, 0)) images.append(image) labels.append(cifar10["labels"][i]) else: cifar10 = unpickle("cifar-10-batches-py/test_batch") for i in range(len(cifar10["labels"])): image = np.reshape(cifar10["data"][i], (3, 32, 32)) image = np.transpose(image, (1, 2, 0)) images.append(image) labels.append(cifar10["labels"][i]) images = distort(images, is_train) one_hot_labels = dense_to_one_hot(np.array(labels)) return shuffle(images, one_hot_labels) def _variable_on_cpu(name, shape, initializer): with tf.device('/cpu:0'): var = tf.get_variable(name, shape, initializer=initializer) return var def _variable_with_weight_decay(name, shape, stddev, wd): var = _variable_on_cpu(name, shape, tf.truncated_normal_initializer(stddev=stddev)) if wd is not None: weight_decay = tf.mul(tf.nn.l2_loss(var), wd, name='weight_loss') tf.add_to_collection('losses', weight_decay) return var def conv2d(x, W): return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME') def inference(images, keep_prob): with tf.variable_scope('conv1') as scope: dim1 = 64 W1 = _variable_with_weight_decay('weights', shape=[5, 5, 3, dim1], stddev=1e-4, wd=0.0) b1 = _variable_on_cpu('biases', [dim1], tf.constant_initializer(0.0)) conv1 = tf.nn.relu(conv2d(images, W1) + b1) pool1 = tf.nn.max_pool(conv1, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool1') h1 = tf.nn.lrn(pool1, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm1') with tf.variable_scope('conv2') as scope: dim2 = 64 W2 = _variable_with_weight_decay('weights', shape=[5, 5, dim1, dim2], stddev=1e-4, wd=0.0) b2 = _variable_on_cpu('biases', [dim2], tf.constant_initializer(0.1)) conv2 = tf.nn.relu(conv2d(h1, W2) + b2) pool2 = tf.nn.max_pool(conv2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='SAME', name='pool2') h2 = tf.nn.lrn(pool2, 4, bias=1.0, alpha=0.001 / 9.0, beta=0.75, name='norm2') with tf.variable_scope('local3') as scope: dim3 = 384 W3 = _variable_with_weight_decay('weights', shape=[IMAGE_SIZE*IMAGE_SIZE*dim2 / 16, dim3], stddev=0.04, wd=0.004) b3 = _variable_on_cpu('biases', [dim3], tf.constant_initializer(0.1)) h3 = tf.nn.relu(tf.matmul(tf.reshape(h2, [-1, IMAGE_SIZE*IMAGE_SIZE*dim2 / 16]), W3) + b3) with tf.variable_scope('local4') as scope: dim4 = 192 W4 = _variable_with_weight_decay('weights', shape=[dim3, dim4], stddev=0.04, wd=0.004) b4 = _variable_on_cpu('biases', [dim4], tf.constant_initializer(0.1)) h4 = tf.nn.relu(tf.matmul(h3, W4) + b4) with tf.variable_scope('softmax_linear') as scope: W5 = _variable_with_weight_decay('weights', shape=[dim4, NUM_CLASSES], stddev=1/192.0, wd=0.0) b5 = _variable_on_cpu('biases', [NUM_CLASSES], tf.constant_initializer(0.0)) y = tf.nn.softmax(tf.matmul(h4, W5) + b5) return y def loss(labels, logits): return -tf.reduce_mean(labels * tf.log(tf.clip_by_value(logits, 1e-10, 1.0))) def train(total_loss): return tf.train.AdamOptimizer(1e-4).minimize(total_loss) def accuracy_score(labels, logits): correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(labels, 1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) return accuracy def main(argv): maybe_download() train_images, train_labels = load(is_train=True) test_images, test_labels = load(is_train=False) max_epoch, batch_size = 200, 50 with tf.Session() as sess: images = tf.placeholder("float", shape=[None, IMAGE_SIZE, IMAGE_SIZE, 3]) labels = tf.placeholder("float", shape=[None, NUM_CLASSES]) keep_prob = tf.placeholder("float") is_train = tf.placeholder("bool") logits = inference(images, keep_prob) total_loss = loss(labels, logits) if is_train: train_op = train(total_loss) accuracy = accuracy_score(labels, logits) sess.run(tf.initialize_all_variables()) feed_dict={images: test_images, labels: test_labels, keep_prob: 1.0, is_train: False} test_logits, test_total_loss, test_acc = sess.run(fetches=[logits, total_loss, accuracy], feed_dict=feed_dict) best_test_acc, best_test_total_loss, num_keep = test_acc, test_total_loss, 0 print "total test loss:%.1f, test accuracy:%.2f" % (best_test_total_loss, best_test_acc) for epoch in range(max_epoch): train_images, train_labels = load(is_train=True) start_time = time.time() for i in range(0, len(train_images), batch_size): batch_images, batch_labels = train_images[i:i+batch_size], train_labels[i:i+batch_size] feed_dict={images: batch_images, labels: batch_labels, keep_prob: 0.5, is_train: True} _, train_logits, train_total_loss, train_acc = sess.run(fetches=[train_op, logits, total_loss, accuracy], feed_dict=feed_dict) duration = time.time() - start_time feed_dict={images: test_images, labels: test_labels, keep_prob: 1.0, is_train: False} test_logits, test_total_loss, test_acc = sess.run(fetches=[logits, total_loss, accuracy], feed_dict=feed_dict) examples_per_sec = (len(train_images) / duration) print "[%d][cifar10]train-loss:%.3f, train-accuracy:%.2f," % (epoch, train_total_loss, 100 * train_acc), print "test-loss:%.3f(best: %.3f), test-accuracy:%.2f(best: %.2f)" % (test_total_loss, best_test_total_loss, 100 * test_acc, 100 * best_test_acc), print '(%.1f examples/sec)' % examples_per_sec if best_test_acc < test_acc: print "[BEST] Acc: %.3f -> %.3f, Loss: %.3f -> %.3f" % (best_test_acc, test_acc, best_test_total_loss, test_total_loss) best_test_acc, best_test_total_loss = test_acc, test_total_loss if __name__ == "__main__": tf.app.run()
実行結果
$ time python cifar10_train.py I tensorflow/stream_executor/dso_loader.cc:105] successfully opened CUDA library libcublas.so locally I tensorflow/stream_executor/dso_loader.cc:105] successfully opened CUDA library libcudnn.so locally I tensorflow/stream_executor/dso_loader.cc:105] successfully opened CUDA library libcufft.so locally I tensorflow/stream_executor/dso_loader.cc:105] successfully opened CUDA library libcuda.so.1 locally I tensorflow/stream_executor/dso_loader.cc:105] successfully opened CUDA library libcurand.so locally I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:900] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero I tensorflow/core/common_runtime/gpu/gpu_init.cc:102] Found device 0 with properties: name: GeForce GTX TITAN X major: 5 minor: 2 memoryClockRate (GHz) 1.076 ... total test loss:0.2, test accuracy:0.10 [0][cifar10]train-loss:0.177, train-accuracy:34.00, test-loss:0.160(best: 0.230), test-accuracy:40.74(best: 10.00) (563.9 examples/sec) [BEST] Acc: 0.100 -> 0.407, Loss: 0.230 -> 0.160 [1][cifar10]train-loss:0.152, train-accuracy:56.00, test-loss:0.151(best: 0.160), test-accuracy:44.96(best: 40.74) (545.4 examples/sec) [BEST] Acc: 0.407 -> 0.450, Loss: 0.160 -> 0.151 [2][cifar10]train-loss:0.162, train-accuracy:40.00, test-loss:0.137(best: 0.151), test-accuracy:51.04(best: 44.96) (552.1 examples/sec) [BEST] Acc: 0.450 -> 0.510, Loss: 0.151 -> 0.137 [3][cifar10]train-loss:0.121, train-accuracy:62.00, test-loss:0.128(best: 0.137), test-accuracy:54.03(best: 51.04) (549.5 examples/sec) [BEST] Acc: 0.510 -> 0.540, Loss: 0.137 -> 0.128 ...