ディープラーニング勉強会 AutoEncoder

某所ディープラーニング勉強会の発表資料です。

# AutoEncoderって何？

出力データが入力データをそのまま再現する3層ニューラルネットだよ。
普通は、隠れ層の次元を入力層＆出力層より小さくするよ。

# AutoEncoderの意味は？

次元削減だよ。
データが分布する多様体を推定しているともいえるよ。
主成分分析に似てるけど、シグモイド関数とかの非線形変換もいけるよ。

# AutoEncoderはいつ使うの？

事前学習だよ。ニューラルネット全体で学習を行うための良い初期パラメータを得るのに行うよ。
訓練データで教師無し学習をしていくよ。n層目まで完了したらn+1層目の学習をするよ。
誤差の逆伝播が遠くの層へうまく伝わらない問題を解決したよ。

# 計算式

アフィン変換（線形変換＋平行移動）して活性化関数に食わせる。

入力層：$x \in [0,1]^d$
隠れ層：$y = f_{W, b}(x) = s(Wx + b) \in [0,1]^{d'}$
出力層：$z = g_{W', b'}(y) = s(W'y + b') \in [0,1]^d$
目的関数：$\min_{W, b, W', b'} {1 \over n}\sum_{i=1}^n L(x^{(i)}, g(f(x^{(i)})))$

* $W'$は$W$の転置行列と制約かけてよい
* $s(x_k)$は活性化関数、ベクトルの要素ごとに適用
    * 標準シグモイド関数 $1 \over 1 + e^{-x_k}$
        * 微分しやすい
* $L(x,z)$は損失関数
    * 二乗誤差 $\sum_{k=1}^d (x_k-z_k)^2$
    * ベルヌーイ分布のクロスエントロピー $-\sum_{k=1}^d x_k \log z_k + (1-x_k) \log (1 - z_k)$
        * $x_k$,$z_k$を、0,1の二値のうち$x_k$,$z_k$の確率で1を取る確率分布とみなす
        * $x_k$の確率のもと$z_k$の情報量の期待値がクロスエントロピー
* $i$は訓練データのインデックス

# 勾配法による学習

$W^{new} = W^{old} - {\epsilon \over n} \sum_{i=1}^n {\partial L(x^{(i)}, g(f(x^{(i)}))) \over \partial W}$
$b^{new} = b^{old} - {\epsilon \over n} \sum_{i=1}^n {\partial L(x^{(i)}, g(f(x^{(i)}))) \over \partial b}$
${b'}^{new} = {b'}^{old} - {\epsilon \over n} \sum_{i=1}^n {\partial L(x^{(i)}, g(f(x^{(i)}))) \over \partial b'}$

* $\partial L \over \partial W$は、k行l列目の要素が$\partial L \over \partial W_{k,l}$の行列を表す
* $\partial L \over \partial b$は、k番目の要素が$\partial L \over \partial b_k$のベクトルを表す

$W' = W^T$
活性化関数を標準シグモイド関数
損失関数をベルヌーイ分布のクロスエントロピー
として偏微分がんばると、

$ {\partial L \over \partial W} = (W(x -z) * y * (1 - y))x^T + ((x -z)y^T)^T$
$ {\partial L \over \partial b} = W(x-z) * y * (1-y) $
$ {\partial L \over \partial b'} = x -z $

* アスタリスクは要素積

# 確率的勾配降下法

オンライン学習（⇔バッチ学習）の一種。
ランダムに選んだデータの微分値で補正する。

$W^{new} = W^{old} - {\epsilon \over n} {\partial L(x^{(i)}, g(f(x^{(i)}))) \over \partial W}$
$b^{new} = b^{old} - {\epsilon \over n} {\partial L(x^{(i)}, g(f(x^{(i)}))) \over \partial b}$
${b'}^{new} = {b'}^{old} - {\epsilon \over n} {\partial L(x^{(i)}, g(f(x^{(i)}))) \over \partial b'}$
ここで$i$はランダムに選択

経験的に、最急降下法より、収束が速く収束値も良い。

# Denoising Autoencoder

訓練データにノイズを加えたものを入力し、出力は元の訓練データとの誤差を取る。
ノイズに対して頑強になる。

* ガウスノイズ：正規分布に従った値を加える
* マスキングノイズ：ランダムに選んだ要素を0にする
* 胡麻塩ノイズ：ランダムに選んだ要素を0か1にする

# Denoising Autoencoderの実装

「[ScalaによるDeep Learningの実装 - Yusuke Sugomori's Blog](http://blog.yusugomori.com/post/63281316031/scala-deep-learning)」のDenoising Autoencoderの実装を、数式に近づけて書きなおしてみたのが下記コード。
ベクトル・行列演算さえ扱えれば、言語によらずさくっと書けるはず。

```scala
import scala.math
import scala.util.Random
import MatrixImplicits._ // 自作のimplicit classによるSeqラッパ

class dA(train_N: Int, n_visible: Int, n_hidden: Int, seed: Int) {
  val rng = new Random(seed)
  
  var W = Seq.fill(n_hidden, n_visible)(uniform(-1.0 / n_visible, 1.0 / n_visible))
  var hbias = Seq.fill(n_hidden)(0.0)
  var vbias = Seq.fill(n_visible)(0.0)

  def uniform(min: Double, max: Double): Double = rng.nextDouble() * (max - min) + min
  def sigmoid(x: Double): Double = 1.0 / (1.0 + math.exp(-x))
  def corrupted(x: Seq[Double], p: Double): Seq[Double] = x.map(_ * (if (rng.nextDouble() < p) 0.0 else 1.0))
  
  def encode(x: Seq[Double]): Seq[Double] = ((W mXc x) + hbias).map(sigmoid) 
  def decode(y: Seq[Double]): Seq[Double] = ((W.T mXc y) + vbias).map(sigmoid)
 
  def train(x: Seq[Double], learning_rate: Double, corruption_level: Double) {
    val tilde_x = corrupted(x, corruption_level)
    val y = encode(tilde_x)
    val z = decode(y)

    val L_vbias = x - z
    val L_hbias = (W mXc L_vbias) * y * y.map(1.0 - _)

    vbias = vbias + L_vbias.map(_ * learning_rate / train_N)
    hbias = hbias + L_hbias.map(_ * learning_rate / train_N)
    W = W + ((L_hbias cXr tilde_x) + (y cXr L_vbias)).map2(_ * learning_rate / train_N)
  }
}
```

# 参考文献

## ディープラーニング

* [ディープラーニング チュートリアル（もしくは研究動向報告）](http://www.vision.is.tohoku.ac.jp/files/9313/6601/7876/CVIM_tutorial_deep_learning.pdf)
    * リンク先はPDFファイル
* [ニューラルネットの逆襲 _ Preferred Research](http://research.preferred.jp/2012/11/deep-learning/)

## AutoEncoder

* [楽しいAutoEncoderと学習の世界 - Swanky Street](http://vaaaaaanquish.hatenablog.com/entry/2013/12/03/033850)
* [Denoising Autoencoderとその一般化 - @beam2d](http://beam2d.github.io/blog/2013/12/23/dae-and-its-generalization/)
* [Denoising Autoencodersにおける確率的勾配降下法（数式の導出） - Yusuke Sugomori's Blog](http://blog.yusugomori.com/post/42116682299/denoising-autoencoders)
    * 最急降下法の数式を導出している気がする
* [Extracting and Composing Robust Features with Denoising Autoencoders](http://dl.acm.org/citation.cfm?id=1390294)
* [Stacked Denoising Autoencoders: Learning Useful Representations in a Deep Network with a Local Denoising Criterion](http://dl.acm.org/citation.cfm?id=1953039)

## 勾配法

* [第16回　最適化のための勾配法：機械学習 はじめよう｜gihyo.jp](http://gihyo.jp/dev/serial/01/machine-learning/0016)
* [確率的勾配降下法 - 数理計画用語集](http://www.msi.co.jp/nuopt/glossary/term_da265770bed70e5f0a764f3d20c0ce3d242e6467.html)