04-29 02:46
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[Artificial Intelligence / Posts] R에서의 딥러닝 본문

Artificial Intelligence/Posts

[Artificial Intelligence / Posts] R에서의 딥러닝

cinema4dr12 2017. 4. 20. 21:45

by Geol Choi | 

Contents

1. 소개
2. R의 딥러닝 패키지들
3. "MXNetR" 패키지
4. "darch" 패키지
5. "deepnet" 패키지
6. "H2O" 패키지
7. "deepr" 패키지
8. 패키지 비교
9. 결론
10. 참고 

1. 소개

딥러닝은 데이터를 고도의 비선형 모델링을 할 수 있는 머신러닝의 최신 트렌드이다. 지난 몇년간 딥러닝은 다양한 응용분야에서 막대한 모멘텀과 우세함을 얻게 되었다. 이러한 응용분야는 이미지와 음성 인식, 자율주행차, 자연어 처리 등 다양하다. 흥미롭게도 딥러닝의 대다수의 수학 컨셉은 수십년간에 걸쳐 알려져 왔다. 그러나, 이들은 딥러닝의 잠재력을 촉발시킨 최근의 발전에 의한 것이었다 (Nair and Hinton 2010; Srivastava et al. 2014).


예전에는 Vanishing Gradients와 과적합(Overfitting) 문제로 인해 인공신경망을 학습시키기 어려웠다.

이제 두 가지 문제는 다른 활성화 함수, 드롭아웃(Dropout) 정규화, 방대한 양의 학습 데이트를 이용하여 모두 해결되었다. 예를 들어, 인터넷을 통해 많은 양의 데이터 - 라벨링 된 데이터 및 라벨링 되지 않은 데이터 - 를 이용할 수 있다. 게다가 GPU와 GPGPU의 활용하여 훨씬 싸고 빠른 컴퓨팅을 할 수 있게 되었다.


오늘에 이르러 딥러닝은 머신 러닝을 필요로 하는 거의 대부분의 작업을 매우 효과있게 해결할 수 있음을 스스로 증명하였다. 그러나, 딥러닝은 특히 복잡하고 구조화된 데이터에 적합하다. 딥러닝읜 근원적인 인공신경망 모델은 고도로 비선형적이다. 이 모델은 보통 비선형 변환(Transformation)을 갖는 다중의 레이어로 구성되어 있으며 용도에 맞게 구조화 되어 있다. 전형적인 심층신경망(Deep Neural Network)은 그림 1.에 묘사하였다.


그림 1. 심층신경망 모델


딥러닝의 성공은 다양한 프로그래밍 언어에 대한 폭넓은 프레임워크와 라이브러리의 개발로 이어지게 되었다.

이러한 예가 Caffee, Theano, Torch, TensorFlow 등이다. 이번 포스팅은 프로그래밍 언어 R에서 활용할 수 있는 다양한 딥러닝 패키지들에 대해 소개하고 이들을 비교하는 내용을 담는다. 다양한 데이터세트를 활용하여 성능과 사용 편의성 등을 비교하기로 한다.


2. R의 딥러닝 패키지들

R 프로그래밍 언어는 세련된 시각화 및 분석 도구 뿐만아니라 사용 편의성으로 인해 통계학자와 데이터 과학자들 사이에서 상당한 인기를 누리고 있다. 딥러닝 시대가 도래함에 따라 다수의 패키지들의 증가로 R의 딥러닝 지원을 할 수 있게 되었다. 이 섹션은 다음 패키지들이 제공하는 R의 딥러닝에 대한 소개를 하고자 한다: MXNetR, darch, deepnet, H2O deepr.


무엇보다도 기본적인 학습 알고리즘이 패키지마다 차이가 있다는 것을 유의하기 바란다. 즉, 표 1.은 각 패키지에 있는 함수/구조에 대한 리스트이다.


표 1. R의 다양한 딥러닝 패키지가 지원하는 메써드들.


패키지

신경망 구조

MXNetR피드-포워드(Feed-forward) 신경망, 회선신경망(CNN)
darch

Restricted Boltzmann Machine, Deep Belief Network

deepnet피드-포워드(Feed-forward) 신경망회선신경망(CNN), Restricted Boltzmann MachineDeep Belief Network, Stacked Autoencoders
H2O피드-포워드(Feed-forward) 신경망, Deep Autoencoders
deepr

h2o와 deepnet 패키지로부터 단순화된 함수들


3. "MXNetR" 패키지

MXNetR 패키지는 C++로 작성된 MXNetR 라이브러리 인터페이스이다. MXNetR 패키지는 Feed-forward 신경망과 회선신경망(CNN)을 지원한다이 패키지는 커스텀 모델 구축을 지원하며, 다음과 같은 두 가지 버전으로 배포된다: CPU 온리(Only) 및 GPU 지원 버전. CPU 버전은 R 안에서 직접 쉽게 설치가 가능하나, GPU 버전은 cuDNN과 같은 써드 파티 라이브러리에 의존적이며 이 소스코드로부터 라이브러리를 빌드해야 한다.


피드-포워드 신경망(멀티레이어 퍼셉트론(Perceptron))은 다음과 같은 MXNetR 함수를 이용하여 구현한다:


1
2
3
4
5
6
7
8
mx.mlp(data,
       label,
       hidden_node = 1,
       dropout = NULL,
       activation = ”tanh”,
       out_activation = ”softmax”,
       device=mx.ctx.default(),
       …)
