프로젝트용 GPU · KYC 없는 암호화폐 결제 대여 방법
한국어
콘솔 열기
실전 가이드 / KERNODECK

DataLoader가 차단될 때: worker보다 데이터를 먼저 확인하세요

num_workers=0과 고정된 순서로 시작하고, 샘플 하나를 확인한 다음 전체 배치를 확인하며, 읽기, 변환, 어셈블리, GPU 전송을 분리하세요. 그런 다음 worker를 점진적으로 다시 도입하세요. GPU가 기다린다고 해서 스토리지가 느리다는 증거는 아닙니다. 데이터 오류, 직렬화 또는 비용이 큰 어셈블리가 연산 전에 체인을 차단할 수 있습니다.

6 분 소요 · 개발자 가이드

로더가 제공해야 할 것을 정의하기

최적화하기 전에 출력 계약을 작성하세요. 항목 수, 각 필드의 타입, 차원, 타깃 범위, 불완전한 입력에 대한 규칙입니다. 예제의 식별자와 배치 내 위치를 구분하세요. 변환이 형태를 바꾸거나 입력을 필터링할 수 있습니다. 학습 프로그램은 이것이 허용되는지 알아야 합니다.

일반 파일, 경계 사례, 데이터셋의 마지막 항목을 포함하는 대표 샘플을 선택하세요. Dataset와 정확히 동일한 준비 과정으로 각 항목을 여세요. 그런 다음 그들의 어셈블리를 살펴보세요. 개별 접근이 성공했다고 해서 여러 결과를 쌓을 수 있다는 증거는 아닙니다. 텍스트의 경우 padding과 마스크를, 이미지의 경우 채널, 차원, 축 순서를 문서화하세요.

범위를 정하세요. 데이터가 로컬인지 원격인지, 디코딩 포함 여부, 변환이 고정인지 무작위인지입니다. 두 설정 사이에 유지하세요. 겉으로 보이는 이득은 제거된 작업에서 비롯될 수 있습니다.

오류를 읽기 위해 단일 프로세스로 돌아가기

먼저 num_workers=0, shuffle=False, 작은 배치로 재현하세요. 그러면 로딩이 메인 프로세스에서 실행되어 오류 추적이 일반적으로 더 읽기 쉽습니다. DataLoader 문서는 디버깅을 위해 이 방법을 권장합니다. 민감한 내용을 로그에 복사하지 않고, 실패하는 항목의 식별자를 디코딩 전에 기록하세요.

분리하여 진행하세요. 원시 접근, 변환, collate_fn, 그다음 전송입니다. 전송 전에 과정이 실패한다면 CUDA를 수정하는 것이 첫 번째 단서는 아닙니다. 여러 worker에서만 차단된다면 해당 프로세스에 전달된 객체와 리소스를 살펴보세요. 첫 반복과 그다음 반복을 비교하세요. worker 시작이 초기 대기를 설명할 수 있지만, 반복되는 문제를 입증하지는 않습니다.

timeout은 대기를 가시화할 수 있지만, 사용할 수 없는 소스나 차단된 worker를 고치지는 못합니다. 이 타임아웃을 무한정 늘리는 대신 마지막으로 알려진 단계를 유지하고 입력 수를 줄이세요.

실습 예제: 세 개의 채널이 예상되지만 다른 이미지

네 개의 교육용 레코드를 생각해 봅시다. 처음 세 개는 [3, 16, 16] 형태의 텐서를 제공하고, 네 번째는 [1, 16, 16]을 제공합니다. 세 개의 채널을 요구하는 계약에서는 네 번째 항목을 어셈블리 전에 식별해야 합니다. 이 시나리오는 여기서 실행되지 않았습니다. 선택한 형태를 바탕으로 예상되는 결과를 설명합니다.

