読者です 読者をやめる 読者になる 読者になる

パッケージをアップデートしたらNVIDIAが認識されなくなった...

事件発生!

Ubuntuマシンで毎回パッケージアップデートのダイアログが出てウザいので何気なくパッケージアップデートを実行しました。

そして翌日、いつものように学習プログラムを走らせる

と、 あれ、GPUのエラー ?!?!

$ nvidia-smi してみる。

NVIDIA-SMI has failed because it couldn’t communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

マジか Σ( ̄ロ ̄ lll)

あぁ、やっちまった..。要らんことしなかったら良かった・・  o(;△;)o

解決。。

ドライバを再度インストールしたら直りました。。

wget http://us.download.nvidia.com/XFree86/Linux-x86_64/367.57/NVIDIA-Linux-x86_64-367.57.run
chmod a+x NVIDIA-Linux-x86_64-367.57.run
sudo service lightdm stop
sudo bash ./NVIDIA-Linux-x86_64-367.44.run --no-opengl-files

ふ〜焦ったよ.. ε-(´∀`*)

気をつけよう。

ディープラーニング学習メモ #5 CNN

Karpathy先生のCS231nの講義スライドも使いつつ覚えておきたいポイントをまとめてみます。

畳み込み(Convolution)のイメージ図

f:id:sanshonoki:20170410064711p:plain:w500

ポイント

  • 入力のdepthとフィルタのdepthは同じ。フィルタを適用して1つの値を出力
  • フィルタをスライドさせながら適用して 1枚の アクティベーションマップを 出力
  • N枚のフィルタから N枚のアクティベーションマップを 出力
畳み込みの演算

F = フィルタサイズ

np.sum(X[x:x+F, y:y+F, :] * W) + b
  • フィルタサイズで切り取った X に W を elementwise掛け算 して
  • 演算結果をすべて足し込んでさらに bias を足す


別の書き方をすると

np.dot(X[x:x+F, y:y+F, :].flatten(), W.flatten()) + b

とも書ける。

ネットワーク全体のイメージ図

INPUT -> [[CONV -> RELU]*N -> POOL?]*M -> [FC -> RELU]*K -> FC
  • N: 0 ~ 3程度
  • M: 0 ~
  • K: 0 ~ 3程度

f:id:sanshonoki:20170408074722j:plain

CONV層 + RELU層 と POOL層を重ねて 高次元の特徴を 複数抽出し、全結合(FC)レイヤで 各特徴の重みを学習する というイメージです。

覚えておきたい計算式

  1. アクティベーションマップのサイズ

    ( W − F + 2P ) / S +1

  2. パラメータ数

    ( F * F * 入力フィルタ数 + 1) * 出力フィルタ数

    +1 は bias項になります。

  3. 必要なメモリサイズ

    ( W * H * フィルタ数 ) * 4 (=float32) バイト

    バッチサイズはGPUのメモリサイズに依存します。(GPUのメモリ上にのる限りは大きくしたほうがよい)

    VGGNetの場合だと

    • 画像1枚あたり 93 M (backwardもいれると x 2) となるようです。。

なぜディープにするのがよいのか?

7x7フィルタを1回適用した場合と3x3フィルタを3回適用した場合を比較してみます。

イメージ パラメータ数
7x7フィルタを1回 f:id:sanshonoki:20170408062235p:plain:w150 (7 * 7 * 3 + 1) * 3 = 444
3x3フィルタを3回 f:id:sanshonoki:20170408062304p:plain:w320 (3 * 3 * 3 + 1) * 3 * 3 = 252

出力アクティベーションマップのサイズは 26 x 26 で同じですが3層に積み重ねるほうがより大きな表現力があり(非線形処理を3回適用するので)、またパラメータ数も少なくなり学習効率がよくなります。

一方でメモリサイズはより必要になってくるのでトレードオフの関係にはなります。 GPUのスペックが向上することでよりディープに学習することが可能になったと言えるでしょう。

どんどんディープになっていくトレンドですが ILCVRC'15の勝者の ResNet は なんと.. 152層 です。 w|;゚ロ゚|w

f:id:sanshonoki:20170408071259j:plain

なぜCNNは成功しているのか?

次のような理解で大体あっていると思う。。

画像認識に適したアーキテクチャ
  • 畳み込み: 何層も畳み込むことで高次元の抽象的な特徴を抽出できる
  • プーリング: 位置のずれにロバストになる
以下の2つの大きな課題があったが解決された
  • 過学習 (Overfitting)
  • 勾配消失問題 (Vanishing gradient problem)
解決の要因
  • 手法の進化
    • ReLU: 深いネットワークでも勾配が逆伝搬できるようになった
    • Dropout: 擬似的にアンサンブル学習することで汎化性能が上がり過学習を抑制できるようになった
  • ハードウェアの進化(特にGPU
    • 大量のデータ、大量のパラメータを処理できるようになった

勾配降下法(gradient descent)の実装サンプル

1次元データでCNNのgradient descentをNumpyで実装してみました。 スクラッチで実装すると少し自信がつく気がします。。 (o・ω・o)

github.com

今回は以上です。次は RNN の記事を書いてみようと思います。

学習データ数と認識精度の関係

パドック画像から競走馬の距離適性を推測する学習をしてみたけど性能が全然よくない…!  

ヒィィ (ノ゚ρ゚)ノ

う〜ん、やっぱりデータのサンプル数が少なすぎるのかな・・

ということでchainerのCIFAR-10のサンプルコードを使って学習データ数と認識精度の関係をちょっと調べてみました。

実験条件
  • epoch数: 100
  • 学習データ数: 1000, 3000, 5000, 10000, 50000
結果

f:id:sanshonoki:20170407214433p:plain

やっぱり、機械学習の世界では 数は性能なり なんですね。。

CUDAを7.5から8.0にアップグレード

Udacityのディープラーニング講座の中で使うTensorFlowのバージョンが1.0となっていてCUDA7.5だと動かない… (>_<)

ということで自宅PCのCUDAを7.5から8.0にアップグレードしました。

今まで自分にとって開発環境のアップグレードは鬼門で 今まで動いていたものがいろいろ動かなくなって

ああ、やらんかったらよかった…

ということが多々あったのですが今回はあまりにもスムーズでうれしかったのでメモを残します。(´ー`)