cs


각각의 파라미터에 대한 설명은 다음과 같다:

  • data: 입력 행렬(Matrix)
  • label: 학습된 라벨
  • hidden_node: 각 은닉 레이어(Hidden Layer) 내 은닉 노드 개수를 포함하는 벡터(Vector)
  • dropout: 마지막 은닉 레이어로부터 출력 레이어에 대한 드롭아웃(Dropout) 비율을 포함하는 [0,1) 사이의 수
  • activation: 활성화 함수의 이름을 포함하는 싱글 스트링(Single String) 또는 벡터. 유효한 값은 {'relu', 'sigmoid', 'softrelu', 'tanh'}임.
  • out_activation: 출력 활성화 함수의 이름을 포함하는 싱글 스트링. 유효한 값은 {'rmse', 'sofrmax', 'logistic'}임.
  • device: mx.cpu (기본값) 상에서 학습시킬지 아니면 mx.gpu 상에서 학습시킬지 정의.
  • ...: mx.model.FeedForward.create에 전달할 다른 파라미터들.

함수 mx.model.FeedForward.create는 내부적으로 mx.mpl에서 이용되며 다음과 같은 파라미터들을 취한다:

  • symbol: the symbolic configuration of the neural network 신경망의 심볼 설정.
  • y: 라벨 배열(Array)
  • x: 학습 데이터
  • ctx: 컨텍스트, 가령 디바이스 (CPU/GPU) 또는 디바이스 리스트 (다중 CPU 또는 GPU)
  • num.round: 모델 학습을 위한 반복 계산 횟수
  • optimizer: 스트링 (기본값은 'sgd')
  • initializer: 파라미터에 대한 Scheme 초기화
  • eval.data: 프로세스에 사용되는 Validation Set.
  • eval.metric: 결과에 대한 평가 함수.
  • epoch.end.callback: 반복 계산이 종료되었을 때의 콜백 (Callback).
  • batch.end.callback: 미니-배치(Mini-batch) 반복 계산이 종료되었을 때의 콜백.
  • array.batch.size: 배열 학습에 사용되는 배치(Batch) 크기.
  • array.layout: {'auto', 'colmajor', 'rowmajor'} 중 하나를 취함.
  • kvstore: 다중 디바이스에 대한 Scheme 동기화.


1
2
3
4
5
6
7
8
9
10
11
model <- mx.mlp(train.x,
                train.y,
                hidden_node = c(128,64),
                out_node = 2,
                activation="relu",
                out_activation = "softmax",
                num.round = 100,
                array.batch.size = 15,
                learning.rate = 0.07,
                momentum = 0.9,
                device=mx.cpu())
cs


차후 학습된 모델을 사용하려면, 첫번째 파라미터로 모델을, 두번째 파라미터로 테스트세트를 명시하는 predict() 함수를 호출하기만 하면 된다:



1
preds = predict(model, testset)
cs


mx.mlp() 함수는 근본적으로 MXNetR의 'Symbol' 시스템을 이용하여 신경망을 정의하는 보다 유연하지만 길이가 긴 프록시이다. 심볼 정의에 있어 이전의 네트워크에 대한 동등한 코드는 다음과 같다:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
data <- mx.symbol.Variable("data")
fc1 <- mx.symbol.FullyConnected(data, num_hidden=128)
act1 <- mx.symbol.Activation(fc1, name="relu1", act_type="relu")
fc2 <- mx.symbol.FullyConnected(act1, name="fc2", num_hidden=64)
act2 <- mx.symbol.Activation(fc2, name="relu2", act_type="relu")
fc3 <- mx.symbol.FullyConnected(act2, name="fc3", num_hidden=2)
lro <- mx.symbol.SoftmaxOutput(fc3, name="sm")
model2 <- mx.model.FeedForward.create(lro,
                                      X = train.x,
                                      y = train.y,
                                      ctx = mx.cpu(),
                                      num.round = 100,
                                      array.batch.size = 15,
                                      learning.rate = 0.07,
                                      momentum = 0.9)
cs


네트워크의 아키텍쳐가 생성되면, MXNetR은 다음 함수를 호출하여 시각적으로 확인할 수 있는 도구를 제공한다:


1
graph.viz(model$symbol$as.json())
cs




여기서 파라미터는 심볼로 표현되는 학습 모델이다. 첫번째 네트워크는 mx.mlp()로 구축되고 두번째 파라미터는 심볼 시스템을 이용하여 구축된다. 심볼 시스템의 정의는 각 레이어에 대하여 각각 다양한 개수의 뉴런과 특정 활성화 함수를 허용하며 입력부터 출력까지 레이어를 쭈욱 훑는다. mx.symbol: mx.symbol.Convolution를 통해 부가의 옵션을 활용할 수 있는데, 이는 입력에 회선을 적용하고 바이어스(Bias)를 추가한다. 이 그래프는 회선 신경망을 생성할 수 있다. 이에 대한 반전은 mx.symbol.Deconvolution인데, 이것은 일반적으로 이미지의 픽셀에 대한 분류 재구성을 위해 mx.symbol.UpSampling에 따라 세그먼테이션 네트워크에서 사용된다. CNN에 사용되는 다른 유형의 레이어는 mx.symbol.Pooling이다: 이것은 기본적으로 가장 높은 응답 신호를 선택하여 데이터를 줄인다. 레이어 mx.symbol.Flatten는 회선과 풀링(Pooling) 레이어를 연결하여 완전히 연결된(Fully Connected) 네트워크를 구성할 수 있다. 추가적으로, 과적합 문제에 대처하기 위해 mx.symbol.Dropout를 사용할 수 있다. mx.symbol.Dropout는 이전의 레이어와 드롭되는 입력의 플롯(Float) 값 부분을 파라미터로 취한다. 아시다시피, mx.mlp() 함수를 통해 표준 멀티-레이어 퍼셉트론의 신속한 설계를 위해서 또는 심볼 표현을 고려하는 확장 실험을 위해 MXNetR을 사용할 수 있다.


