2017년 3월 22일에 나온 아직도 따끈따끈한 논문입니다. GitHub링크는 아래와 같습니다.

https://github.com/luanfujun/deep-photo-styletransfer

간단히 논문에 대해 요약을 하자면 아래와 같습니다.


기존까지 있었던 image style transfer(유명한 neural-style 등)은 이미지에 스타일을 입히는 게 얼추 가능은 했지만, style faithfulness가 약하거나 photorealism이 약했습니다. photorealism이 약한 이유는 사진 내부에 있는 직선 성분과 택스쳐 성분이 왜곡되기 때문이고, style faithfulness가 약한 이유는 예를 들어서 sky style은 sky에 매칭이 되야 하고, building style은 building에 매칭되어야 하는데 이게 잘 안돼서 연관없는 것이 매칭되었기 때문입니다.  따라서 Deep Photo Style Transfer는 이것들을 해결하고자 뭐 여러가지 적용했습니다. 그래서 이전의 알고리즘과는 달리 위 두 가지를 충족시키는 좋은 알고리즘이 되었다 뭐 이정도입니다. 그래서 실제로 이걸 돌려보면 사진의 전체적인 분위기(시각, 계절, 날씨, 택스쳐 재배치 등)이 제대로 됩니다.


아래가 그 예시입니다. (원본을 GitHub에서 링크 따온 것입니다.) 왼쪽부터 순서대로 원본, 스타일, 결과물입니다.



코드가 GtiHub에 있기 때문에 돌려볼려고 clone도 받고 Octave도 설치해서 라플라시안 돌리고 그러려고 했는데... GPU 램 부족하다고 안 되네요 쩝... 나중에 좋은 장비 구축하면 그때가서 돌려보겠습니다.


p.s. 논문은 대충 읽어봤는데 처음해보는 리뷰라 그런지 잘 안 되네요 쿨럭...  나중에 시간이 되면 더 꼼꼼히 읽어서 리뷰해보겠습니다

  1. 스터디중 2017.10.24 12:52 신고

    안녕하세요. 리뷰 잘 읽었습니다.
    한가지 질문을 드려도 될까요?
    segmentation mask에 맞게 transfer 되는건 알겠는데, 그럼 다른 mask 는 transfer에 전혀 관여를 안하는건가요?

    • makeapp 2017.10.28 00:12 신고

      간단하게 논문 조금 훑어보고 예제를 살펴본 정도라서, 저도 정확하게 답변드릴순 없을 거 같습니다. 직접 논문 읽어보시고, 프로그램 실행해보시는게 좋을 거 같습니다.

오랜만에 글을 써봅니다. 원래 CNN으로 CIFAR-10 작업을 하고 있는데, Batch Normalization과 기타 다른 기법도 정리해야 하기도 하고 좀 바쁜 일도 있어서 아직 딥러닝 파트는 글을 다 못 썻네요. 아무튼 이번 글에서는 딥러닝을 활용하여 꾸린 동영상 화질을 개선해볼 겁니다.


이 괴랄한 짓을 하게 된 계기는 다음과 같습니다. 제가 아이유 팬인지라 이번에 아이유 콘서트 포토북을 샀는데, 포토북에 같이 담겨 있는 DVD의 화질이 480p로 괴랄한 관계로 이것을 어떻게든 개선해서 영상을 보겠다는 덕질로부터 시작하게 되었습니다. ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ


아 참고로, 이 개선을 하겠다고 좀 머리 굴려보고 이렇게 컴퓨터 굴려봤는데도 개선의 큰 효과는 거두지 못했습니다. 원체 해상도가 낮았던 영상인지라...제 방법을 그대로 적용하실 분은 가능하면 720p 이상에 작은 세부사항이 없는 영상(눈이 2px정도이면 이건 확대해서 다듬어도 개선이 안 됩니다. 사람이 직접 건드리거나, 모자이크를 살리는 딥러닝을 돌려야 합니다.)에서 적용하시는 걸 권해드립니다.


일단 먼저 예시로 한 프레임을 보도록 합시다. 원본 영상은 720x480입니다.


