본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 9. · 10 Views
이미지 전처리와 증강 완벽 가이드
딥러닝 모델의 성능을 좌우하는 이미지 전처리와 데이터 증강 기법을 실무 중심으로 배웁니다. OpenCV, torchvision, Albumentations 라이브러리를 활용한 다양한 기법을 단계별로 익힙니다.
목차
1. 이미지 읽기와 변환
어느 날 김개발 씨가 첫 컴퓨터 비전 프로젝트를 시작했습니다. 이미지 파일을 불러와서 모델에 넣으려고 하는데, 선배가 물었습니다.
"이미지를 그냥 넣으면 안 돼요. 어떤 형식으로 변환했어요?" 김개발 씨는 당황했습니다.
이미지 읽기와 변환은 컴퓨터 비전의 출발점입니다. 파일 시스템에 저장된 이미지를 NumPy 배열이나 PyTorch 텐서로 변환하는 과정입니다.
이를 통해 딥러닝 모델이 이해할 수 있는 숫자 데이터로 만듭니다. 올바른 변환이 없으면 모델은 이미지를 처리할 수 없습니다.
다음 코드를 살펴봅시다.
import cv2
import numpy as np
from PIL import Image
import torch
from torchvision import transforms
# OpenCV로 이미지 읽기 (BGR 형식)
img_cv = cv2.imread('cat.jpg')
# BGR을 RGB로 변환
img_rgb = cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)
# PIL로 이미지 읽기 (RGB 형식)
img_pil = Image.open('cat.jpg')
# PyTorch 텐서로 변환
to_tensor = transforms.ToTensor()
img_tensor = to_tensor(img_pil) # shape: [C, H, W], 값 범위: [0, 1]
print(f"Tensor shape: {img_tensor.shape}")
김개발 씨는 입사 1개월 차 주니어 개발자입니다. 오늘 팀장님으로부터 고양이 이미지 분류 프로젝트를 배정받았습니다.
신나는 마음으로 코드를 작성하기 시작했는데, 첫 단계부터 막혔습니다. 이미지 파일을 어떻게 읽어야 할까요?
선배 개발자 박시니어 씨가 다가와 모니터를 봅니다. "아, 이미지 처리가 처음이시군요.
걱정 마세요. 차근차근 알려드릴게요." 그렇다면 이미지 읽기와 변환이란 정확히 무엇일까요?
쉽게 비유하자면, 이미지 읽기는 마치 외국어로 된 책을 번역하는 것과 같습니다. 디스크에 저장된 JPG, PNG 파일은 사람 눈에는 예쁜 그림으로 보이지만, 컴퓨터에게는 압축된 이진 데이터일 뿐입니다.
이를 딥러닝 모델이 이해할 수 있는 숫자 배열로 변환해야 합니다. 이미지 읽기가 없던 초창기에는 어땠을까요?
개발자들은 바이너리 파일을 직접 파싱해야 했습니다. JPG 압축 알고리즘을 수작업으로 구현하고, 픽셀 값을 하나씩 추출했습니다.
실수하기도 쉬웠고, 코드가 수백 줄씩 늘어났습니다. 더 큰 문제는 이미지 포맷마다 다른 코드를 작성해야 한다는 점이었습니다.
바로 이런 문제를 해결하기 위해 OpenCV와 PIL 같은 라이브러리가 등장했습니다. OpenCV를 사용하면 단 한 줄로 이미지를 읽을 수 있습니다.
또한 다양한 포맷을 자동으로 처리해줍니다. 무엇보다 NumPy 배열로 바로 변환되어 수학 연산이 쉽다는 큰 이점이 있습니다.
위의 코드를 한 줄씩 살펴보겠습니다. 먼저 cv2.imread() 함수로 이미지를 읽습니다.
이때 주의할 점이 있습니다. OpenCV는 기본적으로 BGR 순서로 이미지를 읽습니다.
우리가 익숙한 RGB가 아닙니다. 다음으로 cv2.cvtColor()로 BGR을 RGB로 변환합니다.
이 과정을 빼먹으면 빨간색과 파란색이 뒤바뀌는 황당한 결과를 보게 됩니다. PIL 라이브러리는 RGB 순서로 읽기 때문에 변환 과정이 필요 없습니다.
마지막으로 transforms.ToTensor()는 PIL 이미지를 PyTorch 텐서로 바꿉니다. 이때 두 가지 중요한 변환이 일어납니다.
첫째, 픽셀 값이 0-255 범위에서 0-1 범위로 정규화됩니다. 둘째, 형태가 [H, W, C]에서 [C, H, W]로 바뀝니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 의료 영상 분석 서비스를 개발한다고 가정해봅시다.
X-ray 이미지는 DICOM 포맷으로 저장되어 있습니다. OpenCV와 전문 라이브러리를 조합해서 이미지를 읽고, PyTorch 텐서로 변환한 뒤, 사전 학습된 모델에 입력합니다.
많은 병원에서 이런 파이프라인을 사용하고 있습니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 BGR과 RGB를 혼동하는 것입니다. 이렇게 하면 모델이 엉뚱한 색상을 학습하게 됩니다.
따라서 항상 색상 순서를 확인하고, 필요하면 변환해야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. "아, BGR을 RGB로 바꿔야 하는군요!" 이미지 읽기와 변환을 제대로 이해하면 컴퓨터 비전 프로젝트의 튼튼한 기초를 다질 수 있습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - OpenCV는 BGR, PIL은 RGB 순서로 읽습니다. 항상 확인하세요.
- ToTensor()는 자동으로 0-1 범위로 정규화합니다.
- 이미지 형태가 [H, W, C]에서 [C, H, W]로 바뀌는 것을 기억하세요.
2. 정규화와 표준화
김개발 씨가 모델을 학습시켰는데 정확도가 너무 낮게 나왔습니다. 박시니어 씨가 코드를 보더니 물었습니다.
"이미지 정규화는 했어요?" 김개발 씨는 정규화가 왜 필요한지 궁금해졌습니다.
정규화는 픽셀 값의 범위를 조정하는 과정입니다. 보통 0-255 범위를 0-1 또는 -1~1로 변환합니다.
표준화는 평균을 0, 표준편차를 1로 만드는 과정입니다. 이를 통해 모델 학습이 안정적으로 진행되고, 수렴 속도가 빨라집니다.
다음 코드를 살펴봅시다.
import torch
from torchvision import transforms
# 정규화: 0-1 범위로 변환 (ToTensor가 자동으로 수행)
normalize_01 = transforms.ToTensor()
# 표준화: ImageNet 평균과 표준편차 사용
normalize_imagenet = transforms.Normalize(
mean=[0.485, 0.456, 0.406], # RGB 채널별 평균
std=[0.229, 0.224, 0.225] # RGB 채널별 표준편차
)
# 전체 변환 파이프라인
transform = transforms.Compose([
transforms.ToTensor(), # 0-1 정규화
normalize_imagenet # ImageNet 표준화
])
img_normalized = transform(img_pil)
김개발 씨는 첫 모델 학습을 돌리고 결과를 기다렸습니다. 한 시간 후, 모니터에 나타난 정확도는 고작 35%였습니다.
뭔가 잘못되었음이 분명했습니다. 좌절한 표정으로 앉아 있는데, 박시니어 씨가 다가왔습니다.
"데이터 전처리는 제대로 했어요?" 박시니어 씨가 코드를 살펴봅니다. "아, 정규화를 안 했네요.
그래서 학습이 제대로 안 된 거예요." 그렇다면 정규화와 표준화란 정확히 무엇일까요? 쉽게 비유하자면, 정규화는 마치 서로 다른 화폐를 하나의 기준 화폐로 환전하는 것과 같습니다.
달러, 유로, 원화를 각각 계산하면 복잡하지만, 모두 달러로 환전하면 비교하기 쉽습니다. 이처럼 0-255 범위의 픽셀 값을 0-1 범위로 통일하면, 모델이 학습하기 쉬워집니다.
정규화가 없던 시절에는 어땠을까요? 신경망은 큰 숫자를 다루는 데 어려움을 겪었습니다.
픽셀 값 255를 그대로 입력하면, 가중치 업데이트가 불안정해졌습니다. 경사가 폭발하거나 소실되는 문제가 빈번했습니다.
더 큰 문제는 학습 속도가 매우 느렸다는 점입니다. 수렴하는 데 몇 배나 오래 걸렸습니다.
바로 이런 문제를 해결하기 위해 정규화와 표준화 기법이 등장했습니다. 정규화를 사용하면 모든 입력값이 비슷한 스케일을 갖게 됩니다.
또한 경사 소실/폭발 문제를 크게 줄일 수 있습니다. 무엇보다 학습 속도가 빨라진다는 큰 이점이 있습니다.
표준화는 한 걸음 더 나아가 평균을 0, 표준편차를 1로 만듭니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 ToTensor()는 자동으로 0-1 정규화를 수행합니다. 이것만으로도 기본적인 정규화는 완료됩니다.
다음으로 Normalize() 변환을 봅시다. 여기서 사용한 평균과 표준편차는 ImageNet 데이터셋의 통계값입니다.
RGB 세 채널 각각에 대한 값입니다. 왜 ImageNet 통계를 사용할까요?
사전 학습된 모델(ResNet, VGG 등)은 ImageNet 데이터로 학습되었습니다. 따라서 같은 통계로 표준화해야 모델이 제대로 작동합니다.
Compose()는 여러 변환을 순서대로 적용하는 파이프라인을 만듭니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 자율주행 자동차의 카메라 영상을 처리한다고 가정해봅시다. 낮과 밤, 맑은 날과 흐린 날의 밝기가 모두 다릅니다.
정규화와 표준화를 적용하면 이런 변화에 강건한 모델을 만들 수 있습니다. 테슬라, 웨이모 같은 기업들이 이 기법을 필수적으로 사용합니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 학습 데이터와 테스트 데이터에 다른 통계를 사용하는 것입니다.
이렇게 하면 모델 성능이 크게 떨어집니다. 따라서 항상 같은 평균과 표준편차를 사용해야 합니다.
또한 사전 학습 모델을 쓸 때는 반드시 ImageNet 통계를 써야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 조언대로 정규화를 적용한 김개발 씨는 모델을 다시 학습시켰습니다. 이번에는 정확도가 78%까지 올랐습니다.
"정규화 하나로 이렇게 달라지다니!" 정규화와 표준화를 제대로 이해하면 모델 성능을 크게 향상시킬 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 사전 학습 모델을 사용할 때는 ImageNet 통계로 표준화하세요.
- 학습과 테스트에 동일한 정규화를 적용해야 합니다.
- Compose로 여러 변환을 파이프라인으로 묶으면 편리합니다.
3. 크기 조정과 크롭
김개발 씨가 수집한 이미지들의 크기가 제각각이었습니다. 어떤 건 1920x1080이고, 어떤 건 640x480입니다.
박시니어 씨가 말했습니다. "모델에 넣으려면 크기를 통일해야 해요." 어떻게 해야 할까요?
크기 조정은 이미지를 원하는 해상도로 변경하는 과정입니다. 크롭은 이미지의 일부 영역을 잘라내는 기법입니다.
딥러닝 모델은 고정된 입력 크기를 요구하므로, 이 과정은 필수입니다. 또한 데이터 증강에도 활용되어 모델의 일반화 성능을 높입니다.
다음 코드를 살펴봅시다.
from torchvision import transforms
# 크기 조정: 짧은 쪽을 256으로 맞추고 비율 유지
resize = transforms.Resize(256)
# 중앙 크롭: 224x224 영역만 추출
center_crop = transforms.CenterCrop(224)
# 랜덤 크롭: 무작위 위치에서 224x224 크롭 (증강용)
random_crop = transforms.RandomCrop(224)
# 랜덤 리사이즈 크롭: 크기와 비율을 무작위로 조정 후 크롭
random_resized_crop = transforms.RandomResizedCrop(
224, # 출력 크기
scale=(0.8, 1.0), # 원본 대비 면적 비율
ratio=(0.9, 1.1) # 가로세로 비율 범위
)
김개발 씨는 인터넷에서 고양이 이미지 1000장을 수집했습니다. 신나는 마음으로 데이터를 확인하는데, 문제가 발생했습니다.
이미지마다 크기가 천차만별이었습니다. 고해상도 사진은 4000x3000이고, 썸네일은 150x150이었습니다.
박시니어 씨에게 물었습니다. "이미지 크기가 다 다른데, 이걸 어떻게 학습시키나요?" 박시니어 씨가 웃으며 답했습니다.
"크기 조정과 크롭을 배울 시간이네요." 그렇다면 크기 조정과 크롭이란 정확히 무엇일까요? 쉽게 비유하자면, 크기 조정은 마치 사진을 확대하거나 축소하는 것과 같습니다.
크롭은 사진의 가운데 부분만 오려내는 것입니다. 신분증 사진을 만들 때 얼굴 부분만 잘라내는 것과 비슷합니다.
이렇게 하면 모든 이미지를 같은 크기로 만들 수 있습니다. 크기 통일이 없던 시절에는 어땠을까요?
개발자들은 배치 학습을 할 수 없었습니다. 이미지마다 크기가 다르면 텐서로 묶을 수 없기 때문입니다.
하나씩 처리해야 했고, 속도가 매우 느렸습니다. 더 큰 문제는 모델 구조를 설계하기 어렵다는 점이었습니다.
입력 크기가 가변적이면 완전 연결 계층을 사용할 수 없습니다. 바로 이런 문제를 해결하기 위해 Resize와 Crop 기법이 등장했습니다.
Resize를 사용하면 모든 이미지를 같은 크기로 만들 수 있습니다. 또한 배치 학습이 가능해져서 GPU를 효율적으로 활용할 수 있습니다.
무엇보다 RandomCrop 같은 증강 기법으로 모델의 일반화 성능을 높일 수 있다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 Resize(256)은 이미지의 짧은 쪽을 256픽셀로 맞춥니다. 긴 쪽은 비율을 유지하며 자동으로 조정됩니다.
예를 들어 800x600 이미지는 341x256이 됩니다. 다음으로 CenterCrop(224)는 중앙에서 224x224 영역을 잘라냅니다.
이는 테스트 시에 주로 사용합니다. RandomCrop(224)는 무작위 위치에서 크롭합니다.
매번 다른 영역이 선택되므로 데이터 증강 효과가 있습니다. RandomResizedCrop은 더 강력합니다.
먼저 무작위로 크기와 비율을 조정한 뒤, 224x224로 크롭합니다. scale=(0.8, 1.0)은 원본 면적의 80%에서 100% 사이를 의미합니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 쇼핑몰의 상품 이미지 분류 시스템을 개발한다고 가정해봅시다.
판매자들이 올린 상품 사진은 크기가 제각각입니다. Resize와 CenterCrop을 적용해서 224x224로 통일한 뒤 ResNet 모델에 입력합니다.
학습 시에는 RandomResizedCrop으로 증강하여 다양한 상황에 강건한 모델을 만듭니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 비율을 무시하고 강제로 크기를 조정하는 것입니다. 예를 들어 800x600을 224x224로 늘리면 이미지가 왜곡됩니다.
따라서 Resize로 비율을 유지하며 조정한 뒤, Crop으로 정사각형을 만들어야 합니다. 또 다른 실수는 학습과 테스트에 다른 크롭을 사용하는 것입니다.
학습 시에는 RandomCrop을 쓰고, 테스트 시에는 CenterCrop을 써야 합니다. 테스트에 RandomCrop을 쓰면 결과가 매번 달라집니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 코드를 수정했습니다.
모든 이미지가 224x224로 통일되었고, 배치 학습이 가능해졌습니다. "이제야 제대로 된 학습을 할 수 있겠네요!" 크기 조정과 크롭을 제대로 이해하면 효율적인 데이터 파이프라인을 구축할 수 있습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - Resize로 비율을 유지하며 크기를 조정한 뒤, Crop으로 정사각형을 만드세요.
- 학습에는 RandomCrop, 테스트에는 CenterCrop을 사용하세요.
- RandomResizedCrop은 강력한 증강 효과를 제공합니다.
4. 회전, 뒤집기, 색상 변환
김개발 씨의 모델이 학습 데이터에서는 90% 정확도를 보였지만, 실제 데이터에서는 60%밖에 나오지 않았습니다. 박시니어 씨가 말했습니다.
"과적합이네요. 데이터 증강을 해야 해요." 어떤 방법이 있을까요?
회전은 이미지를 일정 각도로 돌리는 기법입니다. 뒤집기는 좌우 또는 상하를 반전시킵니다.
색상 변환은 밝기, 대비, 채도를 조정합니다. 이런 증강 기법들은 학습 데이터의 다양성을 높여서 과적합을 방지하고, 모델의 일반화 성능을 크게 향상시킵니다.
다음 코드를 살펴봅시다.
from torchvision import transforms
# 랜덤 수평 뒤집기: 50% 확률로 좌우 반전
horizontal_flip = transforms.RandomHorizontalFlip(p=0.5)
# 랜덤 회전: -10도에서 +10도 사이로 회전
rotation = transforms.RandomRotation(degrees=10)
# 색상 지터: 밝기, 대비, 채도, 색조를 무작위로 조정
color_jitter = transforms.ColorJitter(
brightness=0.2, # 밝기를 ±20% 조정
contrast=0.2, # 대비를 ±20% 조정
saturation=0.2, # 채도를 ±20% 조정
hue=0.1 # 색조를 ±10% 조정
)
# 그레이스케일 변환: 10% 확률로 흑백으로
grayscale = transforms.RandomGrayscale(p=0.1)
김개발 씨는 처음으로 모델 학습을 완료했습니다. 학습 데이터에서 90%라는 훌륭한 정확도가 나왔습니다.
기뻐하며 실제 데이터로 테스트했는데, 정확도가 60%로 떨어졌습니다. 무언가 잘못되었습니다.
박시니어 씨가 학습 곡선을 보더니 말했습니다. "전형적인 과적합이네요.
모델이 학습 데이터만 외워버렸어요. 데이터 증강을 해야 합니다." 그렇다면 데이터 증강이란 정확히 무엇일까요?
쉽게 비유하자면, 데이터 증강은 마치 같은 사진을 여러 각도에서 찍는 것과 같습니다. 정면에서 찍은 고양이, 약간 기울어진 고양이, 좌우가 뒤집힌 고양이 모두 같은 고양이입니다.
이렇게 다양한 변형을 보여주면 모델은 "본질"을 학습하게 됩니다. 데이터 증강이 없던 시절에는 어땠을까요?
모델은 학습 데이터의 세세한 패턴까지 외워버렸습니다. 고양이가 항상 왼쪽을 보고 있으면, 오른쪽을 보는 고양이를 인식하지 못했습니다.
일반화 성능이 형편없었습니다. 더 큰 문제는 더 많은 데이터를 수집해야 한다는 점이었습니다.
데이터 수집은 비용이 많이 들고 시간도 오래 걸립니다. 바로 이런 문제를 해결하기 위해 데이터 증강 기법이 등장했습니다.
회전, 뒤집기, 색상 변환을 사용하면 기존 데이터로부터 무한한 변형을 만들 수 있습니다. 또한 모델이 본질적인 특징을 학습하게 됩니다.
무엇보다 추가 데이터 수집 없이 성능을 크게 향상시킬 수 있다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 RandomHorizontalFlip(p=0.5)은 50% 확률로 이미지를 좌우 반전합니다. 고양이가 왼쪽을 보든 오른쪽을 보든 같은 고양이입니다.
다음으로 RandomRotation(degrees=10)은 -10도에서 +10도 사이로 무작위 회전합니다. 약간 기울어진 이미지에도 강건해집니다.
ColorJitter는 색상 관련 증강을 한 번에 처리합니다. 밝기, 대비, 채도, 색조를 각각 조정합니다.
예를 들어 brightness=0.2는 원래 밝기의 80%에서 120% 사이로 변경합니다. 이는 조명 조건 변화에 강건한 모델을 만듭니다.
RandomGrayscale(p=0.1)은 10% 확률로 이미지를 흑백으로 만듭니다. 이를 통해 모델이 색상에만 의존하지 않고 형태도 학습하게 됩니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 자율주행 자동차의 표지판 인식 시스템을 개발한다고 가정해봅시다.
실제 도로에서 표지판은 다양한 각도, 조명, 날씨에서 나타납니다. 회전, 색상 변환, 밝기 조정 등의 증강을 적용하면 이런 다양한 상황에 강건한 모델을 만들 수 있습니다.
테슬라 오토파일럿은 이런 증강 기법을 적극 활용합니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 과도한 증강입니다. 예를 들어 90도 회전을 적용하면 고양이가 거꾸로 서 있게 됩니다.
이는 현실적이지 않습니다. 따라서 도메인에 맞는 적절한 증강을 선택해야 합니다.
또 다른 실수는 테스트 데이터에도 증강을 적용하는 것입니다. 증강은 학습 시에만 사용해야 합니다.
테스트 시에는 원본 이미지로 평가해야 공정합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 조언대로 증강을 적용한 김개발 씨는 모델을 다시 학습시켰습니다. 이번에는 테스트 정확도가 82%까지 올랐습니다.
"데이터 증강의 효과가 정말 놀랍네요!" 회전, 뒤집기, 색상 변환을 제대로 이해하면 적은 데이터로도 높은 성능을 얻을 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 도메인에 맞는 적절한 증강을 선택하세요. 과도한 증강은 오히려 해롭습니다.
- 증강은 학습 시에만 적용하고, 테스트 시에는 사용하지 마세요.
- ColorJitter로 다양한 조명 조건에 강건한 모델을 만드세요.
5. torchvision.transforms 활용
김개발 씨가 여러 증강 기법을 코드로 작성하다 보니 코드가 길어지고 복잡해졌습니다. 박시니어 씨가 말했습니다.
"transforms.Compose를 사용하면 훨씬 깔끔해요." 어떻게 사용하는 걸까요?
torchvision.transforms는 PyTorch에서 제공하는 이미지 변환 도구 모음입니다. 다양한 전처리와 증강 기법을 함수로 제공하며, Compose로 파이프라인을 구성할 수 있습니다.
학습용과 테스트용 변환을 분리하여 관리하면 코드가 간결하고 유지보수가 쉬워집니다.
다음 코드를 살펴봅시다.
from torchvision import transforms
# 학습용 변환 파이프라인
train_transform = transforms.Compose([
transforms.RandomResizedCrop(224), # 무작위 크롭
transforms.RandomHorizontalFlip(), # 좌우 뒤집기
transforms.RandomRotation(10), # 회전
transforms.ColorJitter(0.2, 0.2, 0.2, 0.1), # 색상 변환
transforms.ToTensor(), # 텐서 변환
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225]) # 표준화
])
# 테스트용 변환 파이프라인 (증강 없음)
test_transform = transforms.Compose([
transforms.Resize(256), # 크기 조정
transforms.CenterCrop(224), # 중앙 크롭
transforms.ToTensor(), # 텐서 변환
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225]) # 표준화
])
김개발 씨는 앞서 배운 모든 기법을 코드로 작성했습니다. 리사이즈, 크롭, 뒤집기, 회전, 색상 변환, 정규화까지 모두 적용했습니다.
그런데 코드가 너무 길어졌습니다. 변환마다 변수를 만들고, 순서대로 적용하는 코드가 반복되었습니다.
박시니어 씨가 코드를 보더니 웃었습니다. "좋은 시도예요.
하지만 transforms.Compose를 쓰면 훨씬 깔끔하게 만들 수 있어요." 그렇다면 transforms.Compose란 정확히 무엇일까요? 쉽게 비유하자면, Compose는 마치 공장의 컨베이어 벨트와 같습니다.
원료가 들어가면 여러 공정을 거쳐 완제품이 나옵니다. 이미지가 파이프라인에 들어가면 크롭, 뒤집기, 정규화를 차례로 거쳐 학습 가능한 텐서로 변환됩니다.
각 공정은 독립적이지만, 순서대로 실행됩니다. 파이프라인이 없던 시절에는 어땠을까요?
개발자들은 변환을 하나씩 수동으로 적용해야 했습니다. 코드가 길어지고, 순서를 실수하기 쉬웠습니다.
또한 학습용과 테스트용 변환을 별도로 관리하기 어려웠습니다. 더 큰 문제는 코드 재사용이 힘들다는 점이었습니다.
프로젝트마다 똑같은 코드를 다시 작성해야 했습니다. 바로 이런 문제를 해결하기 위해 transforms.Compose가 등장했습니다.
Compose를 사용하면 여러 변환을 하나의 객체로 묶을 수 있습니다. 또한 학습용과 테스트용 파이프라인을 명확히 분리할 수 있습니다.
무엇보다 코드가 간결하고 읽기 쉬워진다는 큰 이점이 있습니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 train_transform은 학습용 파이프라인입니다. 첫 단계는 RandomResizedCrop으로 무작위 증강을 합니다.
다음으로 RandomHorizontalFlip, RandomRotation, ColorJitter로 다양한 변형을 추가합니다. 이 모든 변환이 순서대로 적용됩니다.
마지막에는 항상 ToTensor()와 Normalize()가 옵니다. 이 순서는 매우 중요합니다.
ToTensor가 먼저 실행되어야 Normalize가 작동합니다. Normalize는 텐서에만 적용할 수 있기 때문입니다.
test_transform은 테스트용 파이프라인입니다. 학습용과의 차이점은 무작위 증강이 없다는 것입니다.
Resize와 CenterCrop으로 결정론적인 변환만 수행합니다. 테스트는 재현 가능해야 하기 때문입니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 의료 영상 분석 프로젝트를 진행한다고 가정해봅시다.
CT 스캔 이미지를 분류하는 모델을 만듭니다. 학습용 파이프라인에는 회전, 뒤집기, 밝기 조정을 포함시킵니다.
테스트용에는 크기 조정과 정규화만 적용합니다. 이렇게 분리하면 학습과 평가를 명확히 구분할 수 있습니다.
또한 파이프라인을 함수나 클래스로 만들어 재사용할 수 있습니다. 여러 프로젝트에서 같은 변환 설정을 쉽게 공유할 수 있습니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 변환 순서를 잘못 지정하는 것입니다.
예를 들어 Normalize를 ToTensor() 앞에 두면 에러가 발생합니다. PIL 이미지는 정규화할 수 없기 때문입니다.
따라서 항상 ToTensor를 먼저 실행해야 합니다. 또 다른 실수는 학습과 테스트에 같은 파이프라인을 사용하는 것입니다.
테스트에 무작위 증강을 적용하면 결과가 매번 달라집니다. 반드시 두 개의 파이프라인을 만들어야 합니다.
다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 조언대로 Compose를 사용한 김개발 씨는 코드를 리팩토링했습니다.
30줄이던 코드가 15줄로 줄어들었습니다. "이제야 깔끔한 코드가 되었네요!" transforms.Compose를 제대로 이해하면 유지보수하기 쉬운 데이터 파이프라인을 만들 수 있습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 학습용과 테스트용 파이프라인을 명확히 분리하세요.
- ToTensor는 항상 Normalize보다 먼저 실행되어야 합니다.
- 파이프라인을 함수나 설정 파일로 만들어 재사용하세요.
6. Albumentations 라이브러리
김개발 씨가 더 강력한 증강 기법이 필요해졌습니다. torchvision만으로는 부족했습니다.
박시니어 씨가 추천했습니다. "Albumentations를 써보세요.
훨씬 다양하고 빠릅니다." 어떤 라이브러리일까요?
Albumentations는 컴퓨터 비전을 위한 강력한 데이터 증강 라이브러리입니다. torchvision보다 훨씬 빠르고, 더 다양한 증강 기법을 제공합니다.
특히 바운딩 박스, 키포인트, 세그멘테이션 마스크 변환도 지원하여 객체 검출과 세그멘테이션 작업에 필수적입니다.
다음 코드를 살펴봅시다.
import albumentations as A
from albumentations.pytorch import ToTensorV2
import cv2
# Albumentations 변환 파이프라인
transform = A.Compose([
A.RandomResizedCrop(224, 224), # 무작위 크롭
A.HorizontalFlip(p=0.5), # 좌우 뒤집기
A.Rotate(limit=10, p=0.5), # 회전
A.ColorJitter(0.2, 0.2, 0.2, 0.1), # 색상 변환
A.GaussianBlur(blur_limit=(3, 7), p=0.3), # 가우시안 블러
A.RandomBrightnessContrast(p=0.3), # 밝기/대비
A.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]), # 정규화
ToTensorV2() # PyTorch 텐서 변환
])
# 이미지 적용
image = cv2.imread('cat.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
transformed = transform(image=image)['image']
김개발 씨의 프로젝트가 발전했습니다. 이제 단순 분류가 아니라 객체 검출을 해야 합니다.
고양이의 위치를 바운딩 박스로 표시해야 합니다. 문제는 이미지를 회전하면 바운딩 박스도 함께 회전해야 한다는 점이었습니다.
박시니어 씨에게 고민을 털어놓았습니다. "이미지와 바운딩 박스를 따로 변환하면 안 맞아요." 박시니어 씨가 답했습니다.
"Albumentations를 쓰면 자동으로 같이 변환됩니다." 그렇다면 Albumentations란 정확히 무엇일까요? 쉽게 비유하자면, Albumentations는 마치 전문 사진 편집 도구와 같습니다.
Photoshop이 일반 그림판보다 강력하듯이, Albumentations는 torchvision보다 훨씬 다양한 기능을 제공합니다. 또한 속도도 최적화되어 있어서 대용량 데이터셋 처리에 적합합니다.
고급 증강이 필요한 현업에서는 어떤 어려움이 있었을까요? torchvision은 기본적인 증강만 제공합니다.
예를 들어 가우시안 블러, 엘라스틱 변환, 그리드 왜곡 같은 고급 기법이 없습니다. 또한 바운딩 박스나 세그멘테이션 마스크를 이미지와 함께 변환하기 어렵습니다.
개발자들은 직접 수학 계산을 해서 좌표를 변환해야 했습니다. 실수하기 쉽고, 시간도 오래 걸렸습니다.
바로 이런 문제를 해결하기 위해 Albumentations가 등장했습니다. Albumentations를 사용하면 70개 이상의 다양한 증강 기법을 쓸 수 있습니다.
또한 바운딩 박스, 키포인트, 마스크를 이미지와 동기화하여 변환합니다. 무엇보다 속도가 매우 빠르다는 큰 이점이 있습니다.
벤치마크에서 torchvision보다 2-3배 빠릅니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 A.Compose()는 torchvision의 Compose와 비슷하지만, 더 강력합니다. A.GaussianBlur()는 torchvision에 없는 기능입니다.
이미지에 블러 효과를 추가하여 모델을 더욱 강건하게 만듭니다. A.RandomBrightnessContrast()는 밝기와 대비를 동시에 조정합니다.
ColorJitter와 비슷하지만 더 세밀한 제어가 가능합니다. ToTensorV2()는 Albumentations 전용 텐서 변환입니다.
torchvision의 ToTensor와 호환됩니다. 중요한 점은 이미지를 딕셔너리로 전달한다는 것입니다.
transform(image=image)처럼 키워드 인자를 사용합니다. 결과도 딕셔너리로 반환되므로 ['image']로 접근합니다.
바운딩 박스나 마스크도 같은 방식으로 함께 전달할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 자율주행 자동차의 차선 검출 시스템을 개발한다고 가정해봅시다. 도로 이미지와 함께 차선의 세그멘테이션 마스크가 있습니다.
Albumentations를 사용하면 이미지와 마스크를 완벽히 동기화하여 증강할 수 있습니다. 회전, 크롭, 왜곡 등을 적용해도 마스크가 정확히 따라옵니다.
Kaggle 대회에서도 Albumentations는 필수입니다. 상위권 솔루션 대부분이 이 라이브러리를 사용합니다.
강력한 증강은 모델 성능을 크게 향상시킵니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 너무 많은 증강을 동시에 적용하는 것입니다. 70개 기법을 모두 사용하면 이미지가 과도하게 왜곡됩니다.
도메인에 맞는 5-10개 정도만 선택해야 합니다. 또 다른 실수는 확률(p)을 무시하는 것입니다.
모든 증강을 p=1.0으로 설정하면 매번 모든 변환이 적용됩니다. 이미지가 너무 변형됩니다.
적절한 확률(보통 0.3-0.5)을 설정해야 자연스럽습니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 추천대로 Albumentations를 도입한 김개발 씨는 바운딩 박스 변환 문제를 깔끔하게 해결했습니다. 또한 다양한 증강으로 모델 성능이 5% 향상되었습니다.
"이제야 제대로 된 데이터 파이프라인이네요!" Albumentations를 제대로 이해하면 최고 수준의 데이터 증강 시스템을 구축할 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 바운딩 박스나 마스크가 있는 작업에서는 Albumentations를 필수로 사용하세요.
- 너무 많은 증강을 적용하지 말고, 도메인에 맞는 5-10개만 선택하세요.
- 각 증강의 확률(p)을 적절히 조정하여 자연스러운 변형을 만드세요.
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.