ウォンツテック

技術的な話や会社設立に関わる話などを適当にしていきます

機械学習 SVMを使う基準

stanford machine learning 7週目です

SVM (Support Vector Machine)というニューラルネットワークではない学習モデルの一つ。 ロジスティック回帰でやるかSVMでやるかは以下のような基準で切り分ける

学習に利用する特徴点(家の価格を予想する場合は広さ、部屋数、最寄り駅などの情報)の数をnとし、学習するトレーニングセットの数をmとした場合

n が m に比べてかなり大きい場合

例えばnが10000でmが10〜10000くらいの場合 ロジスティック回帰か、SVM without Kernel(線形カーネル)を利用する

n が m に比べてかなり小さい場合

nが1〜1000でmが10〜10000くらいの場合 SVMガウスカーネルで利用する ※mは5万くらいまでが良い。それ以上だとガウスカーネルを利用すると遅い

n が少なくて mが極めて多い場合

nが1〜1000でmが5万以上〜数百万の場合 自分で特徴点の数を増やし(新たに収集し)、ロジスティック回帰か、SVM without Kernel(線形カーネル)を利用する

ニューラルネットワークの利用について

上記の問題全てにニューラルネットワークのモデルを適切に作れば有効に働くが、計算速度が遅いケースがあるため適切にロジスティック回帰かSVMを用いる方が良い

機械学習 モデルのデバッグ

stanfordのmachine learning講習も6週目です

すごく重要な回だったので少しまとめ

アルゴリズムデバッグ手法

cross validationのチェック

学習の正当性を確認するのにデータを

  • training set
  • cross validation set
  • test set

に分けます。 トレーニングセットは学習のためのセットで残り2つは、それが妥当かの確認に使います 大体割合は60%:20%:20%で分けるとの事。 cross validation setはfeatureの数や正規化(λ)の加減、polynomial(ひとつのfeature xに対し、x2, x3などをfeatureに加える方法)の増加などを実施した際に正しく学習出来ているかを確認するためのデータセット。 学習状況の確認手順は以下

  1. training setの数をmとするとfor i =1:m とした繰り返しの中で2〜5を繰り返す
  2. training setのi個分のデータに対しを正規化されたコスト関数で学習し、最小となるパラメータを求める
  3. 2のパラメータを使い正規化していないコスト関数でtraining set i個分に対するコスト関数の値を出す
  4. 2のパラメータを使い正規化していないコスト関数でcross validation set(全データ)に対するコスト関数の値を出す
  5. 3と4の出力結果を元にhigh bias状態かhigh variance状態かを確認する
  6. 状況に合わせてパラメータに修正を加え1〜5を繰り返し試す
  7. 最適な状態でtest setでエラー率を出す

high biasな状態

under fittingで起こる。training setのエラー率が高く、cross validation setでのエラー率も高い 学習を進めるとtraining setとcross validation setのエラー率がほぼ同じになる。最終的に収束するエラー率が高いのでtraining setをいくら増やして学習させても無駄なのでこの状態が現れたら即見直し。

high varianceな状態

over fitting(過学習)で起こる。training setのエラー率が低く、cross validation setでのエラー率は高い 学習を進めると training setのエラー率がcross validation setのエラー率より低く、徐々に差は縮まってくる。 収束するエラー率は期待される値に近づくのでtraining setを集めるなり、他の対処方法でチューニングすべし。

状況に合った対応方法

high bias

  • featureを増やす -> hidden layer増やしたりhidden layerのfeature数を増やす
  • polynomial featureを増やす -> x2, x3やらx1*x2やらを増やすんだけどニューラルネットワークなら上記の方法で良さそう?
  • 正規化λを減らす -> over fitting是正するために入れたλが高すぎる場合にhigh biasになってる可能性あり

high variance

  • training setを増やす
  • featureの数を減らす -> hidden layer多すぎたりhidden layer中のparameter数が多い場合に減らす
  • 正規化λを増やす -> λは増やしすぎるとhigh biasになるので注意。まだ最適でないなら増やす

Stanford UniversityのOnline machine learningコースを受ける

ゼロから作るDeep Learningの本を読み終えた後にtensor flowのチュートリアルやkerasのチュートリアルをいくつかやっていたのですが、もう少し体系的に勉強したいなと思い

