728x90
반응형

💬 왜 "데이터 적재와 전처리"를 따로 배우는 걸까?

딥러닝 모델은 데이터를 먹고 자랍니다.
데이터 없으면 아무것도 못 합니다.

문제:

초창기에는 사람들이 작은 데이터셋으로만 실험했음.
(예: MNIST 손글씨 6만장, CIFAR-10 이미지 5만장)

👉 데이터를 메모리에 "한 번에" 다 올려놓고 학습하면 됐었습니다.

하지만 현실에서는?

  • 데이터가 너무 큼. (1억 장 사진, 10억 개 로그 기록)
  • 메모리에 한 번에 못 담음. (RAM 16GB, 데이터 1TB...)

해결해야 할 문제:

  1. 메모리에 다 올릴 수 없는데 어떻게 모델에 먹일까?
  2. 디스크에서 읽을 때 속도가 느리면 학습이 멈추는데 어떻게 할까?
  3. 파일이 여러 개면 어떻게 효율적으로 읽을까?
  4. 데이터가 편향돼 있으면 학습이 이상해지는데 순서를 어떻게 섞을까?

 

📌 그래서 등장한 것

👉 TensorFlow tf.data.Dataset API

  • 데이터를 조각조각 나눠서 메모리로 가져오고
  • 한 줄씩 읽거나, 몇 개씩 묶어서 신경망에 보내고
  • 미리 준비해서 신경망이 굶지 않게 하고
  • 랜덤하게 섞어서 다양하게 학습하도록 도와주는

데이터 전용 파이프라인.

 

1️⃣ tf.data.Dataset.from_tensor_slices()

  • 작은 데이터를 메모리에 다 넣을 수 있을 때 사용.
  • 예를 들어, 이미지 1만 장, 레이블 1만 개 → 작은 텐서에 저장 가능.

왜 만들었을까?

  • 딥러닝 라이브러리는 모든 걸 "Dataset" 객체로 통일해서 처리하고 싶음.
  • 그래야 shuffle, batch, repeat 같은 작업을 일관되게 할 수 있음.

어떻게 동작해?

  • 큰 텐서를 조각조각 나눠서 한 줄씩 꺼낼 수 있게 만듦.

2️⃣ repeat(), batch(), map()

왜 필요할까?

  • repeat()
    → 데이터가 한 번만 있으면 훈련 다 못 함. 여러 번 반복해야 함.
  • batch()
    → 딥러닝은 여러 개 데이터를 한꺼번에 처리할 때 성능이 좋음. (GPU 병렬처리)
  • map()
    → 원본 데이터를 그대로 쓰면 안 되고, 전처리해야 함. (예: 정규화, augmentation)

3️⃣ shuffle(buffer_size)

왜 섞어야 할까?

  • 학습할 때 같은 패턴만 계속 나오면 모델이 편향(bias)됨.
  • 예를 들어, 집값 예측 데이터가 지역별로 정렬돼 있다면?
    • 싼 동네만 계속 학습하다가
    • 갑자기 비싼 동네 나오면 모델이 못 맞추지 못함.

shuffle()이 해결하는 것:

  • 무작위로 데이터를 섞어서 모델이 고르게 다양한 데이터를 보게 해줌.
  • buffer size로 메모리 크기 조절

4️⃣ 메모리가 부족할 때: 파일 여러 개로 쪼개기 + interleave()

왜 파일을 나눌까?

  • 하나의 파일이 너무 크면
    • 읽는데 시간이 오래 걸림.
    • 디스크 입출력이 bottleneck(병목) 걸림.

그래서

  • 데이터를 여러 파일로 쪼갠다.
  • 동시에 여러 파일을 읽는다.
  • **interleave()**를 쓰면 한 줄씩 번갈아 읽을 수 있다.

interleave() 핵심:

  • 파일 A, 파일 B, 파일 C를
  • 한 줄 A, 한 줄 B, 한 줄 C 식으로 번갈아 가져옴
  • 학습이 훨씬 다양해지고 빨라짐.

5️⃣ prefetch(1)

왜 필요할까?

  • GPU는 아주 빠름.
  • CPU가 데이터를 준비 못하면 GPU가 놀게됨 (시간 낭비).

prefetch()가 하는 일:

  • "현재 배치를 학습하는 동안"
  • "다음 배치를 미리 준비해서 기다리게 함"

그래서
→ GPU를 최대한 쉬지 않고 100% 사용 가능.

전체 흐름 정리

 

 

  • 데이터가 너무 커서 메모리에 다 못 올린다.
  • Dataset API로 파일을 조각조각 읽는다.
  • repeat를 해서 모델이 잘 학습할 수 있게 csv 파일을 중첩시킨다.
  • interleave로 파일마다 한줄씩 읽는다.
  • shuffle을 해서 데이터를 섞고 buffer size를 통해 메모리의 크기에 맞춰준다.
  • map으로 전처리(정규화, 파싱 등)를 해준다.
  • prefetch로 다음 배치를 미리 준비해서 GPU를 계속 굴린다.
  • 만들어진 데이터셋을 model.fit() 에 바로 넣어서 훈련한다.

 

비유하자면 !

 

  • Dataset API = "자동으로 데이터 요리해주는 주방"
  • 모델 = "배고픈 손님"
  • batch = "한 접시에 여러 음식 담기"
  • shuffle = "음식 순서를 무작위로 섞기"
  • map = "요리사가 음식에 소스 바르기"
  • prefetch = "손님이 먹고 있는 동안 다음 음식을 준비"

 

주요 동작들

from_tensor_slices() 텐서를 dataset으로 변환
map() 각 데이터를 전처리하는 함수 적용
shuffle() 데이터 순서 섞기
batch() 여러 데이터를 묶기
repeat() 데이터 반복
interleave() 여러 파일에서 한 줄씩 번갈아 읽기
prefetch() 다음 데이터를 미리 준비하기

 

 

# shuffle(buffer_size)

dataset = dataset.shuffle(1000)

✅ 내부 동작:

  1. 데이터를 1000개까지 메모리 버퍼에 쌓음
  2. 그 중 랜덤하게 하나 꺼내서 반환
  3. 새 데이터를 하나 읽어와서 다시 버퍼에 채움
  4. 반복

이걸 통해 모델이 데이터 순서에 과적합하지 않게 도와줌.

✅ seed를 주면?

  • 매번 같은 셔플 순서를 보장 → 디버깅할 때 유용

# interleave()

 
dataset = filepath_dataset.interleave(
    lambda filepath: tf.data.TextLineDataset(filepath).skip(1),
    cycle_length=5
)

✅ 내부 동작:

  • filepath_dataset에 여러 파일 경로가 있을 때
  • 동시에 5개를 열고, 각 파일에서 한 줄씩 번갈아 읽음

✅ 중요한 옵션:

  • cycle_length: 동시에 몇 개의 파일을 읽을지
  • block_length: 한 파일에서 몇 줄씩 읽고 다른 파일로 넘어갈지
  • num_parallel_calls: 병렬 읽기 개수

📌 왜 쓰냐?

  • 데이터를 다양한 파일에서 균형 있게 읽고, IO 병목을 줄이기 위해

 

728x90
반응형

+ Recent posts