무려 2017년에...4K도 거의 대중화가 된 이 세상에서 480p 영상이라니....

해상도가 워낙 낮아서 폰 화면에서 보는 거 아니라면 좀 보기 껄그러운 수준의 해상도입니다.


자, 이번엔 Image Super Resolution과 OpenCV의 filter2D 기능을 사용하여 좀 더 깔끔하게 하기 위해 sharpen까지 준 프레임입니다.

(Tistory의 업로드 최대 폭이 900px인지라 조금 이미지가 작게 올라갑니다. 원본 사이즈는 1440x960입니다.)


솔직히 이것도 그닥 보기 편한 품질은 아니지만, 그나마 원본 영상의 프레임보다는 많이 개선된 편입니다.



자, 그러면 이제 어떻게 동영상의 품질을 개선했는지 간단하게 설명해보겠습니다.


기본적으로 제 컴퓨터 환경은 다음과 같습니다. 이 환경에서 7,000프레임 정도 되는 영상을 업스케일링 & sharpen을 줬을 때 1시간 30~40분 정도 걸리니, 제 컴퓨터의 GPU(연산은 CPU가 아니라 GPU로 돌렸습니다. 이게 더 빠릅니다.)보다 안 좋으신 분은 좀 더 시간이 걸릴 것을 알고 자는 시간에 돌리는게 정신건강에 매우 이롭습니다.


CPU: i7-5820K

GPU: GTX 970

RAM: DDR4 16GB

SSD: Toshiba Q Series 256GB (Pro 버전인지 아닌지는 기억이 안 나네요. 그냥 기본적인 SSD 성능을 낸다고 보시면 됩니다.)

OS: Ubuntu Gnome 16.04.1 LTS


1. 기본적인 프로그램을 설치한다.

아래는 필수적으로 필요한 프로그램입니다. 구글에 검색하면 다 나오니 알아서 까시면 됩니다.

- CUDA, cuDNN

- Torch

- FFMPEG

- Python Libraries: numpy, Theano, OpenCV, etc(프로그램 돌릴 때 없다고 뜨는 거 그것들 설치해주시면 됩니다. 자세히 기억은 안 나네요)


2. waifu2x를 git에서 clone해온다. 그리고 waifu2x에 필요한 필수적인 프로그램들을 설치한다.(README 참조)

간단하게 waifu2x를 설명해드리자면, 원래는 애니메이션이나 일러스트 등을 업스케일링하는 딥러닝입니다. 근데 어차피 딥러닝 모델은 학습만 하면 되니까, 일반적인 사진을 업스케일링할 수 있는 photo model도 있더라고요.


https://github.com/nagadomi/waifu2x


waifu2x의 READM.md를 읽어보시면 아시겠지만, 거기에도 영상을 업스케일링하는 방법이 간단하게 소개되어 있습니다. 저는 거기서 조금 더 응용해서 적용했습니다.


3. 아래 Python 코드를 다운받아서 어디에 저장해둔다.

이 코드는 좀 안 좋은 영상의 경우엔 초점이 흐릿하게 보이기 때문에 이때 좀 초점을 쨍하게 만들어 주기 위해 sharpen을 주는 코드입니다. 영상 업스케일링에 필수적인 코드는 아니니 필요하신 분만 사용하시면 됩니다.


Sharpen.py


* 함수를 보면 sharpen_filter와 sharpen_deblur 두 가지 종류가 있는데, 각각 적용해보시고 맘에 드시는 거 하나 골라서 함수명만 바꿔주시면 됩니다. 저 같은 경우에는 좀 어두운 환경(콘서트장)에서는 sharpen_filter가 더 적합했고, 약간 몽상적이면서 밝은 분위기 영상에는 sharpen_deblur가 채도도 살짝 높여주면서 영상을 괜찮게 만들어 줬습니다.


4. 영상을 프레임 단위로 쪼개어 png 파일로 저장한다.