www.coursera.org

このStanford Universityが実施しているオンラインの機械学習コースを受講しています。ビデオ講義がメインで所々に選択式や埋込み式のテストが実施され80%以上の正答率だと次の講習に進めます。全体で11週分の講義があり、コードを書いて提出させる形式のテストが週に1回ほどあります。


講義ビデオですが、日本語の字幕を出せます。また講義中の英語が非常に平易なので、ある程度の専門の英単語に慣れてきたら英語字幕でも理解出来るかと思います。数学についても事細かに説明されているので数学の前提知識なしでも進められるかもしれません。


このコースの教授が勧めているのがOctaveという数式計算に特化した言語で、機械学習を勉強するにはこの言語が最適だとの事です。確かにOctaveは行列計算などが紙で計算する方法とだいぶ近いため、numpyのようなコンピュータよりな計算方法より取っ付き安いです。シリコンバレーの人達も機械学習のモデルを実験する際はOctaveを使う事が多いそうです。


Week2(全Week11)まで受けた感想としては、機械学習を勉強する以外の障壁となる知識(数学やツールの使い方等)を極力意識させないように講義をすすめている所が大変素晴らしいです。

TensorFlowを使ってみる 5

Kerasを使ってみる

tensorflowの高機能ライブラリであるcontrib.learnを使ってみたんですが
今一わかりづらかったのでもう一つの高機能ライブラリであるKerasをさわってみます

とりあえず1層でOptimizerは最降下勾配方で最も単純なネットワークを組んでみます

gist.github.com

contrib.learnと比べて層で何をやっているかが非常に明快です。
ただし、結果としてはaccuracyが0.86くらいと前回素のtensorflowで組んだ場合の0.97と比べるとかなり低いです。

と思って調べてみたら、lrの値、learning rateという1回の微分でどの程度重みを移動させるかの値が0.01とかなり低い値を指定してしまっていました。

素のtensorflowで組んだ場合と同じ値の0.5にしたらaccuracyは0.956と精度は近づいてます。

後、精度を出すのに重要なハイパーパラメータである重みの初期値を以下のように合わせてみたんですが、精度は逆に落ちて0.952くらいとなってしまいました。

std_deviation = 0.01

def my_init(shape, name=None):
    print(shape)
    value = std_deviation * np.random.randn(*shape)
    return K.variable(value, name=name)

model.add(Dense(output_dim=100, input_dim=784, init=my_init))

Keras使ってみる 2

Kerasで畳み込みニューラルネットワークを書いてみました

gist.github.com

やはりcontrib learnより何をやっているか分かり易く、Try&Errorが容易に出来そうな気がします

結果はaccuracyが0.991となりました。

TensorFlowを使ってみる 4

畳み込みニューラルネットワークチュートリアルをやってみる

Deep MNIST for Experts  |  TensorFlow

このページの「Build a Multilayer Convolutional Network」以下をやってみました

※mnistは「ゼロから作るDeepLearning本」の方で取得したデータを利用するように変えてあります

気になった所をいくつか抜粋

def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

def main(_):
    ...
    W_conv1 = weight_variable([5, 5, 1, 32])

フィルターのtensorの順序がゼロから作る本と違う。
内部的には正しい計算をしているはずなのでいいとして、TensorFlowのConvolutionの順序は縦、横、チャネル(色)、アウトプットチャネルです。

def conv2d(x, W):
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

stridesに渡す配列の0と3番目の要素は必ず1とし、中の二つの値(同じにする)がstrideとなる。
この場合はstrideが1。
paddingは2種類「SAME」と「VALID」を指定出来てSAMEの場合は入力と出力のサイズが同じになるように自動でpaddingを調整してくれる。VALIDの場合は何もせず。
max_pool_2x2で定義されているstridesとpaddingも同じ。ksizeはpoolフィルタのサイズで2x2。

    W_fc1 = weight_variable([7*7*64, 1024])
    b_fc1 = bias_variable([1024])
    h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
    h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

2回のpoolフィルタで28x28x1→ 14x14x32→ 7x7x64までになったデータを一旦1024個のニューロンに出力してます(Affine変換で)
(2x2のフィルタをstride 2でフィルタしてるので元の半分になる)
今一何のためにやってるかわかりません。
データを圧縮するため?

   keep_prob = tf.placeholder(tf.float32)
    h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

