📗강의노트/핸즈온 머신러닝

[핸즈온 머신러닝] 제 13장 연습문제 풀이

728x90
반응형

Exercise Part.13

CNN

1. 이미지 분류에서 완전 연결 DNN보다 CNN이 나은 점은 무엇인가요?

CNN은 많은 가중치를 재사용하기 때문에 DNN보다 적은 파라미터를 가지기에 속도가 빠르다. 그리고 과대적합의 위험을 줄이며 더 적은 훈련 데이터를 필요로 한다. 그리고 CNN이 어떤 특성을 감지할 수 있는 커널을 학습하면 이미지의 어느 위치에 있는 특성이라도 감지할 수 있다. 반면 DNN은 특정 위치에 존재해야 인지를 한다. DNN은 픽셀이 어떻게 조직되어 있는지 모른다. 즉 주변의 픽셀이 비슷한지 알지 못한다, 하지만 CNN은 이 정보를 내포한다. 하위층은 작은 영역에 있는 특성을 구별하고, 상위층은 저수준 특성을 더 큰 특성으로 연결한다. 그래서 이미지에서는 CNN을 주로 사용한다.

2. 3X3 커널, 스트라이드 2, SAME 패딩으로 된 합성곱층 세 개로 구성된 CNN이 있다. 가장 아래 층은 100개의 특성 맵을 출력하고, 중간 층은 200개, 가장 위의 층은 400개를 출력합니다. 입력 이미지는 200X300 픽셀의 RGB이미지이다. 이 CNN의 전체 파라미터 수는 얼마일까요? 32비트 부동소수를 사용한다면 이 네트워크가 하나의 샘플을 예측하기 위해 적어도 얼마의 RAM이 필요할까요? 50개의 이미지를 미니배치로 훈련할 땐 얼마가 필요할까요?

1층 : 3X3X3 + 1 (bias) = 28 X 100 = 2800 2층 : 3X3X100 + 1 = 901 X 200 = 180,200 3층 : 3X3X200 + 1 = 1,801 X 300 = 720,400

총 903,400개

3. 어떤 CNN을 훈련시킬 때 GPU에서 메모리 부족이 발생했다면, 이 문제를 해결하기 위해 시도해볼 수 있는 다섯 가지는 무엇인가요?

  1. 미니배치의 크기를 줄이기
  2. 하나 이상의 층에서 스트라이드를 크게 하여 차원을 감소시킨다.
  3. 하나 이상의 층을 제거한다.
  4. 32비트 부동소수 대신 16비트 부동소수를 사용한다.
  5. 여러 장치에 CNN을 분산한다.

4. 같은 크기의 스트라이드의 합성곱층 대신 최대 풀링층을 추가하는 이유는 무엇인가요?

Max-pooling은 파라미터는 전혀 없지만 Convolution layer는 많은 양의 파라미터를 가지고 있기 때문이다.

5. LRN 층을 추가해야 할 때는 언제인가요?

가장 활성화된 뉴런을 억제해서, feature map을 다양하게하고 넓은 범위의 특성을 탐색하도록 강제하기 때문에 좋다. 저수준 특성을 많이 찾기에 보통 저수준 층에서 사용된다.

6. LeNet-5와 비교해서 AlexNet의 혁신점은 무엇인가요? GoogLeNet과 ResNet의 혁신점은 무엇인가요?

더 크고 깊으며, pooling layer없이 convolution layer으로만 쌓아올렸다는 것이다. GoogLeNet은 인셉션 모듈을 사용하였다는 것, ResNet은 Residual block을 사용하서 Skip connection을 했다는 것이 혁신점이다.

7. 자신만의 CNN을 만들고 MNIST 데이터셋에서 가능한 최대 정확도를 달성해보세요.

In [29]:
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
In [30]:
from tensorflow.keras.datasets.mnist import load_data
In [39]:
(X_train,y_train),(X_test,y_test) = load_data()
In [40]:
X_train = X_train.astype(np.float32).reshape(-1,28*28) / .255
X_test = X_test.astype(np.float32).reshape(-1,28*28) /.255
y_train = y_train.astype(np.int32)
y_test = y_test.astype(np.int32)
In [41]:
X_train = X_train[5000:]
y_train = y_train[5000:]

X_valid = X_train[:5000]
y_valid = y_train[:5000]
In [42]:
X_train.shape
Out[42]:
(55000, 784)
In [43]:
height = 28
width = 28
channels = 1
n_inputs = height * width

conv1_fmaps = 32
conv1_ksize = 3
conv1_stride = 1
conv1_pad = "SAME"

