05-04 00:07
Notice
Recent Posts
Recent Comments
관리 메뉴

Scientific Computing & Data Science

[Artificial Intelligence / TensorFlow] R-TensorFlow 예제 - Autoencoder 본문

Artificial Intelligence/TensorFlow

[Artificial Intelligence / TensorFlow] R-TensorFlow 예제 - Autoencoder

cinema4dr12 2017. 9. 4. 22:56

Written by Geol Choi | Sep


이번 포스팅에서는 TensorFlow를 이용한 Autoencoder 문제를 다루어 보도록 하겠습니다. TensorFlow에 대한 예제를 설명하기 위한 포스팅이므로 이론에 대한 자세한 설명은 생략하며 대략적인 이론적 개념만 짚고 넘어가겠습니다.


자세한 이론은 아래의 웹사이트, 블로그 및 논문을 참고하시면 많은 정보를 얻으실 수 있을 것입니다:

Theoretical Backgrounds

Autoencoder란 입력과 출력이 같도록 학습시키는 뉴럴 네트워크로서 비지도학습(Unsupervised Learning)의 한 종류이며, 자기조직화맵(Self Organizing Map;SOM), 주성분분석(Principal Component Analysis;PCA), 선형판별분석(Linear Discriminant Analysis;LDA) 등과 같은 차원축소 방법입니다.


그럼 우선 Autoencoder의 구조에 대해 알아보도록 하겠습니다. Autoencoder는 Encoding과 Decoding의 두 단계로 구성되는데, 각각은 다중레이어 퍼셉트론(Multi-layer Perceptron;MLP)과 같이 뉴럴 네트워크로 구성됩니다. 아래의 이미지를 보십시오.



[그림 1.] Autoencoder의 구조 [Image from Wikipedia]



Encoding은 \(d\)개의 입력 \(\mathbf{x}\)로 구성된 입력 공간(Input Space) \(\mathcal{X}\)에서 Encoder를 통해 \(p\)개의 코드 \(\mathbf{z}\)로 구성된 특징 공간(Feature Space)\(\mathcal{F}\)으로 맵핑을 합니다. 즉,


[Encoding]  \( \phi: \mathcal{X} \rightarrow \mathcal{F} \)


로 표현할 수 있습니다. 여기서, 입력공간은 \( \mathbf{x} \in \mathbb{R}^d = \mathcal{X} \)이며, \(\phi\)는 맵핑에 대한 변수인데 뉴럴 네트워크로 표현하는 경우 Weights와 Biases가 되겠습니다. Encoding에 대한 출력 \(\mathbf{z}\)는 출력공간 \(\mathcal{F}\)에 속하는데 \( \mathbf{z} \in \mathbb{R}^p = \mathcal{F} \)로 표현할 수 있으며, 다음과 같이 활성화 함수(Activation Function) \(\sigma\)로 표현할 수 있습니다:


\( \mathbf{z} = \sigma({\mathbf{Wx} + \mathbf{b}}) \), {\(\mathbf{W}, \mathbf{b}\)} \( = \phi \)


일반적으로, Encoding의 출력차원 \(p\)는 입력차원 \(d\)보다 작기 때문에 이 과정은 압축(Compression)이라고 합니다. 만약 \(p=d\)라면, Autoencoder의 뉴럴 네트워크는 잠재적으로 Identity Function을 학습하게 될 것이며 이 경우 사실상 Autoencoder는 쓸모없게 됩니다.


Decoding은 Encoding을 통해 얻은 Code \(\mathbf{z}\)를 원래의 데이터 \(\mathbf{x}\)로 복원하는 과정입니다. Encoding의 과정과 유사하게 다음과 같이 수학적으로 표현할 수 있습니다:


[Decoding]  \( \psi: \mathcal{F} \rightarrow \mathcal{X} \)


Decoding에 있어 Weights와 Biases 및 활성화 함수는 Encoding을 위해 쓰였던 것들과는 일반적으로 다릅니다 (단, 활성화 함수는 같을 수 있습니다). 따라서, Decoder에 대한 Weights를 \(\mathbf{W'}\), Biases를 \(\mathbf{b'}\), 활성화 함수를 \(\sigma'\)라고 할 때 뉴럴 네트워크로 구성된 Decoder는 다음과 같이 수학적으로 표현할 수 있습니다:


\( \tilde{\mathbf{x}} = \sigma '(\mathbf{W'z} + \mathbf{b}') \), {\( \mathbf{W'}, \mathbf{b}' \)} = \(\psi\)


