[Deep Learning] CNN(Convolutional Neural Network)

  • 영상 처리를 위한 신경망
  • Why Convolution
  • 최근 Computer Vision의 대부분은 Convolution에 의존하고 있다고 해도 과언이 아니다.
  • Weights을 공유하며, 특징을 추출하는데 이만한 방법론을 찾기 어렵기 때문이다.
    • 사물인식 - Object Detection (YOLO) + RCNN(Fast, Faster, MASK RCNN)
    • 포즈예측 - Pose Estimation (PoseNet)
    • 윤곽분류 - Instance Segmentation (Detectron)
  • YOLO를 사용하는 이유(찾아보기)

Convolution & Pooling

Convolution

image

  • Convolution(합성곱)은 하나의 함수와 또 다른 함수를 반전 이동한 값을 곱한 다음, 구간에 대해 적분하여 새로운 함수를 구하는 수학 연산자이다.
  • 신경망 자체와 마찬가지로 CNN은 생물학, 특히 고양이의 시각 피질의 수용 영역(Receptive field)에서 영감을 받았다.
  • 실제 뇌에서 시각 피질의 뉴런은 특정 영역, 모양, 색상, 방향 및 기타 일반적인 시각적 특징을 수용하도록 영역별로 전문화가 이루어진다.
  • 어떤 의미에서인지 시스템의 구조 자체가 원시 시각 입력을 변환하여 특정 하위 집합을 처리하는 데 특화된 뉴런으로 보낸다.
  • CNN은 Convolution을 적용하여 시각적 접근 방식을 모방한다.
  • Convolution은 한 함수가 다른 함수를 수정하는 방법을 보여주는 세 번째 함수를 생성하는 두 함수에 대한 연산이다.
  • Convolution에서는 교환성, 연관성, 분배성 등 다양한 수학적 속성이 있다.
  • Convolution을 적용하면 입력의 Shape이 효과적으로 변환된다.
  • Convolution이라는 용어는 세번째 공동함수(Weight Sharing)를 계산하는 프로세스와 이를 적용하는 프로세스를 모두 지칭하는 데 사용된다.
  • 실제 동물의 시야에서 피질의 수용 영역으로의 매핑과 느슨하게 유사한 애플리케이션으로 생각하는 것이 유용하다.

수학적 이해

1D - Convolution

1
2
3
4
5
6
7
8
9
import numpy as np
input = [0, 0, 26, 51, 58, 59, 53, 29, 0, 0, 0]
patch = [-1, 2, -1]

output = np.convolve(input, patch)
print(output)
'''
[  0   0 -26   1  18   6   7  18   5 -29   0   0   0]
'''

2D - Convolution

  • 이미지의 노란색 부분으로 변하는 부분이 Convolution filter와 만나는 부분이다.
  • 그렇게 연산되었을 때, 분홍색의 output 값을 얻을 수 있다.

  • Padding: 흰 색 pixel의 경우 실제 이미지가 있는 부분이고, 짙은 회색의 pixel은 feature map의 크기 조절과 데이터를 충분히 활용하기 위해 가장자리에 0을 더해준 것이다.
  • 이런 방식을 zero-padding이라고 한다.

  • Stride = 1

  • Stride = 2

  • Stride는 성큼성큼 걷는다는 표현의 단어 뜻을 가졌다.
  • 한번에 얼마나 걸을 것인지 나타내는 의미이다.
  • Stride가 1일 때는 한걸음씩, 2일 때는 두걸음씩 걸어가면서 연산을 한다.
  • 주목해야할 것은 output의 사이즈가 달라진다는 것이다.
  • Stride를 이용한 Convolution의 경우 pooling이 자동으로 되는 방식이다.
  • 이후 GAN에서 해당 방식을 다루게 된다.

각종 용어

  • Filter: 가중치(weights parameters)의 집합으로 이루어져 가장 작은 특징을 잡아내는 창이다.

Code

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
# Conv2D함수 정의
def convolve2D(image, kernel, padding=0, strides=1):
    # Cross Correlation
    kernel = np.flipud(np.fliplr(kernel))

    # Gather Shapes of Kernel + Image + Padding
    xKernShape = kernel.shape[0]
    yKernShape = kernel.shape[1]
    xImgShape = image.shape[0]
    yImgShape = image.shape[1]

    # Shape of Output Convolution
    xOutput = int(((xImgShape - xKernShape + 2 * padding) / strides) + 1)
    yOutput = int(((yImgShape - yKernShape + 2 * padding) / strides) + 1)
    output = np.zeros((xOutput, yOutput))

    # Apply Equal Padding to All Sides
    if padding != 0:
        imagePadded = np.zeros((image.shape[0] + padding*2, image.shape[1] + padding*2))
        imagePadded[int(padding):int(-1 * padding), int(padding):int(-1 * padding)] = image
    else:
        imagePadded = image

    # Iterate through image
    for y in range(image.shape[1]):
        # Exit Convolution
        if y > image.shape[1] - yKernShape:
            break
        # Only Convolve if y has gone down by the specified Strides
        if y % strides == 0:
            for x in range(image.shape[0]):
                # Go to next row once kernel is out of bounds
                if x > image.shape[0] - xKernShape:
                    break
                try:
                    # Only Convolve if x has moved by the specified Strides
                    if x % strides == 0:
                        output[x, y] = (kernel * imagePadded[x: x + xKernShape, y: y + yKernShape]).sum()
                except:
                    break

    return output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys
import requests
from io import BytesIO
from PIL import Image
import cv2
import numpy as np
import matplotlib.pyplot as plt

# Grayscale Image
response = requests.get("https://cdn.pixabay.com/photo/2017/08/31/09/40/singapore-2699987_1280.jpg")
img = Image.open(BytesIO(response.content))
open_cv_image = np.array(img) 
open_cv_image = cv2.cvtColor(src=open_cv_image, code=cv2.COLOR_BGR2GRAY)

imgplot = plt.imshow(img)
plt.show() # original image
imgplot = plt.imshow(open_cv_image)
plt.show() # transformed image

image

1
2
3
4
5
6
7
8
9
10
11
12
13
# Edge Detection Kernel
kernel = np.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]])

# Convolve and Save Output
output = convolve2D(open_cv_image, kernel, padding=1)
cv2.imwrite('2DConvolved.jpg', output)
'''
Ture
'''

im = cv2.imread('2DConvolved.jpg')
imgplot = plt.imshow(im)
plt.show()

image

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import imageio
import matplotlib.pyplot as plt
from skimage import color, io
from skimage.exposure import rescale_intensity

check = io.imread('https://assets.burberry.com/is/image/Burberryltd/0A0E4068-B7AE-4753-A989-EAD870D22DAA.jpg?$BBY_V2_ML_3x4$&wid=1278&hei=1700')
check_grayscale = rescale_intensity(color.rgb2gray(check))
check_grayscale.shape
'''
(1700, 1278)
'''


plt.imshow(check_grayscale, cmap="gray");

image

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
check_grayscale.shape
'''
(1700, 1278)
'''


import numpy as np
import scipy.ndimage as nd

horizontal_edge_convolution = np.array([[1,1,1,1,], # 가로 패턴
                                        [0,0,0,0],
                                        [0,0,0,0],
                                        [-1,-1,-1,-1]])

vertical_edge_convolution = np.array([[1, 0, 0, 0, -1], # 세로 패턴
                                     [1, 0, 0, 0, -1],
                                     [1, 0, 0, 0, -1],
                                     [1, 0, 0, 0, -1],
                                     [1, 0, 0, 0, -1]])

check_edges_vert = nd.convolve(check_grayscale, vertical_edge_convolution, mode='constant', cval=0.0)
check_edges_horz = nd.convolve(check_grayscale, horizontal_edge_convolution, mode='reflect')
print(check_edges_vert.shape)
print(check_edges_horz.shape)
'''
(1700, 1278)
(1700, 1278)
'''


plt.imshow(check_edges_vert, cmap="gray");

image

1
plt.imshow(check_edges_horz, cmap="gray");

image

1
2
3
4
5
6
ones_convolution = np.array([[1, 1, 1], # 스무딩 효과
                              [1, 1, 1],
                              [1, 1, 1]])
check_ones = nd.convolve(check_grayscale, ones_convolution)
plt.figure(figsize=(30,10))
plt.imshow(check_ones, cmap="gray")

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
plt.figure(figsize=(30,10))

labels = ["Horizontal Edges", "Original", "Ones Filter", "Vertical Edges"]
images = [check_edges_horz, check_grayscale, check_ones, check_edges_vert]

i = 0
for label, image in zip(labels, images):

    plt.subplot(1,4,i+1)
    plt.grid(False)
    plt.imshow(image, cmap="gray")
    plt.title(label)
    i += 1 