다음 코드는 LeNet 네트워크 예이다:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
data <- mx.symbol.Variable('data')
conv1 <- mx.symbol.Convolution(data = data,
                               kernel = c(5,5),
                               num_filter = 20)
tanh1 <- mx.symbol.Activation(data = conv1, act_type="tanh")
pool1 <- mx.symbol.Pooling(data = tanh1,
                           pool_type = "max",
                           kernel = c(2,2),
                           stride = c(2,2))
conv2 <- mx.symbol.Convolution(data = pool1,
                               kernel=c(5,5),
                               num_filter=50)
tanh2 <- mx.symbol.Activation(data = conv2, act_type = "tanh")
pool2 <- mx.symbol.Pooling(data = tanh2, pool_type = "max", kernel = c(2,2), stride=c(2,2))
flatten <- mx.symbol.Flatten(data = pool2)
fc1 <- mx.symbol.FullyConnected(data = flatten, num_hidden = 500)
tanh3 <- mx.symbol.Activation(data = fc1, act_type = "tanh")
fc2 <- mx.symbol.FullyConnected(data = tanh3, num_hidden = 10)
lenet <- mx.symbol.SoftmaxOutput(data = fc2)
model <- mx.model.FeedForward.create(lenet,
                                     X = train.array,
                                     y = train.y,
                                     ctx = device.cpu,
                                     num.round = 5,
                                     array.batch.size = 100,
                                     learning.rate = 0.05,
                                     momentum = 0.9)
cs


전적으로 MXNetR 패키지는 다중의 CPU와 다중의 GPU를 지원할 정도로 고도로 유연하다. 이 패키지는 표준 피드-포워드 네트워크 구축을 위한 간단한 방법을 제공할 뿐만아니라, CNN LeNet 등과 같이 커스텀화 되고 복잡한 네트워크 구축을 위한 유연한 기능을 제공한다.


4. "darch" 패키지

darch 패키지(darch 2015)는 Deep Belief Network와 같은 딥 아키텍쳐(Deep Architecture) 학습을 구현하며, 레이어 형식의 선학습된 제한 볼츠만 머신(Restricted Boltzmann Machines)으로 구성된다. 또는 이 패키지는 미세조정을 위한 역전파(Backpropagation)를 수반하며 최신 버전에서 선학습(Pre-training) 옵션을 제공한다.


darch() 함수를 통해 Deep Belief Network 학습을 수행한다.


1
2
3
4
5
6
7
8
9
10
darch  <- darch(train.x,
                train.y,
                rbm.numEpochs = 0,
                rbm.batchSize = 100,
                rbm.trainOutputLayer = F,
                layers = c(784,100,10),
                darch.batchSize = 100,
                darch.learnRate = 2,
                darch.retainData = F,
                darch.numEpochs = 20 )
cs


이 함수의 주요 파라미터는 다음과 같다:

  • x: 입력 데이터.
  • y: 타겟 데이터.
  • layers: 각 레이어의 뉴런 개수를 나타내는 정수 벡터 (입력 및 출력 레이어 포함).
  • rbm.batchSize: 선학습 배치(Batch) 크기.
  • rbm.trainOutputLayer: 선학습에 사용되는 불리언(Boolean). true이면 RBM의 출력 레이어도 학습에 포함됨.
  • rbm.numCD: 대조 분기(Contrastive Divergence)가 수행되는 전체 스텝(Steps)의 개수.
  • rbm.numEpochs: 선학습을 위한 Epoch 수.
  • darch.batchSize: 미세 조정 배치 크기.
  • darch.fineTuneFunction: 미세 조정 함수.
  • darch.dropoutInput: 네트워크 입력 상의 드롭아웃 비율.
  • darch.dropoutHidden: 은닉 레이어 상의 드롭아웃 비율.
  • darch.layerFunctionDefault: DBN(Deep Belief )에 대한 기본 활성화 함수이며, 사용가능한 옵션들은 {'sigmoidUnitDerivative', 'binSigmoidUnit', 'linearUnitDerivative', 'linearUnit', 'maxoutUnitDerivative', 'sigmoidUnit', 'softmaxUnitDerivative', 'softmaxUnit', 'tanSigmoidUnitDerivative', 'tanSigmoidUnit' }임.
  • darch.stopErr: 에러가 임계값과 같거나 보다 작은 경우 학습을 종료함.
  • darch.numEpochs: 미세 조정을 위한 Epoch의 개수.
  • darch.retainData: 학습 후 darch 인스턴스 내에 학습 데이터를 저장할 것인지를 결정하는 불리언.

이전의 파라미터에 근거하여 darch 오브젝트를 생성하는 모델을 학습시킬 수 있다. 차후에 이것을 테스트 데이터세트 test.x에 적용하여 예측을 할 수 있다. 이 경우, 별도의 파라미터 타입은 예측의 출력 타입을 명시한다. 예를 들어, 'raw'는 확률, 'bin'은 바이너리 벡터, 'class'는 분류 라벨에 대한 것이 될 수 있다. 결국 예측은 다음과 같이 predict() 함수를 호출할 때 이루어진다:


1
predictions <- predict(darch, test.x, type="bin")
cs


전박적으로 darch의 기본 사용법은 매우 간단하다. darch는 네트워크 학습을 위한 하나의 함수만을 요구한다. 그러나, darch 패키지는 Deep Belief Network에 한정되어 있으며, Deep Belief Network는 다른 네트워크에 비해 일반적으로 훨씬 더 많은 학습을 요구한다.


5. "deepnet" 패키지

deepnet (deepnet 2015)은 다른 패키지에 비해 상대적으로 작지만 다양한 아키텍쳐를 선택할 수 있는 강력한 패키지이다. 이 패키지는 nn.train() 함수를 이용하여 Feed-forward 네트워크를 학습하거나 dbn.dnn.train() 함수를 이용하여 Deep Belief Network에 대한 Weight를 초기화할 수 있다. 이 함수는 내부적으로 rbm.train() 함수를 이용하여 제한 볼츠만 머신(Restricted Boltzmann Machine; RBM)을 학습한다.


게다가 deepnet은 sae.dnn.train() 함수를 통해 Stacked Autoencoders를 다룰 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
nn.train(x,
         y,
         initW = NULL,
         initB = NULL,
         hidden=c(50,20),
         activationfun = "sigm",
         learningrate = 0.8,
         momentum = 0.5,
         learningrate_scale = 1,
         output = "sigm",
         numepochs = 3,
         batchsize = 100,
         hidden_dropout = 0,
         visible_dropout = 0)
cs


초기 Weight initW 및 초기 Bias initB를 설정할 수 있으며, 설정하지 않는 경우 랜덤으로 생성된다. 또한 hidden은 은닉 레이어 내의 노드 개수를 설정할 수 있으며, activationfun는 출력 레이어의 활성화 함수('sigm', 'linear', 'softmax')를 지정하고 은닉 레이어의 활성화 함수('sigm', 'linear', 'tanh')를 지정한다.


다른 방법으로, 아래의 예는 Weight가 Deep Belief Network에 의해(dbn.dnn.train()를 통해) 초기화되는 신경망을 학습시킨다. 차이점은 주로 제한 볼츠만 머신을 학습시키는 대조 분기 알고리즘에 있다. 이것은 cd를 통해 설정되며, 이는 학습 알고리즘 내의 깁스(Gibbs) 샘플링에 대한 반복 계산 횟수를 지정한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
dbn.dnn.train(x,
              y,
              hidden=c(1),
              activationfun="sigm",
              learningrate=0.8,
              momentum=0.5,
              learningrate_scale = 1,
              output="sigm",
              numepochs = 3,
              batchsize = 100,
              hidden_dropout = 0,
              visible_dropout = 0,
              cd = 1)
cs


유사하게, Stacked Autoencoders로부터 Weight를 초기화하는 것이 가능하다. 파라미터 출력 대신, 아래의 예는 이전과 동일하게 동작하지만 sae_output를 이용한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
sae.dnn.train(x,
              y,
              hidden=c(1),
              activationfun="sigm",
              learningrate=0.8,
              momentum=0.5,
              learningrate_scale = 1,
              output="sigm",
              sae_output = "linear",
              numepochs = 3,
              batchsize = 100,
              hidden_dropout = 0,
              visible_dropout=0)
cs


결론적으로 nn.predict()을 통해 학습된 네트워크를 이용하여 결과를 예측할 수 있다. 또한 nn.test()의 도움으로 예측 결과를 에러율로 변환할 수 있다. 첫번째 호출은 신경망과 해당 데이터를 입력으로 요구한다. 두번째 호출은 예측을 할 때 추가적으로 올바른 라벨과 임계값(기본값은 0.5)을 필요로 한다.


1
predictions = nn.predict(nn, test.x) error_rate = nn.test(nn, test.x, test.y, t=0.5)
cs


전적으로 deepnet은 제한된 파라미터를 갖는 경량형 패키지이다. 그러나, deepnet은 다양한 아키텍쳐를 제공한다.


6. "H2O" 패키지

H2O는 분산 컴퓨터 시스템을 활용할 수 있는 능력을 갖춘 오픈소스 소프트웨어 플랫폼이다 (H2O 2015).

H2O의 핵심 코드는 Java로 작성되었으며 JVM과 JDK의 최신 버전이 요구되는데 이들을 다운로드할 수 있는 링크는 다음과 같다: https://www.java.com/en/download/.

H2O 패키지는 많은 프로그래밍 언어들에 대한 인터페이스를 제공하며 원래는 클라우드 기반 플랫폼을 지원하기 위해 설계되었다 (Candel et al. 2015)h2o.init() 함수를 호출함으로 H2O를 시작한다.


1
h2o.init(nthreads = -1)
cs


파라미터 nthreads는 계산에 이용할 코어 개수를 지정한다. 값 -1은 H2O가 시스템 상에 이용가능한 최대 코어 개수를 이용하도록 한다. 기본값은 2이다. 이 루틴은 H2O가 다른 머신 상에 설치되어 있는 경우 IP와 포트 파라미터를 공급받는다. 기본적으로 IP 주소는 127.0.0.1, 포트는 54321을 이용한다. 따라서, 브라우저에서 주소 'localhost:54321'를 입력하여 웹기반 인터페이스에 접속할 수 있다. 현재의 H2O 인스턴스 작업이 완료되면 다음 명령을 통해 연결을 해제한다:


1
h2o.shutdown()
cs


모든 학습 오퍼레이션은 다음과 같이 h2o.deeplearning() 함수를 통해 이루어진다:


1
2
3
4
5
6
7
8
9
10
11
model <- h2o.deeplearning(x = x,
                          y = y,
                          training_frame = train,
                          validation_frame = test,
                          distribution = "multinomial",
                          activation = "RectifierWithDropout",
                          hidden = c(32,32,32),
                          input_dropout_ratio = 0.2,
                          sparse=TRUE,
                          l1=1e-5,
                          epochs=100)
cs


H2O에서 데이터 전달을 위한 인터페이스는 다른 패키지와 조금 다르다:

  • x: 학습 데이터를 갖는 열(Columns)의 이름을 포함한 벡터.

  • y: 변수 이름.

  • training_frame: H2O 프레임 오브젝트h2o.uploadFile() 함수를 호출하여 생성되며 인수로 디렉터리 경로를 취하고 CSV 파일을 환경에 로딩함.

  • validation_frame: H2O 프레임 오브젝트, h2o.uploadFile() 함수를 호출하여 생성되며 인수로 디렉터리 경로를 취하고 CSV 파일을 환경에 로딩함.

데이터는 전체 클러스터에 걸쳐 사용할 수 있어야 하므로 특정 데이터 클래스를 사용하는 것은 분산 환경에 의해 제어되어야 한다.

  • distribution: 스트링 타입이며, {'bernoulli', 'multinomial''poisson''gamma''tweedie',
    'laplace''huber', 'gaussian'} 중 하나를 선택할 수 있음. 'AUTO'는 데이터에 근거하여 파라미터를 선택함.

  • activation: 활성화 함수를 지정함.{'Tanh', 'TanhWithDropout', 'Rectifier',
    'RectifierWithDropout''Maxout', 'MaxoutWithDropout'} 중 하나를 선택할 수 있음.

  • sparse: 불리언 값. 대부분이 0값으로 채워진 정도를 지정하며, H2O가 데이터 관리를 효율적으로 할 수 있도록 함.

  • 나머지 파라미터는 직관적으로 이해할 수 있으며 다른 패키지와 별반 다르지 않음. 미세조정을 위한 많은 파라미터들이 있으나 미리 정의된 값을 사용하는 것이 권장되므로 이 값들을 변경할 경우는 거의 없음.

궁극적으로 다음 코드와 같이 h2o.predict() 함수를 이용하여 예측 모델 생성을 할 수 있다:


1
predictions <- h2o.predict(model, newdata=test_data)
cs


H2O가 제공하는 또다른 강력한 도구는 하이퍼파라미터(Hyperparameters)를 최적화하기 위한 그리드 탐색(Grid Search)이다. 그리드 탐색은 각 파라미터 값을 지정하고 h2o.grid() 함수를 통해 최적의 조합을 찾아낸다.


1
2
3
4
5
hidden_par <- list(c(50,20,50), c(32,32,32))
l1_par <- c(1e-3,1e-8)
hyperp <- list(hidden=hidden_par, l1=l1_par)
model_grid <- h2o.grid("deeplearning", hyper_params=hyperp, x=x, y=y,
distribution="multinomial", training_frame=train, validation_frame=test)
cs


H2O 패키지는 두 개의 아키텍쳐와 다양한 L1-정규화(Regularization) Weight를 포함하는 4개의 서로 다른 모델을 학습시킬 것이다. 따라서, 많은 수의 하이퍼파라미터 조합을 쉽게 테스트하여 어느 조합이 가장 성능이 좋은지 찾는다:


1
2
3
4
5
for (model_id in model_grid@model_ids) {
  model <- h2o.getModel(model_id)
  mse <- h2o.mse(model, valid=TRUE)
  print(sprintf("MSE on the test set %f", mse))
}
cs


또한 H2O는 Deep Autoencoders를 이용한다. 이 모델을 학습시키기 위해 동일한 함수 h2o.deeplearning()를 이용하지만 파라미터 조합은 약간 다르다.


1
2
3
4
5
6
7
8
anomaly_model <- h2o.deeplearning(x = names(train),
                                  training_frame = train,
                                  activation = "Tanh",
                                  autoencoder = TRUE,
                                  hidden = c(50,20,50),
                                  sparse = TRUE,
                                  l1 = 1e-4,
                                  epochs = 100)
cs


여기서는 테스트세트와 라벨없이 학습 데이터만을 사용한다. autoencoder 파라미터는 Feed-forward 네트워크 대신 Deep Autoencoder를 사용하도록 지정한다. 이전과 마찬가지로 서로 다른 레이어에서 몇 개의 은닉 노드를 사용할 것인지를 결정할 수 있다. 만약 하나의 정수값을 사용한다면 순수한 autoencoder를 얻게 된다.


학습을 마친 후, 재구성(Reconstruction) 에러를 살펴 볼 수 있다. 특정 h2o.anomaly() 함수를 이용하여 재구성 에러를 계산할 수 있다.


1
2
3
4
# Compute reconstruction error (MSE between output and input layers)
recon_error <- h2o.anomaly(anomaly_model, test)
# Convert reconstruction error data into R data frame
recon_error <- as.data.frame(recon_error)
cs