명령어는 다음과 같습니다. 어디에 폴더 하나 만드시고 거기에 저장하시면 됩니다. 참고로 이미지 파일들이 동영상 파일의 10배 가까이 용량을 차지하기 때문에 용량이 넉넉한 곳을 마련해두시는게 좋습니다.

ffmpeg -i 동영상파일 -f image2 %08d.png


5. 영상에서 오디오 파일을 추출한다.

나중에 개선된 프레임을 다시 합칠 때에는 오디오가 없는 상태이기 때문에, 이때 오디오를 넣어주기 위해서 원본 영상에서 오디오를 추출해냅니다.

ffmpeg -i 동영상파일 -acodec copy 오디오파일


6. 프레임 목록을 만듭니다.

아래 명령어만 입력하시면 됩니다.

find "$(cd 이미지폴더; pwd)" -name "*.png" | sort > frames.txt


7. (선택) 프레임에 sharpen을 줍니다.

선택 사항이며, 화질구지인 480p에서는 어느정도 효과를 얻었습니다.

python Sharpen.py경로 frames.txt경로


8. 프레임을 업스케일링합니다.

제일 중요한 부분입니다. 먼저 새 프레임 폴더를 만들고, torch를 이용해 waifu2x를 돌립니다. 노이즈 레벨은 3정도가 적당했습니다.


mkdir new_frames

th waifu2x폴더/waifu2x.lua -force_cudnn 1 -model_dir models/photo -m noise_scale -noise_level 3 -resume 1 -l frames.txt 경로 -o new_frames/%08d.png


* waifu2x 옵션은 이외에도 여러가지가 있고, GPU 대신에 CPU에서 돌릴 수 있는 옵션 등이 있으므로 명령어 옵션을 체크하고 커스텀해주시면 됩니다.


여기서 95% 이상의 시간이 소요됩니다.


9. 프레임과 오디오 파일을 합쳐서 동영상을 만듭니다.

ffmpeg -f image2 -framerate fps수 -i new_frames/%08d.png -i 오디오파일 -r 오디오파일fps수 -vcodec mpeg4 -acodec copy -crf 16 video.mp4


이외에 많은 ffmpeg 옵션이 있으므로 구글링 해보시는 것을 권해드립니다. 코덱도 mpeg4 외에 좀 더 용량이 작은 libx264를 쓸 수는 있으나, 윈도 환경에서 VLC를 제외하고 곰플레이어, 윈도 기본 내장 플레이어 등에서 정상적으로 동영상이 재생 안 되는 것으로 확인되어 가능하면 용량이 좀 더 크더라도(대략 1.5배?) mpeg4를 쓰는 것이 정신건강에 더 좋을 거 같습니다. 아니면 libx264 호환 윈도 코덱을 까시면 됩니다.


이렇게 하면 그나마 20% 정도 개선된 동영상을 얻으실 수 있으며 원본 영상의 해상도가 더 높을 수록, 세부 요소가 더 적은 영상일 수록 더 큰 개선 효과를 얻으실 수 있을 거 같습니다. 따로 동영상 프레임 추출부터 재합성까지 자동화하는 Bash용 스크립트도 하나 만들어뒀는데, 이것은 나중에 GitHub에 정리해서 업로드하겠습니다.


+ 추가: 정리해서 업로드했습니다. https://github.com/AMakeApp/DVD2FHD

오늘의 주제는 Neural Network 최적화입니다. Sigmoid보다 좀 더 효율적이라고 알려져 있는 ReLU, 초기 Weight를 좀 더 효율적으로 초기화시키는 Xavier Initializer, Dropout을 다뤄볼 것입니다.


먼저 Neural Network가 최적화되었음을 확인할 수 있게 간단히 Train & Test가 가능한 MNIST(Mixed National Institute of Standards and Technology database) 데이터셋을 사용합니다. MNIST는 숫자 손글씨를 28x28의 흑백 이미지와 그 숫자 손글씨가 어떤 숫자를 나타내는지 label이 붙어있는 데이터셋입니다. TensorFlow에서 제공하는 MNIST는 55,000개의 train set, 5,000개의 validation set, 10,000개의 test set으로 구성되어 있습니다. train set 이미지를 모아서 보면 아래 이미지와 같습니다.


