Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

역전파와 CNN 비교

Choo sun sick edited this page Aug 20, 2020 · 10 revisions

데이터 학습하기

CNN 모델 소개

이제 모델에 손글씨 데이터를 학습시켜 봅시다. 이번에는 CNN(Convolution Neural Network) 모델을 이용하여 학습 하겠습니다. CNN 모델은 이미지 인식이나 음성 인식 등 다양한 분야에서 사용됩니다.


library(dslabs)
source("./layers.R")
source("./utils.R")
source("./optimizer.R")
source("./cnn_simplenet_models.R")
init <- function(tensor=FALSE){
 mnist_data <- get_data(tensor)
 #손글씨 데이터
 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)
}

먼저 CNN 모델 구현 및 작동에 필요한 함수를 불러옵니다. 이어서 모델이 학습 할 MNIST 데이터 셋을 가져옵니다.

model.forward <- function(network, x){
 conv_params <- list(W = network$W1, b = network$b1, stride = 1, pad = 0)
 affine_params_1 <- list(W = network$W2, b = network$b2)
 affine_params_2 <- list(W = network$W3, b = network$b3)
 
 conv_temp <- forward("Convolution", x, conv_params)
 relu_temp_1 <- forward("ReLU", conv_temp$out)
 pool_temp <- forward("Pooling", relu_temp_1$out, pool_params)
 flatten_temp <- forward("Flatten", pool_temp$out)
 affine_temp_1 <- forward("Affine", flatten_temp$out, affine_params_1)
 relu_temp_2 <- forward("ReLU", affine_temp_1$out)
 affine_temp_2 <- forward("Affine", relu_temp_2$out, affine_params_2)
 return(list(x = affine_temp_2$out, Affine_1.forward = affine_temp_1, Affine_2.forward = affine_temp_2, Relu_1.forward = relu_temp_1, Relu_2.forward = relu_temp_2, conv_temp = conv_temp, pool_temp=pool_temp, flatten = flatten_temp))
}
model.backward <- function(model.forward, network, x, t) {
 # 순전파
 loss_temp <- loss(model.forward, network, x, t)
 # 역전파
 dout <- 1
 dout <- backward("SoftmaxWithLoss",loss_temp$softmax,dout)
 dout1 <- backward("Affine",loss_temp$predict$Affine_2.forward,dout$dx)
 dout2 <- backward("ReLU",loss_temp$predict$Relu_2.forward,dout1$dx)
 dout3 <- backward("Affine",loss_temp$predict$Affine_1.forward,dout2$dx)
 dout_3 <- backward("Flatten",loss_temp$predict$flatten,dout3$dx)
 dx <- backward("Pooling",loss_temp$predict$pool_temp,dout_3,pool_params)
 dx1 <- backward("ReLU",loss_temp$predict$Relu_1.forward,dx$dx)
 dx2 <- backward("Convolution",loss_temp$predict$conv_temp,dx1$dx)
 grads <- list(W1 = dx2$dW, b1 = dx2$db, W2 = dout3$dW, b2 = dout3$db, W3 = dout1$dW, b3 = dout1$db)
 return(grads)
}

학습을 위한 모델들을 살펴 봅시다. model.forward 함수는 손실 값을 구하기 위한 함수입니다. 이 모델은 3층 CNN 모델입니다. 층 구성은 convolution-relu-pool(1층 계산), affine-relu(2층 계산), affine (3층 계산) 으로 이루어져 있습니다. model.backward 함수는 model.forward 함수의 과정을 거꾸로 진행하는 과정입니다. 이 함수는 가중치 파라미터들을 갱신된 값을 계산하는 역할입니다. 이 두 함수가 훈련 과정의 핵심입니다. 이제 학습을 위한 파라미터를 작성하여 모델을 학습시킬 준비를 마칩니다.

init(tensor=TRUE)
pool_params <- list(pool_h=2, pool_w=2, stride=2, pad=0)

아래의 model.train 함수는 손실값을 계산하고 가중치 파라미터들을 갱신하는 훈련 과정을 함수로 만든 것입니다.

model.train <- function(train_x, train_t, test_x, test_t, batch_size, epoch, optimizer_name, debug=FALSE){
 train_loss_list <- data.frame(loss_value = 0)
 test_acc <- data.frame(acc = 0)
 train_size <- dim(train_x)[4]
 iter_per_epoch <- max(train_size / batch_size)
 iters_num <- iter_per_epoch * epoch
 params <- list(input_dim=c(28,28,1), filter_size = 5, filter_num = 30,
 pad = 0, stride = 1, hidden_size = 100, output_size = 10,
 weight_init_std = 0.01)
 network <- simple_net_params(params = params) 
 for(i in 1:iters_num){
 batch_mask <- sample(train_size, batch_size)
 x_batch <- train_x[,,,batch_mask]
 x_batch <- array(x_batch,c(28,28,1,100))
 t_batch <- train_t[batch_mask,]
 gradient <- model.backward(model.forward,network, x_batch, t_batch)
 network <- get_optimizer(network, gradient, optimizer_name)
 loss_value <- loss(model.forward=model.forward, network = network, x_batch, t_batch)$loss
 print(loss_value)
 train_loss_list <- rbind(train_loss_list,loss_value)
 if(i %% iter_per_epoch == 0){
 acc <- model.evaluate(model.forward, network, x_test_normalize, t_test_onehotlabel)
 test_acc <- rbind(test_acc$acc,acc)
 print(acc)
 }
 }
 return(list(network=network,train_loss_list=train_loss_list,test_acc=test_acc))
}

