본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] 데이터 증강 파이프라인 가속화를 위한 itertools 및 functools 2가지 조합 방법과 해결책

by Papa Martino V 2026. 4. 22.
728x90

itertools & functools
itertools & functools

 

 

딥러닝 모델의 성능을 결정짓는 핵심 요소 중 하나는 데이터의 다양성입니다. 하지만 수만 장의 이미지를 메모리에 모두 올리고 증강(Augmentation)을 수행하는 것은 물리적인 한계가 따릅니다. 대부분의 개발자는 리스트(List) 기반의 처리에 익숙하지만, 이는 대규모 데이터셋에서 심각한 메모리 병목을 초래합니다. 이 문제를 해결하기 위한 가장 우아하고 강력한 해결책은 파이썬의 표준 라이브러리인 itertoolsfunctools.partial을 조합하는 것입니다. 이 조합은 '지연 평가(Lazy Evaluation)'를 통해 메모리 점유율을 0에 가깝게 유지하면서도, 함수형 프로그래밍 스타일로 복잡한 증강 파이프라인을 선언적으로 구축할 수 있게 해줍니다. 본 포스팅에서는 엔지니어링 관점에서 이 두 모듈의 조합이 데이터 파이프라인의 효율성을 어떻게 극대화하는지 심층적으로 다룹니다.


1. 전통적 방식 vs Itertools + Partial 조합의 구조적 차이

데이터 증강 시 발생하는 오버헤드와 이를 해결하는 두 방식의 기술적 차이를 표로 요약하였습니다.

비교 항목 기존 방식 (List/Loop) Itertools + Partial 조합 실무적 이점
평가 방식 Eager (즉시 생성) Lazy (지연 생성) 대규모 데이터셋에서도 OOM 방지
메모리 사용량 데이터 수에 비례 (O(N)) 상수 수준 (O(1)) 저사양 서버에서도 대용량 처리 가능
함수 유연성 하드코딩된 인자 전달 partial을 통한 인자 고정 증강 파라미터 제어가 매우 간결함
파이프라인 결합 중첩된 for문 또는 함수 호출 itertools.chain/islice 조합 선언적이고 읽기 쉬운 코드 구조
처리 속도 순차적 리스트 생성 오버헤드 필요 시점에만 연산 초기 응답 속도 및 스루풋 향상

2. 실무에 즉시 적용 가능한 데이터 증강 Example (7+)

itertools와 functools를 활용해 개발자가 실무 프로젝트에서 바로 활용할 수 있는 7가지 핵심 해결책입니다.

Ex 1. functools.partial로 맞춤형 증강 함수 고정하기

from functools import partial
import numpy as np

def rotate_image(image, angle):
    # 실제 회전 로직 (예시)
    return f"Image rotated by {angle} degrees"

# 각기 다른 각도를 가진 증강 함수들을 미리 생성
rotate_90 = partial(rotate_image, angle=90)
rotate_180 = partial(rotate_image, angle=180)

# 호출 시 이미지 인자만 전달하면 됨
print(rotate_90("img_data"))

Ex 2. itertools.product를 이용한 증강 파라미터 조합 생성

import itertools

angles = [0, 90, 180]
flips = [True, False]
brightness = [0.8, 1.0, 1.2]

# 가능한 모든 증강 조합을 메모리 소모 없이 생성
aug_combinations = itertools.product(angles, flips, brightness)

for angle, flip, bright in aug_combinations:
    # 이 시점에만 조합이 생성되어 메모리 효율적임
    process_pipeline(angle, flip, bright)

Ex 3. itertools.cycle을 활용한 무한 데이터 스트림 구축

import itertools

# 소규모 데이터셋을 무한히 반복하여 학습 루프에 공급
raw_data = ["sample_1", "sample_2", "sample_3"]
infinite_loader = itertools.cycle(raw_data)

# 에폭(Epoch) 제한 없이 데이터를 계속해서 증강 파이프라인에 주입 가능
batch = [next(infinite_loader) for _ in range(10)]

Ex 4. itertools.islice를 활용한 메모리 효율적 배치(Batch) 슬라이싱

import itertools

