문과 아재도 쉽게하는 R 데이터 분석 – (12) 딥러닝 (Deep Learning)

in #kr6 years ago

R로 하는 딥러닝 맛보기

R로 할수있는 일에는 잘 알려져있고 응용통계 분야에서 계속 써오던 기법말고도 딥러닝 기법들도 써볼수있습니다. 다만, 딥러닝과 같은 경우 텐서플로우등을 감싸고 있는 R전용 연결고리를 잘 설정해주어야 합니다.

R은 딥러닝 전용 프로그래밍언어가 아니여서 한계가 있을수 있어 프로그래머들은 파이썬을 선호하는 편이지만, 분명 R도 딥러닝을 할수있게 이미 방법을 마련해놓았습니다.

준비하기

R버전 3.4이상에서는 아래와 같은 명령어로 바로 keras를 이용할수 있습니다.

install.packages("keras")

딥러닝 라이브러리는 구글에서 만든 텐서플로우가 대세지만, 이를 다시 쉽게 사용할수있도록 감싼 keras를 통해 더욱더 쉽게 딥러닝 기능을 이용할수 있습니다.

library(keras)
install_keras()

조금 기다리면 네트워크 상황에 따라 조금 기다리면 준비가 되는것을 알수있습니다. 딥러닝은 영상이미지를 골라내는 용도로 특히나 많이 쓰이기 때문에 대표격인 MNIST손글씨 데이터를 가지고 딥러닝을 돌려봅니다.

mnist <- dataset_mnist()

image

그림이미지 불러와서 형태 주무르기

그림정보는 어떻게 보면 우리가 지금까지 살펴봤던 여러 데이터와 본질적으로 다른게 없습니다. 일단 흑백이미지라고 했을때, X, Y좌표에 찍혀져 있는 색정보가 강도에 따라서 0에서 255까지 2차원으로 분포해 있을겁니다. 다만, 색깔정보가 들어간다면 빨강, 초록, 파랑의 원색정보가 들어가기 때문에 차원은 더 늘어지만, 일단 우리가 쓰는 샘플 예제는 흑백사진이므로 계산하기가 더 쉽습니다.
오히려 그림정보는 조금 더 명확하게 숫자가 떨어진다는점이 차이입니다.

기본적인 데이터들은 아래와 같이 저장되어 있습니다.

mnist$train$x

다만, 그림파일은 60000개의 이미지를 가지고 있고 이는 각각 28개의 픽셀을 가로 세로로 가지고 있으므로 60000 * 28 * 28 와 같은 형식으로 저장되어 있는 3차원 배열입니다.

하지만 사실 가로 세로 2차원으로 늘어져있는것보다 이를 그냥 일렬로 나열하는것도 기계입장에서는 별 다른 차이가 없습니다. 그냥 28 * 28 = 784 픽셀의 정보를 가지는 한줄짜리 벡터로 나열해놓는것이 더 실용적일수 있기 때문에, 이렇게 변환합니다.

train <- mnist$train$x
test <- mnist$test$x
dim(train) <- c(60000, 784)
dim(test) <- c(60000, 784)

dim에 대해 한번 짚고 넘어가자면, dimension의 약자로써, 차원을 이렇게 저렇게 바꿔줄수 있습니다. dim()만을 호출하는건 그 대상의 차원정보를 알려주고 뭔가를 할당한다면 해당하는 차원으로 바꿔줍니다.

x <- 1:12
dim(x) <- c(3,4)

위와같은 코드는 1~12까지 x에 일렬로 저장되어있는 벡터일텐데, dim()함수를 통해서 3행 4열으로 다시 형태를 바꿔주는것을 알수있습니다. 프로그래밍 언어로써 좋은 문법은 아니나, 이런식으로 작동하는것을 알아두면 편합니다.

라벨링 데이터 불러오기

딥러닝도 라벨링된 데이터가 있어야 판단할 기준이 생기기 때문에 라벨링 데이터가 필요합니다.

label_train <- mnist$train$y
label_test <- mnist$test$y

다만, 여기서 라벨링된 데이터는 0~9까지의 숫자로 되어있으나 딥러닝을 시키기에는 이 데이터가 원-핫 인코딩이 되어있는 편이 좋습니다. 원-핫 인코딩은 다음과 같은 데이터입니다.

답이 2라면 -> 0 1 0 0 0 0 0 0 0
답이 9라면 -> 0 0 0 0 0 0 0 0 1

위와같은 식입니다. 이 과정에 대한 이유는, 각 숫자에 대한 정답을 구할 때 정답이면 1을 곱해주고, 오답이면 0을 곱하는 과정으로 유의미하게 계산과정이 풀릴수 있기 때문입니다.

label_train <- to_categorical(label_train, 10)
label_test <- to_categorical(label_test, 10)

훈련 모델 만들기

model <- keras_model_sequential() 
model %>% 
  layer_dense(units = 256, activation = "relu", input_shape = c(784)) %>% 
  layer_dropout(rate = 0.4) %>% 
  layer_dense(units = 128, activation = "relu") %>%
  layer_dropout(rate = 0.3) %>%
  layer_dense(units = 10, activation = "softmax")