conv2_fmaps = 64
conv2_ksize = 3
conv2_stride = 1
conv2_pad = "SAME"
conv2_dropout_rate = 0.25

pool3_fmaps = conv2_fmaps

n_fc1 = 128
fc1_dropout_rate = 0.5

n_outputs = 10

tf.reset_default_graph()

with tf.name_scope("inputs"):
    X = tf.placeholder(tf.float32, shape=[None, n_inputs], name="X")
    X_reshaped = tf.reshape(X, shape=[-1, height, width, channels])
    y = tf.placeholder(tf.int32, shape=[None], name="y")
    training = tf.placeholder_with_default(False, shape=[], name='training')

conv1 = tf.layers.conv2d(X_reshaped, filters=conv1_fmaps, kernel_size=conv1_ksize,
                         strides=conv1_stride, padding=conv1_pad,
                         activation=tf.nn.relu, name="conv1")
conv2 = tf.layers.conv2d(conv1, filters=conv2_fmaps, kernel_size=conv2_ksize,
                         strides=conv2_stride, padding=conv2_pad,
                         activation=tf.nn.relu, name="conv2")

with tf.name_scope("pool3"):
    pool3 = tf.nn.max_pool(conv2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="VALID")
    pool3_flat = tf.reshape(pool3, shape=[-1, pool3_fmaps * 14 * 14])
    pool3_flat_drop = tf.layers.dropout(pool3_flat, conv2_dropout_rate, training=training)

with tf.name_scope("fc1"):
    fc1 = tf.layers.dense(pool3_flat_drop, n_fc1, activation=tf.nn.relu, name="fc1")
    fc1_drop = tf.layers.dropout(fc1, fc1_dropout_rate, training=training)

with tf.name_scope("output"):
    logits = tf.layers.dense(fc1, n_outputs, name="output")
    Y_proba = tf.nn.softmax(logits, name="Y_proba")

with tf.name_scope("train"):
    xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y)
    loss = tf.reduce_mean(xentropy)
    optimizer = tf.train.AdamOptimizer()
    training_op = optimizer.minimize(loss)

with tf.name_scope("eval"):
    correct = tf.nn.in_top_k(logits, y, 1)
    accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))

with tf.name_scope("init_and_save"):
    init = tf.global_variables_initializer()
    saver = tf.train.Saver()
In [50]:
def get_model_params():
    gvars = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)
    return {gvar.op.name : value for gvar, value in zip(gvars,tf.get_default_session().run(gvars))}

def restore_model_params(model_params):
    gvar_names = list(model_params.keys())
    assign_ops = {gvar_name: tf.get_default_graph().get_operation_by_name(gvar_name + "/Assign")
                  for gvar_name in gvar_names}
    init_values = {gvar_name: assign_op.inputs[1] for gvar_name, assign_op in assign_ops.items()}
    feed_dict = {init_values[gvar_name]: model_params[gvar_name] for gvar_name in gvar_names}
    tf.get_default_session().run(assign_ops, feed_dict=feed_dict)
In [51]:
def shuffle_batch(X, y, batch_size):
    rnd_idx = np.random.permutation(len(X))
    n_batches = len(X) // batch_size
    for batch_idx in np.array_split(rnd_idx, n_batches):
        X_batch, y_batch = X[batch_idx], y[batch_idx]
        yield X_batch, y_batch
In [52]:
n_epochs = 1000
batch_size = 50

best_loss_val = np.infty
check_interval = 500
checks_since_last_progress = 0
max_checks_without_progress = 20
best_model_params = None 


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(n_epochs):
        n_batches = len(X_train) // batch_size
        for i in range(n_batches):
            X_batch, y_batch = next(shuffle_batch(X_train,y_train,batch_size))
            sess.run(training_op,feed_dict={X:X_batch,y:y_batch,training:True})
            if i % check_interval == 0:
                loss_val = loss.eval(feed_dict={X:X_valid,y:y_valid})
                if loss_val < best_loss_val:
                    best_loss_val = loss_val
                    checks_since_last_progress = 0
                    best_model_params = get_model_params()
                else:
                    checks_since_last_progress += 1
        acc_batch = accuracy.eval(feed_dict={X:X_batch,y:y_batch})
        acc_val = accuracy.eval(feed_dict={X:X_valid,y:y_valid})
        print("Epoch : {0} / batch_Acc : {1:.4f}% / valid_acc : {2:.4f}% / best_loss : {3:.4f}"
              .format(epoch,acc_batch*100,acc_val*100, best_loss_val))
        
        if checks_since_last_progress > max_checks_without_progress:
            print("조기 종료")
            break
    if best_model_params:
        restore_model_params(best_model_params)
    acc_test = accuracy.eval(feed_dict={X:X_test[:5000],y:y_test[:5000]})
    print("Test ACC : {0:.4f}".format(acc_test))
    save_path = saver.save(sess,"./my_mnist_model")
    
Epoch : 0 / batch_Acc : 98.0000% / valid_acc : 97.2000% / best_loss : 0.0993
Epoch : 1 / batch_Acc : 100.0000% / valid_acc : 97.5800% / best_loss : 0.0585
Epoch : 2 / batch_Acc : 100.0000% / valid_acc : 98.9400% / best_loss : 0.0491
Epoch : 3 / batch_Acc : 100.0000% / valid_acc : 98.7800% / best_loss : 0.0294
Epoch : 4 / batch_Acc : 100.0000% / valid_acc : 99.0200% / best_loss : 0.0257
Epoch : 5 / batch_Acc : 100.0000% / valid_acc : 99.1400% / best_loss : 0.0257
Epoch : 6 / batch_Acc : 100.0000% / valid_acc : 99.3000% / best_loss : 0.0257
Epoch : 7 / batch_Acc : 98.0000% / valid_acc : 99.4200% / best_loss : 0.0173
Epoch : 8 / batch_Acc : 100.0000% / valid_acc : 99.4000% / best_loss : 0.0173
Epoch : 9 / batch_Acc : 100.0000% / valid_acc : 99.6000% / best_loss : 0.0173
Epoch : 10 / batch_Acc : 100.0000% / valid_acc : 99.4200% / best_loss : 0.0100
Epoch : 11 / batch_Acc : 98.0000% / valid_acc : 99.6400% / best_loss : 0.0100
Epoch : 12 / batch_Acc : 100.0000% / valid_acc : 99.7400% / best_loss : 0.0100
Epoch : 13 / batch_Acc : 100.0000% / valid_acc : 99.6400% / best_loss : 0.0084
Epoch : 14 / batch_Acc : 100.0000% / valid_acc : 99.6800% / best_loss : 0.0084
Epoch : 15 / batch_Acc : 100.0000% / valid_acc : 99.7200% / best_loss : 0.0084
Epoch : 16 / batch_Acc : 100.0000% / valid_acc : 99.6400% / best_loss : 0.0084
Epoch : 17 / batch_Acc : 100.0000% / valid_acc : 99.4400% / best_loss : 0.0043
Epoch : 18 / batch_Acc : 100.0000% / valid_acc : 99.7400% / best_loss : 0.0043
Epoch : 19 / batch_Acc : 100.0000% / valid_acc : 99.8200% / best_loss : 0.0043
Epoch : 20 / batch_Acc : 100.0000% / valid_acc : 99.9000% / best_loss : 0.0026
Epoch : 21 / batch_Acc : 100.0000% / valid_acc : 99.9200% / best_loss : 0.0026
Epoch : 22 / batch_Acc : 100.0000% / valid_acc : 99.8400% / best_loss : 0.0019
Epoch : 23 / batch_Acc : 100.0000% / valid_acc : 99.6200% / best_loss : 0.0019
Epoch : 24 / batch_Acc : 100.0000% / valid_acc : 99.8600% / best_loss : 0.0019
Epoch : 25 / batch_Acc : 100.0000% / valid_acc : 99.7000% / best_loss : 0.0016
Epoch : 26 / batch_Acc : 100.0000% / valid_acc : 99.8200% / best_loss : 0.0016
Epoch : 27 / batch_Acc : 100.0000% / valid_acc : 99.6200% / best_loss : 0.0016
Epoch : 28 / batch_Acc : 100.0000% / valid_acc : 99.9200% / best_loss : 0.0016
Epoch : 29 / batch_Acc : 100.0000% / valid_acc : 99.6600% / best_loss : 0.0016
Epoch : 30 / batch_Acc : 100.0000% / valid_acc : 99.9000% / best_loss : 0.0016
Epoch : 31 / batch_Acc : 100.0000% / valid_acc : 99.8200% / best_loss : 0.0016
Epoch : 32 / batch_Acc : 100.0000% / valid_acc : 99.6600% / best_loss : 0.0016
조기 종료
Test ACC : 0.9804

8. Inception v3를 사용하여 사이즈가 큰 이미지 분류하기