네 뭐.... 엄청 많습니다. ㅋㅋㅋ


이제 본론으로 돌아와서, 이 MNIST에서 주어지는 train set을 학습시켜서 Neural Network가 test set의 이미지 숫자를 정상적으로 인식해내게 하면 됩니다. 먼저 가장 먼저 했던 Softmax로 위를 분류해보겠습니다. 모델의 종류만 다르고 실제로 학습 & 테스트 시에 dropout_rate 유무를 제외하고는 모든 코드가 같기 때문에 간결한 설명을 위해서 각 모델에 대한 설명만 하겠습니다. 코드는 첨부된 Jupyter Notebook 파일 또는 Python 파일을 참조해주시기 바랍니다.


기본적으로 image는 28x28(=768)의 데이터(1과 0으로 음영 구분), label은 10개의 배열(image에 맞는 숫자 index에 표기)이므로 아래와 같이 input placeholder를 짭니다.

X = tf.placeholder(tf.float32, [None, 28*28], name="x")
Y = tf.placeholder(tf.float32, [None, 10], name="y")

Xavier Initializer를 제외한 모든 Weight 초기화는 tf.random_normal로 했고, 최적화 모델은 기존에 쓰던 GradientDescentOptimizer보다 더 좋은 AdamOptimizer를 사용하였습니다. learning_rate는 0.001입니다.


1. Softmax

DNN Optimization(Softmax).ipynb

DNN Optimization(Softmax).py

간단히 28*28 행렬에서 곱을 하여 10 행렬을 만들어야 하기 때문에 아래와 같이 모델을 만듭니다.

w = tf.Variable(tf.zeros([28*28, 10]), name="Weight")
b = tf.Variable(tf.zeros([10]), name="Bias")

H = tf.nn.softmax(tf.matmul(X, w) + b)

이후 이 모델을 학습시키고 test set을 돌리면 다음과 같은 결과가 나옵니다. Epoch는 55,000개의 train set의 반복한 횟수입니다. (최적화 기술에 대한 비교를 위해 모든 기타 옵션을 똑같이 고정했기 때문에, Softmax의 경우 random_normal 대신 0으로, 최적화 모델도 rate랑 모델도 바꿔보면 92% 정도까지 나옵니다.)

Epoch: 1
Test Accuracy: 0.4371
Epoch: 2
Test Accuracy: 0.5924
Epoch: 3
Test Accuracy: 0.7421
Epoch: 4
Test Accuracy: 0.7831
Epoch: 5
Test Accuracy: 0.8081
Epoch: 6
Test Accuracy: 0.8268
Epoch: 7
Test Accuracy: 0.8429
Epoch: 8
Test Accuracy: 0.858
Epoch: 9
Test Accuracy: 0.8761
Epoch: 10
Test Accuracy: 0.8849
Epoch: 11
Test Accuracy: 0.892
Epoch: 12
Test Accuracy: 0.8962
Epoch: 13
Test Accuracy: 0.9006
Epoch: 14
Test Accuracy: 0.9036
Epoch: 15
Test Accuracy: 0.905


2. 4-Layer DNN, ReLU

DNN Optimization(4-Layer DNN, ReLU).ipynb

DNN Optimization(4-Layer DNN, ReLU).py DNN Optimization(4-Layer DNN, ReLU).ipynb

이번엔 지난 번에 배운 NN을 적용하고, activation function으로 sigmoid 대신 더 효율적이라고 알려져 있는 ReLU를 사용합니다. ReLU는 sigmoid와는 다르게 치역의 범위가 [0, ∞] 이며 간단하게 max(0, x)으로 나타낼 수 있습니다. 어떻게 보면 sigmoid의 1보다 좀 더 가중치를 두게 하여 더 효율적인 학습을 하게 했다고 볼 수 있을 거 같습니다. 모델은 다음과 같습니다.

