이번 시간에는 지금까지 쓰던 sequential 방식으로 레이어를 쌓는 게 아닌 다른 방법을 소개하겠다.
일단 레이어가 어떤 식으로 바뀌는지 쉽게 이해하기 위해 레이어를 시각화 해주는 함수를 사용해보겠다.
from tensorflow.keras.utils import plot_model
plot_model(model, to_file='model.png', show_shapes=True, show_layer_names=True)
model.fit 밑에 이 코드를 입력하면
이런 식으로 모델의 레이어를 시각화해준다.
Functional API는 Sequential API가 위에서 아래로 레이어를 순차적으로 쌓는 방식이라면, 데이터의 흐름을 직접 연결해서 모델을 구성하는 방식이다. 모델 레이어 하나하나를 함수처럼 설계하고, 구조를 명시적으로 정의한다.
Sequential 모델은 단순하게 순차적인 구조만 지원해서 구조적 제약이 비교젓 심하지만, Functional은 함수처럼 생성하고 사용자가 직접 연결을 유연하게 할 수 있어서 복잡한 모델 구조를 구현 가능하다.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=(28,28,1)),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax'),
])
기존 sequential을 사용하면 위에 보여주었던 이미지처럼 순차적인 흐름을 가진 구조를 가진다.
그럼 이번엔 functional을 사용해보자.
input1 = tf.keras.layers.Input(shape=(28, 28,1))
flatten1 = tf.keras.layers.Flatten()(input1)
dense1 = tf.keras.layers.Dense(28*28, activation='relu')(flatten1)
reshape1 = tf.keras.layers.Reshape((28,28,1))(dense1)
concat1 = tf.keras.layers.Concatenate()([input1,reshape1])
flatten2 = tf.keras.layers.Flatten()(concat1)
output = tf.keras.layers.Dense(10, activation='softmax')(flatten2)
model = tf.keras.Model(inputs=input1, outputs=output)
Functional은 레이어 하나하나를 함수를 정의하듯 정의하고, 어떤 레이어와 연결되어 있는지를 코드마다 지정해주어야 한다.
(Reshape 레이어는 입력 텐서의 shape를 새롭게 바꾸고, Conecatenate 레이어는 여러 개의 텐서를 하나의 텐서로 합친다.)
해당 모델을 시각화해보면,
이런 식의 흐름을 가진 구조를 보인다. 이 구조는 원본 그대로의 입력과 dense, reshape를 거친 값을 다시 한번에 합쳐서 처리한다.
이는 병렬 경로라고도 불리는데, 병렬 경로를 사용하면 다른 레이어들이 동시에 입력을 처리하면서 입력 데이터의 다양한 특성을 병렬적으로 추출할 수 있고, 레이어가 깊을수록 정보가 축소되거나 왜곡될 가능성이 높은데, 위 코드의 병렬 경로를 통해서 정보를 보존하여서 성능과 학습 안정성이 향상될 수 있고, 훈련 데이터에만 특화되지 않기에 overfitting 현상을 줄일 수 있다.