plt.show()

image

1
2
3
4
# combine vertical and horizontal edges
combined = check_edges_horz + check_edges_vert
plt.figure(figsize=(30,10))
plt.imshow(combined, cmap="gray")

image

ImageNet으로 학습이 다 되었을 때 필터의 역할

Pooling Layer

  • 풀링 레이어를 사용하여 피처맵의 차원을 줄인다.
  • 보통 Convolution을 적용한 이후 레이어를 풀링하여 점점 더 작은 피쳐맵을 얻는다.
  • 이렇게 줄어든 피쳐를 이용하여 ANN형태의 신경망에 넣어 분류를 수행하게 된다.

Example

1
2
3
4
from skimage.measure import block_reduce

reduced = block_reduce(combined, (2,2), np.max)
plt.imshow(reduced, cmap="gray");

image

1
2
3
4
reduced.shape
'''
(850, 639)
'''
  • CNN의 특징을 잡아내는 방식에 대해 살펴보았는데, 패치와 같은 형태로 특징을 잡아내기 때문에 얻어질 수 있는 장점을 간단히 생각해보면,
    • Local Feature: 지역적 특징을 잡아 낸다.
    • Weight Sharing
    • Translation invariance: 어느정도 움직임이 있더라도 해석이 큰 무리가 없다.

CNN 분류기

전형적인 CNN Architecture

  • CNN의 첫번째 단계는 Convolution이다.
  • 특히 입력 이미지의 영역을 수신을 담당하는 뉴런에 매핑하는 변환이다.
  • Convolution Layer는 다음과 같이 시각화 할 수 있다.

  • 빨간 박스는 원래 입력 이미지를 나타내고, 파란색은 해당하는 네트워크의 뉴런을 나타낸다.
  • 속 안에 있는 작은 박스는 선택된 영역이 어떤 과정을 처리되는지 볼 수 있다.
  • 여러가지 필터를 통과해서 하나의 이미지가 여러개의 특징으로 나눠진 것을 볼 수 있다.(Receptive field로 수영 영역을 나타낸다.)
  • CNN은 여러 라운드의 Convolution, Pooling(필터를 통과하여 정보를 효과적으로 줄이는 디지털 신호 기술), 그리고 결국 완전 연결된 신경망과 출력 레이어를 가질 수 있다.
  • CNN의 일반적인 출력 계층은 분류 또는 감지 문제를 지향한다.

A Convolution in Action

  • CNN이 인기있는 이유
    • 이전 이미지 학습 기술에 비해 이미지 전처리(자르게 / 센터링, 정규화 등)가 상대적으로 거의 필요하지 않다.
    • 이와 관련하여 이미지 모든 종류의 일반적인 문제(이동, 조명 등)에 대해 견고하다.
  • 실제로 최첨단 이미지 분류 CNN을 훈련하는 것은 계산적으로 중요하지 않다.
  • 전이 학습을 통해 기성품을 만들어 사용할 수 있다.

다른 네트워크 표현 방식

실습 - Cifar 10

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
from tensorflow.keras import datasets
from tensorflow.keras.models import Sequential, Model # <- May Use
from tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten


(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()

# Normalize pixel values to be between 0 and 1
train_images, test_images = train_images / 255.0, test_images / 255.0
'''
Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
170500096/170498071 [==============================] - 3s 0us/step
'''


class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
               'dog', 'frog', 'horse', 'ship', 'truck']

plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i], cmap=plt.cm.binary)
    # The CIFAR labels happen to be arrays, 
    # which is why you need the extra index
    plt.xlabel(class_names[train_labels[i][0]])
plt.show()

image

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
train_images[0].shape
'''
(32, 32, 3)
'''


train_labels[1]
'''
array([9], dtype=uint8)
'''


32*32*3
'''
3072
'''


# Setup Architecture
# 기존 신경망과 달리 Dense 대신에 Conv2가 생겼다.
# 풀링 레이어와 마지막에는 Dense인 일반 신경망이 또 등장한다.
model = Sequential() # 과제시에는 이 모델을 Tre-trained model로 대체하면 된다. 
model.add(Conv2D(32, (3,3), activation='relu', input_shape=(32,32,3)))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(64, (3,3), activation='relu'))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(64, (3,3), activation='relu'))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(10, activation='softmax'))