이제 학습을 진행시켜 봅시다.

model_temp <- model.train(train_x = x_train_normalize,train_t = t_train_onehotlabel,batch_size = 100,epoch = 20,optimizer_name = "adam",TRUE)

모델 학습 과정은 1에폭 당 약 20분의 시간이 걸립니다. 또한, 학습이 진행되는 동안 실시간으로 변화하는 손실 값과 에폭 당 테스트 셋에 대한 정확도가 출력되어 볼 수 있습니다. 참고로 위 코드에서와 같이 20에폭을 실행할 경우 약 6~7시간이라는 오랜 시간이 걸립니다. 따라서 오랜 시간이 걸리는 것을 원하지 않는 분들은 epoch 파라미터의 숫자 20을 1로 바꾸어 주면 더 짧은 시간이 소요됩니다.

model.evaluate(model.forward, model_temp$network, x_test_normalize, t_test_onehotlabel)
[1] 0.9834

모델 훈련의 결과를 테스트 셋 데이터를 통해 알아보면 98.34 %의 정확도를 가진 모델이 만들어졌음을 알 수 있습니다. 참고로 이 정확도의 경우 직접 코드를 실행할 경우 학습시 초기 값의 랜덤값으로 인해 약 98% 대의 다른 수치가 나올 수 있습니다.

이층 신경망 모델과 CNN 모델 비교

CNN 모델의 성능을 이층 신경망 모델과 비교해 봅시다. 먼저 그래프를 통해 로스 값 차이부터 살펴봅시다.

손실값 비교

그림에서 검은색이 CNN 모델의 손실 값이고 빨간색이 이층 신경망 모델의 손실값입니다. 그림을 보면 CNN 모델의 손실값이 더 낮은 위치에 분포해 있다는 것을 확인할 수 있습니다.

정확도 비교

그림에는 3가지 선이 있습니다. 검은색 선이 CNN 모델의 정확도이며, 빨간색 선이 경이층 신경망 모델의 정확도이고 파란색 직선이 기준 값이 되는 98% 선입니다. 그림에서 보면 검은색 선이 빨간색보다 높이 위치한 것을 확인할 수 있습니다. 또한, 검은색 선이 파란색의 기준점 98%와 거의 겹치는 것도 확인할 수 있습니다.

결론적으로 보면 CNN 모델이 이층 신경망 모델 보다 손실 값이 더 낮고 정확도는 더 높은 것을 확인할 수 있습니다. 즉 CNN 모델의 성능이 더 좋은 것입니다.

숫자맞추기

위 모델이 MNIST의 숫자 이미지를 10개를 사용하여 어떻게 숫자를 예측하는지 살펴 보겠습니다. 먼저 MNIST 숫자 이미지를 확인합니다. 대표적으로 1개만 확인합니다.

mnist_data <- get_data()
draw_image(mnist_data$x_train[2,])

숫자0

위 숫자 이미지는 0입니다. 과연 이 모델은 10개의 숫자를 모두 맞출 수 있을까요? 지금까지 학습시킨 모델에게 10개의 숫자가 무엇인지 물어보겠습니다.

predict_10 <- predict_cnn(network=network,x=array(x_train_normalize[,,,1:10],c(28,28,1,10)))
apply(predict_10,1,which.max)-1
[1] 5 0 4 1 9 2 1 3 1 4
apply(predict_10,1,max)
[1] 0.9984279 1.0000000 1.0000000 0.9999999 0.9998252 1.0000000 1.0000000 1.0000000 0.9999834 1.0000000
mnist_data$t_train[1:10]
[1] 5 0 4 1 9 2 1 3 1 4

10개의 숫자들을 예측하고 predict_10으로 저장한 다음 최대 값이 있는 위치를 찾아 봅니다. 참고로 R은 다른 프로그램처럼 0부터 세지 않고 1부터 셉니다. 따라서 최대값의 위치에서 1을 빼주면 우리가 예측한 숫자의 값이 나옵니다. 각 위치에 대하여 몇%의 확률로 예측했는지도 확인해볼 수 있습니다. 첫 번째 09984279 값은 약 99.8%의 확률로 숫자가 5임을 예측합니다. 두 번째의 1 값은 약 100%의 확률로 숫자가 0임을 예측합니다. 대부분의 숫자들을 99% 혹은 100%에 가깝게 예측합니다. 데이터의 실제 숫자값 기록과 비교해보면 똑같은 것을 확인할 수 있는데 이 말은 즉 모델이 이미지 데이터를 보고 숫자 10개를 맞춘 것입니다.

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /