Chapter 6. 그 밖의 영상 처리 문제

2024. 1. 7. 14:57딥러닝 모델: fastai

♣ 다중 레이블 분류의 정의

다중 레이블 분류: 이미지 내에 포함된 하나 이상의 물체 범주를 식별하는 문제. 물체가 여러 종류 존재할 수도 있지만 찾고 싶은 종류의 물체가 전혀 없는 상황도 모두 포함됨. 

 

♣ 데이터 살피기

이미지마다 분류된 물체가 한 종류 이상인 PASCAL 데이터셋 사용

 

PASCAL 데이터셋은 각 이미지의 파일명과 레이블 정보를 기록한 csv 파일을 제공함. 

train.csv 파일 확인하기

 

파일 이름과 타깃값(labels), is_valid 정보를 제공함. 

 

♣ 데이터를 모델 학습에 적합한 형태로 만들기(데이터 블록 구성하기)

위의 DataFrame 객체를 DataLoaders 객체로 만드는 방법으로 DataBlock API 사용을 권고함. 

파이토치와 fastai는 학습용 및 검증용 데이터셋을 표현하고 접근하는 두 가지 주요 클래스를 제공함. 

  • Dataset: 단일 데이터를 표현하는 독립변수 및 종속변수 튜플을 반환함
  • DataLoaer: 미니배치 스트림을 제공하는 반복자로, 각 미니배치는 여러 독립변수와 여러 종속변수에 대한 튜플로 구성됨. 

fastai에서는 이 두 클래스를 기반으로 학습용 및 검증용 데이터셋을 함께 다루는 별도의 두 클래스를 제공함. 

  • Datasets: 학습용 및 검증용 Dataset을 포함하는 반복자
  • DataLoaders: 학습용 및 검증용 DataLoader를 포함하는 객체 

 

DataBlock을 단계적으로 구축하기

  • 디폴트 파라미터로 구성된 데이터블록 생성하기(DataBlock 객체 생성하기)

  • DataBlock 객체로 Datasets 객체 생성하기(이때 실제 데이터 소스를 명시해야 함. 여기서는 앞에서 정의한 df_train csv 파일을 적용함)

 

datasetsDataBlock에서 정의한 규칙을 기반으로 데이터셋을 생성하는 메서드임. DataBlock 객체를 생성하고 규칙을 정의한 후에, 이 규칙을 기반으로 datasets 메서드를 호출하면 훈련 및 검증 데이터셋이 포함된 데이터셋 객체를 반환함. 여기서 datasets 메서드는 DataLoader에서 사용할 훈련 및 검증 데이터셋을 생성함. 

 

datasets 메서드의 반환값은 다음과 같음. 

 

     - dsets.train: 훈련 데이터

     - dsets.valid: 검증 데이터셋

 

정리하면, dblock에서 정의한 규칙을 기반으로 df_train 데이터프레임을 사용하여 datasets 메서드를 호출하면 훈련 및 검증 데이터셋이 포함된 데이터셋 객체를 얻을 수 있음. 

 

  • 위에서 만든 dsets.train 데이터에 접근하여 첫 번째 데이터 확인하기 

같은 열이 두 번 반환된 이유는 기본적으로 데이터블록에 입력과 타깃 두 요소가 포함된다고 가정하기 때문임. 따라서 데이터셋으로부터 원하는 입력과 타깃을 가져오는 각 함수를 get_x 및 get_y 인자에 지정해야 함(즉 위에서 datasets 메서드를 사용하면 train, valid 데이터셋을 반환하는데, 여기서 get_x, get_y 등의 규칙을 넣어서 데이터셋을 반환하도록 하는 것) 

 

  • DataLoader에서 사용할 훈련, 검증 데이터셋의 입력값과 타깃값을 반환하는 함수 넣기

DataBlock 객체를 생성할 때 데이터셋의 입력값과 타깃값을 가져오는 함수를 규칙으로 넣음. 

이렇게 생성한 데이터 객체에서 훈련 및 검증 데이터셋을 반환하기 위해 datasets 메소드 안에 df_train을 넣음. 

이제 입력과 타깃값을 가져오는 규칙이 있기 때문에 처음에 dsets.train[0]에서 해당 데이터의 정보를 모두 반환한 것과 달리 입력값과 타깃값만 반환됨. 

 

*위에서 get_x, get_y를 정의할 때 사용한 lambda는 간단하게 함수를 정의하고 참조하는 방법이지만, 좀 더 자세하게 작성한 코드가 더 이상적임. 

 

 

이미지를 열려면 완전한 경로로 독립변수를 구성해야 함. 그리고 공백 문자로 쪼개진 목록을 종속변수로 하여 타깃값 구성하기

 

 

실제로 이미지 파일을 열고 텐서로 변환하려면 여러 변형 과정이 필요함. fastai에서는 이를 처리하는 블록을 정의했음. 