8.1 여러 종류의 동물 이미지를 내려받으세요. matplotlib.image.mpimg.imread() 함수나 scipy.misc.imread() 함수를 사용해 파이썬에서 이미지를 로드하세요. 이미지 크기를 바꾸고 잘라내어 299 × 299픽셀로 만들고, 알파 채널을 포함하지 않고 세 개의 채널(RGB)만 있는지 확인합니다. Inception에서 훈련에 사용한 이미지들은 -1.0에서 1.0 사이의 값을 가지도록 전처리되었습니다. 따라서 여기서 준비한 이미지들도 마찬가지로 전처리되어야 합니다.

In [93]:
width = 299
height =299
channels = 3
In [94]:
import matplotlib.image as mpimg
import os
test_image = mpimg.imread(os.path.join("image.png"))[:,:,:channels]
plt.imshow(test_image)
plt.axis("off")
plt.show()
In [95]:
test_image = 2 * test_image - 1

8.2 가장 최근에 미리 훈련된 Inception v3 모델을 내려받습니다. 체크포인트는 https://goo.gl/XgKiSi 에서 내려받을 수 있습니다. 클래스 이름의 목록은 https://goo.gl/brXRtZ 에 있습니다. 하지만 이 목록 맨 위에 background 클래스를 추가해야 합니다.

In [96]:
import sys
import tarfile
from six.moves import urllib

TF_MODELS_URL = "http://download.tensorflow.org/models"
INCEPTION_V3_URL = TF_MODELS_URL + "/inception_v3_2016_08_28.tar.gz"
INCEPTION_PATH = os.path.join("datasets", "inception")
INCEPTION_V3_CHECKPOINT_PATH = os.path.join(INCEPTION_PATH, "inception_v3.ckpt")

def download_progress(count, block_size, total_size):
    percent = count * block_size * 100 // total_size
    sys.stdout.write("\rDownloading: {}%".format(percent))
    sys.stdout.flush()
    
def fetch_pretrained_inception_v3(url=INCEPTION_V3_URL,path=INCEPTION_PATH):
    if os.path.exists(INCEPTION_V3_CHECKPOINT_PATH):
        return
    os.makedirs(path,exist_ok=True)
    tgz_path = os.path.join(path,"inception_v3.tgz")
    urllib.request.urlretrieve(url,tgz_path,reporthook=download_progress)
    inception_tgz = tarfile.open(tgz_path)
    inception_tgz.extractall(path=path)
    inception_tgz.close()
    os.remove(tgz_path)
In [63]:
fetch_pretrained_inception_v3()
Downloading: 100%
In [97]:
import re

CLASS_NAME_REGREX = re.compile(r"^n\d+\s+(.*)\s*$",re.M | re.U)

def load_class_names():
    with open(os.path.join("datasets","inception","imagenet_class_names.txt"),"rb") as f:
        content = f.read().decode("utf-8")
        return CLASS_NAME_REGREX.findall(content)
In [98]:
class_names = ["background"] + load_class_names()
In [99]:
class_names[:5]
Out[99]:
['background',
 'tench, Tinca tinca',
 'goldfish, Carassius auratus',
 'great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias',
 'tiger shark, Galeocerdo cuvieri']

8.3 다음과 같이 inception_v3() 함수를 호출해 Inception v3 모델을 만듭니다. 반드시 inception_v3_arg_scope() 함수로 생성한 이름 범위 안에서 만들어야 합니다. 또한 다음과 같이 is_training=False와 numclasses=1001로 지정해야 합니다.

In [108]:
from tensorflow.contrib.slim.nets import inception
import tensorflow.contrib.slim as slim

tf.reset_default_graph()

X = tf.placeholder(tf.float32,shape=[None,299,299,3],name="X")
with slim.arg_scope(inception.inception_v3_arg_scope()):
    logits,end_points = inception.inception_v3(X,num_classes=1001,is_training=False)
predictions = end_points["Predictions"]
saver = tf.train.Saver()

8.4 세션을 열고 Saver를 사용해 앞서 내려받은 미리 훈련된 모델의 체크포인트를 복원하세요.

In [109]:
with tf.Session() as sess:
    saver.restore(sess,INCEPTION_V3_CHECKPOINT_PATH)
INFO:tensorflow:Restoring parameters from datasets/inception/inception_v3.ckpt

8.5 모델을 실행해서 준비한 이미지를 분류해보세요. 이미지마다 상위 다섯 개 예측을 추정 확률과 함께 출력해보세요. 모델이 얼마나 정확한가요?

