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ありがとうございます!)。
今回はダミーデータに対してやってるので、またいつかコードレビューをしつつ、サンプルデータとか実データでもやってみたい。