LoginSignup
84
89

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-05-08

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

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」のDenoising Autoencoderの実装を、数式に近づけて書きなおしてみたのが下記コード。
ベクトル・行列演算さえ扱えれば、言語によらずさくっと書けるはず。

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)
  }
}

参考文献

ディープラーニング

AutoEncoder

勾配法

84
89
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
84
89