In [132]:
# X_test = test_image.reshape(-1, height, width, channels)
X_test = test_image
with tf.Session() as sess:
    saver.restore(sess,INCEPTION_V3_CHECKPOINT_PATH)
    predictions_val = predictions.eval(feed_dict={X:X_test})
INFO:tensorflow:Restoring parameters from datasets/inception/inception_v3.ckpt
In [136]:
most_likely_class_index = np.argmax(predictions_val[0])
most_likely_class_index
Out[136]:
276
In [139]:
class_names[most_likely_class_index]
Out[139]:
'African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus'
In [140]:
top_5 = np.argpartition(predictions_val[0],-5)[-5:]
top_5 = reversed(top_5[np.argsort(predictions_val[0][top_5])])
for i in top_5:
    print("{0} : {1:.2f}%".format(class_names[i],100* predictions_val[0][i]))
African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus : 95.66%
hyena, hyaena : 2.28%
bearskin, busby, shako : 0.04%
European fire salamander, Salamandra salamandra : 0.04%
swimming trunks, bathing trunks : 0.02%

9. 대규모 이미지 분류를 위한 전이 학습

9.1 클래스마다 최소한 100개의 이미지가 들어 있는 훈련 세트를 만드세요. 예를 들어 위치에 따라(해변, 산, 도심 등) 자신의 사진을 분류하거나, 꽃 데이터셋(https://goo.gl/EgJVXZ )이나 MIT의 장소 데이터셋(http://places.csail.mit.edu/) (등록이 필요하고 매우 큽니다) 같은 기존의 데이터셋을 사용할 수도 있습니다.

In [149]:
# 데이터셋 먼저 다운로드 
import sys
import tarfile
from six.moves import urllib

FLOWERS_URL = "http://download.tensorflow.org/example_images/flower_photos.tgz"
FLOWERS_PATH = os.path.join("datasets", "flowers")

def fetch_flowers(url=FLOWERS_URL, path=FLOWERS_PATH):
    if os.path.exists(FLOWERS_PATH):
        return
    os.makedirs(path, exist_ok=True)
    tgz_path = os.path.join(path, "flower_photos.tgz")
    urllib.request.urlretrieve(url, tgz_path, reporthook=download_progress)
    flowers_tgz = tarfile.open(tgz_path)
    flowers_tgz.extractall(path=path)
    flowers_tgz.close()
    os.remove(tgz_path)
In [150]:
fetch_flowers()
In [152]:
flowers_root_path = os.path.join(FLOWERS_PATH,"flower_photos")
flower_classes = sorted([dirname for dirname in os.listdir(flowers_root_path)
                        if os.path.isdir(os.path.join(flowers_root_path,dirname))])
flower_classes
Out[152]:
['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips']
In [156]:
from collections import defaultdict

image_paths = defaultdict(list)

for flower_class in flower_classes:
    image_dir = os.path.join(flowers_root_path,flower_class)
    for filepath in os.listdir(image_dir):
        if filepath.endswith(".jpg"):
            image_paths[flower_class].append(os.path.join(image_dir,filepath))
In [160]:
for path in image_paths.values():
    path.sort()
In [172]:
import matplotlib.image as mpimg

n_class = 2

for flower_class in flower_classes:
    print("클래스 : ",flower_class)
    plt.figure(figsize=(10,5))
    for index, example_image_path in enumerate(image_paths[flower_class][:n_class]):
        example_image = mpimg.imread(example_image_path)[:, :, :channels]
        plt.subplot(100 + n_class * 10 + index + 1)
        plt.title("{}X{}".format(example_image.shape[1],example_image.shape[0]))
        plt.imshow(example_image)
        plt.axis("off")
    plt.show()
클래스 :  daisy
클래스 :  dandelion
클래스 :  roses
클래스 :  sunflowers
클래스 :  tulips

9.2 전처리 단계에서 이미지 크기를 줄이고 잘라서 299 × 299 크기로 만들고 무작위성을 추가하여 데이터 증식을 하세요.

In [204]:
from PIL import Image

def prepare_image(image,target_width=299,target_height=299,max_zoom=0.2):
    
    # 이미지에서 타겟 크기에 맞는 최대 비율의 네모 상자 크기를 찾는다.
    height = image.shape[0]
    width = image.shape[1]
    image_ratio = width / height
    target_image_ratio = target_width / target_height
    crop_vertically = image_ratio < target_image_ratio
    crop_width = width if crop_vertically else int(height*target_image_ratio)
    crop_height = int(width / target_image_ratio) if crop_vertically else height
    
    # 상자의 크기를 랜덤한 비율로 줄이기.
    resize_factor = np.random.rand() * max_zoom + 1.0
    crop_width = int(crop_width / resize_factor)
    crop_height = int(crop_height / resize_factor)
    
    # 다음 상자가 놓일 이미지의 위치를 랜덤하게 선택
    x0 = np.random.randint(0,width - crop_width)
    y0 = np.random.randint(0,height - crop_height)
    x1 = x0 + crop_width
    y1 = y0 + crop_height

    # 이미지 자르기
    image = image[y0:y1, x0:x1]
    
    # 50% 확률로 이미지를 수평으로 반전시킨다.
    if np.random.rand() < 0.5:
        image = np.fliplr(image)
        
     # 타겟 크기에 맞게 이미지 크기를 변경
    image = np.array(Image.fromarray(image).resize((target_width,target_height)))
    
    # 마지막으로 컬러 값이 0.0 ~ 1.0사이의 32비트가 되도록 해준다
    return image.astype(np.float32) / 255
    
    
In [205]:
plt.figure(figsize=(6,8))
plt.imshow(example_image)
plt.title("{}X{}".format(example_image.shape[1],example_image.shape[0]))
plt.axis('off')
plt.show()
In [206]:
prepared_image = prepare_image(example_image)

plt.figure(figsize=(8,8))
plt.imshow(prepared_image)
plt.title("{}X{}".format(prepared_image.shape[1],prepared_image.shape[0]))
plt.axis('off')
plt.show()
In [209]:
rows,cols = 2,3

plt.figure(figsize=(14,8))
for row in range(rows):
    for col in range(cols):
        prepared_image = prepare_image(example_image)
        plt.subplot(rows,cols,row * col + col + 1)
        plt.title("{}X{}".format(prepared_image.shape[1],prepared_image.shape[0]))
        plt.imshow(prepared_image)
        plt.axis('off')
    plt.show()

9.3 이전 연습문제의 미리 훈련된 Inception v3 모델을 사용해 병목층(즉, 출력층 직전의 마지막 층)까지의 모든 층을 동결하고, 이 분류 문제에 맞는 적절한 출력 개수를 가진 출력층으로 바꾸세요(예를 들어 꽃 데이터셋은 다섯 개의 상호 배타적인 클래스를 가지고 있으므로 출력층은 다섯 개의 뉴런을 가져야 하고 소프트맥스 활성화 함수를 사용해야 합니다).

In [211]:
from tensorflow.contrib.slim.nets import inception
import tensorflow.contrib.slim as slim

tf.reset_default_graph()

X = tf.placeholder(tf.float32,shape=[None,height,width,channels],name="X")
training = tf.placeholder_with_default(False,shape=[])
with slim.arg_scope(inception.inception_v3_arg_scope()):
    logits, end_points = inception.inception_v3(X,num_classes=1001,is_training=training)
    
inception_saver = tf.train.Saver()
In [213]:
logits.op.inputs[0]
Out[213]:
<tf.Tensor 'InceptionV3/Logits/Conv2d_1c_1x1/BiasAdd:0' shape=(?, 1, 1, 1001) dtype=float32>
In [217]:
logits.op.inputs[0].op.inputs[0]
Out[217]:
<tf.Tensor 'InceptionV3/Logits/Conv2d_1c_1x1/Conv2D:0' shape=(?, 1, 1, 1001) dtype=float32>
In [218]:
logits.op.inputs[0].op.inputs[0].op.inputs[0]
# 이 층이 인셉션층의 마지막 층이다. 여기에 새로운 층을 쌓아야한다. 
Out[218]:
<tf.Tensor 'InceptionV3/Logits/Dropout_1b/cond/Merge:0' shape=(?, 1, 1, 2048) dtype=float32>
In [219]:
end_points
Out[219]:
{'Conv2d_1a_3x3': <tf.Tensor 'InceptionV3/InceptionV3/Conv2d_1a_3x3/Relu:0' shape=(?, 149, 149, 32) dtype=float32>,
 'Conv2d_2a_3x3': <tf.Tensor 'InceptionV3/InceptionV3/Conv2d_2a_3x3/Relu:0' shape=(?, 147, 147, 32) dtype=float32>,
 'Conv2d_2b_3x3': <tf.Tensor 'InceptionV3/InceptionV3/Conv2d_2b_3x3/Relu:0' shape=(?, 147, 147, 64) dtype=float32>,
 'MaxPool_3a_3x3': <tf.Tensor 'InceptionV3/InceptionV3/MaxPool_3a_3x3/MaxPool:0' shape=(?, 73, 73, 64) dtype=float32>,
 'Conv2d_3b_1x1': <tf.Tensor 'InceptionV3/InceptionV3/Conv2d_3b_1x1/Relu:0' shape=(?, 73, 73, 80) dtype=float32>,
 'Conv2d_4a_3x3': <tf.Tensor 'InceptionV3/InceptionV3/Conv2d_4a_3x3/Relu:0' shape=(?, 71, 71, 192) dtype=float32>,
 'MaxPool_5a_3x3': <tf.Tensor 'InceptionV3/InceptionV3/MaxPool_5a_3x3/MaxPool:0' shape=(?, 35, 35, 192) dtype=float32>,
 'Mixed_5b': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_5b/concat:0' shape=(?, 35, 35, 256) dtype=float32>,
 'Mixed_5c': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_5c/concat:0' shape=(?, 35, 35, 288) dtype=float32>,
 'Mixed_5d': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_5d/concat:0' shape=(?, 35, 35, 288) dtype=float32>,
 'Mixed_6a': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_6a/concat:0' shape=(?, 17, 17, 768) dtype=float32>,
 'Mixed_6b': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_6b/concat:0' shape=(?, 17, 17, 768) dtype=float32>,
 'Mixed_6c': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_6c/concat:0' shape=(?, 17, 17, 768) dtype=float32>,
 'Mixed_6d': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_6d/concat:0' shape=(?, 17, 17, 768) dtype=float32>,
 'Mixed_6e': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_6e/concat:0' shape=(?, 17, 17, 768) dtype=float32>,
 'Mixed_7a': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_7a/concat:0' shape=(?, 8, 8, 1280) dtype=float32>,
 'Mixed_7b': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_7b/concat:0' shape=(?, 8, 8, 2048) dtype=float32>,
 'Mixed_7c': <tf.Tensor 'InceptionV3/InceptionV3/Mixed_7c/concat:0' shape=(?, 8, 8, 2048) dtype=float32>,
 'AuxLogits': <tf.Tensor 'InceptionV3/AuxLogits/SpatialSqueeze:0' shape=(?, 1001) dtype=float32>,
 'PreLogits': <tf.Tensor 'InceptionV3/Logits/Dropout_1b/cond/Merge:0' shape=(?, 1, 1, 2048) dtype=float32>,
 'Logits': <tf.Tensor 'InceptionV3/Logits/SpatialSqueeze:0' shape=(?, 1001) dtype=float32>,
 'Predictions': <tf.Tensor 'InceptionV3/Predictions/Reshape_1:0' shape=(?, 1001) dtype=float32>}
In [221]:
prelogits = tf.squeeze(end_points["PreLogits"],axis=[1,2])
prelogits
Out[221]:
<tf.Tensor 'Squeeze_1:0' shape=(?, 2048) dtype=float32>
In [222]:
n_outputs = len(flower_classes)

with tf.name_scope("new_output_layer"):
    flower_logits = tf.layers.dense(prelogits,n_outputs,name='flower_logits')
    Y_proba = tf.nn.softmax(flower_logits,name="Y_proba")
In [223]:
y = tf.placeholder(tf.int32,shape=[None])

with tf.name_scope("train"):
    xentropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=flower_logits,labels=y)
    loss = tf.reduce_mean(xentropy)
    optimizer = tf.train.AdamOptimizer()
    flower_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="flower_logits")
    training_op = optimizer.minimize(loss,var_list = flower_vars)
    
