Programming Language/Python

[err 해결] python 멀티프로세싱 - EOFError: Ran out of input

brong 2024. 8. 9. 16:49
728x90
Traceback (most recent call last):
  File "C:\\Users\\Administrator\\Desktop\\gpf\\GPF_24_team\\pretrain-gnns\\chem\\pretrain_edgepred.py", line 112, in <module>
    main()
  File "C:\\Users\\Administrator\\Desktop\\gpf\\GPF_24_team\\pretrain-gnns\\chem\\pretrain_edgepred.py", line 103, in main
    train_acc, train_loss = train(args, model, device, loader, optimizer)
  File "C:\\Users\\Administrator\\Desktop\\gpf\\GPF_24_team\\pretrain-gnns\\chem\\pretrain_edgepred.py", line 32, in train
    for step, batch in enumerate(tqdm(loader, desc="Iteration")):
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\site-packages\\tqdm\\std.py", line 1181, in __iter__
    for obj in iterable:
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\site-packages\\torch\\utils\\data\\dataloader.py", line 368, in __iter__
    return self._get_iterator()
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\site-packages\\torch\\utils\\data\\dataloader.py", line 314, in _get_iterator
    return _MultiProcessingDataLoaderIter(self)
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\site-packages\\torch\\utils\\data\\dataloader.py", line 927, in __init__
    w.start()
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\multiprocessing\\process.py", line 121, in start
    self._popen = self._Popen(self)
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\multiprocessing\\context.py", line 224, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\multiprocessing\\context.py", line 327, in _Popen
    return Popen(process_obj)
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\multiprocessing\\popen_spawn_win32.py", line 93, in __init__        
    reduction.dump(process_obj, to_child)
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\multiprocessing\\reduction.py", line 60, in dump
    ForkingPickler(file, protocol).dump(obj)
AttributeError: Can't pickle local object 'DataLoaderAE.__init__.<locals>.<lambda>'
PS C:\\Users\\Administrator\\Desktop\\gpf\\GPF_24_team\\pretrain-gnns\\chem> Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\multiprocessing\\spawn.py", line 116, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "C:\\ProgramData\\anaconda3\\envs\\gpf_3_9_19\\lib\\multiprocessing\\spawn.py", line 126, in _main
    self = reduction.pickle.load(from_parent)
EOFError: Ran out of input

 

원인

  • Python - multiprocessing 모듈 사용할 때 발생
  • multiprocessing 모듈이 로컬 함수 or 람다 함수 같이 피클 (pickle)할 수 없는 객체를 직렬화하려 시도할 때 발생

 

코드

 

def train(args, model, device, loader, optimizer):
    model.train()

    train_acc_accum = 0
    train_loss_accum = 0

    for step, batch in enumerate(tqdm(loader, desc="Iteration")):
  • train() 함수에서 loader 호출
    loader = DataLoaderAE(dataset, batch_size=args.batch_size, shuffle=True, num_workers = args.num_workers)
  • loader는 DataLoaderAE 클래스
    • num_workers = 8 (default) 로 설정되어있음. → 멀티프로세싱
class DataLoaderAE(torch.utils.data.DataLoader):

    def __init__(self, dataset, batch_size=1, shuffle=True, **kwargs):
        super(DataLoaderAE, self).__init__(
            dataset,
            batch_size,
            shuffle,
            collate_fn=lambda data_list: BatchAE.from_data_list(data_list),
            **kwargs)

dataloader.py > class DataLoaderAE

  • 람다 함수는 피클링 불가하기 때문에 멀티프로세싱 환경에서 전달하면 안 됨.
  • 그런데 DataLoaderAE 클래스에서 collate_fn 에 람다 함수가 사용되고 있던 것!

 

해결1: 멀티프로세싱 하지마.

  • num_workers = 0 으로 셋팅하면 됨.
  • 단, 데이터 로드-전처리 병렬 처리 불가 ⇒ 학습 속도 느려짐 ⇒ 싫어 !!

 

해결2: 람다 함수를 일반 함수로 변경하기

# dataloader.py line 56 ~, DataLoaderAE 부분 
def __init__(self, dataset, batch_size=1, shuffle=True, **kwargs):
        super(DataLoaderAE, self).__init__(
            dataset,
            batch_size,
            shuffle,
            collate_fn=self.my_collate_fn,
            **kwargs)

    @staticmethod
    def my_collate_fn(data_list):
        return BatchAE.from_data_list(data_list)
  • collate_fn 에서 람다 함수 제거하고 함수로 바로 매핑
  • 이 때 이 함수 my_collate_fn()는 정적 메서드로 정의
    • 정적 메서드 → 피클링 가능함.

 

피클링이란?

python에서 객체를 직렬화(serialize)하는 과정.

 

직렬화: python 객체(리스트, 딕셔너리, 클래스 인스턴스 등) → 바이트 스트림 형태

역직렬화: 바이트 스트림 → python 객체 (→ 언피클링)

 

직렬화된 바이트 스트림은 파일로 저장하거나 네트워크를 통해 전송할 수 있음.

 

언제 사용하는가?

  • 데이터 저장, 네트워크 통신, 병렬 처리 시에 사용
  • 병렬 처리 - 멀티프로세싱 환경에서 프로세스 간 객체 전달할 때 사용됨!

제한 사항

  • 피클링할 수 없는 객체: 파이썬 파일 핸들, 네트워크 소켓, 람다 함수
    • → 실행 환경에 종속적 or 메모리 주소에 기반한 객체이기 때문!
  • 보안 위험: 신뢰할 수 없는 데이터 언피클링 하는 것 조심 ~~

파이썬 multiprocessing 모듈

  • 프로세스 간 데이터 주고받을 때 피클링 사용.
  • 멀티프로세싱 환경에서 전달되는 모든 객체는 피클링 가능해야 함.
  • → 람다 함수, 로컬 함수 등 있으면 오류