나도 모르는 새 이미 쓰고 있던 머신러닝 디자인 패턴 2.
머신러닝 시스템 을 어떤 구성요소로 디자인할 지 고민 해봅시다. Batch training, checkpoint, transfer learning 등 모델 학습 과정에 활용하기 좋은 기초적인 디자인 패턴 에 대해 예시 코드로 알아봅니다.
패턴 씹뜯맛즐 – Batch training, transfer learning, checkpoint
모델 학습에 유용한 디자인 패턴
머신러닝 시스템 을 개발할 때 다양한 디자인 패턴 을 활용하면 효율성과 성능을 높일 수 있습니다. 그 중에서도 Batch training, transfer Learning, checkpoint 패턴은 널리 사용되는 유용한 시스템 패턴 들입니다. 이러한 패턴 들을 적재적소에 사용하여 개발 효율성을 높이고 모델의 성능을 향상시킬 수 있으므로, 딥러닝 엔지니어라면 이 패턴들에 대해 잘 이해하고 활용할 줄 아는 것이 중요합니다.
Batch training
Batch training 디자인 패턴 은 대량의 데이터를 처리할 때 주로 사용되는 머신러닝 학습의 기초적인 방식입니다. 전체 데이터셋을 한 번에 모델에 입력하는 대신 일정 크기의 배치로 나누어 처리하는 방식입니다. 이렇게 하면 메모리 사용량을 줄이고 학습 속도를 높일 수 있으며, 배치 단위로 그래디언트를 계산하고 업데이트하므로 학습의 안정성도 향상됩니다. 배치 크기는 보통 32, 64, 128 등의 값을 사용하며, 최적의 배치 크기는 문제와 데이터의 특성에 따라 달라질 수 있습니다.
import tensorflow as tf
from tensorflow.keras.datasets import mnist
# MNIST 데이터셋 로드
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 데이터 전처리
x_train = x_train.reshape((60000, 28, 28, 1)) / 255.0
x_test = x_test.reshape((10000, 28, 28, 1)) / 255.0
y_train = tf.keras.utils.to_categorical(y_train)
y_test = tf.keras.utils.to_categorical(y_test)
# 배치 크기 설정
batch_size = 128
# 모델 구조 정의
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
# 모델 컴파일
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 모델 학습
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=5,
validation_data=(x_test, y_test))
# 모델 평가
test_loss, test_acc = model.evaluate(x_test, y_test)
print('Test accuracy:', test_acc)
머신러닝 을 다룰 때 기본적으로 데이터작업-모델정의-학습옵션설정-모델평가 방식을 수행하고있습니다. batch_size 설정과 fit() 메소드를 활용하여 구현하고 있네요.
Checkpoint
다음으로 Checkpoint 디자인 패턴 은 머신러닝 모델의 학습 과정에서 중간 상태를 저장하고 필요할 때 이를 불러와서 학습을 이어갈 수 있게 해주는 방법입니다. 딥러닝 모델의 학습은 대규모 데이터셋을 사용하므로 장시간이 소요되는 경우가 많고, 학습 도중 예기치 못한 중단이 발생할 수 있습니다. 이러한 상황에서 처음부터 다시 학습을 시작하는 것은 비효율적이므로, Checkpoint 디자인 패턴 을 활용하여 중간 상태를 저장하고 복구할 수 있습니다. 모델의 가중치, 옵티마이저 상태 등을 일정 간격으로 저장하여 체크포인트를 생성하고, 학습이 중단되거나 최적의 모델을 선택해야 할 때 이 체크포인트를 활용하여 이전 상태에서부터 학습을 재개할 수 있습니다.
# 체크포인트 설정
checkpoint_path = 'checkpoint/model.ckpt'
checkpoint = tf.train.Checkpoint(model=model, optimizer=optimizer)
# 체크포인트 저장 함수
def save_checkpoint(checkpoint_path):
checkpoint.save(file_prefix=checkpoint_path)
# 체크포인트 로드 함수
def load_checkpoint(checkpoint_path):
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_path))
#------------------------------------------
# 학습 루프
num_epochs = 10
for epoch in range(num_epochs):
# 학습 코드 (생략)
# ...
# 체크포인트 저장
if (epoch + 1) % 5 == 0: # 5 에포크마다 체크포인트 저장
save_checkpoint(checkpoint_path)
#------------------------------------------
# 체크포인트 로드 예시
loaded_model = create_model()
loaded_optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
checkpoint = tf.train.Checkpoint(model=loaded_model, optimizer=loaded_optimizer)
load_checkpoint(checkpoint_path)
# 로드된 모델과 옵티마이저로 학습 재개
for epoch in range(num_epochs):
# 학습 코드 (생략)
# ...
체크포인트에는 모델의 구조, 가중치, 옵티마이저 상태, 에포크 정보 등이 포함되며, 이를 로드할 때는 저장된 정보를 바탕으로 모델과 옵티마이저를 초기화하고 학습을 이어나갈 수 있습니다. 일반적으로 HDF5, PyTorch의 pth, TensorFlow의 ckpt 등의 파일 형식이 사용되며, 체크포인트 파일은 모델 이름, 에포크 번호, 시간 등을 포함한 명명 규칙을 따라 저장합니다.
Checkpoint 패턴을 적용할 때는 체크포인트 저장 간격을 적절히 설정해야 합니다. 체크포인트를 너무 자주 저장하면 디스크 공간을 많이 차지하고 저장 시간이 길어질 수 있으며, 너무 드물게 저장하면 중간 상태를 복구하는 데 어려움이 있을 수 있습니다.
Transfer learning
마지막으로 Transfer Learning 디자인 패턴 은 이미 학습된 모델의 지식을 새로운 문제에 활용하는 방법입니다. 대규모 데이터셋으로 사전 학습된 머신러닝 모델을 가져와서, 새로운 도메인이나 작업에 맞게 일부 레이어를 재학습시킵니다. 이를 통해 적은 양의 데이터로도 높은 성능을 얻을 수 있고 학습 시간도 크게 단축시킬 수 있습니다. 전이 학습은 데이터가 부족하거나 유사한 도메인 간의 지식 전달이 필요한 경우에 특히 유용하게 사용될 수 있습니다.
import tensorflow as tf
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 1. 데이터 경로 설정
train_data_dir = 'path/to/train/data'
validation_data_dir = 'path/to/validation/data'
# 이미지 크기 설정
img_width, img_height = 224, 224
batch_size = 32
# 2. 데이터 제너레이터 설정
train_datagen = ImageDataGenerator(rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
validation_datagen = ImageDataGenerator(rescale=1./255)
train_generator = train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical')
validation_generator = validation_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='categorical')
# 3. 사전 학습된 MobileNet V2 모델 로드
base_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(img_width, img_height, 3))
# 4. 모델 구조 설정
x = base_model.output
x = tf.keras.layers.GlobalAveragePooling2D()(x)
x = tf.keras.layers.Dense(1024, activation='relu')(x)
predictions = tf.keras.layers.Dense(num_classes, activation='softmax')(x)
model = tf.keras.models.Model(inputs=base_model.input, outputs=predictions)
# 5. 사전 학습된 레이어 고정
for layer in base_model.layers:
layer.trainable = False
# 6. 모델 컴파일
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001),
loss='categorical_crossentropy',
metrics=['accuracy'])
# 모델 학습
num_epochs = 10
model.fit(train_generator,
steps_per_epoch=train_generator.samples // batch_size,
validation_data=validation_generator,
validation_steps=validation_generator.samples // batch_size,
epochs=num_epochs)
# 7. 모델 저장
model.save('transfer_learning_model.h5')
코드에서는 사전 학습된 MobileNet V2 모델을 사용하여 Transfer Learning을 수행합니다. 주요 단계는 다음과 같이 나눌 수 있습니다.
- 데이터 경로 설정 및 이미지 크기 지정
- 데이터 제너레이터 설정하여 이미지 데이터 로드 및 전처리
- 사전 학습된 MobileNet V2 모델 로드 (
include_top=False
로 설정하여 분류기 레이어 제외) - 모델 구조 설정 (풀링 레이어, 밀집 레이어 추가)
- 사전 학습된 레이어 고정 (
layer.trainable = False
) - 모델 컴파일 및 학습
- 학습된 모델 저장
이 예시에서는 사전 학습된 MobileNet V2 모델의 특징 추출 부분만 그대로 사용하고(include_top=False
), 마지막에 새로운 분류기 레이어를 추가하여 Transfer Learning을 수행합니다. 사전 학습된 레이어는 고정(layer.trainable = False
)되어 학습되지 않고, 새로 추가된 레이어만 학습됩니다. 비슷한 환경에서 추출된 특징들을 그대로 활용하면서, 주어진 테스크 특성에 맞게 분류기와의 연결만 새롭게 구축하는 방식입니다. Transfer Learning을 통해 적은 양의 데이터로도 효과적으로 머신러닝 모델을 학습시킬 수 있으며, 학습 시간을 단축할 수 있습니다.
디자인 패턴 유용한 이유 ‘바퀴를 다시 발명하지 마라’
위에서 살펴본 디자인 패턴 들은 아주 기본적이면서도 절대 간과되지 않는 기능들일 겁니다(흠칫). 특히나 다양한 종류의 실험을 계획하고 수행하다보면, 잘 정리된 학습 기록들과 리포트들을 보면서 가슴이 벅차오르고 편안해진 경험이 있지 않나요?
사실 오늘 내용은 다양한 디자인 패턴 중에서도 학습과 관련된 극히 일부의 예시일 뿐입니다. 머신러닝 솔루션을 구축하는 것은 비즈니스목표발견-타당성조사-모델학습-개발-배포 과정을 거쳐, 다시 처음으로 돌아가 발전하는 나선형의 여정입니다. 더욱이 더 복잡한 MLOps 까지 서비스를 확장하기 위해서는 데이터 표현, 문제 표현, 탄력성, 재현성, 책임있는 AI 등 각 세부 항목에서도 위와 같은 유용한 솔루션들이 필요합니다. 특히 임베딩(데이터 표현), 멀티모달 입력(데이터 표현), 앙상블(문제 표현), 연속 모델 평가(탄력성), 윈도 추론(재현성) 등의 패턴도 꼭 참고 자료에서 확인해보시길 추천드립니다.
탄탄한 기본기가 꾸준히 쌓여 어려움을 하나씩 개선해간다면, 언젠가 완전자동화 시스템까지 능숙하게 다룰 날이 성큼 다가올 것 같네요. 마치 살아 움직이는 듯 스스로 성장할 수 있는 시스템을 만들어내는 그날까지 열심히 공부해봐야겠습니다.
다음 포스트는 더 넓은 관점에서 서비스 아키텍처를 어떤 모양으로 구성할 지 고민해보는 Monolithic vs Micro-service 편으로 이어집니다.