過学習を防ぐためにいくつかのニューロンの伝搬を止めるdropout層というのが挿入されてます

    W_fc2 = weight_variable([1024, 10])
    b_fc2 = bias_variable([10])
    y_conv = tf.matmul(h_fc1_drop, W_fc2) + b_fc2

    y_ = tf.placeholder(tf.float32, [None, 10])
    cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y_conv))
    train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

最後は数字のクラス分けをするために10の値で出力しています(Affine変換)

ちなみにこれでmnistを学習すると

step 11000, training accuracy 1
step 11100, training accuracy 1
step 11200, training accuracy 1
step 11300, training accuracy 0.99
step 11400, training accuracy 1
step 11500, training accuracy 1
step 11600, training accuracy 1
step 11700, training accuracy 1
step 11800, training accuracy 1
step 11900, training accuracy 1
step 12000, training accuracy 1
step 12100, training accuracy 0.99
step 12200, training accuracy 1

こんな感じで0.99を超えました。


試したコード
experiment2.py · GitHub

TensorFlowを使ってみる 3

実際自分で書いた数字で試してみる

前回書いたサンプルコードを使い、実際にmacのお絵描きソフトで書いた以下の数字を認識するかやってみました。
mnistで試してるだけだとなんだか本当に合ってんだかよくわからないですからね。


f:id:sodex:20170214171049p:plain f:id:sodex:20170214171058p:plain f:id:sodex:20170214171104p:plain


gist.github.com

結果は

0.9746
[1 5 7]

となり、こんな汚い数字でも無事認識していました。

数字の取り込みはPILを使いgrayscaleで読み込み(convert("L"))、numpyでmatrixにし、flattenで1次元配列にしたあと反転(255で引く)と正規化(255で割る)を実施しています。

TensorFlowを使ってみる 2

TensorFlowのOptimizerを使ってみる

MNIST For ML Beginners  |  TensorFlow

TensorFlowのチュートリアル機械学習初学者向けのドキュメントを読んで、サンプルのコード

tensorflow/mnist_softmax.py at master · tensorflow/tensorflow · GitHub

をゼロから作るDeepLearning本でやってた2層に改修して実験

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import sys

from tensorflow.examples.tutorials.mnist import input_data

import tensorflow as tf

FLAGS = None


def main(_):
  # Import data
  mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

  # Create the model
  x = tf.placeholder(tf.float32, [None, 784])
  std = 0.01
  W1 = tf.Variable(tf.random_normal([784, 100], stddev=std))
  b1 = tf.Variable(tf.zeros([100]))
  W2 = tf.Variable(tf.random_normal([100, 10], stddev=std))
  b2 = tf.Variable(tf.zeros([10]))
  a1 = tf.matmul(x, W1) + b1
  z1 = tf.sigmoid(a1)
  a2 = tf.matmul(z1, W2) + b2
  y = tf.nn.softmax(a2)


  y_ = tf.placeholder(tf.float32, [None, 10])
  cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
  train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

  sess = tf.InteractiveSession()
  tf.global_variables_initializer().run()

  # Train
  for _ in range(10000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

  # Test
  correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
  accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
  print(sess.run(accuracy, feed_dict={x: mnist.test.images,
                                      y_: mnist.test.labels}))

if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument('--data_dir', type=str, default='/tmp/tensorflow/mnist/input_data',
                      help='Directory for storing input data')
  FLAGS, unparsed = parser.parse_known_args()
  tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

サンプルコードだと重み変数(W)を生成する時に0で初期化してるけど、初期値全部0はよろしくないはずで、Optimizerがよしなにやってくれるんですかね。
実験コードではrandom_normalの標準偏差を0.01にしてます。

Trainingの回数を1万回でだいたいaccuracyが0.931くらいになりました。
ちなみに元のサンプルコードは1層のはずなのにaccuracyが0.923くらいとやたら精度が高い気がします。
1層だと線形で、線形だと簡単な論理演算(XOR)すら表現出来なかったはずなのにと..

※出力層でsoftmaxに渡す値の活性化関数にsigmoidを使っていましたが、これは恒等関数(何もしない)が正しかったです。
書き直したらaccuracyは0.974となりました。