여기서, 복원된 입력을 \(\mathbf{x}\) 대신 \(\tilde{\mathbf{x}}\)로 표현한 이유는, Decoder에 의한 출력값이 일반적으로 정확히 입력 \(\mathbf{x}\)와 일치하지는 않기 때문입니다.


Autoencoder에 대한 손실 함수(Loss Function)는 원래의 입력 \(\mathbf{x}\)과 복원된 입력 \(\tilde{\mathbf{x}}\)와의 차이의 제곱인 L-2 Norm으로 표현할 수 있습니다:


\( \mathcal{L}(\mathbf{x}, \tilde{\mathbf{x}}) = \begin{Vmatrix} \mathbf{x} - \tilde{\mathbf{x}} \end{Vmatrix}^2 = \begin{Vmatrix} \mathbf{x} - \sigma'(\mathbf{W'z+b'}) \end{Vmatrix}^2 = \begin{Vmatrix} \mathbf{x} - \sigma'( \mathbf{W'}\sigma(\mathbf{Wx+b}) + \mathbf{b'}) \end{Vmatrix}^2       \)


일반적으로 N개의 데이터를 갖는 입력 \(\mathbf{x}\)에 대한 Loss는 다음과 같이 평균값으로 구할 수 있습니다:


\( \mathcal{L(\mathbf{x}, \tilde{\mathbf{x}})} = \displaystyle{ \frac{1}{N} \sum_{i=1}^{N}{ \begin{Vmatrix} x_i - \tilde{x}_i \end{Vmatrix}^2} } \)


따라서, 최종적으로 Autoencoder를 구성하는 과정은 다음과 같이 하나의 수식으로 표현할 수 있습니다:


