Autoencoder는 이미지 데이터의 압축을 위해 연구된 인공신경망 (Artificial Neural Networks, ANNs)이다. Autoencoder의 구조는 일반적인 feedforward neural networks (FNNs)와 유사하지만, autoencoder는 비지도 학습 (unsupervised learning) 모델이다 [1]. Autoencoder는 기존에 대부분 데이터의 압축을 위해 활용되었으나, 최근에는 딥 러닝 (deep learning)에 대한 연구가 활발해지면서 입력 벡터의 차원 축소, 은닉층의 학습 등에 많이 이용되고 있다 [2, 3].
Autoencoder의 구조는 일반적인 FNN의 구조와 매우 유사하며, 한 가지 다른 점은 입력층 (input layer)과 출력층 (output layer)의 크기가 항상 같다는 것이다. 아래의 [그림 1]은 은닉층 (hidden layer)이 1개인 autoencoder의 구조를 나타낸다. 입력층과 출력층의 크기는 같으며, 입력층-은닉층 구간을 encoder, 은닉층-출력층 구간을 decoder라고 한다.
[그림 1] 은닉층이 1개인 autoencoder의 구조
Autoencoder의 중요한 동작은 입력 벡터의 차원을 축소하는 것이다. 이러한 동작은 입력층-은닉층 구간인 encoder에서 수행되며, 차원이 축소된 입력 벡터를 code 또는 latent variables라고 한다. Encoder 영역에서 생성된 code는 은닉층-출력층 구간인 decoder를 거쳐 입력 벡터와 동일한 출력 벡터로 변환된다.
일반적으로 autoencoder는 FNNs처럼 역전파 (backpropagation) 알고리즘을 이용하여 학습을 수행행한다. FNNs 모델에 대한 역전파 알고리즘에 대한 설명은 이 글에 자세하게 서술되어 있다. 이 글에서 이용되는 기호와 각 기호가 갖는 의미는 아래의 [표 1]과 같으며, 뉴런의 활성 함수 (activation function)로는 시그모이드 함수 (sigmoid function)를 이용하였다.
[그림 1] 학습 연산 정의에 이용되는 기호들
[식 1]은 [그림 1]과 같은 구조를 갖는 autoencoder의 출력층 가중치 학습 연산이다. 출력층 가중치는 은닉층-출력층 사이의 연결강도를 의미한다.
[식 2]는 은닉층 가중치의 학습 연산이며, 은닉층 가중치는 입력층-은닉층 사이의 연결강도를 의미한다.
출력층 뉴런의 바이어스 학습 연산은 아래의 [식 4]과 같다.
마지막으로, 은닉층 뉴런의 바이어스 학습 연산은 [식 5]와 같다.
Autoencoder의 출력값 계산과 가중치 학습을 프로그래밍 언어로 구현하면 아래의 [코드 1]과 같다. 구현에 이용된 프로그래밍 언어는 Java이다.
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | private void computeOutputsHL(final double[] vector) { double net; for(int i = 0; i < SIZE_HIDDEN_LAYER; i++) { net = biasWeightsHL[i]; for(int j = 0; j < SIZE_INPUT_VECTOR; j++) { net += weightsHL[i][j] * vector[j]; } outputsHL[i] = 1 / (1 + Math.exp(-net)); } } private void computeOutputsOL() { double net; for(int i = 0; i < SIZE_INPUT_VECTOR; i++) { net = biasWeightsOL[i]; for(int j = 0; j < SIZE_HIDDEN_LAYER; j++) { net += weightsOL[i][j] * outputsHL[j]; } outputsOL[i] = 1 / (1 + Math.exp(-net)); } } private void updateWeights(final int index) { double[] deltaHL = new double[SIZE_HIDDEN_LAYER]; double[] deltaOL = new double[SIZE_INPUT_VECTOR]; // Compute delta of the output layer for(int i = 0; i < SIZE_INPUT_VECTOR; i++) { deltaOL[i] = (learningVectors[index][i] - outputsOL[i]) * (1 - outputsOL[i]) * outputsOL[i]; } for(int i = 0; i < SIZE_INPUT_VECTOR; i++) { for(int j = 0; j < SIZE_HIDDEN_LAYER; j++) { weightsOL[i][j] += LEARNING_RATE * deltaOL[i] * outputsHL[j]; } biasWeightsOL[i] += LEARNING_RATE * deltaOL[i]; } // Compute delta of the hidden layer for(int i = 0; i < SIZE_HIDDEN_LAYER; i++){ double sum = 0; for(int j = 0; j < SIZE_INPUT_VECTOR; j++) { sum += deltaOL[j] * weightsOL[j][i]; } deltaHL[i] = sum * (1 - outputsHL[i]) * outputsHL[i]; } for(int i = 0; i < SIZE_HIDDEN_LAYER; i++) { for(int j = 0; j < SIZE_INPUT_VECTOR; j++) { weightsHL[i][j] += LEARNING_RATE * deltaHL[i] * learningVectors[index][j]; } biasWeightsHL[i] += LEARNING_RATE * deltaHL[i]; } } | cs |
[코드 1] Java를 이용한 autoencoder의 구현
가중치를 조정하는 updateWeights 함수에서는 계산량을 줄이기 위해 출력층의 $\delta$를 저장하여 은닉층의 가중치 조정에 이용하였다. 출력값을 계산할 때는 반드시 computeOutputsHL이 호출된 다음, computeOutputsOL이 호출되어야 한다. 그러나 가중치를 조정할 때는 반대로 출력층에 대한 가중치를 조정한 다음, 은닉층에 대한 가중치를 조정해야 한다.
[1] Yoshinori YAGINUMA, Takashi KIMOTO. 1996. Multi-Sensor Fusion Model for Constructing Internet Representation using Autoencoder Neural Networks. Neural Networks, 1996., IEEE International Conference on Vol. 3, pp. 1646 - 1651.
[2] Quoc V. Le. 2015. A Tutorial on Deep Learning, Part 2: Autoencoders, Convolutional Neural Networks and Recurrent Neural Networks.
[3] Andrew Ng. Sparse autoencoder. CS294A Lecture notes.
'지능형시스템_' 카테고리의 다른 글
[머신러닝] - RNNs (Recurrent Neural Networks) (3) | 2016.10.06 |
---|---|
[머신 러닝] - 은닉 마르코프 모델 (Hidden Markov Model, HMM) (11) | 2016.09.02 |
[머신러닝] - Complex-Valued Neuron (CVN) (1) | 2016.07.08 |
[머신러닝] - Overfitting (과적합) (0) | 2016.05.07 |
[지능형시스템] - Artificial Bee Colony(ABC) Algorithm (0) | 2016.04.13 |