EXCELSIOR

[러닝 텐서플로]Chap07.4 - 텐서플로 추상화와 간소화, TF-Slim 본문

DeepLearning/Learning TensorFlow

[러닝 텐서플로]Chap07.4 - 텐서플로 추상화와 간소화, TF-Slim

Excelsior-JH 2018. 7. 1. 19:32

Chap07.4 - 텐서플로 추상화와 간소화, TF-Slim

7.5 TF-Slim

TF-Slim은 텐서플로를 가볍게(?) 사용할 수 있는 텐서플로의 확장된 추상화 라이브러리이며, 복잡한 모델을 빠르고 직관적으로 정의하고 학습할 수 있다. TF-Slim은 텐서플로 내에 포함되어 있으므로 별도의 설치를 하지 않아도 된다.

TF-Slim의 추상화는 모두 CNN(Convolutional Neural Network)에 관한 것이다. CNN의 경우 동일한 합성곱 계층(Convolution Layer)을 여러번 재사용하는 보일러플레이트(boilerplate code)코드가 많다. 이러한 코드가 많을 경우 모델이 복잡해질 뿐만아니라 가독성 또한 떨어지게 된다. TF-Slim은 이러한 복잡한 CNN 모델을 High-Level, 추상화, arument scoping 등을 이용해 깔끔하게 작성할 수 있게 해준다.

그리고, TF-Slim은 자체적인 모델을 생성하고 학습할 수 있을 뿐만아니라, 사전에 학습된 모델인 VGG, AlexNet, Inception 등을 제공한다.

7.5.1 TF-Slim 기능 및 사용방법

Usage

TF-Slim을 사용하기 위해서는 다음의 코드로 TF-Slim을 임포트한다.

  import tensorflow.contrib.slim as slim


Variables

TF-Slim은 초기화(initializer), 정규화(regularizer), 디바이스(device)를 하나의 래퍼(Wrapper)로 정의하여 변수를 쉽게 만들 수 있다. 아래의 예제 코드는 L2 정규화와 CPU를 사용하는 절단정규분포(truncated_normal_initializer())로 초기화한 가중치(변수) weights를 정의하는 코드이다.

  import tensorflow as tf
import tensorflow.contrib.slim as slim

weights = slim.variable('weights',
                       shape=[10, 10, 3, 3],
                       initializer=tf.truncated_normal_initializer(stddev=0.1),
                       regularizer=slim.l2_regularizer(0.05),
                       device='/CPU:0')


Layers

TF-Slim을 이용하면 순수 텐서플로를 이용해서 CNN 모델을 구현하는 것보다 훨씬 짧은 코드로 구현할 수 있다. 특히 보일러플레이트 코드와 불필요한 중복을 제거할 수 있다. 먼저, 합성곱 계층을 TF-Slim을 이용해서 정의 해보자.

  # 샘플 코드
net = slim.conv2d(inputs, 64, [5, 5], padding='SAME',
                 weights_initalizer=tf.truncated_normal_initializer(stddev=0.01),
                 weights_regularizer=slim.l2_regularizer(0.0005), scop='conv1')


위의 샘플 코드에서 처럼 합성곱 연산, 가중치 초기화, 정규화, 활성화 함수 등을 한번에 설정해줄 수 있다.

그리고, TF-slim은 repeat을 이용해 동일한 합성곱 계층들을 한줄로 표현할 수 있다. 아래의 코드는 5개의 동일한 합성곱 계층을 쌓은 것을 나타낸 코드이다.

  # 샘플코드 - 같은 합성곱 계층을 5번 쌓기
net = slim.conv2d(net, 128, [3, 3], scope='con1_1')
net = slim.conv2d(net, 128, [3, 3], scope='con1_2')
net = slim.conv2d(net, 128, [3, 3], scope='con1_3')
net = slim.conv2d(net, 128, [3, 3], scope='con1_4')
net = slim.conv2d(net, 128, [3, 3], scope='con1_5')