def get_data_stream():
    for i in range(1000000):
        yield f"data_{i}"

stream = get_data_stream()
# 전체 데이터를 리스트로 변환하지 않고 100개씩 끊어서 처리
batch_1 = list(itertools.islice(stream, 100))

Ex 5. functools.partial과 map을 결합한 병렬 증강 예어

from functools import partial

# 특정 확률로 증강을 적용하는 고차 함수
def apply_with_prob(func, prob, data):
    if np.random.rand() < prob:
        return func(data)
    return data

# 50% 확률로 수평 뒤집기를 수행하는 특수 함수 생성
augment_flip = partial(apply_with_prob, flip_horizontal, 0.5)

# 데이터 스트림에 적용
augmented_stream = map(augment_flip, data_generator)

Ex 6. itertools.chain을 사용한 다중 소스 데이터 통합

import itertools

# 여러 폴더나 소스에서 오는 데이터를 하나의 파이프라인으로 병합
source_a = (f"A_{i}" for i in range(5))
source_b = (f"B_{i}" for i in range(5))

# 물리적으로 합치지 않고 논리적으로 연결하여 순회
combined_pipeline = itertools.chain(source_a, source_b)
for data in combined_pipeline:
    print(data)

Ex 7. 복합 파이프라인: 고정된 파라미터와 제너레이터의 조합

def final_pipeline(data_stream, aug_func):
    """partial로 정의된 함수를 itertools 스트림에 적용"""
    return map(aug_func, data_stream)

# 1. 원본 제너레이터
data = (f"img_{i}" for i in range(1000))
# 2. 증강 함수 고정
my_aug = partial(rotate_image, angle=45)
# 3. 파이프라인 연결 (실행 전까지 아무 연산도 안 함)
pipeline = final_pipeline(data, my_aug)

# 4. 실제 소비 시점에만 동작
for result in itertools.islice(pipeline, 5):
    print(result)

3. 이 조합이 해결하는 3가지 핵심 문제와 주의점

  1. 메모리 고갈 해결: itertools는 이터레이터를 반환하므로 수억 개의 데이터 증강 시나리오를 설계해도 실제 사용 전까지는 메모리를 거의 점유하지 않습니다.
  2. 코드 복잡도 해결: functools.partial을 사용하면 수많은 매개변수를 가진 증강 함수를 단일 인자 함수처럼 취급할 수 있어, map이나 filter와 같은 고차 함수와의 결합이 매우 용이해집니다.
  3. 유지보수성 향상: 파이프라인의 각 단계가 독립적인 이터레이터로 분리되어 있어, 특정 증강 단계를 추가하거나 제거하는 것이 리스트 가공 방식보다 훨씬 간결합니다.

주의점: 이터레이터는 한 번 소비(Consumption)되면 다시 사용할 수 없습니다. 만약 동일한 증강 데이터를 여러 번 순회해야 한다면 itertools.tee를 사용하거나, 데이터 소스를 다시 생성하는 로직이 필요합니다.


4. 결론: 왜 현대적 AI 파이프라인에 필수적인가?

결론적으로 itertoolsfunctools.partial의 조합은 파이썬이 제공하는 **'함수형 최적화'의 정수**입니다. 데이터 증강은 단순한 반복 작업이 아니라, 자원을 얼마나 효율적으로 분배하느냐의 싸움입니다. 이 기법을 통해 개발자는 하드웨어의 한계를 뛰어넘어 고도의 정밀함을 갖춘 데이터 스트리밍 시스템을 구축할 수 있습니다. 단순 루프에서 벗어나 선언적이고 지연 평가를 활용하는 파이프라인으로 전환하는 것, 그것이 바로 대규모 머신러닝 시스템의 안정성을 해결하는 가장 확실한 방법입니다.


참고 출처

  • Python Software Foundation - Standard Library: itertools, functools Documentation
  • "Fluent Python" (2nd Edition) - Luciano Ramalho (Iterators and Generators Chapter)
  • Python Cookbook (3rd Edition) - David Beazley (Functions and Iterators Chapter)
  • Real Python - "Python's itertools: A Guide to Iterators and Generators"
728x90