Keras는 TensorFlow 패키지에 포함되어 있으며, 아래 코드 한 줄로 간단히 불러와 사용할 수 있습니다.
import tensorflow from tensorflow import keras
Keras의 함수형 API(Functional API)는 순차형(Sequential) API로 만든 모델보다 훨씬 유연한 모델을 구축할 수 있게 해줍니다. 함수형 API는 비선형 위상(non-linear topology)을 가진 모델을 다룰 수 있고, 레이어 공유, 그리고 여러 개의 입력과 출력을 처리하는 것도 가능합니다. 일반적으로 딥러닝 모델은 여러 레이어로 구성된 방향성 비순환 그래프(DAG, Directed Acyclic Graph) 형태이며, 함수형 API를 사용하면 이러한 레이어 그래프를 손쉽게 만들 수 있습니다.
아래 코드는 Google Colaboratory 환경에서 실행했습니다. Google Colab은 브라우저에서 별도 설정 없이 파이썬 코드를 실행할 수 있게 해주며, GPU도 무료로 사용할 수 있습니다. Colaboratory는 Jupyter Notebook을 기반으로 만들어졌습니다.
예제 코드
다음은 CIFAR10 데이터셋용 장난감(toy) ResNet 모델을 함수형 API로 구현한 예제입니다. 핵심은 layers.add()를 활용해 이전 블록의 출력을 현재 블록의 출력에 더하는 잔차 연결(residual connection) 부분입니다.
print("CIFAR10용 Toy ResNet 모델")
print("모델에 사용될 레이어 생성")
inputs = keras.Input(shape=(32, 32, 3), name="img")
x = layers.Conv2D(32, 3, activation="relu")(inputs)
x = layers.Conv2D(64, 3, activation="relu")(x)
block_1_output = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(block_1_output)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(x)
block_2_output = layers.add([x, block_1_output])
x = layers.Conv2D(64, 3, activation="relu", padding="same")(block_2_output)
x = layers.Conv2D(64, 3, activation="relu", padding="same")(x)
block_3_output = layers.add([x, block_2_output])
x = layers.Conv2D(64, 3, activation="relu")(block_3_output)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(256, activation="relu")(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(10)(x)
model = keras.Model(inputs, outputs, name="toy_resnet")
print("모델 상세 정보")
model.summary()코드 출처 − https://www.tensorflow.org/guide/keras/functional
실행 결과
Model: "toy_resnet" ________________________________________________________________________________ Layer (type) Output Shape Param # Connected to ================================================================================ img (InputLayer) [(None, 32, 32, 3)] 0 ________________________________________________________________________________ conv2d_32 (Conv2D) (None, 30, 30, 32) 896 img[0][0] ________________________________________________________________________________ conv2d_33 (Conv2D) (None, 28, 28, 64) 18496 conv2d_32[0][0] ________________________________________________________________________________ max_pooling2d_8 (None, 9, 9, 64) 0 conv2d_33[0][0] ________________________________________________________________________________ conv2d_34 (Conv2D) (None, 9, 9, 64) 36928 max_pooling2d_8[0][0] ________________________________________________________________________________ conv2d_35 (Conv2D) (None, 9, 9, 64) 36928 conv2d_34[0][0] ________________________________________________________________________________ add_12 (Add) (None, 9, 9, 64) 0 conv2d_35[0][0], max_pooling2d_8[0][0] ________________________________________________________________________________ conv2d_36 (Conv2D) (None, 9, 9, 64) 36928 add_12[0][0] ________________________________________________________________________________ conv2d_37 (Conv2D) (None, 9, 9, 64) 36928 conv2d_36[0][0] ________________________________________________________________________________ add_13 (Add) (None, 9, 9, 64) 0 conv2d_37[0][0], add_12[0][0] ________________________________________________________________________________ conv2d_38 (Conv2D) (None, 7, 7, 64) 36928 add_13[0][0] ________________________________________________________________________________ global_average_pooling2d (None, 64) 0 conv2d_38[0][0] ________________________________________________________________________________ dense_40 (Dense) (None, 256) 16640 global_average_pooling2d[0][0] ________________________________________________________________________________ dropout_2 (Dropout) (None, 256) 0 dense_40[0][0] ________________________________________________________________________________ dense_41 (Dense) (None, 10) 2570 dropout_2[0][0] ================================================================================ Total params: 223,242 Trainable params: 223,242 Non-trainable params: 0
코드 설명
이 모델은 하나의 입력과 하나의 출력을 가지지만, 내부 구조가 단순히 순차적으로 연결되지 않습니다.
함수형 API는 이처럼 비선형 연결 위상을 가진 모델을 쉽게 다룰 수 있게 해줍니다.
레이어들이 순차적으로만 연결된 것이 아니기 때문에 순차형(Sequential) API로는 이 모델을 구현할 수 없습니다.
바로 이 지점에서 잔차 연결(residual connection)이 중요한 역할을 합니다.
layers.add()를 통해 이전 블록의 출력을 현재 블록의 출력에 더함으로써, 깊은 네트워크에서도 기울기 소실 문제를 완화하고 학습을 안정화할 수 있습니다.위 예제에서는 CIFAR10 데이터셋을 대상으로 하는 샘플 ResNet 모델을 만들어 이를 시연했습니다.