model.summary()
'''
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 30, 30, 32)        896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 13, 13, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64)          0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 4, 4, 64)          36928     
_________________________________________________________________
flatten (Flatten)            (None, 1024)              0         
_________________________________________________________________
dense (Dense)                (None, 64)                65600     
_________________________________________________________________
dense_1 (Dense)              (None, 10)                650       
=================================================================
Total params: 122,570
Trainable params: 122,570
Non-trainable params: 0
_________________________________________________________________
'''


# 모델학습방식을 정의함
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])


# 모델 학습시키기
model.fit(train_images, train_labels, epochs=10, validation_data=(test_images, test_labels))
'''
Epoch 1/10
1563/1563 [==============================] - 12s 3ms/step - loss: 1.7422 - accuracy: 0.3538 - val_loss: 1.2091 - val_accuracy: 0.5710
Epoch 2/10
1563/1563 [==============================] - 5s 3ms/step - loss: 1.1525 - accuracy: 0.5935 - val_loss: 1.0467 - val_accuracy: 0.6338
Epoch 3/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.9682 - accuracy: 0.6619 - val_loss: 0.9441 - val_accuracy: 0.6660
Epoch 4/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.8643 - accuracy: 0.6978 - val_loss: 0.9450 - val_accuracy: 0.6696
Epoch 5/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.7686 - accuracy: 0.7298 - val_loss: 0.8979 - val_accuracy: 0.6853
Epoch 6/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.7188 - accuracy: 0.7505 - val_loss: 0.8680 - val_accuracy: 0.6982
Epoch 7/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.6604 - accuracy: 0.7669 - val_loss: 0.8537 - val_accuracy: 0.7098
Epoch 8/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.6057 - accuracy: 0.7868 - val_loss: 0.8590 - val_accuracy: 0.7102
Epoch 9/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.5586 - accuracy: 0.8048 - val_loss: 0.8772 - val_accuracy: 0.7120
Epoch 10/10
1563/1563 [==============================] - 5s 3ms/step - loss: 0.5185 - accuracy: 0.8171 - val_loss: 0.9077 - val_accuracy: 0.7122
<tensorflow.python.keras.callbacks.History at 0x7f770220cb70>
'''


# 수행
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
'''
313/313 - 0s - loss: 0.9077 - accuracy: 0.7122
'''

전이학습(Transfer Learning)

  • 전이학습은 기존 데이터로 학습된 네트워크를 재사용 가능하도록 하는 라이브러리이다.
  • 이를 통해 수천 시간의 GPU로 학습된 모델을 다운받아 내 작업에 활용할 수 있다.
  • 학습되었다는 것은 가중치(Weights)와 편향(bias)이 포함되어 학습 된 모델의 일부를 재사용하기에 Transfer learning 이라고 표현한다.
  • 일부만 사용해서 활용할 수도 있고, 전체를 다 재학습할 수도 있다.
  • 교육 데이터를 적게 사용하고, 교육속도가 빠르며, 더 잘 일반화하는 모델을 가질 수 있다.

사용하는 방법

  1. 이전에 학습한 모델에서 파라미터를 포함한 레이어를 가져온다.
  2. 향후 교육 과정 중에 포함된 정보가 손상되지 않도록 해당 정보를 동결(freeze, 가중치를 업데이트 하지 않음)한다.
  3. 동결된 층 위에 새로운 층(학습 가능한 층)을 더한다.
    • 출력층(output)의 수를 조절하여 새로운 데이터셋에서 원하는 예측방법(분류, 회귀 등)으로 전환하는 방법을 배울 수 있게 된다.
  4. 새로운 데이터셋에서 새로 추가한 계층만을 학습한다.
    • 만약 기존 레이어를 동결하지 않으면, 학습된 레이어에서 가져온 weight까지 학습하게 된다.
    • 위 경우 학습할 것이 많아지므로 시간이 오래걸린다.
  • 중요한 벤치마크 모델을 적절하게 선택할 수 있다.
  • 이미지 분류기 ResNet50를 기준으로 실습한다.
  • ResNet은 CNN의 일종인데, 기존의 Squential 모델과 달리 skipped connection이 있는 모델이다.
  • 이 연결을 통해 더 깊은 층을 만들더라도 학습이 가능해진다.

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
from keras.applications.resnet50 import ResNet50
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense

# 클래스의 개수 정의 : Cats & Dogs 
NUM_CLASSES = 2

