근황 토크 및 자유게시판/TIL

[Pytorch] 네부캠 day-12

scone 2023. 11. 17. 20:38

Hyperparameter Tuning

  • 크게 3가지, model, data, Hyperparameter Tuning
  • 모델 스스로 학습하지 않는 값에 대해 사람이 지정
    • learning rate, 모델의 크기, optimizer, etc..
    • cf) NAS, AutoML
  • 하이퍼 파라메터에 의해 값이 크게 좌우 될 때도 있음
    • 2015, 2016, 구글의 recipe 대로 안하면 성능이 떨어졌던 때
    • 근래는 데이터가 너무 많기 때문에 일반 기업에서도 하기 어려운 감이 있음.
    • 대회에서 마지막 0.01을 쥐어짜야 할 때, 도전해볼만 하다. 이미 어느정도 성능 나올 때!
    • Distillation (디스틸레이션), 모델을 압축하거나 가볍게 만드는 기법
      • 큰 모델(선생 모델)의 지식을 더 작고 간단한 모델(학생 모델)에 전달하는 방법
      • 선생 모델의 성능을 유지하면서도 더 작은 연산량으로 빠르게 추론 가능.
      • 디스틸레이션 하는 과정에서 하이퍼 파라미터 튜닝하기도 한다.

https://content.iospress.com/articles/journal-of-intelligent-and-fuzzy-systems/ifs190033

  • grid v.s. random
    • grid Layout Search : 일정한 범위를 정하여 학습 수행
    • Random Layout Search : 랜덤하게 정하여 학습 수행
    • 전통적인 기법 (Old School)
      • Random Search 를 통해 서치를 진행한 후, 성능이 잘 나오는 구간에 대하여 Grid Search

  • 베이지안 기반 기법
    • BOHB (2018)
  • Ray
    • 분산 명령
    • multi-node multi processing 지원 모듈
    • ML/DL의 병렬 처리를 위해 개발된 모듈
    • 기본적으로 현재의 분산병렬 ML/DL 모듈의 표준
    • Hyperparameter Search 를 위한 다양한 모듈 제공
    • train_cifar → 반드시 하나의 함수로 만들어져야 Ray 적용 가능.
    data_dir = os.path.abspath("./data")
    load_data(data_dir)
    
    # config에 search space 지정; grid search
    config = {
        "l1" : tune.sample_from(lambda _:2**np.random.randint(2,9))
        "l2" : tune.sample_from(lambda _:2**np.random.randint(2,9))
        "lr" : tune.loguniform(1e-4, 1e-1),         #log scale로 uniform하게 가져옴.
        "batch_size" : tune.choice([2,4,8,16]),
    }
    
    # 의미 없다고 생각되는 metric들을 잘라내는 역할
    scheduler = ASHAScheduler(
        metric="loss", mode="min", max_t=max_num_epochs,grace_period=1, reduction_factor=2)
    # 결과를 출력하는 양식
    reporter = CLIReporter(
        metric_columns=["loss", "accuracy", "training_iteration"])
    
    # 병렬처리 양식
    result=tune.run(   # train_cifar : 학습 할때의 함수
        partial(train_cifar, data_dir=data_dir),               # 데이터 쪼개기
        resources_per_trial = {"cpu":2, "gpu":gpus_per_trial}, # 한번 trial의 자원
        config=config,
        num_samples=num_samples,
        scheduler=scheduler,
        progress_reporter=reporter)
    

Early stopping with ASHA.  https://medium.com/riselab/cutting-edge-hyperparameter-tuning-with-ray-tune-be6c0447afdf

 