아래 함수는 각 레코드가 id, x, y 필드를 가지며, x는 CPU 텐서이고 y는 정수 인덱스라고 가정합니다. 이미지를 조용히 삭제하는 대신 불일치를 거부합니다. 프로젝트에서는 흑백 이미지를 세 개의 채널로 변환해야 하는지, 아니면 가져올 때 거부해야 하는지 명시적으로 결정하세요. 이 결정은 데이터의 의미와 모델이 기대하는 전처리에 따라 달라집니다.

수정 후에는 네 개의 식별자가 모두 남아 있어야 하며, 어셈블된 텐서는 [4, 3, 16, 16] 형태여야 합니다. 타깃에 맞는 가드를 추가하세요. 차원이 올바른 이미지라도 유효하지 않은 어노테이션을 가질 수 있습니다.

제안된 교육용 어셈블리, 실행되지 않음
import torch
from torch.utils.data import DataLoader

def assemble(records):
    for item in records:
        if tuple(item["x"].shape) != (3, 16, 16):
            raise ValueError(f"예상치 못한 형태: {item['id']}")
    return {
        "ids": [item["id"] for item in records],
        "x": torch.stack([item["x"] for item in records]),
        "y": torch.tensor([item["y"] for item in records],
                          dtype=torch.long),
    }

# dataset은 설명된 레코드를 생성하는 Dataset입니다.
# 멀티프로세스 스크립트에서는 main 가드 아래에서 loader를 생성하세요.
if __name__ == "__main__":
    loader = DataLoader(dataset, batch_size=4, num_workers=0,
                        shuffle=False, collate_fn=assemble)
    iterator = iter(loader)
    batch = next(iterator)

데이터를 바꾸지 않고 워커 다시 도입하기

batch, 순서, 변환을 유지한 채 워커를 0에서 소수로 늘려보세요. 한 에포크를 완전히 테스트한 뒤 두 번째도 테스트하세요. 일부 오류는 이터레이터가 재시작될 때나 자원이 소비된 뒤에야 나타납니다. 병렬 처리를 늘리는 것은 준비 작업이 실제로 병렬로 진행될 수 있을 때만 유용합니다.

시작 방식은 시스템과 Python 버전에 따라 다릅니다. spawn을 사용하는 경우 프로그램 진입점을 if __name__ == '__main__'으로 보호하고, Dataset, collate_fn, 워커 함수를 지역 람다가 아니라 모듈 수준에서 정의하세요. 프로세스 문서에서는 상속된 잠금이나 스레드가 교착 상태를 일으킬 수 있는 이유도 설명합니다. 라이브러리가 요구하는 경우 각 프로세스에 고유한 접근 초기화를 유지하세요.

IterableDataset의 경우 식별자를 통해 워커 간 분할을 확인하세요. 여러 워커가 각자 동일한 스트림 전체를 소비해서는 안 됩니다. 배치 개수만 판단하지 말고 중복과 누락된 요소도 찾아보세요.

명확한 단위로 대기 시간과 처리량 측정하기

두 가지 상호 보완적인 관찰을 사용하세요. 로더만 순회하면 정해진 구간 동안 준비된 예시 개수를 셀 수 있습니다. 통합 순회는 모델이 이 데이터를 소비할 때 어떤 일이 일어나는지 살펴봅니다. 전자는 준비 과정을 분리하는 데 도움이 되지만, 훈련 처리량을 자동으로 나타내지는 않습니다.

프로토콜에서는 실제로 전달된 예시 개수를 세고, 경과한 초로 나누세요. 시작 구간, 데이터 캐시, 변환, 반복 횟수 등 제외한 실행을 명시하세요. 가장 좋은 값만 고르지 말고 각 실행의 값을 유지하세요. 아래 표는 기록지이며, 어떤 성능 수치도 미리 채워져 있지 않습니다.

형태가 다양하면 초당 예시 개수가 부하 변화를 감출 수 있습니다. 디코딩된 픽셀이나 실제로 준비된 토큰 등 적절한 단위를 추가하되 예시 개수도 함께 유지하세요. 전체 루프에서 대기 지점을 찾으려면 다음 배치 읽기를 계산과 별도로 명명하세요.