위에서는 범주의 목록이 CategoryBlock과는 다른 방식으로 인코딩됨. CategoryBlock에서는 문자열과 정수를 매핑한 vocab에서 범주에 맞는 단일 정숫값을 가져와서 표현하지만 MultiCategoryBlock은 범주가 있는 부분만 1, 나머지는 0으로 채워진 정수 벡터로 표현됨. 이런 표현 방식을 원-핫 인코딩이라고 함. 

 

앞서 출력된 원-핫 인코딩 형식의 벡터가 어떤 범주를 표현하는지 확인하기. 모든 색인을 찾아주는 편리한 torch.where 함수를 사용함. 

 

 

  • DataLoader에서 사용할 훈련, 검증 데이터셋을 나누는 규칙 넣기

지금까지는 is_valid 열을 무시했음. 즉 DataBlock의 디폴트 기능을 이용하여 학습용과 검증용 데이터셋을 임의로 분리함. 

명시적으로 검증용 데이터셋을 지정하려면 splitter 인자로 전달될 함수를 작성해야 함. 

 

  • DataLoader 생성하기

DataLoader는 Dataset에 포함된 항목들을 미니배치 형태로 모아줌. DataLoaders를 생성하여 모든 데이터가 같은 크기가 되도록 만들기

 

만들어진 DataLoaders에서 표본 출력하기

* datasets는 가공된 데이터셋을 반환하고, dataloaders는 해당 데이터셋을 미니배치로 나눈 데이터로더를 반환

 

♣ 이진 교차 엔트로피

  • Learner 만들기

Learner 객체는 네 가지 주요 내용(모델, DataLoaders, 옵티마이저, 손실함수)를 포함함. 

 

모델을 함수처럼 호출하려면 미니배치 형태의 독립변수를 인자로 넣어줘야 함. DataLoader에서 미니배치 하나를 가져와서 모델에 넣어보기

activs의 모양이 torch.Size([64, 20])인 이유는 설정한 배치가 64이고, 범주 20개에 대한 확률을 계산하기 때문임. 

 

 

배치 크기가 64이므로 activs[64]는 존재하지 않기에 출력이 불가하다. 

 

  • 적합한 손실함수 선택하기

원-핫 인코딩된 종속변수에는 nll_loss 또는 소프트맥스를 즉시 사용할 수 없음. 

 

 - sofrmax에서는 모든 예측값의 합이 1이 되어야 하며 예측값 중 하나를 다른 값보다 훨씬 크게 만드는 경향이 있음. 하지  만 다중 레이블 문제에서는 이미지 내에 존재하는 여러 물체 각각에 대한 신뢰도를 구해야 함. 따라서 활성의 총합이 1이 되도록 강제하는 방법이 유용하지 않음. 

- nll_loss는 한 데이터의 단일 레이블에 대응하는 활성값 하나만 반환하기 때문에 다중 레이블 문제에서는 의미가 없는 손실임. 

 

-nn.BCELoss

F.binary_cross_entropy와 같지만 모듈로 정의됨. 원-핫 인코딩된 타깃의 교차 엔트로피를 계산하지만 초기에 시그모이드를 적용하지는 않음. 일반적으로 원-핫 인코딩된 타깃이 있을 때는 시그모이드 및 이진 교차 엔트로피를 모두 포함한 F.binary_cross_entropy_with_logits 또는 nn.BCEWithLogitsLoss를 사용함. 

 

 

  • 평가지표 정의하기

해당 label이 출력될 확률을 0~1 사이의 수로 만들기 위해 시그모이드를 적용하고, 그 후에는 어떤 값을 0 또는 1로 간주할지를 정하는 임계점(threshold)를 선택함. 그러면 임계점을 넘는 모든 값은 1로, 임계점 아래의 모든 값은 0으로 간주함. 

 

 

  • 모델 학습하기

partial을 이용하여 threshold를 바꿀 수 있음. partial은 함수의 일부 인자에 고정값을 할당한 새로운 버전의 함수를 생성함.

임계점을 0.2로 하여 모델을 학습시키기

 

 

임계점이 너무 낮으면 레이블링된 물체를 선택하지 못할 가능성이 높음. 임계점을 낮게 설정하고 검증용 데이터셋의 손실값과 평가지표를 반환하는 validate 메서드를 호출하면 이를 확인할 수 있음.

 

반면 임계점이 너무 높으면 모델이 자신 있는 물체 단 하나만 선택할 가능성이 높음. 

 

몇 가지 다른 임계점을 시도해서 어떤 값에서 가장 잘 작동하는지를 확인하면 최적의 임계점을 발견할 수 있음. 

 

get_preds 메서드를 이용하여 예측값 얻기 

 

이제 평가지표 함수에 예측값과 타깃값을 넣어서 성능을 평가할 수 있음. 다만 get_preds 메서드가 이미 기본적으로 출력 활성화 함수(여기서는 시그모이드)를 적용했으므로, accuracy_multi에서 sigmoid를 중복해서 적용하지 않도록 조치해야 함. 

 