def nn_layer(input_data, output_size):
    W = tf.Variable(tf.random_normal([input_data.get_shape().as_list()[1], output_size]))
    B = tf.Variable(tf.random_normal([output_size]))
    return tf.matmul(input_data, W) + B

with tf.name_scope("Layer2"):
    L2 = tf.nn.relu(nn_layer(X, 14*14))
    
with tf.name_scope("Layer3"):
    L3 = tf.nn.relu(nn_layer(L2, 14*14))
    
with tf.name_scope("Layer4"):
    H = nn_layer(L3, 10)


실행 결과는 다음과 같습니다. 위의 Softmax보다 좀 더 개선된 모습을 볼 수 있습니다.

Epoch: 1
Test Accuracy: 0.8417
Epoch: 2
Test Accuracy: 0.8828
Epoch: 3
Test Accuracy: 0.8995
Epoch: 4
Test Accuracy: 0.9103
Epoch: 5
Test Accuracy: 0.9194
Epoch: 6
Test Accuracy: 0.9253
Epoch: 7
Test Accuracy: 0.9283
Epoch: 8
Test Accuracy: 0.9276
Epoch: 9
Test Accuracy: 0.935
Epoch: 10
Test Accuracy: 0.9351
Epoch: 11
Test Accuracy: 0.9375
Epoch: 12
Test Accuracy: 0.9401
Epoch: 13
Test Accuracy: 0.9404
Epoch: 14
Test Accuracy: 0.9389
Epoch: 15
Test Accuracy: 0.9427


3. 4-Layer DNN, ReLU, Xavier Initializer

DNN Optimization(4-Layer DNN, ReLU, Xavier Init).ipynb

DNN Optimization(4-Layer DNN, ReLU, Xavier Init).py

과거의 Deep Learning에서는 Weight의 초기값을 단순히 random으로 초기화하거나 학습이 진행만 된다면 0으로 초기화하기도 하였습니다. 그러나 이 초기값 초기화의 중요성이 대두되면서 Xavier Initializer와 같은 새로운 초기화 알고리즘이 등장하게 되었습니다. 꽤 효과적인 Xavier Initializer는 다음과 같은 알고리즘으로 초기화를 합니다.

def xavier_init(n_inputs, n_outputs, uniform=True):
  """Set the parameter initialization using the method described.
  This method is designed to keep the scale of the gradients roughly the same
  in all layers.
  Xavier Glorot and Yoshua Bengio (2010):
           Understanding the difficulty of training deep feedforward neural
           networks. International conference on artificial intelligence and
           statistics.
  Args:
    n_inputs: The number of input nodes into each output.
    n_outputs: The number of output nodes for each input.
    uniform: If true use a uniform distribution, otherwise use a normal.
  Returns:
    An initializer.
  """
  if uniform:
    # 6 was used in the paper.
    init_range = math.sqrt(6.0 / (n_inputs + n_outputs))
    return tf.random_uniform_initializer(-init_range, init_range)
  else:
    # 3 gives us approximately the same limits as above since this repicks
    # values greater than 2 standard deviations from the mean.
    stddev = math.sqrt(3.0 / (n_inputs + n_outputs))
    return tf.truncated_normal_initializer(stddev=stddev)

실제로는 TensorFlow에 구현되어 있기 때문에 아래와 같이 간단하게 사용하여 모델을 작성할 수 있습니다. (본 강의에서는 w만 Xavier Initializer 쓴 거 같던데, 전 그냥 bias까지 썻습니다. 어차피 큰 차이는 없는 거 같기에...)

def nn_layer(name, input_data, output_size):
    W = tf.get_variable(name=name + "_W",
                        shape=[input_data.get_shape().as_list()[1], output_size],
                        initializer=tf.contrib.layers.xavier_initializer())
    B = tf.get_variable(name=name + "_B",
                        shape=[output_size],
                        initializer=tf.contrib.layers.xavier_initializer())
    return tf.matmul(input_data, W) + B

with tf.name_scope("Layer2"):
    L2 = tf.nn.relu(nn_layer("L2", X, 14*14))
    
