본문 바로가기
공부/R & Python

16-2. Convolutional Neural Network

by 드인 2020. 3. 6.

16-2. Convolutional Neural Network


1) Features

- 신경망 모델(Neural Net)은 입력값으로 객체의 특성(feature)을 받고, 

- 출력된 값과 실제 값을 비교하는 과정을 거침 (지도학습; Supervised Learning)

- 하나의 이미지는 수많은 픽셀들이 모여 형성하고 있으며, 특정 색에 해당하는 특정 값을 가짐

- 따라서, 이미지의 모든 픽셀값들을 입력값으로 갖는 신경망 모델을 만들 수 있음

2) Intuitions

- 하지만, 고해상도 이미지의 경우 특성feature의 수가 너무 많아지므로

- 모든 뉴런들이 모든 픽셀들과 모두 연결되어 있을 경우 (fully connected) 모델 학습에 큰 어려움이 있음

- 따라서, 각 뉴런들이 이미지의 일부의 특성feature만 연결될 수 있는 구조가 더 적합함

- Convolution operation을 통해 이를 구현할 수 있음

3) Convolution Operation

- 임의의 값으로 설정된 filter가 전체 이미지 중 일부의 선형 결합을 계산함

- 각각의 결과값은 하나의 Neuron이 되며, filter는 해당 Neuron의 가중치가 됨

- 결과값의 사이즈를 정하기 위해선 Stride, Padding 그리고 Depth을 고려해야함

 

4) Pooling

- Convoltional Layer 사이에 Pooling Layer를 넣어주는 방법이 많이 사용됨

- 추출해낸 이미지에서 지역적인 부분의 특징만을 뽑아 다음 layer로 넘겨줌

- 이를 통해, 1) 가중치들의 수를 줄일 수 있으며 2) 과적합(overfitting)을 방지함

- 대표적으로 가장 큰 값(Local Maxima)만을 뽑아내는 Max Pooling이 많이 사용됨

5) MNIST

- 손으로 쓴 숫자들을 인식하기 위해 사용되는 데이터

- 28x28 pixel (784)의 흑백 이미지(0~255)들이 있음

- 0부터 9까지 총 70,00개의 손글씨 이미지들이 있음

- 상대적으로 신경망 모델을 학습하기에 작은 사이즈를 가지고 있음

- 출처(http://yann.lecun.com/exdb/mnist)

 

6) CNN in R

- 신경망 모델 생성을 위한 패키지 : mxnet

 

- MNIST 데이터 불러오기

mn1 <- read.csv("mini_mnist.csv")
set.seed(123)
N<-nrow(mn1)

tr.idx<-sample(1:N, size=N*2/3, replace=FALSE)

학습 데이터 : 2/3

테스트 데이터 : 1/3


train_data<-data.matrix(mn1[tr.idx,])
test_data<-data.matrix(mn1[-tr.idx,])

test<-t(test_data[,-1]/255)
features<-t(train_data[,-1]/255)
labels<-train_data[,1]

0과 1사이에  분포하도록(Normalized)

(0 : 검정색 / 255 : 흰색)


features_array <- features
dim(features_array) <- c(28,28,1,ncol(features))
test_array <- test
dim(test_array) <- c(28,28,1,ncol(test))

입력 데이터의 차원을 설정 (픽셀 * 객체 개수)

ncol(features) : 학습 데이터 수(866)


ncol(features)

[출력 결과]

[1] 866

 

table(labels)

[출력 결과]

labels

   0    1    2

282 307 277

 

- Convolutional Layer 구성

my_input = mx.symbol.Variable('data')
conv1 = mx.symbol.Convolution(data=my_input, kernel=c(4,4), stride=c(2,2), pad=c(1,1), num.filter = 20, name='conv1')
relu1 = mx.symbol.Activation(data=conv1, act.type='relu', name='relu1')
mp1 = mx.symbol.Pooling(data=relu1, kernel=c(2,2), stride=c(2,2), pool.type='max', name='pool1')

 

conv2 = mx.symbol.Convolution(data=mp1, kernel=c(3,3), stride=c(2,2), pad=c(1,1), num.filter = 40, name='conv2')
relu2 = mx.symbol.Activation(data=conv2, act.type='relu', name='relu2')
mp2 = mx.symbol.Pooling(data=relu2, kernel=c(2,2), stride=c(2,2), pool.type='max', name='pool2')

 

fc1 = mx.symbol.FullyConnected(data=mp2, num.hidden = 1000, name='fc1')

1000개의 뉴런들이 모두 연결되어 있음
relu3 = mx.symbol.Activation(data=fc1, act.type='relu', name='relu3')
fc2 = mx.symbol.FullyConnected(data=relu3, num.hidden = 3, name='fc2')

 

sm = mx.symbol.SoftmaxOutput(data=fc2, name='sm')

3개의 뉴런들 중 가장 확률이 높은 값이 0~2 중 하나를 가리킴

 

- 모델 훈련

mx.set.seed(100)
device <- mx.cpu()
model <- mx.model.FeedForward.create(symbol=sm, 
                                                    optimizer = "sgd",
                                                    array.batch.size=30,
                                                    num.round = 70, learning.rate=0.1,
                                                    X=features_array, y=labels, ctx=device,
                                                    eval.metric = mx.metric.accuracy,
                                                    epoch.end.callback=mx.callback.log.train.metric(100))

Stochastic Gradient Descent

batch size = 30 (총 29개 그룹)

Iteration(epoch) : 70

Learning Step : 0.1

 

graph.viz(model$symbol)

 

- 모델 테스트

predict_probs <- predict(model, test_array)
predicted_labels <- max.col(t(predict_probs)) - 1
table(test_data[, 1], predicted_labels)
sum(diag(table(test_data[, 1], predicted_labels)))/length(predicted_labels)

 

- 네트워크 시각화 함수 : graph.vis(model$symbol)

graph.viz(model$symbol)