%>% 연산자는 파이프 연산자로써 유명한 dplyr 이라는 패키지에서 제공하는 기능입니다. 보통의 프로그래밍 언어에서는 함수안에 함수안에 함수 exp(mean(1:5)) 이런식으로 써주었는데, 가독성이 떨어지는 면이 존재하기 때문에 이를 순차적으로 표현할수 있는 연산자입니다.
데이터를 특정 기능으로 보낸다는 식으로 이해하면 되는데,

exp(mean(1:5))
1:5 %>% mean %>% exp

두 문장은 각각 같은 표현입니다. 계산순서는 1) 1부터 5까지의 벡터의 2) mean 과 3) exp를 차례로 구하게 됩니다.

그렇다면, 처음에 언급했던 딥러닝 모델은 어떻게 해석할수 있을까요?

일단 우리가 옆으로 늘여놨던 그 육만개의 이미지들은 784개 원소를 가진 하나의 벡터 형식으로 잘 쌓여져 있는데, 이에대한 형태 정보를 input_shape 로 주고 있습니다.

활성화 함수는, 실제 우리 뇌가 동작하는 방식을 생각하면 쉬운데, 예를들어 내가 행복을 느끼기 위해서는 일정이상의 뇌 시냅스가 활성화되어야 한다고 생각해봅시다. 어떤식의 수치가 들어왔을때 이를 어떻게 변환할것인가를 계산하는 함수를 활성화 함수라고 합니다.

relu의 경우는 0이하의 숫자는 0으로 간주하고, 나머지 양의 값들만 인정하는 형태입니다.

image

softmax함수는 결과값들의 합들을 1(100%)로 해서 결과값을 출력해주기 때문에,

0~9 숫자들이 각각의 값들 0.1, 0.8, 0.0001, ...을 가지기 때문에 이중에 어떤 숫자가 택해질지는 제일 높은 확률값을 가지는 숫자가 최종 답이 됩니다.

unit은 밖으로 튀어나오는 결과의 형태를 말하는데, 여기서는 처음 그림의 픽셀수인 784를 받아서 256으로 보내고, 이를 다시 128개로 뽑아내고 마지막은 최종적으로 0~9 숫자 중 하나를 나타내는 10개의 출력결과로 보내고 있습니다.

드롭아웃은 오버피팅을 방지하기 위해 훈련시킬때 적당히 몇개를 빼고 계산하는 방법인데, 일반적으로 효과적이라고 합니다.

컴파일 하기

모델은 사실 도화지에 그림을 그리는것이나 다름이 없고, 실제로 모델을 생성하기 위해 컴파일이 필요합니다.

model %>% compile(
  loss = "categorical_crossentropy",
  optimizer = optimizer_rmsprop(),
  metrics = c("accuracy")
)

손실함수는 우리가 처음에 핫-원 인코딩을 해서 넣어준 이유입니다. 보통 예측결과가 틀렸으면 이에대한 벌칙을 줘서 다시한번 뒤로 돌아가면서 모델의 여러 값들을 변경하는 과정을 거치게 됩니다. 보통은 교차 엔트로피 오차(Cross Entrophy Error) 방식을 쓰게 되는데 이를 설정해주기 위해 loss 옵션을 주고 있습니다.

optimizer도 마찬가지로 오차를 수정해나가는 과정에서 필요한 옵션인데, 몇가지 대표적인 모델이 존재합니다.

실제로 훈련시키기

history <- model %>% fit(
  train, label_train, 
  epochs = 30, batch_size = 128, 
  validation_split = 0.2
)

열심히 Epoch (훈련 한바퀴라고 보면 됩니다) 가 돌아가면서 계속 모델이 바뀌어가는것을 확인할수 있습니다. 실제적으로 plot(history)로 그래프를 찍어볼수도 있습니다.

실제로 예측해보기

model %>% predict_classes(test)

실제로 예측하는 과정은 다른것들과 마찬가지로 모델만있으면 되고, 테스트데이터를 흘려보내기만 하면 됩니다. 위와같이 predict_classes로 예측하면, 여러가지 숫자들이 튀어나오게 됩니다. 예측한 결과값인데 실제 라벨링된 테스트데이터와 비교를 통해 제대로 딥러닝이 되었는지 확인해 볼수 있습니다.

model %>% evaluate(test, label_test,verbose = 0)

$loss
[1] 1.109982

$acc
[1] 0.9304

93.04퍼센트의 예측확률을 가지고 있습니다. 어때요 참 쉽죠?

Sort:  

며칠 전 처음 님의 R에 대한 글을 봤을 때, 이 시리즈가 딥러닝쪽으로 흘러갈 지는 상상하지 못했습니다. 재밌군요 :)
그런데 위 예제는 6만개 샘플 전체로 훈련시키고 다시 6만개 전체로 테스트한 건 가요? 왠지 그러면 예측 확률이 실제보다 높게 나올 것 같아서요. ^^
참고로 저는 과학 분야에서 자료 처리를 파이쏜과 포트란으로 하고 있으며, PCA같은 방법은 종종 쓰는데, 딥러닝 분야는 별로 아는게 없습니다.

Congratulations @gillime! You received a personal award!

1 Year on Steemit

Click here to view your Board

Do not miss the last post from @steemitboard:

Christmas Challenge - Send a gift to to your friends

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @gillime! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!