표의 모든 열을 보려면 스크롤하세요.
여러분의 부하로 채우는 기록지, 가정된 성능 수치 없음
설정확인한 항목관측된 시간기대 결론
workers=0식별자, 형태, 타깃초 단위로 측정올바른 기준
소수의 워커동일한 입력 집합초 단위로 측정실제 이득 또는 추가 비용
동일 설정, 두 번째 에폭손실이나 중복 없음초 단위로 측정시작과 캐시의 영향

메모리, 프리페칭, 전송을 각각 다루기

워커와 대기 중인 배치는 호스트 메모리를 소비합니다. VRAM만 중요하다고 결론 내리기 전에 실험 중 메모리를 모니터링하세요. 더 깊은 프리페칭은 점유율을 높이면서 대기 지점을 옮길 수 있지만, 초당 처리 결과가 더 많아진다고 보장하지는 않습니다. 먼저 의심되는 변수를 줄이고 동일한 범위에서 비교하세요.

pin_memory와 비블로킹 전송은 가속기로 데이터를 넘기는 것과 관련됩니다. PyTorch 최적화 가이드에서는 이를 하드웨어와 부하에 맞춰 검토할 요소로 제시합니다. 이들은 잘못된 디코딩을 고쳐 주지는 않습니다. 먼저 워커에서 CPU 데이터로 시작한 다음, 계산을 주도하는 프로세스에서 전송을 구성하세요. 이득과 실제 중첩은 가정하지 말고 관찰해야 합니다.

persistent_workers를 사용한다면 두 에포크 사이에 유지되는 리소스와 상태를 고려하세요. 단일 배치에서 만족스러운 설정만으로는 파일 닫힘 또는 소스 갱신을 검증하기에 충분하지 않습니다.

데이터가 올바르게 유지될 때만 설정을 수용하세요

기대하는 결과는 선택한 프레임 안에서 조용한 오류 없이 모든 예정된 입력을 받는 루프입니다. 최적화 전후의 식별자와 타깃을 비교하세요. 마지막 불완전한 배치를 제외한다면 drop_last를 설명하세요. 변환이 무작위라면 그러한 정책과 모순되는 픽셀 동일성을 요구하기보다 그 정책을 점검하세요.

측정된 필요를 충족하는 가장 단순한 설정을 유지하세요. 스토리지, 디코딩 또는 모델이 이미 한계를 정하고 있다면 워커 수를 늘려도 아무것도 개선되지 않을 수 있습니다. 서버의 CPU, RAM 및 스토리지 리소스는 GPU 이름만으로 추정할 수 없습니다. Kernodeck 환경을 준비할 때 이러한 필요를 별도로 명시하세요.

자주 묻는 질문

num_workers=0은 GPU 학습을 비활성화하나요?

아니요. 데이터 로딩을 메인 프로세스에 배치할 뿐입니다. 모델은 여전히 GPU에서 계산할 수 있습니다. 이 설정은 무엇보다 읽기, 변환 및 조립 오류를 더 직접적으로 읽을 수 있게 해줍니다.

CPU 코어 수만큼 워커를 선택해야 하나요?

자동은 아닙니다. 적절한 설정은 준비 작업, 메모리, 데이터 접근 및 모델의 소비 속도에 따라 달라집니다. 동일한 부하를 유지하고 전달되는 입력을 점검하면서 몇 가지 값을 비교하세요.

더 작은 배치가 중단되는 워커를 고치나요?

메모리 압박은 바뀔 수 있지만, 잘못된 주석, 직렬화할 수 없는 자원, 읽을 수 없는 파일을 고치지는 못합니다. 먼저 워커 0으로 재현하여 원인 단계를 파악하세요.

next(iterator)에 소요된 시간이 디스크를 측정하나요?

아니요. iterator=iter(loader) 후 next(iterator)는 배치를 기다립니다. 디코딩, 변환, 조립, 프로세스 간 통신 및 사전 로딩이 개입할 수 있습니다. 읽기 전용 측정과 전체 루프 추적은 서로 다른 질문에 답합니다.