위의 코드를 repeat()을 이용해 한줄로 나타낼 수 있다. 단, repeat은 계층의 크기가 동일한 경우에만 사용 가능하다.

  # 샘플코드 - slim.repeat()을 이용해 한줄로 나타내기
net = slim.repeat(net, 5, slim.conv2d, 128, [3, 3], scope='con1')


만약, 형태가 다른 경우에는 stack을 이용해 나타낼 수 있다.

  # 샘플코드 - 형태가 다른 합성곱 계층을 5개 쌓기
net = slim.conv2d(net, 64, [3, 3], scope='con1_1')
net = slim.conv2d(net, 64, [1, 1], scope='con1_2')
net = slim.conv2d(net, 128, [3, 3], scope='con1_3')
net = slim.conv2d(net, 128, [1, 1], scope='con1_4')
net = slim.conv2d(net, 256, [3, 3], scope='con1_5')

# 샘플코드 - slim.stack()을 이용해 한줄로 나타내기
net = slim.stack(net, slim.conv2d, [(64, [3, 3]), (64, [1, 1]),
                                  (128, [3, 3]), (128, [1, 1]),
                                  (256, [3, 3])], scope='con')


TF-Slim에는 slim.conv2d 계층 뿐만아니라 아래의 표와 같이 다양한 계층을 사용할 수 있다.

LayerTF-Slim
BiasAddslim.bias_add
BatchNormslim.batch_norm
Conv2dslim.conv2d
Conv2dInPlaneslim.conv2d_in_plane
Conv2dTranspose (Deconv)slim.conv2d_transpose
FullyConnectedslim.fully_connected
AvgPool2Dslim.avg_pool2d
Dropoutslim.dropout
Flattenslim.flatten
MaxPool2Dslim.max_pool2d
OneHotEncodingslim.one_hot_encoding
SeparableConv2slim.separable_conv2d
UnitNormslim.unit_norm

arg_scope

TF-Slim은 arg_scope이라는 스코프를 가지고 있는데, 이것을 이용하면 같은 스코프에 정의되어 있는 여러 계층에 같은 인자들을 한번에 전달할 수 있다. 아래의 샘플 코드는 slim.arg_scope을 이용해 패딩, 활성화함수, 초기화, 정규화를 slim.conv2d 계층에 동일하게 설정하는 코드이다.

  # 샘플코드 - arg_scope을 이용해 slim.conv2d에 같은 인자 설정하기
with slim.arg_scope([slim.conv2d],
                   padding='SAME',
                   activation_fn=tf.nn.elu,
                   weights_initializer=tf.truncated_normal_initializer(stddev=0.01)):
   inputs = tf.reshape(x, [-1, 28, 28, 1])
   
   net = slim.conv2d(inputs=inputs, num_outputs=32, kernel_size=[5, 5], scope='conv1')
   net = slim.max_pool2d(inputs=net, kernel_size=[2, 2], scope='pool1')
   net = slim.conv2d(net, 64, [5, 5], scope='conv2')
   net = slim.max_pool2d(net, [2, 2], scope='pool2')
   net = slim.flatten(net, scope='flatten3')

7.5.2 TF-Slim으로 MNIST 분류 CNN 모델 구현하기

TF-Slim의 사용방법을 알아보았으니, 이번에는 Chap04 - 합성곱 신경망 CNN에서 구현한 CNN모델을 TF-Slim을 이용해 구현해 보도록하자. 7.5.1에서 TF-Slim에 대한 각 기능을 샘플코드로 살펴보았기 때문에 별도의 코드 설명은 생략한다.

TF-Slim을 이용해 구현한 MNIST 분류 CNN 모델의 전체코드는 다음과 같다.


7.5.3 TF-Slim으로 VGG-16 모델 구현하기

