Skip to content
Jaehwan edited this page May 16, 2020 · 1 revision

bare backward propagation

역전파를 이용하여 네트웍에 MNIST 모델 학습시키기

이 글은 활성화 함수인 sigmoid(), softmax(), Relu()의 순전파, 역전파를 제외한 모든 것을 구현하는 모든 코드를 가지고 있다. 이 코드를 다 이해한다면, 역전파에 대한 기초적인 내용은 알게 되었다고 해도 무방하다. 우선 우리가 사용할 함수들의 코드를 가지고 있는 것을 가져온다.

source("./functions.R")
source("./utils.R")
source("./optimizer.R")

MNIST 자료를 가져오는 방법에 대한 내용은 Mnist 손글씨 데이터 읽어오는 패키지 소개을 참고한다. 자료를 가져오는 코드는 아래와 같다. 아래 코드에 대한 소개는 다음을 참고한다.

# install.packages("dslabs") 이미 설치한 것이 있으면 생략
library(dslabs)

mnist_data <- get_data()

x_train_normalize <- mnist_data$x_train
x_test_normalize <- mnist_data$x_test

t_train_onehotlabel <- making_one_hot_label(mnist_data$t_train,60000, 10)
t_test_onehotlabel <- making_one_hot_label(mnist_data$t_test,10000, 10)

이제 본격적으로 우리가 학습시킬 네트웍을 만든다.

TwoLayerNet <- function(input_size, hidden_size, output_size, weight_init_std = 0.01) {
  W1 <- weight_init_std*matrix(rnorm(n = input_size*hidden_size), nrow = input_size, ncol = hidden_size)
  b1 <- matrix(rep(0,hidden_size),nrow=1,ncol=hidden_size)
  W2 <- weight_init_std*matrix(rnorm(n = hidden_size*output_size), nrow = hidden_size, ncol = output_size)
  b2 <- matrix(rep(0,output_size),nrow=1,ncol=output_size)
  return (list(W1 = W1, b1 = b1, W2 = W2, b2 = b2))
}

앞에서 만든 네트웍을 학습시킬 모델을 만든다. 이 함수를 다 따로 만든 이유는 우선 model.forward()은 예측을 하기 위해 필요하다. loss()은 당연히 손실값을 알아보기 위해서 필요하다.

model.forward <- function(network, x){
  Affine_1 <- Affine.forward(network$W1, network$b1, x)
  Relu_1 <- Relu.forward(Affine_1$out)
  Affine_2 <- Affine.forward(network$W2, network$b2, Relu_1$out)
  return(list(x = Affine_2$out, Affine_1.forward = Affine_1, Affine_2.forward = Affine_2, Relu_1.forward = Relu_1))
}

loss <- function(model.forward, network, x, t){
  temp <- model.forward(network, x)
  y <- temp$x
  last_layer.forward <- SoftmaxWithLoss.forward(y, t)
  return(list(loss = last_layer.forward$loss, softmax = last_layer.forward, predict =  temp))
}


gradient <- function(model.forward, network, x, t) {
  # 순전파
  temp <- loss(model.forward, network, x, t)
  # 역전파
  dout <- 1
  last.backward <- SoftmaxWithLoss.backward(temp$softmax, dout)
  Affine_2.backward <- Affine.backward(temp$predict$Affine_2.forward, dout  =  last.backward$dx)
  Relu_1.backward <- Relu.backward(temp$predict$Relu_1.forward, dout  =  Affine_2.backward$dx)
  Affine_1.backward <- Affine.backward(temp$predict$Affine_1.forward, dout  =  Relu_1.backward$dx)
  grads  <- list(W1  =  Affine_1.backward$dW, b1  =  Affine_1.backward$db, W2  =  Affine_2.backward$dW, b2  =  Affine_2.backward$db)
  return(grads)
}

지금까지 만든 것을 테스트해보자.

train_size <- dim(x_train_normalize)[1]
batch_size <- 100
train_loss_list <- data.frame(lossvalue  =  0)
train_acc_list <- data.frame(train_acc  =  0)
test_acc_list <- data.frame(test_acc  =  0)
iter_per_epoch <- max(train_size / batch_size)
<<<<<<< HEAD

temp_TwoLayerNet <- TwoLayerNet(input_size = 784, hidden_size = 50, output_size = 10)

grads <- gradient(model.forward=model.forward, network = temp_TwoLayerNet, x=x_train_normalize[1:batch_mask,], t= t_train_onehotlabel[1:batch_mask,])
loss_value <- loss(model.forward=model.forward, network = temp_TwoLayerNet, x=x_train_normalize[1:batch_mask,], t_train_onehotlabel[1:batch_mask,])$loss

윗 코드를 실행하면 다음과 같은 결과가 나옵니다.

>loss_value
=======
grads <- gradient(model.forward=model.forward, x=x_train_normalize[1:batch_size,], t= t_train_onehotlabel[1:batch_size,])
loss_value <- loss(model.forward=model.forward, x=x_train_normalize[1:batch_size,], t_train_onehotlabel[1:batch_size,])$loss
loss_value
>>>>>>> 1d79622fc87995d2f04d929befa789a06ab79210
[1] 2.302899

이렇게 돌아가는 모델을 평가하는 평가 함수를 만들겠습니다.

model.evaluate <- function(model, network, x, t){
    temp <- model(network, x)
    y <- max.col(temp$x)
    t <- max.col(t)
    accuracy <- (sum(ifelse(y == t,1,0))) / dim(x)[1]
    return(accuracy)
}

실제로 무식하게 돌려봅니다.

for(i in 1:2000){
  batch_mask <- sample(train_size ,batch_size)
  x_batch <- x_train_normalize[batch_mask,]
  t_batch <- t_train_onehotlabel[batch_mask,]

  grad <- gradient(model.forward = model.forward, network = temp_TwoLayerNet, x_batch, t_batch)
  
  temp_TwoLayerNet <- sgd.update(temp_TwoLayerNet, grad)
  
  loss_value <- loss(model.forward=model.forward, network = temp_TwoLayerNet, x_batch, t_batch)$loss
  train_loss_list <- rbind(train_loss_list,loss_value)
  
  if(i %% iter_per_epoch == 0){
    train_acc <- model.evaluate(model.forward, temp_TwoLayerNet, x_train_normalize, t_train_onehotlabel)
    test_acc <- model.evaluate(model.forward, temp_TwoLayerNet, x_test_normalize, t_test_onehotlabel)
    train_acc_list <- rbind(train_acc_list,train_acc)
    test_acc_list <- rbind(test_acc_list,test_acc)
    print(c(train_acc, test_acc))
  }
}

Clone this wiki locally