[DL] Keras 딥러닝 모델

jul ee·2025년 6월 9일

데이터 성장기

목록 보기
126/139

🖇  기본 임포트
🖇  1. Sequential API
🖇  2. Functional API
🖇  3. Subclassing API
🖇  어떤 방식을 언제 선택해야 할까?


딥러닝 모델을 구성하는 방법에는 여러 가지가 있다. 그중 Keras를 사용할 때는 대부분 3가지 방법 중 하나를 선택하게 된다.

  • Sequential API
  • Functional API
  • Subclassing API

각각의 방식은 구조, 표현력, 유연성에서 차이가 있다.

이 글에서는 세 가지 방법의 개념과 구조, 예제를 비교하면서 어떤 상황에서 어떤 방식을 선택하면 좋을지 정리해 보았다. 각각의 방식이 어떤 구조와 개념적 배경을 갖고 있는지, 왜 그렇게 쓰이는지에 대해 이해하는 과정도 함께 담아보았다.




🖇  기본 임포트

딥러닝 모델을 구현하기 위해서는 TensorFlow와 Keras의 모듈을 임포트해야 한다.

from tensorflow.keras import models, layers, utils
import tensorflow as tf

🖇  1. Sequential API

가장 단순하고 직관적인 방식으로, 순차적인 구조에 적합하다.

Sequential API는 위에서 아래로, 순차적으로 레이어를 쌓아가는 방식이다. 마치 블록을 위에서부터 아래로 쌓듯이 하나씩 레이어를 추가하는 구조다. 입력에서 출력까지 흐름이 단방향이고 직선적이며 분기나 병합이 없다.

MLP 구조나 단순한 CNN 모델에서 주로 사용된다.

  • 구현이 간단하고 읽기 쉽지만, 입력이 여러 개이거나 출력이 여러 개인 모델 또는 레이어 간 연결이 복잡한 모델은 표현할 수 없다.

  • Sequential API는 내부적으로 자동으로 입력 형태를 추론하고 레이어를 쌓는 방식이기 때문에 디버깅이나 복잡한 흐름 제어가 어렵다.

예제 1:   add() 메서드로 레이어 추가