전반적으로 H2O는 Feed-forward 네트워크 또는 Deep Autoencoders 학습에 사용할 수 있는 고도의 사용자 친화적 패키지이다. H2O는 분산 컴퓨팅을 지원하며 웹 인터페이스를 제공한다.


7. "deepr" 패키지

deepr 패키지(deepr 2015)는 어떠한 딥러닝 알고리즘도 실행하지는 않으며 다만 H2O로 작업을 전달한다.

The package was originally designed at a time when the H2O package was not yet available on CRAN. 이 패키지는 원래 CRAN에서 H2O 패키지를 지원하지 않던 때에 설계된 것이다. 이제 H2O를 CRAN에서 지원하므로 이 패키지는 비교대상에서 제외할 것이다. train_rbm() 함수는 RBM의 deepnet 실행을 사용하여 부가의 출력을 갖는 모델을 학습시킨다.


8. 패키지 비교

본 섹션에서는 앞서 언급한 패키지들을 다양한 지표로 비교하고자 한다. 이 지표들은 사용성, 확장성, 설치용이성, 병렬 컴퓨팅 지원, 하이퍼파라미터(Hyperparameters) 선택 지원 등이다. 또한, 'Iris', 'MNIST', 'Forest Cover Type' 등 세 개의 공통적인 데이터세트에 대하여 성능을 비교 평가한다. 이 비교가 연구자와 개발자들이 R에서의 딥러닝 패키지를 선택하는데 도움이 되길 바란다.

설치

CRAN을 통해 설치를 하는 것은 매우 간단하고 편리하다. 그러나, 어떤 패키지들은 써드파티 라이브러리에 의존한다. 예를 들어,  H2O는 Java 개발킷(Java Development Kit; JDK)뿐만아니라 최신 버전의 Java를 요구한다. darchMXNetR 패키지는 GPU를 사용할 수 있도록 한다. 이러한 목적으로 darch는 R 패키지인 gputools에 의존하는데, 이 패키지는 Linux와 MacOS만 지원한다. MXNetR은 cuDNN에 의존적이므로 기본 옵션은 GPU를 지원하지 않는다. 이는 라이선스 제한으로 인해 패키지에 포함할 수 없기 때문이다. 따라서, MXNetR의 GPU 버전은 CUDA SDK와 cuDNN 소스로부터 MXNet을 컴파일을 위해 Rtools와 C++11 최신 컴파일러가 요구된다.

확장성

확장성과 관련하여 MXNetR은 상기 나열된 패키지 중 최상위에 있다. MXNetR은 풍부하고 다양한 파라미터 제공은 말할 것도 없이 네트워크를 정의하는데 있어 레이어 별 접근방식 덕분에 다양한 아키텍쳐를 실험할 수 있도록 한다. H2Odarch가 공동 2위를 차지하고 있다고 생각한다. H2O는 Feed-forward 네트워크와 Deep Autoencoder를 강조하는 반면, darch는 한정 볼츠만 머신과 Deep Belief Network에 주안점을 두고 있다. 두 패키지 모두 넓은 범위의 튜닝 파라미터를 제공한다. 간과하지 말아야 할 것은, deepnet은 다소 경량형 패키지이나 다양한 아키텍쳐로 동작하는 것을 좋아하는 이들에게 유용할 수 있다. 그러나, deepnet을 방대한 데이터세트 처리용도로 사용하는 것은 권장하지 않는다. 왜냐하면, 현재 버전은 GPU 지원에 있어 다소 미흡하고 상대적으로 적은 파라미터 세트를 제공하므로 미세한 조정이 어렵기 때문이다.

사용성

H2OMXNetR은 속도와 사용성 면에서 뛰어나다. MXNetR은 학습을 시작하기 위한 최소한의 준비과정만 요구되며 H2O는 as.h2o() 함수를 이용한 매우 직관적인 랩퍼(Wrapper)를 제공하여 데이터를 H2OFrame 오브젝트로 변환한다. 두 패키지 모두 모델을 관찰할 수 있는 부가의 도구를 제공한다. deepnet은 One-hot 인코딩 행렬 형태로 라벨을 취한다. 이는 보통 대부분의 데이터가 벡터 형태로 클래스를 가지고 있기 때문에 약간의 전처리가 요구됨을 의미한다. 그러나, 학습을 하는 동안 진행과정과 관련하여 그다지 자세한 정보를 알려주지는 않는다. 또한 deepnet 패키지는 모델을 관찰할 수 있는 부가의 도구가 부족하다. 반면에 darch는 매우 훌륭한 결과를 갖는다. 전반적으로 H2O 또는 MXNetR이 사용성 부분에 있어 승자라고 생각한다. 둘다 학습 시간이 짧은데다가 피드백을 제공하기 때문이다. 이는 파라미터를 신속하게 조절하고 예측 성능을 개선할 수 있도록 하기 때문이다.

병렬화

딥러닝은 대규모 데이터세트를 다루는 것이 일반적이다. 그러한 고로 패키지가 어느 정도 병렬화를 지원하는 것은 매우 유용하다. 표 2.는 병렬화 지원에 대한 비교를 나타내며, 공식 문서에 명시된 것만을 기재하였다.


표 2. 병렬화 비교.

패키지

다중 CPU

다중 GPU클러스터

플랫폼

MXNetRXXLinux\MacOS\Windows
darchXLinux\MaxOS
H20XXLinux\MacOS\Windows
deepnetNo information