with tf.name_scope("eval"):
    correct = tf.nn.in_top_k(flower_logits,y,1)
    accuracy = tf.reduce_mean(tf.cast(correct,tf.float32))
    
with tf.name_scope("init_and_save"):
    init = tf.global_variables_initializer()
    saver = tf.train.Saver()
    
In [227]:
[v.name for v in flower_vars]
Out[227]:
['flower_logits/kernel:0', 'flower_logits/bias:0']

9.4 준비한 데이터셋을 훈련 세트와 테스트 세트로 나누세요. 훈련 세트에서 모델을 훈련시키고 테스트 세트에서 모델을 평가해보세요.

In [228]:
flower_class_ids = {flower_class : index for index,flower_class in enumerate(flower_classes)}
flower_class_ids
Out[228]:
{'daisy': 0, 'dandelion': 1, 'roses': 2, 'sunflowers': 3, 'tulips': 4}
In [231]:
flower_paths_and_classes = []
for flower_class, paths in image_paths.items():
    for path in paths:
        flower_paths_and_classes.append((path,flower_class_ids[flower_class]))
In [239]:
test_ratio = 0.2
train_size = int(len(flower_paths_and_classes) * (1 - test_ratio))

np.random.shuffle(flower_paths_and_classes)

flower_paths_and_classes_train = flower_paths_and_classes[:train_size]
flower_paths_and_classes_test = flower_paths_and_classes[train_size:]
In [240]:
flower_paths_and_classes_train[:3]
Out[240]:
[('datasets/flowers/flower_photos/tulips/14957470_6a8c272a87_m.jpg', 4),
 ('datasets/flowers/flower_photos/sunflowers/2927020075_54c9186797_n.jpg', 3),
 ('datasets/flowers/flower_photos/dandelion/14283011_3e7452c5b2_n.jpg', 1)]