with tf.name_scope("Layer3"):
    L3 = tf.nn.relu(nn_layer("L3", L2, 14*14))
    
with tf.name_scope("Layer4"):
    H = nn_layer("L4", L3, 10)

실행 결과는 다음과 같습니다. 이전과는 달리, 엄청나게 개선된 모습을 볼 수 있습니다.

Epoch: 1
Test Accuracy: 0.9509
Epoch: 2
Test Accuracy: 0.972
Epoch: 3
Test Accuracy: 0.9754
Epoch: 4
Test Accuracy: 0.9773
Epoch: 5
Test Accuracy: 0.9724
Epoch: 6
Test Accuracy: 0.9776
Epoch: 7
Test Accuracy: 0.9772
Epoch: 8
Test Accuracy: 0.977
Epoch: 9
Test Accuracy: 0.9791
Epoch: 10
Test Accuracy: 0.9791
Epoch: 11
Test Accuracy: 0.9773
Epoch: 12
Test Accuracy: 0.9807
Epoch: 13
Test Accuracy: 0.9811
Epoch: 14
Test Accuracy: 0.9757
Epoch: 15
Test Accuracy: 0.9787


4. 4-Layer DNN, ReLU, Xavier Initializer, Dropout

DNN Optimization(4-Layer DNN, ReLU, Xavier Init, Dropout).ipynb

DNN Optimization(4-Layer DNN, ReLU, Xavier Init, Dropout).py

이번에는 Dropout이라는 기술을 써볼 겁니다. 아주 간단합니다. Neural Network에서 일정 비율의 node들을 비활성화 시킨 채로 학습을 진행하고, 이후에 test 할 때 모두 활성화시키는 기술입니다. 실제로 효과가 꽤 있다고는 하는 거 같다만, 여기서는 그렇게 눈에 띄게 효과가 나타나진 않습니다. 모델과 결과는 다음과 같습니다.

def nn_layer(name, input_data, output_size):
    W = tf.get_variable(name=name + "_W",
                        shape=[input_data.get_shape().as_list()[1], output_size],
                        initializer=tf.contrib.layers.xavier_initializer())
    B = tf.get_variable(name=name + "_B",
                        shape=[output_size],
                        initializer=tf.contrib.layers.xavier_initializer())
    return tf.matmul(input_data, W) + B

dropout_rate = tf.placeholder(tf.float32)

with tf.name_scope("Layer2"):
    _L2 = tf.nn.relu(nn_layer("L2", X, 14*14))
    L2 = tf.nn.dropout(_L2, dropout_rate)
    
with tf.name_scope("Layer3"):
    _L3 = tf.nn.relu(nn_layer("L3", L2, 14*14))
    L3 = tf.nn.dropout(_L3, dropout_rate)
    
with tf.name_scope("Layer4"):
    _H = nn_layer("L4", L3, 10)
    H = tf.nn.dropout(_H, dropout_rate)