# 입력 이미지의 차원 수 : RGB
CHANNELS = 3
# 학습된 네트워크 특징
IMAGE_RESIZE = 224
RESNET50_POOLING_AVERAGE = 'avg'
DENSE_LAYER_ACTIVATION = 'softmax'
OBJECTIVE_FUNCTION = 'categorical_crossentropy'

# 출력 Metric
LOSS_METRICS = ['accuracy']

# EARLY_STOP_PATIENCE < NUM_EPOCHS
NUM_EPOCHS = 10
EARLY_STOP_PATIENCE = 3

# These steps value should be proper FACTOR of no.-of-images in train & valid folders respectively
# Training images processed in each step would be no.-of-train-images / STEPS_PER_EPOCH_TRAINING
STEPS_PER_EPOCH_TRAINING = 10
STEPS_PER_EPOCH_VALIDATION = 10

# These steps value should be proper FACTOR of no.-of-images in train & valid folders respectively
# NOTE that these BATCH* are for Keras ImageDataGenerator batching to fill epoch step input
BATCH_SIZE_TRAINING = 100
BATCH_SIZE_VALIDATION = 100

# 테스트 배치의 개수
BATCH_SIZE_TESTING = 1


# 모델 제작
model = Sequential()

# 1st layer as the lumpsum weights from resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5
# NOTE that this layer will be set below as NOT TRAINABLE, i.e., use it as is
# weights = resnet_weights_path 학습해둔 모델이 있으면 이렇게 불러올 수 있음
model.add(ResNet50(include_top = False, pooling = RESNET50_POOLING_AVERAGE)) 
model.add(Dense(NUM_CLASSES, activation = DENSE_LAYER_ACTIVATION))

# 이미 학습된 영역은 학습하지 않겠다고 설정하는 옵션 
model.layers[0].trainable = False
'''
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/resnet/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5
94773248/94765736 [==============================] - 1s 0us/step
'''


# 모델 구조
model.summary()
'''
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
resnet50 (Functional)        (None, 2048)              23587712  
_________________________________________________________________
dense_2 (Dense)              (None, 2)                 4098      
=================================================================
Total params: 23,591,810
Trainable params: 4,098
Non-trainable params: 23,587,712
_________________________________________________________________
'''


from tensorflow.keras import optimizers

# optimizer, compile
sgd = optimizers.SGD(lr = 0.01, decay = 1e-6, momentum = 0.9, nesterov = True)
model.compile(optimizer = sgd, loss = OBJECTIVE_FUNCTION, metrics = LOSS_METRICS)


from keras.applications.resnet50 import preprocess_input
from keras.preprocessing.image import ImageDataGenerator

# 입력 이미지 사이즈 정의
image_size = IMAGE_RESIZE
# 입력 이미지, 데이터 증량(Augmentation)
datagen = ImageDataGenerator(
    preprocessing_function=preprocess_input,
    featurewise_center=True,
    featurewise_std_normalization=True,
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True)
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(train_images)

#(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()


# 모델 학습 (전이 학습)
model.fit(datagen.flow(train_images, train_labels, batch_size=32),
          steps_per_epoch=len(train_images) / 32, epochs=NUM_EPOCHS)
'''
Epoch 1/10
1562/1562 [==============================] - 34s 20ms/step - loss: 1290.5127 - accuracy: 0.5002
Epoch 2/10
1562/1562 [==============================] - 31s 20ms/step - loss: 1280.6297 - accuracy: 0.5026
Epoch 3/10
1562/1562 [==============================] - 31s 20ms/step - loss: 1282.0677 - accuracy: 0.4996
Epoch 4/10
1562/1562 [==============================] - 31s 20ms/step - loss: 1279.7756 - accuracy: 0.4971
Epoch 5/10
1562/1562 [==============================] - 31s 20ms/step - loss: 1274.8621 - accuracy: 0.5003
Epoch 6/10
1562/1562 [==============================] - 31s 20ms/step - loss: 1288.3699 - accuracy: 0.5023
Epoch 7/10
1562/1562 [==============================] - 31s 20ms/step - loss: 1271.4807 - accuracy: 0.4997
Epoch 8/10
1562/1562 [==============================] - 31s 20ms/step - loss: 1282.5470 - accuracy: 0.4975
Epoch 9/10
1562/1562 [==============================] - 31s 20ms/step - loss: 1251.9614 - accuracy: 0.5004
Epoch 10/10
1562/1562 [==============================] - 31s 20ms/step - loss: 961.2878 - accuracy: 0.4987
<tensorflow.python.keras.callbacks.History at 0x7f76f00e8f28>
'''

