Inception module 의 구조는 Network in Network(NiN) 컨셉을 차용하여, 모듈 안에서 더욱 복잡하고 기능적인 설계를 보여주었습니다.
Network in Network 을 개략적으로 표현한 그림
동일한 입력이 모듈 안에서 여러 가지로 갈라지고, 각각 특징적인 기능을 수행합니다. 이후 다시 하나의 지점으로 모여 모듈에서 빠져나가며 출력되는 구조를 확인할 수 있습니다.
앞선 모듈의 출력이 다음 모듈의 입력으로 활용되는 구조를 생각할 때, 서로 다른 모양의 중간 출력을 하나로 합칠 방식을 고민해야 합니다. 각 가지에서 나온 중간 출력이 같은 모양을 가질 경우, add 연산을 사용하면 간단하게 합칠 수 있지만, 서로 다른 모양일 경우 각자의 상태를 유지하기 위해 concatenation 연산을 수행합니다.
(미션) 직접 concatenation/add 연산 결과를 출력하여 크기를 비교해봅시다.
import numpy as np
tensor1 = np.random.randint(0, 10, size=(2, 3, 4))
tensor2 = np.random.randint(10, 20, size=(2, 3, 4))
# concatenate 함수를 사용하여 tensor1과 tensor2를 axis=0 방향으로 연결한 결과를 result1에 할당하세요.
result1 = None
# add 함수를 사용하여 tensor1과 tensor2를 요소별로 더한 결과를 result2에 할당하세요.
result2 = None
print("Tensor 1:")
print(tensor1)
print("Tensor 2:")
print(tensor2)
print("Result 1:")
print(result1)
print("Result 2:")
print(result2)
# tensor1과 tensor2의 크기를 출력하세요.
print("Tensor 1 shape:")
print(None)
print("Tensor 2 shape:")
print(None)
# result1과 result2의 크기를 출력하세요.
print("Result 1 shape:")
print(None)
print("Result 2 shape:")
print(None)
다음은 inception module의 단위 구조를 구현한 예시 코드입니다. (참고자료: Tensorflow로 모델을 구현하는 세가지 방법, 케창딥 245~260p)
class Inception(tf.keras.Model):
# c1--c4 are the number of output channels for each branch
def __init__(self, c1, c2, c3, c4):
super().__init__()
self.b1_1 = tf.keras.layers.Conv2D(c1, 1, activation='relu')
self.b2_1 = tf.keras.layers.Conv2D(c2[0], 1, activation='relu')
self.b2_2 = tf.keras.layers.Conv2D(c2[1], 3, padding='same',
activation='relu')
self.b3_1 = tf.keras.layers.Conv2D(c3[0], 1, activation='relu')
self.b3_2 = tf.keras.layers.Conv2D(c3[1], 5, padding='same',
activation='relu')
self.b4_1 = tf.keras.layers.MaxPool2D(3, 1, padding='same')
self.b4_2 = tf.keras.layers.Conv2D(c4, 1, activation='relu')
def call(self, x):
b1 = self.b1_1(x)
b2 = self.b2_2(self.b2_1(x))
b3 = self.b3_2(self.b3_1(x))
b4 = self.b4_2(self.b4_1(x))
return tf.keras.layers.Concatenate()([b1, b2, b3, b4])
(미션) 아래 예시와 같이 단일 모듈만 설정했을 경우에, 입력 데이터의 크기와 모듈을 지나 출력되는 특성맵 크기 비교하여 적어봅시다.
class GoogleNet(tf.keras.Model):
def add_module(self):
return tf.keras.models.Sequential([
tf.keras.Input(shape=(128, 96, 96, 3),
Inception(64, (96, 128), (16, 32), 32)])
"""
1. 인풋데이터의 형태 128x96x96x3
2. b1: 128x96x96x64
128x96x96x64
3. b2-1: 128x96x96x96
b2-2: 128x96x96x128
128x96x96x128
4. b3-1: 128x96x96x16
b3-2: 128x96x96x32
128x96x96x32
5. b4-1: 128x96x96x3
b4-2: 128x96x96x32
128x96x96x32
모든 아웃풋을 concatenate하면
128x96x96x256 형태의 output이 출력됩니다.
"""
딥러닝 초기부터 시작해 지금까지도, 더 많은 레이어를 깊이 쌓아 고차원의 모델을 만들 수 있다는 건 일반적인 상식이 되었습니다. 하지만 중첩된 레이어 구조일 수록, 충분한 학습이 이루어지기도 전에 중단되는 vanishing gradient 현상이 발생할 위험이 높아집니다.
vanishing gradient : 역전파 과정에서 더 많은 레이어를 거칠 수록 gradient 값이 줄어들기 때문에 발생한다고 알려져 있습니다. 이 상황에서 반드시 떠올려야 할 것은 역전파 과정에 활용되는 경사하강법gradient descent 과 이를 위한 연쇄법칙chain rule 입니다.
$$ \omega_{1} = \omega_{0} - \lambda \frac{\partial L}{\partial \omega_{0}} $$
(미션) 아래 도표에서 간략한 신경망 구조의 예시를 통해서, vanishing gradient 가 나타나는 상황에 대해 설명해봅시다. 이 때 gradient 계산을 위해 연쇄법칙을 활용해봅시다. 그리고 어떤 조건에서 vanishing gradient 상황이 발생하는지 이야기해봅시다.