In [243]:
# 이미지 전처리 / 훈련시에는 배치만드는 용도
from random import sample

def prepare_batch(flower_paths_and_classes,batch_size):
    batch_paths_and_classes = sample(flower_paths_and_classes,batch_size)
    images = [mpimg.imread(path)[:,:,:channels] for path, labels in batch_paths_and_classes]
    prepared_images = [prepare_image(image) for image in images]
    X_batch = 2 * np.stack(prepared_images) - 1
    y_batch = np.array([labels for path, labels in batch_paths_and_classes], dtype=np.int32)
    return X_batch,y_batch
In [244]:
X_batch,y_batch = prepare_batch(flower_paths_and_classes_train,batch_size=4)
In [247]:
X_batch.shape,X_batch.dtype, y_batch.shape, y_batch.dtype
Out[247]:
((4, 299, 299, 3), dtype('float32'), (4,), dtype('int32'))
In [248]:
X_test, y_test = prepare_batch(flower_paths_and_classes_test,batch_size=len(flower_paths_and_classes_test))
In [249]:
X_test.shape
# 훈련하는 동안 그때 그때 훈련 배치를 생성하는 것이 더 좋습니다. 
# 그래야 이미지마다 변종 데이터가 많아 데이터 증식의 효과를 누릴 수 있습니다.
Out[249]:
(734, 299, 299, 3)
In [251]:
n_epochs = 10
batch_size = 40
n_iter = len(flower_paths_and_classes_train) // batch_size