Find \( \phi, \psi = \mathrm{arg} \min_{\phi, \psi}{\mathcal{L}(\mathbf{x,x'})} \)

TensorFlow를 이용한 Autoencoder 구현

간단한 이론적 배경을 이해하였다면, 이제 R-TensorFlow를 이용하여 간단한 예제를 구현해 보겠습니다.


본 예제 코드에서는 MNIST 손글씨 숫자 데이터를 이용하였습니다.

1. 패키지 라이브러리 불러오기

본 예제에서는 다음 3개의 R 패키지 라이브러리를 불러옵니다:

  • tensorflow: DNN 계산을 위한 R의 TensorFlow 라이브러리입니다.

  • plotly: DNN의 계산 과정을 그래프로 시각화하기 위한 라이브러리입니다.

  • EBImage: MNIST 데이터이 이미지를 표시하기 위한 라이브러리입니다.

2. MNIST 데이터셋 불러오기

28×28(=784) 크기의 MNIST 손글씨 숫자 데이터셋을 불러옵니다:


1
2
3
## import MNIST data
datasets <- tensorflow::tf$contrib$learn$datasets
mnist <- datasets$mnist$read_data_sets("MNIST-data", one_hot = TRUE)
cs


3. 학습 파라미터 정의

1
2
3
4
5
6
## define parameters
learning_rate <- 0.01
training_epochs <- 20L
batch_size <- 256L
display_step <- 1L
examples_to_show <- 10L
cs


위의 코드에서 learning_ratetraining_epochsbatch_sizedisplay_stepexamples_to_show는 변수명에서 알 수 있듯이 각각 학습률, 학습 반복횟수, 배치 크기, 결과를 표시할 주기, 결과를 보여 줄 예제 개수를 의미합니다.

4. 네트워크 모델 생성

코드를 설명하기 전 본 예제에서 구성한 전체 네트워크 모델의 구조에 대해 설명드리고자 합니다.


우선, Encoder의 입력은 28×28 크기의 손글씨 이미지의 전체 픽셀 개수로서 784개이며, 은닉 레이어(Hidden Layer)의 노드 개수는 256개이며, 인코딩된 코드의 수는 128개입니다.



[그림 2.] Encoder의 네트워크 구조



각 변수의 차원은 다음과 같습니다:


\(\mathbf{x}\): [784,1]

\(\mathbf{W_1}\): [784,256]

\(\mathbf{b_1}\): [256,1]


Hidden Layer \(\mathbf{h}\)는 \( \mathbf{h} = \mathbf{W_1}^T\mathbf{x} + \mathbf{b_1} \)이며, 이와 관련된 변수의 차원은 다음과 같습니다:


\(\mathbf{h}\): [256,1]

\(\mathbf{W_2}\): [256,128]

\(\mathbf{b_2}\): [128,1]

\(\mathbf{z}\): [128,1]


또한 출력(Encoded) 값 \(\mathbf{z}\)는 \(\mathbf{z}\)는 \( \mathbf{z} = \mathbf{W_2}^T\mathbf{h} + \mathbf{b_2} \)입니다.





[그림 3.] Decoder의 네트워크 구조



[그림 3.]은 Decoder의 네트워크 구조이며, 각 변수의 차원과 관련 계산은 다음과 같습니다:


\(\mathbf{z}\): [128,1]

\(\mathbf{W_1}'\): [128,256]

\(\mathbf{b_1}'\): [256,1]

\(\mathbf{h}'\): [256,1]

\(\mathbf{W_2}'\): [256,784]

\(\mathbf{b_2}'\): [784,1]

\(\tilde{\mathbf{x}}\): [784,1]


\( \mathbf{h}' = \mathbf{W_1}'^T \mathbf{z} + \mathbf{b_1}'  \)

\( \tilde{\mathbf{x}} = \mathbf{W_2}'^T \mathbf{h}' + \mathbf{b_2}' \)


다음의 이미지들은 위에서 언급한 Encoder와 Decoder의 일련의 과정을 그래프 모델로 표현한 것입니다.


[그림 4.] Encoder의 그래프 모델




[그림 5.] Decoder의 그래프 모델



위의 이미지에서 Operation으로 표현한 [+], [×], [t]는 각각 행렬(또는 벡터)의 덧셈, 곱셈, 전치(Transpose)입니다.


위와 같이 구성한 네트워크의 파라미터는 다음과 같습니다.


1
2
3
4
## network parameters
n_hidden_1 <- 256L # 1st layer num features
n_hidden_2 <- 128L # 2nd layer num features
n_input <- 784L # MNIST data input (img shape: 28*28)
cs


입력 \(\mathbf{x}\)는 다음과 같이 TensorFlow의 placeholder로 정의합니다:


1
2
## tf Graph input
<- tensorflow::tf$placeholder(tensorflow::tf$float32, tensorflow::shape(NULL, n_input))
cs


또한 각 레이어의 Weight와 Bias는 list로 정의하였습니다:


1
2
3
4
5
6
7
8
9
10
11
12
## store layers weight & bias
weights <- base::list(
  'encoder_h1'= tensorflow::tf$Variable(tf$random_normal(base::c(n_input, n_hidden_1)), dtype=tf$float32),
  'encoder_h2'= tensorflow::tf$Variable(tf$random_normal(base::c(n_hidden_1, n_hidden_2)), dtype=tf$float32),
  'decoder_h1'= tensorflow::tf$Variable(tf$random_normal(base::c(n_hidden_2, n_hidden_1)), dtype=tf$float32),
  'decoder_h2'= tensorflow::tf$Variable(tf$random_normal(base::c(n_hidden_1, n_input)), dtype=tf$float32))
 
biases <- base::list(
  'encoder_b1'= tensorflow::tf$Variable(stats::rnorm(n=n_hidden_1), dtype=tf$float32),
  'encoder_b2'= tensorflow::tf$Variable(stats::rnorm(n=n_hidden_2), dtype=tf$float32),
  'decoder_b1'= tensorflow::tf$Variable(stats::rnorm(n=n_hidden_1), dtype=tf$float32),
  'decoder_b2'= tensorflow::tf$Variable(stats::rnorm(n=n_input), dtype=tf$float32))
cs


이제 Encoder를 정의하는데, Encoder의 활성화 함수는 Sigmoid로 하였습니다 ([그림 4.] Encoder 그래프 모델 참고):


1
2
3
4
5
6
7
8
9
10
## building the encoder
encoder <- function(x) {
  # encoder hidden layer with sigmoid activation #1
  layer_1 <- tensorflow::tf$nn$sigmoid(tensorflow::tf$add(tensorflow::tf$matmul(x, weights$encoder_h1), biases$encoder_b1))
  
  # decoder hidden layer with sigmoid activation #2
  layer_2 <- tensorflow::tf$nn$sigmoid(tensorflow::tf$add(tensorflow::tf$matmul(layer_1, weights$encoder_h2), biases$encoder_b2))
  
  return(layer_2)
}
cs


Decoder 역시 Encoder와 유사합니다 ([그림 5.] Decoder 그래프 모델 참고):


1
2
3
4
5
6
7
8
9
10
## building the decoder
decoder <- function(x) {
  # Encoder Hidden layer with sigmoid activation #1
  layer_1 <- tensorflow::tf$nn$sigmoid(tensorflow::tf$add(tensorflow::tf$matmul(x, weights$decoder_h1), biases$decoder_b1))
  
  # Decoder Hidden layer with sigmoid activation #2
  layer_2 <- tensorflow::tf$nn$sigmoid(tensorflow::tf$add(tensorflow::tf$matmul(layer_1, weights$decoder_h2), biases$decoder_b2))
  
  return(layer_2)
}
cs

 

Encoder와 Decoder의 오퍼레이션을 각각 encoder_op와 decoder_op라는 이름의 변수로 설정합니다:


1
2
3
## construct model
encoder_op <- encoder(x)
decoder_op <- decoder(encoder_op)
cs

5. Prediction 및 Target 정의

Autoencoder에 있어 예측(Prediction) 결과는 디코딩 오퍼레이션에 의한 결과(decoder_op)이며, 타겟(또는 Ground Truth Label)에 해당하는 값은 입력 데이터 \(\mathbf{x}\)입니다:


1
2
3
4
5
## prediction
y_pred <- decoder_op
 
## targets (labels) are the input data.
y_true <- x
cs

6. Loss 및 Optimizer 정의

손실함수(Loss 또는 Cost)는 앞서 이론적 배경에서 살펴 보았듯이 Prediction(y_pred)과 True(y_true) 값의 차이의 제곱의 평균으로 표현하였습니다:


1
2
## define loss and optimizer, minimize the squared error
cost <- tensorflow::tf$reduce_mean(tensorflow::tf$pow(y_true - y_pred, 2))
cs


Optimizer는 RMSPropOptimizer로 하였으며, 최소화 대상은 손실함수(Cost)입니다:


1
optimizer <- tensorflow::tf$train$RMSPropOptimizer(learning_rate=learning_rate)$minimize(cost)
cs


7. 그래프 출력을 위한 변수 정의

학습이 진행되는 동안 Loss의 변화를 그래프로 출력하기 위한 변수를 Data Frame으로 정의합니다. 즉, Epoch에 대하여 Cost의 변화를 그래프 출력하기 위한 것입니다:


1
2
3
4
## initialize variable for plotting
learning_val <- base::matrix(data=0.0, nrow=1, ncol=2)
learning_val <- base::as.data.frame(learning_val)
names(learning_val) <- base::c("Epoch""Cost")
cs


8. 그래프 변수 초기화 및 세션 초기화

TensorFlow의 그래프 변수를 초기화하고 세션을 정의하여 이를 초기화합니다:


1
2
3
4
5
6
## initializing the variables
init <- tensorflow::tf$global_variables_initializer()
 
## create session and initialize  variables
sess <- tensorflow::tf$Session()
sess$run(init)
cs


한편, 각 Epoch에 대하여 정해진 모든 배치 그룹을 학습시키는데, 가령 N개의 데이터에 대하여 한 번에 학습시킬 배치 크기(batch_size)가 256이라면 배치 그룹의 개수는 \(N / \mathrm{batch_size}\)를 계산하여 정수값 만큼이 됩니다. 전체 배치 그룹의 개수를 total_batch라는 변수로 정합니다:


1
total_batch <- base::as.integer(mnist$train$num_examples / batch_size)
cs

9. 학습

이제 주어진 파라미터와 그래프 모델에 따라 학습을 진행합니다:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
## training cycle
for(epoch in 1:training_epochs) {
  # loop over all batches
  for(i in 1:total_batch) {
    # load batch_size training examples in each training iteration
    batches <- mnist$train$next_batch(base::as.integer(batch_size))
    batch_xs <- batches[[1]]
    
    # Run optimization op (backprop) and cost op (to get loss value)
    sess$run(optimizer, feed_dict = dict(x = batch_xs))
  }
  
  # calculate cost value
  cost_val <- sess$run(cost, feed_dict = dict(x = batch_xs))
  learning_val <- rbind(learning_val, c(epoch, cost_val))
  
  # display logs per epoch step
  if((epoch %% display_step) == 0{
    base::print(base::sprintf("Epoch: %04d, cost: %.9f", epoch, cost_val))
  }
}
 
base::print("Optimization Finished!")
cs


10. 결과 그래프 출력

학습이 진행되는 동안, 변수 learning_val에 매 Epoch에 대한 Cost 값을 저장하였으며, 이 값들을 R의 plotly 라이브러리 패키지를 이용하여 다음과 같이 그래프로 출력합니다:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## plotting with Plotly
learning_val <- learning_val[-1,]
<- plotly::plot_ly(data = learning_val,
                     x = ~Epoch,
                     y = ~Cost,
                     name = 'Cost Value',
                     type = 'scatter',
                     mode = 'lines+markers',
                     line = list(color = 'rgb(205, 12, 24)',width = 3)) %>%
  layout(title = "Cost Values as Epoch Proceeds",
         xaxis = list(title = "Epoch"),
         yaxis = list (title = "Cost"))
 
# print results
base::print(p)
cs


[1] "Epoch: 0001, cost: 0.211664513"
[1] "Epoch: 0002, cost: 0.167342752"
[1] "Epoch: 0003, cost: 0.154167175"
[1] "Epoch: 0004, cost: 0.143830478"
[1] "Epoch: 0005, cost: 0.139932245"
[1] "Epoch: 0006, cost: 0.138962433"
[1] "Epoch: 0007, cost: 0.131788254"
[1] "Epoch: 0008, cost: 0.125737846"
[1] "Epoch: 0009, cost: 0.123493254"
[1] "Epoch: 0010, cost: 0.122119352"
[1] "Epoch: 0011, cost: 0.123237431"
[1] "Epoch: 0012, cost: 0.113606587"
[1] "Epoch: 0013, cost: 0.115150392"
[1] "Epoch: 0014, cost: 0.113827899"
[1] "Epoch: 0015, cost: 0.110151969"
[1] "Epoch: 0016, cost: 0.109858140"
[1] "Epoch: 0017, cost: 0.105749488"
[1] "Epoch: 0018, cost: 0.107643574"
[1] "Epoch: 0019, cost: 0.101675756"
[1] "Epoch: 0020, cost: 0.103440434"
[1] "Optimization Finished!"


그래프 출력결과는 다음과 같이 Epoch이 진행되는 동안 Cost가 대체적으로 감소함을 보입니다.


[그림 6.] Epoch vs Cost


11. 입력-출력 비교

마지막으로 입력 이미지와 Autoencoder를 통해 얻은 출력 이미지 비교를 통해 모델이 얼마나 잘 학습되었는지를 확인할 수 있습니다.


우선 MNIST 테스트 이미지에 대하여 예측결과(y_pred)를 계산하여 이를 encode_decode 변수로 저장합니다:


1
2
## applying encode and decode over test set
encode_decode <- sess$run(y_pred, feed_dict=dict(x= mnist$test$images[1:examples_to_show,]))
cs


R의 EBImage 라이브러리 패키지를 이용하여 각 테스트 이미지와 Autoencoder를 통해 얻은 예측 이미지를 하나씩 비교하였습니다:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
## compare the results
xt <- list()
for(ii in 1:examples_to_show) {
  img1 <- mnist$test$images[ii,]
  img1 <- matrix(img1, nrow=28, ncol=28)
  img1 <- EBImage::Image(img1)
  
  img2 <- encode_decode[ii,]
  img2 <- matrix(img2, nrow=28, ncol=28)
  img2 <- EBImage::Image(img2)
  
  xt <- c(xt, list(img1))
  xt <- c(xt, list(img2))
}
 
xt <- EBImage::combine(xt)
EBImage::display(xt, title='Autoencoder', all=TRUE, method="raster")
cs




[그림 7.] 테스트 이미지와 Autoencoder의 예측 이미지 비교


그림을 살펴보면, 대체적으로 예측 이미지가 원본 테스트 이미지와 유사하게 나오지만 노이즈처럼 듬성듬성 흰 점들이 보이는 등 썩 만족스럽지는 않습니다.


앞서 계산한 결과에서 Cost 값은 0.1 정도 수준인데 더많은 Training Cycle(20 → 50)을 통해 Cost 값을 조금 더 낮추어 보았습니다:


1
training_epochs <- 50L
cs



[그림 8.] 테스트 이미지와 Autoencoder의 예측 이미지 비교 (More Training Cycles)


여전히 노이즈가 있는 상태이지만 앞의 결과보다는 이미지가 더욱 선명해졌음을 확인할 수 있습니다.


다양한 Layer의 개수 및 노드 수를 통해 최적의 결과를 얻을 수 있는 시도를 해보는 것도 의미있는 실험이 될 수 있을 것 같습니다.

전체 코드

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#############################################################################
# Auto Encoder Example using TensorFlow library.
#############################################################################
# @Author: Geol Choi, phD.(cinema4dr12@gmail.com)
# @Date: July 16, 2017
#############################################################################
 
## remove existing variables
base::rm(list = ls())
gc()
 
## import libraries
if (! ("tensorflow" %in% rownames(installed.packages()))) { install.packages("tensorflow") }
base::library(tensorflow)
 
if (! ("plotly" %in% rownames(installed.packages()))) { install.packages("plotly") }
library(plotly)
 
if (! ("EBImage" %in% rownames(installed.packages()))) { install.packages("EBImage") }
base::library(EBImage)
 
## import MNIST data
datasets <- tensorflow::tf$contrib$learn$datasets
mnist <- datasets$mnist$read_data_sets("MNIST-data", one_hot = TRUE)
 
## parameters
learning_rate <- 0.01
training_epochs <- 50L
batch_size <- 256L
display_step <- 1L
examples_to_show <- 10L
 
## network parameters
n_hidden_1 <- 256L # 1st layer num features
n_hidden_2 <- 128L # 2nd layer num features
n_input <- 784L # MNIST data input (img shape: 28*28)
 
## tf Graph input
<- tensorflow::tf$placeholder(tensorflow::tf$float32, tensorflow::shape(NULL, n_input))
 
## store layers weight & bias
weights <- base::list(
  'encoder_h1'= tensorflow::tf$Variable(tf$random_normal(base::c(n_input, n_hidden_1)), dtype=tf$float32),
  'encoder_h2'= tensorflow::tf$Variable(tf$random_normal(base::c(n_hidden_1, n_hidden_2)), dtype=tf$float32),
  'decoder_h1'= tensorflow::tf$Variable(tf$random_normal(base::c(n_hidden_2, n_hidden_1)), dtype=tf$float32),
  'decoder_h2'= tensorflow::tf$Variable(tf$random_normal(base::c(n_hidden_1, n_input)), dtype=tf$float32))
 
biases <- base::list(
  'encoder_b1'= tensorflow::tf$Variable(stats::rnorm(n=n_hidden_1), dtype=tf$float32),
  'encoder_b2'= tensorflow::tf$Variable(stats::rnorm(n=n_hidden_2), dtype=tf$float32),
  'decoder_b1'= tensorflow::tf$Variable(stats::rnorm(n=n_hidden_1), dtype=tf$float32),
  'decoder_b2'= tensorflow::tf$Variable(stats::rnorm(n=n_input), dtype=tf$float32))
 
## building the encoder
encoder <- function(x) {
  # encoder hidden layer with sigmoid activation #1
  layer_1 <- tensorflow::tf$nn$sigmoid(tensorflow::tf$add(tensorflow::tf$matmul(x, weights$encoder_h1), biases$encoder_b1))
  
  # decoder hidden layer with sigmoid activation #2
  layer_2 <- tensorflow::tf$nn$sigmoid(tensorflow::tf$add(tensorflow::tf$matmul(layer_1, weights$encoder_h2), biases$encoder_b2))
  
  return(layer_2)
}
 
## building the decoder
decoder <- function(x) {
  # Encoder Hidden layer with sigmoid activation #1
  layer_1 <- tensorflow::tf$nn$sigmoid(tensorflow::tf$add(tensorflow::tf$matmul(x, weights$decoder_h1), biases$decoder_b1))
  
  # Decoder Hidden layer with sigmoid activation #2
  layer_2 <- tensorflow::tf$nn$sigmoid(tensorflow::tf$add(tensorflow::tf$matmul(layer_1, weights$decoder_h2), biases$decoder_b2))
  
  return(layer_2)
}
 
## construct model
encoder_op <- encoder(x)
decoder_op <- decoder(encoder_op)
 
## prediction
y_pred <- decoder_op
 
## targets (labels) are the input data.
y_true <- x
 
## define loss and optimizer, minimize the squared error
cost <- tensorflow::tf$reduce_mean(tensorflow::tf$pow(y_true - y_pred, 2))
optimizer <- tensorflow::tf$train$RMSPropOptimizer(learning_rate=learning_rate)$minimize(cost)
 
## initialize variable for plotting
learning_val <- base::matrix(data=0.0, nrow=1, ncol=2)
learning_val <- base::as.data.frame(learning_val)
names(learning_val) <- base::c("Epoch""Cost")
 
## initializing the variables
init <- tensorflow::tf$global_variables_initializer()
 
## create session and initialize  variables
sess <- tensorflow::tf$Session()
sess$run(init)
 
total_batch <- base::as.integer(mnist$train$num_examples / batch_size)
 
## training cycle
for(epoch in 1:training_epochs) {
  # loop over all batches
  for(i in 1:total_batch) {
    # load batch_size training examples in each training iteration
    batches <- mnist$train$next_batch(base::as.integer(batch_size))
    batch_xs <- batches[[1]]
    
    # Run optimization op (backprop) and cost op (to get loss value)
    sess$run(optimizer, feed_dict = dict(x = batch_xs))
  }
  
  # calculate cost value
  cost_val <- sess$run(cost, feed_dict = dict(x = batch_xs))
  learning_val <- rbind(learning_val, c(epoch, cost_val))
  
  # display logs per epoch step
  if((epoch %% display_step) == 0{
    base::print(base::sprintf("Epoch: %04d, cost: %.9f", epoch, cost_val))
  }
}
 
base::print("Optimization Finished!")
 
## plotting with Plotly
learning_val <- learning_val[-1,]
<- plotly::plot_ly(data = learning_val,
                     x = ~Epoch,
                     y = ~Cost,
                     name = 'Cost Value',
                     type = 'scatter',
                     mode = 'lines+markers',
                     line = list(color = 'rgb(205, 12, 24)',width = 3)) %>%
  layout(title = "Cost Values as Epoch Proceeds",
         xaxis = list(title = "Epoch"),
         yaxis = list (title = "Cost"))
 
# print results
base::print(p)
 
## applying encode and decode over test set
encode_decode <- sess$run(y_pred, feed_dict=dict(x= mnist$test$images[1:examples_to_show,]))
 
## compare the results
xt <- list()
for(ii in 1:examples_to_show) {
  img1 <- mnist$test$images[ii,]
  img1 <- matrix(img1, nrow=28, ncol=28)
  img1 <- EBImage::Image(img1)
  
  img2 <- encode_decode[ii,]
  img2 <- matrix(img2, nrow=28, ncol=28)
  img2 <- EBImage::Image(img2)
  
  xt <- c(xt, list(img1))
  xt <- c(xt, list(img2))
}
 
xt <- EBImage::combine(xt)
EBImage::display(xt, title='Autoencoder', all=TRUE, method="raster")
cs



Comments