Pytorch Troubleshooting

  • OOM (Out Of Memory)
    • 어려워
      • 왜 발생했는지 모르겠음.
      • 어디서 발생했는지 모르겠음.
      • Error backtracking 이 이상한데로 감
      • 메모리의 이전상황의 파악이 어려움. (iteration 과정 중이면..)
    • 1차원적인 해결법
      • Batch Size 줄이기
      • GPU clean
      • Run
  • GPUUtil 사용하기
    • nvidia-smi 처럼 GPU 상태를 보여주는 모듈
      • nvidia-smi 는 스냅샷 일뿐, iteration 마다의 GPU 상태를 보여주지 않음.
    • Colab은 환경에서 GPU 상태 보여주기 편함
    • iter 마다 메모리가 늘어나는지 확인
    !pip install GPUtil
    import GPUtil
    GPUtil.showUtilization()
    
  • torch.cuda.empty_cache()
    • 사용되지 않은 GPU상 cahce 정리
    • 가용 메모리 확보
    • del 과는 구분이 필요
      • del 이후
      • 가비지 콜렉터가 돌아가면서 남는 메모리를 가져옴
      • 이 과정을 강제한다는 느낌.
    • reset 대신 쓰기 좋은 함수
    • loop이 시작되기 전에 한번 써주면 이전의 학습에 의한 영향을 덜 받겠다.
  • trainning loop에 tensor로 축적 되는 변수는 확인할 것.
    • tensor로 처리된 변수는 gpu 상에 메모리 사용.
    • required_gradient=True 라면, gradient를 위한 메모리 버퍼까지 사용하게 된다.
    • 해당 변수가 loop 안에 있을 때, GPU에 computational graph 를 생성한다. (메모리 잠식)
    total_loss = 0
    for i in range(10000):
        optimizer.zero_grad()
        output = model(input)
        loss = criterion(output)
        loss.backward()
        optimizer.step()
        total_loss += loss        # loss1 + loss2 + loss3 + loss4 = total
                                  # loss 값은 사실 한번만 필요한데 연산을 위해
                                  # 메모리에 계속 적재된다.
    
  • 1-d tensor의 경우 python 기본 객체로 변환하여 처리할 것. (일회용, 적재 x 위해)
    • .item 또는 float 등으로 기본 객체로 변경
  • # 적재되는 경우 total_loss = 0 for x in range(10): # assume loss is computed iter_loss = torch.randn(3,4).mean() iter_loss.requires_grad = True iter_loss += iter_loss ------------------------------------------------------------------------ # 적재 x total_loss = 0 for x in range(10): # assume loss is computed iter_loss = torch.randn(3,4).mean() iter_loss.requires_grad = True iter_loss += iter_loss.item iter_loss += float(iter_loss)
  • del 명령어 적절히 사용하기
    • 필요가 없어진 변수는 적절한 삭제가 필요함.
    • python 메모리 배치 특성상 loop 이 끝나도 메모리 차지함.
    for x in range(10):
        i = x
    print(i)       # loop이 끝나도 9가 출력됨.
    del i
    
  • 학습 시 OOM 발생했다면, batch 사이즈를 1로 해서 실험해보기
    • batch size가 어디까지 가능한지 확인하기 위해 아래와 같은 코드를 구성한다.
    # 배치 사이즈를 줄여서 시도
    oom = False
    try :
        run_model(batch_size)
    except RuntimeError :   # out of memory
        oom = True
    
    # 줄였는데도 안되면 1로만 시
    if oom :
        for _ in range(batch_size):
            run_model(1)
    
  • torch.no_grad()
    • Inference 시점에서 torch.no_grad() 구문 사용.
    • backward pass 로 인해 쌓이는 메모리에서 자유로움
    with torch.no_grad():
        for data, target in test_loader:
            output = network(data)
            test_loss += F.nll_loss(output, target, size_average=False).item()
            pred = output.data.max(1, keepdim=True)[1]
            correct += pred.eq(target.data.view_as(pred)).sum()
    
  • CUDNN_STATUS_NOT_INIT
    • 디바이스를 제대로 설치 안했을 때 생기는 에러
  • device-side-assert
    • OOM의 일종
  • 그 밖의 에러
    • 그밖의 GPU 에러
    • colab에서 너무 큰 사이즈는 실행하지 말 것
      • Linear, CNN, LSTM
    • CNN의 대부분의 에러는 크기가 안맞아서 생기는 경우.
      • (torchsummary 등으로 사이즈를 맞출 것.)
    • tensor의 float precision을 16bit로 줄일 수도 있음.
      • 최후의 수단 정도.
 

이유를 알 수 없는 GPU 에러 정리(device-side assert, CUDA error, CUDNN_STATUS_NOT_INITIALIZED 등등…)

딥러닝 모델 학습에 있어서 빠지면 서러운 GPU는 간혹 알 수 없는 오류를 뿜으며 뻗을 때가 있죠. 이 포스팅에서는 깃허브 이슈 페이지와 스택 오버플로우에서 자주 만날 수 있는 GPU-side 에러들에

brstar96.github.io