with  tf.Session() as sess:
    init.run()
    inception_saver.restore(sess,INCEPTION_V3_CHECKPOINT_PATH)
    
    for epoch in range(n_epochs):
        print("Epoch :", epoch,end="")
        for i in range(n_iter):
            print(".",end="")
            X_batch,y_batch = prepare_batch(flower_paths_and_classes_train,batch_size)
            sess.run(training_op,feed_dict={X:X_batch,y:y_batch,training:True})
            
        acc_train = accuracy.eval(feed_dict={X:X_batch,y:y_batch})
        print("Training ACC :", acc_train)
        
        save_path = saver.save(sess,"./my_flowers_model")
INFO:tensorflow:Restoring parameters from datasets/inception/inception_v3.ckpt
Epoch : 0.........................................................................Training ACC : 0.45
Epoch : 1.........................................................................Training ACC : 0.425
Epoch : 2.........................................................................Training ACC : 0.65
Epoch : 3.........................................................................Training ACC : 0.575
Epoch : 4.........................................................................Training ACC : 0.55
Epoch : 5.........................................................................Training ACC : 0.575
Epoch : 6.........................................................................Training ACC : 0.55
Epoch : 7.........................................................................Training ACC : 0.55
Epoch : 8.........................................................................Training ACC : 0.65
Epoch : 9.........................................................................Training ACC : 0.575
In [ ]:

n_test_batch = 10 X_test_batch = np.array_split(X_test,n_test_batch) y_test_batch = np.array_split(y_test,n_test_batch) with tf.Session() as sess: saver.restore(sess,"./my_flowers_model") print("Testing Time for Final ACC....") acc_test = np.mean([ accuracy.eval(feed_dict={X:X_test_batch,y:y_test_batch}) for X_test_batch, y_test_batch in zip(X_test_batch,y_test_batch)]) print("Test Accuracy:",acc_test)



10. 텐서플로의 딥드림 설명서(https://goo.gl/4b2s6g )를 살펴보세요. CNN으로 학습한 패턴을 시각화하거나 딥러닝을 사용해 그림을 생성하는 재미있는 방법을 배울 수 있습니다.

In [ ]:
# 사이트 들어가서 직접해보기


728x90
반응형