アイアナブログ 〜統計学・機械学習・AI〜

データコンサル会社アイアナのブログ。統計学、Rを使ったデータ分析、Pythonを使ったAIなど

RでDeep Learningの一種をやってみる

このブログのTips052で、RでDeep Learningをやっているのを紹介してもらったので、自分も試してみました。

Deep Learningすげぇ!!」という話は良く聞くのですが、亜種がいっぱいあるみたいで、まだあまり調査しきれてません。また時間があれば調査してまとめられると良いのですが。

以下、RでDA(Denoising Autoencoders)を実行するプログラムです。

sigmoid <- function(x){
     return (1 / (1 + exp(-x)))
}

dA <- setRefClass(
        Class="dA",
        fields=list(input="matrix", n_visible="numeric",
                    n_hidden="numeric", W="matrix",
                    W.prime="matrix", hbias="vector",
                    vbias="vector", rng="numeric"),
        methods=list(
          get_corrupted_input=function(input, corruption_level){
            stopifnot(corruption_level < 1)  # アサーション
            return(rbinom(size=1, n=ncol(input) * nrow(input), 
                          prob=1 - corruption_level) * input)  # size=1とすることで2項分布からベルヌーイ分布を得る
          },
         
        # Encode
        get_hidden_values=function(input){
            # print("-------------------get_hidden_values()")
            # print("input=")
            # print(input)
            # print(".self$W=")
            # print(.self$W)
            # print("-------------------")
            return(sigmoid(input %*% .self$W + .self$hbias))
        },
        
        # Decode
        get_reconstructed_input=function(hidden){
            # print("-------------------get_reconstructed_input()")
            # print("hidden=")
            # print(hidden)
            # print(".self$W.prime=")
            # print(.self$W.prime)
            # print("-------------------")
            .self$W.prime <- t(.self$W)
            return(sigmoid(hidden %*% .self$W.prime + .self$vbias))
        },
        
        train=function(lr=0.1, corruption_level=0.3, input=NULL){
            if(is.null(input)==FALSE){
                .self$input <- input
            }
            input <- .self$input
            # print("-------------------train()")
            # print("input=")
            # print(input)
            # print("-------------------")
            tilde_x <- .self$get_corrupted_input(input, corruption_level)
            y <- .self$get_hidden_values(tilde_x)
            z <- .self$get_reconstructed_input(y)
            
            L_h2 <- input - z
            L_h1 <- (L_h2 %*% .self$W) * y * (1 - y)
            
            L_vbias <- L_h2
            L_hbias <- L_h1
            L_W <- (t(tilde_x) %*% L_h1) + (t(L_h2) %*% y)
            
            .self$W <- .self$W + lr * L_W
            .self$hbias <- .self$hbias + lr * colMeans(L_hbias)
            .self$vbias <- .self$vbias + lr * colMeans(L_vbias)
            # print("=============================")
            # print(L_hbias)
            # print(L_vbias)
            # print(colMeans(L_hbias))
            # print(colMeans(L_vbias))
            # print("=============================")
            
        },
        
        negative_log_likelihood=function(corruption_level=0.3){
            tilde_x <- .self$get_corrupted_input(.self$input, corruption_level)
            y <- .self$get_hidden_values(tilde_x)
            z <- .self$get_reconstructed_input(y)
            # print("=============================")
            # print(tilde_x)
            # print(y)
            # print(z)
            # print(log(z))
            # print(log(1-z))
            # print("=============================")
            
            
            cross_entropy = - mean(rowSums(.self$input * log(z) + (1 - .self$input) * log(1 - z)))
            
            return(cross_entropy)
        },
        
        reconstruct=function(x){
            y <- .self$get_hidden_values(x)
            z <- .self$get_reconstructed_input(y)
            return(z)
        }, 
        
        # コンストラクタ
        initialize=function(input=NULL, n_visible=NULL, 
                            n_hidden=NULL, W=NULL, W.prime=NULL, 
                            hbias=NULL, vbias=NULL, rng=NULL){
            if(is.null(input) == TRUE){
              input <<- matrix(NA)
            }
            else{
              input <<- input
            }
            
            if(is.null(n_visible) == TRUE){
              n_visible <- 2
              n_visible <<- n_visible
            }
            else{
              n_visible <<- n_visible
            }
            
            if(is.null(n_hidden) == TRUE){
              n_hidden <- 3
              n_hidden <<- n_hidden
            }
            else{
              n_hidden <<- n_hidden
            }
            
            if(is.null(rng) == TRUE){
              rng <- 1234
              rng <<- rng
            }
            else{
              rng <<- rng
            }
            
            if(is.null(W) == TRUE){
              a <- 1 / n_visible
              set.seed(rng)
              W <-  matrix(runif(n_visible * n_hidden, min=-a, max=a), 
                           n_visible, n_hidden)
              W <<- W
              W.prime <<- t(W)
            }
            else{
              W <<- W
              W.prime <<- t(W)
            }
            
            if(is.null(hbias) == TRUE){
              hbias <<- rep(0, n_hidden)  # initialize h bias 0
            }
            else{
              hbias <<- hbias
            }
            
            if(is.null(vbias)==TRUE){
              vbias <<- rep(0, n_visible)  # initialize v bias 0
            }
            else{
              vbias <<- vbias
            }
        }
    )
)



test_dA <- function(learning_rate=0.1, corruption_level=0.3, 
                    training_epochs=50){
  data <- rbind(c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
                c(1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
                c(1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
                c(1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
                c(0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
                c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
                c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1),
                c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1),
                c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1),
                c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0))
  rng <- 123  # seed
  
  # construct dA
  da <- dA$new(input=data, n_visible=20, n_hidden=5, rng=rng)
  
  # train
  for(epoch in seq(training_epochs)){
      da$train(lr=learning_rate, corruption_level=corruption_level)
      cost = da$negative_log_likelihood(corruption_level=corruption_level)
      print(paste('Training epoch ', epoch, '  cost is ', cost))
      learning_rate <- learning_rate * 0.95
  }
  
  # test
  x <- rbind(c(1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1),
             c(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0))
  
  print(da$reconstruct(x))
}

test_dA()


とりあえず動くところまでは確認(@konsonsanありがとうございます!)。
今回はダミーデータに対してやってるので、またいつかコードレビューをしつつ、サンプルデータとか実データでもやってみたい。