TF-Slim을 이용해 CNN 모델 중 VGG모델을 구현해 보도록 하자. VGG모델은 2014년에 발표된 모델이며, 2014년 ISLVRC에서 2위를 차지한 모델이다. VGG는 계층의 수가 16일때와 19사이일 때 결과가 가장 좋으며, 이번 예제에서는 TF-Slim을 이용해 13개의 합성곱 계층(Conv layer)와 3개의 완전연결 계층(FC, Fully-Connected layer), VGG-16 모델을 구현해 본다. 이번 예제 코드는 단순히 모델만 구현하는 것이므로 데이터 입력 및 학습에 대한 코드는 포함하지 않았다.


위의 그림에서 보듯이 VGG-16은 동일한 계층을 여러번 쓰는것을 확인할 수 있다. 따라서, TF-Slim의 slim.arg_scopeslim.repeat을 이용해 VGG-16을 구현할 수 있다.

  # https://github.com/tensorflow/tensorflow/tree/r1.8/tensorflow/contrib/slim
def vgg16(inputs):
   with slim.arg_scope([slim.conv2d, slim.fully_connected],
                         activation_fn=tf.nn.relu,
                         weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
                         weights_regularizer=slim.l2_regularizer(0.0005)):
       net = slim.repeat(inputs, 2, slim.conv2d, 64, [3, 3], scope='conv1')
       net = slim.max_pool2d(net, [2, 2], scope='pool1')
       net = slim.repeat(net, 2, slim.conv2d, 128, [3, 3], scope='conv2')
       net = slim.max_pool2d(net, [2, 2], scope='pool2')
       net = slim.repeat(net, 3, slim.conv2d, 256, [3, 3], scope='conv3')
       net = slim.max_pool2d(net, [2, 2], scope='pool3')
       net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv4')
       net = slim.max_pool2d(net, [2, 2], scope='pool4')
       net = slim.repeat(net, 3, slim.conv2d, 512, [3, 3], scope='conv5')
       net = slim.max_pool2d(net, [2, 2], scope='pool5')
       net = slim.fully_connected(net, 4096, scope='fc6')
       net = slim.dropout(net, 0.5, scope='dropout6')
       net = slim.fully_connected(net, 4096, scope='fc7')
       net = slim.dropout(net, 0.5, scope='dropout7')
       net = slim.fully_connected(net, 1000, activation_fn=None, scope='fc8')
   return net

7.5.4 사전 학습된 VGG-16모델 사용하기

이번에는 사전 학습된 VGG 모델을 다운로드 받아 사용해보자. 아래의 예제코드는 이미지 url 경로(http://54.68.5.226/car.jpg) 를 urlib모듈을 이용해 읽은 다음, 이 이미지를 사전 학습된 VGG-16 모델을 가지고 분류하는 작업을 나타낸 코드이다.

먼저, TensorFlow가 제공하는 모델들이 있는 GitHub 저장소를 클론한다.

  git clone https://github.com/tensorflow/models

그런 다음 클론한 경로를 파이썬의 sys 모듈을 이용해 설정해준다.

  import sys
sys.path.append('<클론한 경로>' + '/models/research/slim')


그리고, 사전 학습된 VGG-16 모델을 download.tensorflow.org에서 다운로드 받은 후 적당한 위치에 압축을 풀어주고 이것을 target_dir로 지정한다.

  target_dir = '<vgg 사전학습된 모델이 있는 경로>'


전체 코드는 다음과 같다.

  INFO:tensorflow:Restoring parameters from ../data/vgg16/vgg_16.ckpt
Class: sports car, sport car |Prob: 0.6969962
Class: car wheel |Prob: 0.09234831
Class: convertible |Prob: 0.0891054
Class: racer, race car, racing car |Prob: 0.08648531
Class: beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon |Prob: 0.011633869


7.5.5 정리

이번 포스팅에서는 TF-Slim에 대해 살펴보았다. TF-Slim은 CNN 모델링에 있어서 간편하게 작성할 수 있도록 다양한 계층등을 추상화해서 제공하며, AlexNet, VGG, Inception 등 성능이 좋은 사전 학습된 모델들을 제공한다. TF-Slim에 대해 자세한 설명은 https://github.com/tensorflow/tensorflow/tree/r1.8/tensorflow/contrib/slim 에서 확인할 수 있다.

Comments