SJ_Koding

개인 기록용 PyTorch 오류 모음 본문

PyTorch Code/Pytorch

개인 기록용 PyTorch 오류 모음

성지코딩 2024. 3. 28. 14:08

1. timm에서 model를 load한 뒤, 저장된 pt파일을 불러와 inference를 시키면 성능이 크게 감소했음.

--> model.eval()를 반드시 실행해줘야함. with torch.no_grad는 parameter update를 통제할 뿐, forward 과정까지의 update를 통제하지는 않는다. timm은 default mode로 train mode로 설정 되어있으므로 eval()을 통해 모드를 바꿔줘야한다. eval()모드는 BatchNormalization의 파라메터를 Train시 셋팅한 값을 그대로 가져오지만, train()은 입력 데이터에 따라 BN의 parameter를 변화시키기 때문에, 성능이 엉망이 되었던 것이다. (추가로 dropout 레이어도 완전히 무시해준다.)

아마 대부분은 Train 직후 model를 load하여 추론에 사용할 것이다. 대부분 학습이 종료 될 때, train() 후 eval() 모드로 바꾼 직후에 Test inference를 진행하므로 문제가 없었을 것이다. 너무 당연했기 때문에 막상 eval() 빠져있을 때, 쉽게 발견하지 못했던 것 같다.

--> eval()모드 수행

2. validation 과정에서 GPU가 점점 쌓이다가 OOM(Out of Memory) 발생

Knowledge distillation을 수행 하던 중 발생한 현상인데, is_train의 매개 변수로 학습중인지 여부를 받아 그에 따른 로직으로 함수를 간략화 한 상황이었다. teacher model의 parameter freezing을 신경쓰다가 student model의 valid 시 torch.no_grad()를 수행하지 않았다. 이로 인해 미분 연산이 계속해서 진행되면서 GPU 메모리에 계속 쌓였던 현상으로 파악된다.

--> student model의 validate 과정에서 with torch.no_grad() 추가하여 해결

3. Knowledge distillation을 진행 할 때 성능이 전혀 개선되지 않고 오히려 '크게' 망가짐

통상적으로 성능이 안좋아질 순 있지만 크게 망가뜨리지는 않다고  생각한다. 그래서 원인을 찾아보았는데, 한 가지 간과한 점이 있다. Knowledge distillation 논문을 보면 Softmax수식에 T를 나누어 확률 분포를 smoothing하여 너무 과하게 의존하지 않도록 유도한다. 근데 나는 softmax에 스칼라값을 넣어도 에러가 나지 않는다는 것을 간과하였다. 즉, F.softmax(torch.Tensor([0.1231])) 를 수행한 결과는 에러가 아닌 [1.] 이 되는 것이다. 결국엔 output_size가 1인 teacher모델은 계속해서 [1., 1., 1., 1., 1., ...](배치크기만큼) 을 반환하고 이를 모방하려고 하니 모델이 망가져 버린 것이다.

--> Sigmoid 출력값에서 1을 빼어 나머지 클래스의 값으로 지정하여 해결.
torch.Tensor([0.1231]) --> torch.Tensor([1 - 0.1231, 0.1231])  T로 나누는 연산을 적용할 수 없음, sigmoid의 역함수를 활용해야하는데 너무 복잡하므로, teacher모델을 softmax출력으로 다시 학습한 후 진행하여 해결. 제프리 힌튼의 방법론을 그대로 사용

4. RuntimeError: CUDA error: device-side assert triggered CUDA kernel errors might be asynchronously reported at some other API call, so the stacktrace below might be incorrect. For debugging consider passing CUDA_LAUNCH_BLOCKING=1. Compile with `TORCH_USE_CUDA_DSA` to enable device-side assertions.

초보때 많이 봤던 실수인데, 다중 분류시 모델의 output shape과 target의 범위가 다를경우 자주 볼 수 있다. 예를 들어 타겟이 0, 1, 2, ..., 15로 총 16개가 있지만 model output이 17개의 텐서라면 에러가 발생한다.

--> output수와 target수를 일치시키자.

5. IndexError: positional indexers are out-of-bounds

K-fold를 진행하면서 발생한 오류. 아래 코드를 보며 이상한 점을 찾아보자.

kf = KFold(n_splits=5, shuffle=True, random_state=1020)

for idx, (train_index, valid_index) in enumerate(kf.split(train_df)):
    train_df, valid_df = train_df.iloc[train_index], train_df.iloc[valid_index]

    train_dataset = CustomDataset(train_df, train_transforms)
    train_loader = DataLoader(train_dataset, batch_size=8, shuffle=True)

    valid_dataset = CustomDataset(valid_df, test_transforms)
    valid_loader = DataLoader(valid_dataset, batch_size=8, shuffle=False)
    (생략)

정답은 아래 더보기 클릭

더보기

fold로 나뉘어진 train_index를 통해 train_df를, 같은 코드로 valid_df를 추출했고 첫 번째 fold는 정상적으로 진행되었다. 이때 두 번째 fold에서 이미 train_df는 train_index로 추출되었으므로 기존 데이터셋에 덮어쓰기가 되버렸다. 그래서 index 매칭이 안된 오류! 변수 이름을 바꿔주어야한다. 

해결:

original_train_df = train_df.copy()  # 원본 데이터 프레임을 복사합니다.

for idx, (train_index, valid_index) in enumerate(kf.split(original_train_df)):
    train_df = original_train_df.iloc[train_index]
    valid_df = original_train_df.iloc[valid_index]

6. AttributeError: 'tuple' object has no attribute 'to'

주로 분류 테스크를 진행할 때, DataLoader로 부터 target값을 불러오는 경우에 종종 볼 수 있다.
이는 라벨인코딩이 진행되어있지 않은 Object형으로 라벨이 이루어졌을 때 나타난다.

--> 라벨인코딩 진행하여 해결