아래 방법을 사용해서 최적의 thresh를 찾을 수 있음

 

 

---------------------------------------------------------------------------------------------------------------------------------------------------

♣ 회귀 문제 데이터 확인

 

ls 메서드를 이용하여 디렉터리 구조를 살피면 0부터 23까지의 숫자에 해당하는 디렉터리 24개와 .obj 파일이 있음

 

디렉토리 안의 데이터 살피기

 

get_image_files 함수를 사용하여 모든 이미지 파일을 재귀로 가져올 수 있음

 

이미지 파일명에 해당하는 pose 파일명을 반환하는 함수 만들기

 

첫 번째 이미지 살펴보기

PILImage.create 함수는 이미지 파일을 fastai의 PIL 이미지로 변환함. 따라서 im은 해당 이미지 파일을 PIL 이미지로 변환한 객체가 됨. to_thumb 메서드는 이미지를 축소한 버전을 반환함. 160은 축소된 이미지의 가로 크기를 나타내는데, 여기서는 160 픽셀로 설정되어 있음. to_thumb 메서드는 Fastai 라이브러리에서 제공하는 기능 중 하나임. 

 

♣ 머리의 중심 위치를 추출하는 함수

 

위 함수는 좌표 요소가 둘인 텐서를 반환함

 

이 함수는 각 입력 이미지의 좌표를 만환하므로 BataBlock 생성자의 인자 중 get_y에 할당될 수 있음. 

 

 

♣ DataBlock 생성하기

 

위의 DataBlock에서는 한 사람의 이미지만 검증 데이터로 사용함. 모델을 일반화하려면 본 적 없는 인물 데이터가 필요한데, 데이터셋에는 동일 인물의 이미지가 여러 번 등장하기 때문임. 

 

blocks에서 두 번째 block으로 PointBlock을 사용하면 fastai가 레이블이 좌표로 표현된다는 사실을 파악함. 또한 데이터 증강을 적용하는 순간에 이미지 뿐만 아니라 좌표에도 같은 증강 기법을 적용해야 한다는 점도 파악함. 

 

실제로 모델링을 하기 전에 이미지와 타깃값 데이터가 정상인지 확인해야 함

 

 

미니배치 모양 확인하기

 

 

 

xb는 이미지를, yb는 머리 중심 위치 좌표를 반환함. 

 

♣ 모델 학습하기

 

 

y_range는 타깃의 범위를 지정하는 옵션임. 여기서는 -1부터 1까지의 범위로 설정되어 있음. 따라서 좌푯값이 항상 -1과 1 사이의 범위로 조정됨. y_range 인자를 설정하면 아래의 함수가 모델 마지막 계층에 설정됨. 

 

이는 sigmoid_range 함수로 y_range를 구현한 형태임. 

 

그렇다면 모델의 출력 활성의 범위를 (lo, hi)으로 강제하는 이유는 무엇인가?

- 모델의 출력이 다양한 범위에 있을 때, 특정 범위로 출력을 조정하여 모델의 학습을 안정화시킬 수 있음

- 일부 활성화 함수는 특정 입력 범위 내에서만 안정적으로 동작하므로, 이런 제한이 모델의 안정성을 향상시킬 수 있음

 

범위를 -1과 1 사이로 강제하면 다음과 같은 모양의 그래프가 나옴. 

 

 

손실 함수를 지정하지 않았으니 fastai가 자동으로 정한 함수가 사용됨. 손실 함수 확인하기

주어진 좌표에 가능한 가까운 값을 예측하려고 하는데 MSELoss(평균제곱오차 손실)이 바로 그런 일을 함. 다른 손실 함수를 사용하고 싶다면 vision_learner 함수의 loss_func 인자에 지정하면 됨.

또한 MSE 자체가 이미 유용한 평가지표이므로 별도의 평가지표를 지정하지 않았음. 

 

 

적당한 학습률 찾기

 

적당해 보이는 1e-2를 학습률로 채택하여 학습 진행하기

 

Learner의 show_results 메서드를 사용하면 검증용 데이터를 대상으로 결과를 시각적으로 확인할 수 있음. 좌측은 실제 좌표, 우측은 모델이 예측한 좌표를 나타냄. 

 

 

♣ 세 종류의 문제에 사용되는 손실 함수

 

- 단일 레이블 분류 문제: nn.CrossEntropyLoss

- 다중 레이블 분류 문제: nn.BCEWithLogitsLoss

- 회귀 문제: nn.MSELoss

 

 

♣ 해당 코드

https://www.kaggle.com/code/polljjaks/chapter6/edit/run/158311378

 

Chapter6. 그 밖의 영상 처리 문제

Explore and run machine learning code with Kaggle Notebooks | Using data from No attached data sources

www.kaggle.com