Epoch: 1
Test Accuracy: 0.9436
Epoch: 2
Test Accuracy: 0.9665
Epoch: 3
Test Accuracy: 0.9705
Epoch: 4
Test Accuracy: 0.9711
Epoch: 5
Test Accuracy: 0.9767
Epoch:  DNN Optimization(6-Layer DNN, ReLU, Xavier Init, Dropout, Ensemb6
Test Accuracy: 0.9754
Epoch: 7
Test Accuracy: 0.9774
Epoch: 8
Test Accuracy: 0.9802
Epoch: 9
Test Accuracy: 0.9807
Epoch: 10
Test Accuracy: 0.9781
Epoch: 11
Test Accuracy: 0.9798
Epoch: 12
Test Accuracy: 0.9795
Epoch: 13
Test Accuracy: 0.9805
Epoch: 14
Test Accuracy: 0.9804
Epoch: 15
Test Accuracy: 0.979


5. 6-Layer DNN, ReLU, Xavier Initializer, Dropout

DNN Optimization(6-Layer DNN, ReLU, Xavier Init, Dropout).ipynb

DNN Optimization(6-Layer DNN, ReLU, Xavier Init, Dropout).py

모델은 4번과 같으며 여기서 14*14 행렬로 레이어를 2개 더 늘렸습니다. 미미한 정확도 상승을 확인할 수 있습니다.

Epoch: 1
Test Accuracy: 0.9351
Epoch: 2
Test Accuracy: 0.9634
Epoch: 3
Test Accuracy: 0.9696
Epoch: 4
Test Accuracy: 0.9729
Epoch: 5
Test Accuracy: 0.9743
Epoch: 6
Test Accuracy: 0.9754
Epoch: 7
Test Accuracy: 0.975
Epoch: 8
Test Accuracy: 0.9782
Epoch: 9
Test Accuracy: 0.9776
Epoch: 10
Test Accuracy: 0.9776
Epoch: 11
Test Accuracy: 0.9772
Epoch: 12
Test Accuracy: 0.9787
Epoch: 13
Test Accuracy: 0.9795
Epoch: 14
Test Accuracy: 0.9794
Epoch: 15
Test Accuracy: 0.9793


6. 6-Layer DNN, ReLU, Xavier Initializer, Dropout, Ensemble(5 NNs)

DNN Optimization(6-Layer DNN, ReLU, Xavier Init, Dropout, Ensemb

DNN Optimization(6-Layer DNN, ReLU, Xavier Init, Dropout, Ensemb

이번엔 Ensemble(앙상블)을 해보겠습니다. Dropout보다 간단한 기술인데(기술이라고 해야하나..), 여러 개의 NN을 학습시켜서 여러 개의 NN에 test data를 넣고 predicted label을 평균 내는 등의 방법으로 정확도를 좀 더 개선하는 방법입니다. 강의에서는 3% 정도까지 정확도가 상승된다고 하셨는데, 실제로 제가 돌려봤을 때에는 0.5% 정도? 정확도가 상승하는 것을 확인할 수 있었습니다.

NN: 0 Epoch: 1 Test Accuracy: 0.9483 NN: 0 Epoch: 2 Test Accuracy: 0.9664 NN: 0 Epoch: 3 Test Accuracy: 0.9707 NN: 0 Epoch: 4 Test Accuracy: 0.9713 NN: 0 Epoch: 5 Test Accuracy: 0.9752 NN: 0 Epoch: 6 Test Accuracy: 0.9779 NN: 0 Epoch: 7 Test Accuracy: 0.9764 NN: 0 Epoch: 8 Test Accuracy: 0.9766 NN: 0 Epoch: 9 Test Accuracy: 0.9776 NN: 0 Epoch: 10 Test Accuracy: 0.9744 NN: 0 Epoch: 11 Test Accuracy: 0.9775 NN: 0 Epoch: 12 Test Accuracy: 0.9772 NN: 0 Epoch: 13 Test Accuracy: 0.9796 NN: 0 Epoch: 14 Test Accuracy: 0.9798 NN: 0 Epoch: 15 Test Accuracy: 0.9786 NN: 1 Epoch: 1 Test Accuracy: 0.9525 NN: 1 Epoch: 2 Test Accuracy: 0.959 NN: 1 Epoch: 3 Test Accuracy: 0.9666 NN: 1 Epoch: 4 Test Accuracy: 0.972 NN: 1 Epoch: 5 Test Accuracy: 0.9736 NN: 1 Epoch: 6 Test Accuracy: 0.9736 NN: 1 Epoch: 7 Test Accuracy: 0.9746 NN: 1 Epoch: 8 Test Accuracy: 0.9771 NN: 1 Epoch: 9 Test Accuracy: 0.9771 NN: 1 Epoch: 10 Test Accuracy: 0.9766 NN: 1 Epoch: 11 Test Accuracy: 0.978 NN: 1 Epoch: 12 Test Accuracy: 0.9788 NN: 1 Epoch: 13 Test Accuracy: 0.9787 NN: 1 Epoch: 14 Test Accuracy: 0.98 NN: 1 Epoch: 15 Test Accuracy: 0.9787 NN: 2 Epoch: 1 Test Accuracy: 0.9537 NN: 2 Epoch: 2 Test Accuracy: 0.966 NN: 2 Epoch: 3 Test Accuracy: 0.9742 NN: 2 Epoch: 4 Test Accuracy: 0.9731 NN: 2 Epoch: 5 Test Accuracy: 0.976 NN: 2 Epoch: 6 Test Accuracy: 0.9777 NN: 2 Epoch: 7 Test Accuracy: 0.9748 NN: 2 Epoch: 8 Test Accuracy: 0.978 NN: 2 Epoch: 9 Test Accuracy: 0.9766 NN: 2 Epoch: 10 Test Accuracy: 0.9784 NN: 2 Epoch: 11 Test Accuracy: 0.9787 NN: 2 Epoch: 12 Test Accuracy: 0.9767 NN: 2 Epoch: 13 Test Accuracy: 0.9813 NN: 2 Epoch: 14 Test Accuracy: 0.9804 NN: 2 Epoch: 15 Test Accuracy: 0.9815 NN: 3 Epoch: 1 Test Accuracy: 0.9547 NN: 3 Epoch: 2 Test Accuracy: 0.9677 NN: 3 Epoch: 3 Test Accuracy: 0.9722 NN: 3 Epoch: 4 Test Accuracy: 0.9708 NN: 3 Epoch: 5 Test Accuracy: 0.9728 NN: 3 Epoch: 6 Test Accuracy: 0.9753 NN: 3 Epoch: 7 Test Accuracy: 0.9773 NN: 3 Epoch: 8 Test Accuracy: 0.9783 NN: 3 Epoch: 9 Test Accuracy: 0.977 NN: 3 Epoch: 10 Test Accuracy: 0.9775 NN: 3 Epoch: 11 Test Accuracy: 0.9795 NN: 3 Epoch: 12 Test Accuracy: 0.9794 NN: 3 Epoch: 13 Test Accuracy: 0.9792 NN: 3 Epoch: 14 Test Accuracy: 0.9809 NN: 3 Epoch: 15 Test Accuracy: 0.9802 NN: 4 Epoch: 1 Test Accuracy: 0.9469 NN: 4 Epoch: 2 Test Accuracy: 0.9663 NN: 4 Epoch: 3 Test Accuracy: 0.9673 NN: 4 Epoch: 4 Test Accuracy: 0.9742 NN: 4 Epoch: 5 Test Accuracy: 0.9723 NN: 4 Epoch: 6 Test Accuracy: 0.9739 NN: 4 Epoch: 7 Test Accuracy: 0.9763 NN: 4 Epoch: 8 Test Accuracy: 0.9772 NN: 4 Epoch: 9 Test Accuracy: 0.9758 NN: 4 Epoch: 10 Test Accuracy: 0.9797 NN: 4 Epoch: 11 Test Accuracy: 0.9783 NN: 4 Epoch: 12 Test Accuracy: 0.9798 NN: 4 Epoch: 13 Test Accuracy: 0.9805 NN: 4 Epoch: 14 Test Accuracy: 0.9808 NN: 4 Epoch: 15 Test Accuracy: 0.9804


Ensemble Accuracy: 0.9846

이렇게 간단히 MNIST를 사용하여 딥러닝에서 사용되는 여러 기술을 적용해보고 테스트를 해봤습니다. 다음 번에는 CNN, RNN 등을 나갈 예정입니다.


*Ensemble은 생각보다 TensorFlow에서 구현하는 방법이 잘 나오지 않아서 아래 링크를 참조했습니다.

https://github.com/Hvass-Labs/TensorFlow-Tutorials/blob/master/05_Ensemble_Learning.ipynb

  1. Study 2017.10.17 11:39 신고

    DNN 구현할 때 Output Data로 14×14를 넣으신 이유는 Layer를 2번 돌리기 때문일까요?

    • makeapp 2017.10.28 00:10 신고

      네, 중간 레이어 크기를 적당하게 잡아주기 위해서 적당히 14x14를 넣었습니다.

+ Recent posts

티스토리 툴바