파라미터 선택

중요하게 고려해야 할 또다른 옵션은 하이퍼파라미터의 선택이다. H2O 패키지는 빠른 수렴을 위해 개별 뉴런에 대한 완전 자동화된 적응형 학습방식을 사용한다. H2O는 n개의 폴드(Fold)를 갖는 교차 검증(Cross Validation)을 사용할 수 있는 옵션을 가지며, 하이퍼파라미터와 모델 선택을 최적화하기 위한 그리드 검색을 목적으로 h2o.grid() 함수를 제공한다.


MXNetR은 각 반복계산 후 학습 정확도를 표시한다. darch는 각 Epoch 후 에러를 보여준다. 두 패키지 모두 수렴이 될 때까지 기다리지 않고 다양한 하이퍼파라미터를 수동으로 테스트할 수 있도록 한다. 이는, 정확도가 개선되지 않을 경우 언제라도 학습 과정을 중지할 수 있도록 하게 하기 위함이다. 이에 반해, deepnet은 학습이 완료될 때까지 어떠한 정보도 표시하지 않는데, 이로 인해 하이퍼파라미터의 자동 수정은 매우 모험적이다.

성능 및 런타임

패키지의 성능에 대한 정보를 제공하기 위해 매우 간단한 성능 비교를 수행하였다. 성능 측정은 모두 Windows OS 상에서 인텔 CPU Core i7, NVidia GeForce 750M GPU를 갖는 시스템 상에서 수행되었다.


다음 세 가지의 데이터세트를 이용하여 비교를 수행하였다:

  • 'MNIST' (LeCun et al. 2012)

  • 'Iris' (Fisher 1936)

  • 'Forest Cover Type' (Blackard and Dean 1998)

이에 대한 자세한 내용은 참고에 수록하였다.


베이스라인으로 삼기 위해 H2O 패키지에 구현되어 있는 랜덤 포레스트(Random Forest) 알고리즘을 사용하였다. 랜덤 포레스트는 다중 결정 트리를 구성하여 동작하는 앙상블 학습 방법이다. 흥미롭게도 이 방법은 파라미터 튜닝없이도 고성능에 도달하는 능력을 보여주었다.

결과

성능 측정 결과는 표 3.에 정리하였으며, 'MNIST', 'Iris', 'Forest Cover Type' 데이터세트에 대해서는 그림 2.,3. 4.에 각각 도식화하였다.

  • 'MNIST' 데이터세트 :
    표 3.과 그림 2.에 의하면, MXNetR과 H2O는 'MNIST' 데이터세트에 대해 런타임과 예측 성능 사이에 우수한 트레이드오프(Tradoe-off) 성능을 보인다. 
    darchdeepnet은 네트워크를 학습하는데 있어 상대적으로 오래 걸리면서도 정확도가 낮다.

  • 'Iris' 데이터세트 : 
    이 데이터 상에서 또다시 MXNetR와 H2O의 성능이 가장 우수하였다. 그림 3.에서 볼 수 있듯, deepnet은 정확도가 가장 낮았으며, 아마도 선학습이 오해를 불러 일으킬 수 있는 작은 사이즈의 데이터세트이기 때문일 것이라 생각된다. 이러한 이유로, darch 100darch 500/300은 선학습 과정없이 역전파를 통해 학습된다. 표에서 * 심볼로 이를 표시하였다.

  • 'Forest Cover Type' 데이터세트 :
    H2OMXNetR은 대략 정확도 67%를 보여주지만, 이마저도 다른 패키지에 비해서는 훨씬 우수하다. darch 100와 darch 500/300의 학습은 수렴에 실패하였으며, 이러한 이유로 비교대상에서 제외되었다.

이 간단한 성능 비교가 사용자가 R의 딥러닝 패키지를 선택하는데 있어 의미있는 통찰을 제공할 수 있었으면 좋겠다.

유의사항: 그림 3. 과 그림 4.로부터 랜덤 포레스트는 딥러닝 패키지보다 좋은 성능을 낼 수 있다.

이에 대한 여러가지 검증된 이유가 있다.

첫째, 빅데이터 또는 증강 데이터에서 성능을 제대로 발휘하는 딥러닝에 대해 성능을 비교한 대상 데이터세트 모두 너무 작다. 둘째, 이들 데이터세트의 데이터는 수작업한 피쳐(Features)로 구성되어 있는데, 이로 인해 딥 아키텍쳐(Deep Architecture)가 가공되지 않은 오리지널 데이터로부터 피쳐 학습 시의 장점을 희석시키므로 전통적인 방법들로는 부족할 수 있다. 마지막으로, 다양한 방법을 비교하기 위해 매우 유사한 아키텍쳐를 선택하였다.

표 3. R의 다양한 딥러닝 패키지에 대한 정확도 및 런타임 비교.

역전파로 학습되는 모델들만 표시함 (선학습 제외).

모델/데이터세트MNISTIRISFOREST COVER TYPE
정확도
(%)
런타임 (sec)정확도
(%)
런타임
(sec)
정확도
(%)
런타임
(sec)
MXNetR (CPU)98.33147.7883.041.4666.8030.24
MXNetR (GPU)98.27336.9484.773.0967.7580.89
darch 10092.091368.3169.12 *1.71
darch 500/30095.884706.2354.78 *2.10
deepnet DBN97.856775.4030.430.8914.0667.97
deepnet DNN97.052183.9278.260.4226.0125.67
H2O98.08543.1489.560.5367.365.78
Random Forest96.77125.2891.302.8986.259.41




 그림 2. 'MNIST' 데이터세트에 대한 런타임 및 정확도 비교