model = models.Sequential()
model.add(layers.Input(shape=(28, 28)))
model.add(layers.Dense(300, activation='relu'))
model.add(layers.Dense(100, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()
utils.plot_model(model, show_shapes=True)

예제 2:   리스트 형태로 레이어 정의

model = models.Sequential([
    layers.Input(shape=(28, 28), name='Input'),
    layers.Dense(300, activation='relu', name='Dense1'),
    layers.Dense(100, activation='relu', name='Dense2'),
    layers.Dense(10, activation='softmax', name='Output')
])
model.summary()
utils.plot_model(model, show_shapes=True)



🖇  2. Functional API

모듈처럼 조립하는 방식으로, 유연하고 복잡한 모델을 표현할 수 있다.

Functional API는 각 레이어를 함수처럼 조립하듯 연결하는 방식이다. Sequential 방식보다 훨씬 유연해서 다음과 같은 구조도 표현할 수 있다.

  • 다중 입력/출력
  • 병렬 네트워크
  • 중간 결과 재활용
  • 스킵 연결

입출력 텐서를 변수처럼 다루고, 그 사이를 함수 형태로 연결하는 개념이다. 모델 흐름이 눈에 잘 보이고, 재사용과 디버깅도 편해서 많이 사용된다. 또한 모델을 시각화하거나 구조적으로 설명할 때도 명확하다.

예제 1:   단일 입력/출력 기본 구조

inputs = layers.Input(shape=(28, 28, 1))
x = layers.Flatten()(inputs)
x = layers.Dense(300, activation='relu')(x)
x = layers.Dense(100, activation='relu')(x)
outputs = layers.Dense(10, activation='softmax')(x)

model = models.Model(inputs=inputs, outputs=outputs)
model.summary()
utils.plot_model(model, show_shapes=True)

예제 2:   입력과 은닉층 결과를 연결 (Concatenate)

inputs = layers.Input(shape=(28, 28))
hidden1 = layers.Dense(100, activation='relu')(inputs)
hidden2 = layers.Dense(30, activation='relu')(hidden1)
concat = layers.Concatenate()([inputs, hidden2])
output = layers.Dense(1)(concat)

model = models.Model(inputs=inputs, outputs=output)
model.summary()
utils.plot_model(model, show_shapes=True)

예제 3:   다중 입력 + 다중 출력

입력이 두 개, 출력이 두 방향으로 나뉘는 복잡한 구조를 구현할 수 있다. 예측 문제를 분기하거나 멀티태스크 학습 등에서 유용하게 사용된다.

input_1 = layers.Input(shape=(40,), name="Input_1")
input_2 = layers.Input(shape=(10,), name="Input_2")

x1 = layers.Dense(100, activation='relu')(input_1)
x2 = layers.Dense(100, activation='relu')(input_2)

concat = layers.Concatenate()([x1, x2])
output_1 = layers.Dense(1, name="dense_2")(concat)

x = layers.Dense(40, activation='relu', name="dense_3")(concat)
output_2 = layers.Dense(10, name="dense_4")(x)

model = models.Model(inputs=[input_1, input_2], outputs=[output_1, output_2])
model.summary()
utils.plot_model(model, show_shapes=True)



🖇  3. Subclassing API

클래스로 모델을 정의하는 방식으로, 완전한 자유도를 제공한다.

Subclassing 방식은 Model 클래스를 상속받아 모델을 직접 정의하는 방식이다. 모델 구성뿐 아니라 call() 함수에서 레이어 흐름도 직접 제어할 수 있어서 가장 자유롭다.

  • 조건문, 반복문 등 파이썬 코드와 결합해 동적 구조를 구현할 수 있다.
  • 강화학습, RNN, 조건부 분기 네트워크 같은 복잡한 구조에서 특히 유용하다.

Functional API조차 표현할 수 없는 커스텀 로직을 필요로 할 때 사용하는 방식이다. 다만 자유도가 높은 만큼 코드가 복잡하고 디버깅이 어려울 수 있다.

예제:   Functional에서 만든 모델을 Subclassing으로 구현

class CustomModel(models.Model):
    def __init__(self):
        super().__init__()
        self.dense1 = layers.Dense(100, activation='relu')
        self.dense2 = layers.Dense(100, activation='relu')
        self.concat = layers.Concatenate()
        self.output1 = layers.Dense(1, name="dense_2")
        self.shared = layers.Dense(40, activation='relu', name="dense_3")
        self.output2 = layers.Dense(10, name="dense_4")

    def call(self, inputs):
        input1, input2 = inputs
        x1 = self.dense1(input1)
        x2 = self.dense2(input2)
        merged = self.concat([x1, x2])
        out1 = self.output1(merged)
        x = self.shared(merged)
        out2 = self.output2(x)
        return [out1, out2]

# 입력 테스트
input1 = tf.random.normal([32, 40])
input2 = tf.random.normal([32, 10])
model = CustomModel()
output = model([input1, input2])
model.summary()



🖇  어떤 방식을 언제 선택해야 할까?

Keras의 세 가지 딥러닝 모델 구현 방식 중 어떤 방식을 어떨 때 사용하면 좋을지 정리해 보았다.

  • 구조가 단순하고 빠르게 테스트하고 싶다면 → Sequential
  • 모델 구조가 조금이라도 복잡하거나 시각화가 필요하다면 → Functional
  • 학습 중 동적인 조건 분기나 반복이 필요하다면 → Subclassing
방식특징추천 상황
Sequential API가장 단순
순차적인 레이어만 구성 가능
기본 MLP, 간단한 CNN, 빠르게 테스트할 때
Functional API유연하고 직관적
대부분의 모델 구현 가능
대부분의 모델 (CNN, RNN, Autoencoder 등)
Subclassing API완전한 사용자 정의
제어 흐름까지 직접 작성 가능
조건문/반복문/동적 구조가 필요한 고급 모델



인사이트 및 회고

딥러닝 모델을 구성할 수 있는 방법은 다양하지만, 가장 많이 사용되는 세 가지 방식과 그 특징을 함께 살펴보았다.

Sequential API는 빠르게 실습할 때 편하고, Functional API는 대부분의 실무 모델을 다룰 수 있으며, Subclassing은 복잡한 사용자 정의 구조를 구현할 때 사용할 수 있겠다는 것을 알 수 있었다.

더 다양한 예제로 세 가지 방법의 차이와 쓰임새를 체득할 수 있도록 비교해 보아야겠다. 구조를 잘 이해하면 어떤 방식으로든 딥러닝 모델을 자유롭게 설계할 수 있을 거라 기대한다.

profile
AI에 관심을 가지고, 데이터로 가치를 만들어 나가는 과정을 기록합니다.

0개의 댓글