Review

  • Convolution은 필터 개념의 새로운 함수를 생성하여 연산하고 다음 레이어로 전달하는 가중치를 새롭게 만들어준다.
  • Convolution은 커널(가중치 모음, 필터)은 CNN을 학습하는 과정에서 학습된다.
  • Pooling은 데이터를 다운 샘플링하기 위해 피쳐 맵 영역의 최대 또는 평균을 사용하는 차원 감소 기술이다.

합성곱 층(Convolutional Layer)

  • 합성곱 연산을 통해 이미지 특징을 추출하는 역할을 한다.
  • kernal or filter라는 n * m 크기의 행렬로 높이(height) * 너비(width) 크기의 이미지를 처음부터 끝까지 겹치며 훑으면서 n * m 크기의 겹쳐지는 부분의 각 이미지와 커널의 원소 값을 곱해서 모두 더한 값을 출력하는 것이다.
  • 커널은 일반적으로 3 * 3 or 5 * 5를 사용한다.

패딩(Padding)

image

  • 합성곱 연산의 결과로 얻은 특성 맵은 입력보다 크기가 작아진다는 특징이 있다.
  • 합성곱 층을 여러개 쌓았다면 최종적으로 얻은 특성 맵은 초기 입력보다 작아진 상태가 되어버린다.
  • 합성곱 연산 이후에도 특성 맵의 크기가 입력의 크기와 동일하게 유지되도록 하고 싶을 때 Padding을 사용한다.
  • Padding은 합성곱 연산을 하기 전에 입력의 가장자리에 지정된 개수의 폭만큼 행과 열을 추가해주는 것이다.
  • 지정된 개수의 폭만큼 테두리를 추가한다.
  • 주로 값을 0으로 채우는 Zero padding을 사용한다.

스트라이드(Stride)

image

  • 필터를 적용하는 위치와 간격을 Stride라고 한다.
  • 스트라이드가 2라면 필터를 적용하는 윈도우가 두 칸씩 이동한다

최대 풀링(Max Pooling)

image

  • Pooling이란 세로 가로 방향의 공간을 줄이는 연산이다.
  • 출력 데이터의 크기를 줄이거나 특정 데이터를 강조하기 위해 사용한다.
  • Max pooling은 최댓값을 구하는 연산으로, 영역에서 가장 큰 원소를 하나 꺼낸다.
  • 풀링의 윈도우 크기와 스트라이드는 같은 값으로 설정하는 것이 보통이다.

전이 학습(Transfer Learning)

  • 이미지넷이 제공하는 거대한 데이터셋으로 학습한 가중치 값들은 실제 제품에 활용해도 효과적이고 많이들 그렇게 이용한다.
  • 학습된 가중치(혹은 그 일부)를 다른 신경망에 복사한 다음, 그 상태로 재학습을 수행한다.

Skipped Connection

image

  • 층을 깊게 하는 것이 성능 향상에 중요하지만, 층이 지나치게 깊으면 학습이 잘 되지 않고 오히려 성능이 떨어지는 경우가 많다.
  • ResNet에서는 그런 문제를 해결하기 위해 Skipped connection을 도입했다.
  • Skipped connection은 입력 데이터를 합성곱 계층을 건너뛰어 출력에 바로 더하는 구조를 말한다.
  • 위 그림에서 입력 x를 연속한 두 합성곱 계층을 건너뛰어 출력에 바로 연결한다.
  • 이 단축 경로가 없었다면 두 합성곱 계층의 출력이 F(x)가 되나, 스킵 연결로 인해 F(x) + x 가 된다.
  • 스킵 연결은 층이 깊어져도 학습을 효율적으로 할 수 있도록 해주는데, 이는 역전파 때 스킵 연결이 신호 감쇠를 막아주기 때문이다.
  • 스킵 연결은 데이터를 그대로 흘리는 것으로, 역전파 때도 상류의 기울기를 그대로 하류로 보낸다.
  • 여기서 핵심은 상류의 기울기에 아무런 수정도 가하지 않고 그대로 흘린다는 것이다.
  • 스킵 연결로 기울기가 작아지거나 지나치게 커질 걱정 없이 앞 층에 의미 있는 기울기가 전해지리라 기대할 수 있다.
  • 층을 깊게 할수록 기울기가 작아지는 소실 문제를 이 스킵 연결이 줄여주는 것이다.

Reference

0%