CUDA8.0のインストール

  1. NVIDIAのダウンロードサイトからCUDAをダウンロードしてきます。

    自分のPCにあったものを選択します。Ubuntu14.04用は https://developer.nvidia.com/compute/cuda/8.0/Prod2/local_installers/cuda_8.0.61_375.26_linux-run

  2. ダウンロードしたスクリプトを実行
chmod a+x cuda_8.0.61_375.26_linux-run
sudo service lightdm stop # Stop X-Server
sudo bash ./cuda_8.0.61_375.26_linux.run --silent --no-opengl-libs --toolkit

1分ぐらい待つと何のメッセージ出力がなく終了します。

えっ?( ´・д・)

と思うぐらい拍子抜けです。

続いて以下のコマンドでCUDAがインストールされていることを確認します。

nvidia-smi # check GPU is available
nvcc -V # cuda version should be 8.0

cuDNN(v5.1)のインストール

続いてcuDNNをインストール。こちらもNVIDIAのサイトからダウンロードしてきます。 cuDNNはNVIDIAのユーザー登録が必要です。

ユーザー登録面倒な方はこちらからダウンロードしてください http://momonoki.blob.core.windows.net/data/cudnn/cudnn-8.0-linux-x64-v5.1.tgz

tar xvfz cudnn-8.0-linux-x64-v5.1.tgz
cat /usr/local/cuda/version.txt # /usr/local/cudaがcuda-8.0へのリンクになっていることを確認
sudo cp cuda/include/cudnn.h /usr/local/cuda/include
sudo cp cuda/lib64/* /usr/local/cuda/lib64

chainerやTensorFlowの再インストール

そのままだとCUDAのバージョン不一致で動かないので一度アンインストールしてからインストールします。

# reinstall chainer
pip uninstall chainer
pip install chainer

# reinstall TensorFlow
pip uninstall tensorflow
pip install tensorflow-gpu

再インストールしたらMNISTのサンプル等でGPUありで動くかを確認します。

以上です。

これで AWSGPUインスタンス(何かびびってしまう。。)を使わずに自宅PCで課題を進められます。 (*´Д`)

ディープラーニング学習メモ #4 誤差の逆伝搬

今日は誤差逆伝搬法(Backpropagation)について書いてみます。

Karpathy先生のCS231nの講義が秀逸すぎるのでそれを見れば十分です! (◍•ᴗ•◍)

これではあんまりなので特に覚えておきたいポイントをまとめてみようと思います。。

global勾配にlocal勾配を掛けて次のノードにエラーの誤差を伝搬させる

f:id:sanshonoki:20170321043543j:plain:w450

微分の連鎖律(チェインルール)です。

基本的な演算での伝搬を覚えよう

Add演算はそのまま誤差を伝搬させる

f:id:sanshonoki:20170322041057j:plain:w450

Mul演算は互いの値をクロスに掛けて誤差を伝搬させる

f:id:sanshonoki:20170322041124j:plain:w450

Max演算は値が大きい方へのみ誤差を伝搬させる

f:id:sanshonoki:20170322041153j:plain:w450

分岐ノードは誤差を加算する

f:id:sanshonoki:20170322050746j:plain:w450

RNNのhiddenノードも出力層からの誤差と次のRNNセルからの誤差が加算されます。(hは次のRNNセルへの入力でもあるため)

f:id:sanshonoki:20170322050844j:plain:w450

ベクトルの場合も同じ

computational graph network layer graph
f:id:sanshonoki:20170323051220j:plain:w400 f:id:sanshonoki:20170323051243j:plain:w200

入力がベクトルの場合も同じです。ただ、行列(W)の次元を考慮する必要があります。 掛け算するために転置(T)をしたり、掛ける順番を考慮しないと怒られます..。

ポイント
  • あるノードでの順方向(X)と逆方向(dX)の次元は同じ(当たり前だけど)
  • 出力されるべき次元に合わせて転置や掛ける順番を考える (紙に書けというアドバイスをよく見かける。地道に慣れろということ)
  • この例では W は (outsize, insize) になっているが実際のフレームワークでは W は基本的に (insize, outsize) という次元になる。バッチ単位で処理するため

個人的には computational グラフで考えると誤差の伝搬が計算しやすいです。

バッチ単位で考えたとき

f:id:sanshonoki:20170323051256j:plain:w300

このようにバッチ単位でまとめて行列計算したいときは W は (insize, outsize) となります。 また、WX ではなく D = XW と掛け算します。

今回はここまでです。 マウスで文字を書くのつらい.. (ノ゚ο゚)ノ

ディープラーニング学習メモ #3 誤差と微分

誤差関数の最小化問題

機械学習が何をやっているか、、一言で言えば 誤差を最小化する Wを見つける ということになります。

関数の最小値を求めると言えば高校の数学でも微分を使って最小値を求めていましたが、機械学習の最小化問題は枠組みが少し違っています。

高校の数学 機械学習
L'(w) = 0 となる w を 直接的に計算する あるwが与えられたとき、L'(w) が 0 に近づく wを動かす向き を見つける
 L = w^{2} のとき  \frac{dL}{dw} = 2w

 \frac{dL}{dw}  = 0 となるのは  w = 0 のとき

このとき、最小値  L(0) = 0
f:id:sanshonoki:20170312073508p:plain:w300

右図のように勾配(gradient)を計算して変数を更新していきます。 実際には誤差関数はいくつかの変数からなる関数なので偏微分(partial derivative)で勾配を求めます。

いずれにせよ、微分は知っておく必要があります。。┗(`・∀・´●)

合成関数の偏微分

実際にはいくつもの演算が組み合わさった結果を微分することになるので目的の変数の勾配を計算するにはチェインルール(連鎖律)を知っておく必要があります。

マストです。。 (゜ロ゜)

計算例

 y = wx + b L(w, b) = \frac{(t - y)^{2}}{2} であるとき

 d = t - y とおくと  L = d^{2} / 2


 \frac{\delta L}{\delta w} = \frac{\delta L}{\delta d} * \frac{\delta d}{\delta w}

 = \frac{\delta (d^{2} / 2) }{\delta d} * ( \frac{\delta d}{\delta y} * \frac{\delta y}{\delta w} )

 = d * \frac{\delta (t - y)}{\delta y} * \frac{\delta (wx + b)}{\delta w}

 = d * -1 * x

 = (y - t) * x

イメージ

個人的にはPFNの岡野原さんのスライドがイメージを掴みやすかったです。

IIBMP2016 深層生成モデルによる表現学習

f:id:sanshonoki:20170313050821j:plain f:id:sanshonoki:20170313050840j:plain

覚えておきたい基本的な微分の計算

とりあえず、以下を知っていれば大抵は何とかなるはず・・・

関数 導関数
 ax  a
 x + c  1
 x^{2}  2x
 \frac{1}{x}  -\frac{1}{x^{2}}
 e^{x}  e^{x}
 \log x  \frac{1}{x}

勾配降下法(gradient descent)の実装サンプル

クラッチで実装すると自信がつく気がします。。 (o・ω・o)

github.com

競走馬の距離適性を計算する

前回パドック画像を収集しました。今回は各パドック画像のラベリングを行い学習データを作ります。

距離適性の計算

これまたnetkeibaにお世話になります。m(._.*)m

netkeibaの各馬のデータには 適性レビュー というデータがあります。 この適性レビューの 距離適性のパラメータ を利用します。

例えば、オルフェーヴルの距離適性のデータは以下のようになっています。 距離適性が 短い/長い のバーの長さの割合で表現されています。

f:id:sanshonoki:20170305072822p:plain:w400

htmlコードを見てみます。

f:id:sanshonoki:20170305073742p:plain

“短い” と “長い” のバーの長さが widthの数値で取得できそうです。(^○^)

  • 短い: 43
  • 長い: 73

距離適性は次式

 73 / (43 + 73) =  0.6293103448275862

で計算します。

この値が 0.0 に近ければ 短距離馬 で 1.0 に近ければ 長距離馬 になります。

距離適性の取得

馬名を入力として 先ほどの距離適性の値を取得します。 使ったコードはこちらにあります。

github.com

結果と分類

2525頭分の計算結果は https://github.com/tanakatsu/netkeiba_distance_aptitude/blob/master/sample.sorted_score.txt

になります。

私の肌感覚でざっくり分類すると、

category score
長距離 0.6-
中距離 0.4-0.59
マイラー 0.2-0.39
短距離 -0.19

っていうところでしょうか。

ただ、明確に線引きすることは難しそうなので長距離と短距離の分類(Classification)とかではなく回帰(Regression)として扱うのがよさそうです。

次はいよいよ学習です。 ((((o゚▽゚)o)))