본문 바로가기

공부방/Upstage AI Lab 4기

[CV 문서 분류 대회] 베이스라인 돌려보고 흐름 파악하기

베이스라인 코드를 쭉 살펴봤다. 원본은 공개가 금지라서 공부한 내용 토대로 말로 정리. 

1. 시드를 먼저 고정

2. 데이터셋 클래스 정의

3. 에폭 1회 학습 함수 만들고

4. 하이퍼파라미터 정의

5. 데이터 전처리 파이프라인(리사이즈, 노멀라이즈, 텐서로 변환 작업을 함)으로 트레인 데이터셋과 테스트 데이터셋을 변환해줌.  

베이스라인에서 전처리에 쓴 라이브러리: Albumentations 라이브러리

import albumentations as A


trn_transform = A.Compose([
    # 1. Augmentation
    A.RandomRotate90(),
    A.HorizontalFlip(p=0.5), # 50% 확률로 좌우반전
    A.VerticalFlip(p=0.5), #20% 확률
    A.RandomBrightnessContrast(p=0.2), #20% 확률
    
    #리사이즈
    A.Resize(height=img_size, width=img_size),
    #정규화
    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    #텐서 변환
    ToTensorV2(),
])

참고)
일반적인 전처리 파이프라인 순서:

  1. Augmentation (회전, 뒤집기, 밝기 조절 등)
  2. Resize (이미지 크기 조정)
  3. Normalize (픽셀값 정규화)
  4. ToTensor (PyTorch 텐서로 변환)

augmentation은 원본 픽셀 값을 가진 상태에서 수행 -> 어그멘테이션 한 데이터까지 모두 합쳐서 normalize -> tensor 변환

A.Compose 함수는 여러 전처리 단계를 순차적으로 연결해주는 컨테이너 역할을 한다. Compose에는 확률 설정 기능이 있어서 p 파라미터로 각 변환의 적용 확률을 설정할 수 있다. (이번 문서 분류에는 해당하지 않는 내용이지만, 세그멘테이션 문제를 풀 때 마스크가 들어가는데 이런 경우에는 마스크까지 같이 돌려주거나 변환에 적용해주기 때문에 사용이 편리하다고 한다.)

이 트랜스폼된 이미지는 데이터셋 클래스를 정의하는 부분에서 __getitem__ 함수 안에 들어가 img를 변환해서 반환해준다. 

6. 데이터셋 정의
위에서 만든 데이터셋클래스의 인스턴스로서 트레인 데이터셋, 테스트 데이터셋을 만든다. 

7. 데이터 로더 
파이토치의 DataLoader를 이용해서, 데이터를 배치 단위로 모델에 넣어줌.

# DataLoader 정의

trn_loader = DataLoader(
    trn_dataset, #ImageDataset 클래스의 인스턴스
    batch_size=BATCH_SIZE, #한 번에 모델에 공급할 데이터의 크기
    shuffle=True,#True: 에포크마다 데이터 순서를 무작위로 섞음 
				 #테스트 데이터에서는 이 값을 False로 설정하여 일관된 순서로 예측
    num_workers=num_workers, #데이터 로딩에 사용할 CPU 프로세스 수
    pin_memory=True,#GPU 학습을 위한 메모리 최적화 옵션, 
    				#True로 설정하면 데이터를 CPU의 고정된(pinned) 메모리에 할당
    drop_last=False #마지막 배치의 처리 방식 설정. False: 마지막 배치가 batch_size보다 작아도 사용, 
    				#True: 마지막 배치가 batch_size보다 작으면 버림
)

 트레인 데이터와 테스트 데이터 로더의 설정이 다른데, 각각 학습 또는 추론에 맞체 설정을 바꿔놓은 것이다.

그렇다면 여기서 중요한 건 배치 사이즈같은데, 배치 사이즈는 어떻게 적당한 값을 찾을 수 있을까? -> https://working-with-science.tistory.com/97

 

8. 모델 로드
모델을 로드하는 과정에서 여러 파라미터가 있는데 pretrained=True 이런 것이 있었다.

model = timm.create_model(
    model_name,
    pretrained=True,  # ImageNet으로 사전학습된 가중치 사용
    num_classes=17 # 문서 타입이 17개라는 의미
)

pretrained=True는 ImageNet(약 120만개 이미지, 1000개 클래스)으로 사전학습된 가중치를 사용한다는 뜻이다. 원래 ResNet의 마지막 층을 17개 출력으로 바꾸는 부분이 num_classes=17. 이 부분만 처음부터 학습되고, 나머지 층은 사전학습된 가중치에서 미세조정된다. 

그리고 loss_fun = nn.CrossEntropyLoss() 를 썼다(분류 문제에서 쓰는 일반적인 손실함수)

optimizer = Adam(model.parameters(), lr=LR) 이거는 # 최적화할 모델의 파라미터들

 

9. 에포크 한 번 돌면서 학습

에포크는 전체 데이터셋을 학습하는 횟수. 

10. 테스트 이미지에 대한 추론

11. 결과 저장