그림 3. 'IRIS' 데이터세트에 대한 런타임 및 정확도 비교




그림 4. 'Forest Cover Type' 데이터세트에 대한 런타임 및 정확도 비교


9. 결론

본 포스팅에서 딥 러닝을 위한 5개의 R 패키지들을 비교하였다:


(1) deepnet의 현재 버전은 사용가능한 아키텍쳐 측면에서 가장 구별된 패키지라고 생각된다. 그러나, 이것을 구현하는 측면에서는 가장 빠른 것도 아니고 그렇다고 사용자 친화적인 옵션을 제공하는 것도 아니다. 게다가, deepnet은 몇몇 다른 패키지만큼 많은 튜닝 파라미터를 제공하고 있는 것 같지도 않다.


(2) 반면에 H2OMXNetR은 높은 수준의 사용자 경험을 제공한다. 두 패키지 모두 부가의 결과 정보를 제공하고, 학습 속도도 빠르며 괜찮은 결과를 얻게 해준다. H2O는 데이터 과학자들이 간단한 파이프라인 내에서 데이터 마이닝과 데이터 검색을 위해 사용할 수 있는 클러스터 환경에 보다 적합하다. 유연성 및 프로토파이팅에 더 주안점을 둔다면, MXNetR이 가장 적합한 선택일 것이다. MXNetR은 바닥부터 커스텀 네트워크 아키텍쳐를 구성할 수 있는 직관적인 심볼 도구를 제공한다. 또한 MXNetR은 다중 CPU/GPU 성능을 활용하여 개인용 컴퓨터에서 최적화된 실행능력을 보인다.


(3) darch는 제한적이지만 Deep Belief Network에 중점을 둔 기능을 제공한다. 분명 딥러닝에 대한 R의 지원은 목표를 향해 순항 중이다. 초기에는 R이 제공하는 기능은 다른 프로그래밍 언어들에 비해 뒤떨어졌었다. 그러나, 이제 더이상 그렇지 않다. H2O와 MXNetR의 등장으로 R 사용자들은 그들의 손에 두 개의 강력한 도구가 주어졌다. 향후 CaffeTorch와 같은 또다른 인터페이스가 등장할 것으로 기대된다.


10. 참고

'MNIST'는 가장 잘 알려진 숫자 인식용 데이터세트이다. 이 데이터세트는 라벨링 된 60,000개의 학습용 샘플과 10,000개의 테스트용 샘플을 포함하며 여기 사이트로부터 CSV 포맷을 다운받을 수 있다. 'Forest Cover Type' 데이터세트는 Kaggle 챌린지에서 시작되었으며 Kaggle 사이트에서 다운받을 수 있다. 15,120개의 라벨링 된 데이터를 포함하며 70%는 학습용, 30%는 테스트용 데이터로 분리하였다. 이 데이터세트는 54개의 피쳐와 7개의 카테고리를 갖는다. 또한 'Iris' 데이터세트는 머신러닝에서 매우 인기가 높다. 이는 3개의 클래스와 150개의 샘플을 포함하는 작은 데이터세트이며 학습과 테스트를 위해 7:3 비율로 분리하였다.

실용 어플리케이션이 딥러닝의 잠재력을 이끌어 내려면 훨씬 더 큰 데이터세트가 필요함을 바로 알 수 있었다. 이 이슈를 알고 있음에도 매우 간단한 비교를 위해 이 데이터를 비교 대상으로 테스트하였다. 그러나, 수행된 실험들은 모든 패키지들이 빅데이터와 적합한 것은 아니므로 개발자들이 올바른 선택을 할 수 있는 도구를 제공해야 한다. 'MNIST' 데이터세트에 대해 모든 네트워크는 500개 및 300개의 유닛을 각각 포함하는 2개의 은닉레이어를 갖도록 설계되었다. 단 하나의 예외는 darch 100인데 100개의 요소를 포함하는 하나의 은닉레이어를 가지고 있다.

다른 데이터세트에 대하여 은닉 유닛의 개수는 10 단위로 감소하므로 아키텍쳐는 각각 50개, 30개의 유닛을 포함하는 2개의 은닉레이어를 갖는다. 가능하다면 어레이 배치(Batch) 크기는 500개의 요소, 모멘텀 0.9, 학습률 0.07, 드롭아웃 비율 0.2로 설정된다. 라운드(MXNetR) 또는 Epoch(다른 패키지들)의 수는 50으로 설정되었다.

darch 아키텍쳐는 15개의 Epoch와 100개의 배치 크기를 갖는 선학습을 사용한다. 'Iris' 데이터세트는 다른 데이터세트에 비해 크기가 작다. 랜덤으로 섞여진 150개의 샘플만을 가지고 있으며 학습용과 테스트용 세트로 구분되어 있다. 따라서, 이를 참조하는 테이블의 모든 개수는 평균 5번 실행되는 수준이다. 배치 크기 파라미터는 5로 감소하며 학습률은 0.007로 감소한다. 세번째 데이터세트인 'Forest Cover Type'는 15 및 120 샘플을 갖는다.

네트워크 아키텍쳐는 'Iris' 데이터세트와 동일하다. 이 데이터세트는 더욱 도전적이라 Epoch의 수는 50에서 100으로 증가하였다.


Comments