페이지

레이블이 비지도학습인 게시물을 표시합니다. 모든 게시물 표시
레이블이 비지도학습인 게시물을 표시합니다. 모든 게시물 표시

2022년 4월 27일 수요일

라벨 없는 영상 데이터 들로부터 딥러닝을 통해 유사 이미지 탐색해오기-1편

 이전 뉴스레터11편에서 안면 인식시스템을 설명하면서 샴(siamese) 신경망 네트워크, 3(Triplet) 손실 함수, 유사도 함수 등을 다룬 바 있다. 본 프로젝트에서는 Kaggle Flowers Recognition 데이터세트에 있는 600 개 꽃들의 라벨 없는 영상데이터들을 3중 손실함수를 이용하여 샴 네트워크상에서 훈련한다. 통상 딥러닝을 통한 영상 분류에 있어서 수백, 수천 이상의 훈련 샘플/이미지와 매우 큰 데이터세트가 필요하다는 인식과는 다르게 수백 건의 라벨 없는 이미지 데이터들로 3중 손실을 통한 훈련을 시행하여 임베딩끼리의 cosine 유사도로 이미지 유사도 검색이 가능한 지 살펴본다.


비지도 유사 이미지 검색 처리 절차

 3중 손실함수를 통한 비지도 유사 이미지 검색 처리 절차는 아래 그림 1과 같다. 프로젝트 환경은 Nvidia A100 GPU 140GB 메모리와 30GB CEPH 타입 디스크를 사용하였고 Tensorflow 2.6.0, Keras 2.6.0, cuda 11.3, 그리고 python3.8 환경에서 개발하였다.


<그림 1. 유사 이미지 검색 처리절차>


데이터 준비

본 프로젝트에 사용된 데이터세트는 이곳 에서 다운로드 받을 수 있다. 데이터세트 240 X 240 픽셀 크기의 데이지, 민들레, 장미, 해바라기, 튤립의 5가지 종류의 총 4242 개의 꽃 이미지를 보유한다. 본 시스템에서는 각 종류당 120 개만 사용하여 데이지 꽃부터 일련번호를 1번부터 부여하여 튤립까지 총 600번까지의 .jpg 파일을 anchor 디렉토리에 위치시키고 시작한다.

아래 섹션에서 설명하는 3중 손실함수로 훈련하기위해서 우선 anchor600개의 이미지들을 위치시키고, positiveanchor 이미지와 쌍을 이루도록 증식 및 변환을 가하여 위치시키고 negative 이미지들은 임의로(random) 생성된 anchor positive 이미지를 더해서 생성한다. 아래 그림 2anchor 이미지 들로부터 positive image 들을 생성하는 함수이다. ①은 이미지의 중앙 50%를 잘라내는 것이고 ②는 2번에 1번꼴로 이미지를 왼쪽에서 오른쪽으로 뒤집는다. ③은 임의 대비(contrast) 요소의 lower_bound=0.2, upper_bound1.8 로 설정. 이러한 이미지 증식방식은 이전 뉴스레터인 대조학습에서 효과적인 방법으로 언급된 방식을 차용하였다.


<그림 2. positive 이미지 생성 함수>


Data pipeline을 준비하기위해 아래 그림 3과 같이 anchor positive 이미지들을 sort 된 순서로 불러와서 서로 match 되도록 한다.

 


 <그림 3. Anchor, positive 준비>

 

 Negative 이미지들은 아래 그림 4와 같이 anchor positive를 임의로 섞은 다음에 이 둘을 ③과 같이 concatenate 하여 생성한다. 이러한 이미지 들로부터 dataset을 생성한다.


<그림 4. Negative 이미지 생성>


  anchor, positive, negative3가지 이미지가 같은 구조의 샴 네트워크에 입력되므로 이 세가지 dataset zip 한 이후에 shuffle 하고 resize dataset으로 변환한다. 그리고 아래 그림 5와 같이 train valid dataset을 분할한다. ①은 train을 전체 80%로 할당하고 valid 는 그 나머지. ②는 batch 크기를 8로 설정했다.


<그림 5. Train, valid dataset 분할>


 아래 그림 6과 같이 train_dataset을 출력해보니 첫번째가 anchor, 두번째가 positive, 세번째로 negative 이미지가 출력된다.



<그림 6. Triplet 데이터 확인>


 ResNet50 기반 임베딩 준비

 아래 그림 7과 같이 ResNet50 모델 weight를 기반으로 customer layer3개의 dense layer를 추가하여 임베딩 layer 를 만든다. ①에 include_top=False로하고 우리가 원하는 customer layer를 추가한다. ②에 256 벡터크기의 dense2 layer output 이 된다. ③에 inputsbase_cnn.input , outputs=output 으로 embedding을 생성한다. ④와 같이 함으로써, ResNet50 layer155번째인 conv5_block1_out부터 trainable=True, 그 이전 층들은 False 로 선언한다. 전이학습을 통한 파인튜닝에 대한 내용은 이전 뉴스레터를 참고.



<그림 7. 임베딩 준비>


Siamese 네트워크 모델 준비

3중 손실의 훈련을 위한 모델을 수립하는 단계를 살펴보자. (siamese) 네트워크에 관해서는, 이전 뉴스레터논문을 참고하기 바란다. 이를 위하여 anchor, positive, negative의 입력을 받는 3embedding 이 포함된 샴(Siamese) 네트워크를 아래 그림 8과 같이 구성한다. ①은 ResNet50 전이학습을 통한 encoder 파트. ②는 커스텀 layer로 추가한 파인튜닝 층. ③은 각각의 embedding layer. ap_distanceanchor positive 사이의 거리를 나타내고, an_distanceanchornegative 사이의 거리를 출력.

이러한 ap_distance an_distancetuple 로 출력하는 DistanceLayer를 사용한다


<그림 8. Siamese 네트워크>

 

 DistanceLayer 클래스안에 아래 그림 9와 같은 ap_distanceap_distance 값을 tuple return 하는 함수를 사용하여 모델에 [anchor_input, positive_input, negative_input]이 입력되고 output ap_distance an_distance 의 거리가 출력되도록 정의함으로써 Siamese_network 을 구성한다. 이 거리들이 이후 loss 산출에 사용된다.



<그림 9. 거리 측정 layer>


  지금까지 비지도 유사 이미지 검색 절차 중 데이터준비, ResNet50 기반 임베딩 준비, Siamese 네트워크 모델 준비등에 대해서 살펴보았다. 다음 2편에서는 3중 손실을 통한 훈련 시행, 이미지 검색을 위한 특징 추출, 유사 이미지 검색 모듈에 대해서 살펴보겠다.



라벨 데이터가 적은 경우에도 딥러닝을 통한 영상 분류 성능을 보장할 수 있을까? – 3편

 2편에서는 손실 함수와 유사도 함수 그리고 mask를 통한 labels 그리고 similarity matrix 생성, 그리고 8 X 1 행렬의 positives 8 X 6 행렬의 negatives를 결합한 logits 1 X 8positives 샘플들의 인덱스를 포함한 labels를 살펴보았다.

logits labels 생성

Pytorch CrossEntropyLoss에서 targetindex 로 출력하는 예를 보면,

criterion = nn.CrossEntropyLoss(),

loss = criterion(input, target) 

이다. 이때 input에 해당하는 것이 logits, target에 해당하는 것이 labels이다. 아래 그림 10에서, positives negatives의 횡적 결합한 8 X 7 행렬이 logits 이고 labels positives 샘플들의 인덱스를 포함한 1 X 8 행렬로써, labelsCrossEntropy를 각 행의 logits를 보고 0값의 벡터를 보고 positive 쌍이 첫번째 인덱스에 있음을 알려주는 indicator function으로 일반적으로 사용하는 라벨과는 다른 내용이다.

 

<그림 10. Positives, negatives 행렬>


아래 그림 11의 ①을 통해 대조 학습을 위한 온도 계수를 logits에 적용하는 부분이다. 1편의 그림 1에서 Ʈ는 출력 카테고리 간의 구분을 명확 혹은 부드럽게 출력하는 온도 계수라고 설명하였다. ②에서 logits labels를 리턴 한다.

지금까지 살펴본 info_nce_loss 함수는 simclr.py train 함수에서 사용한다.

logits, labels = self.info_nce_loss(features)

loss = self.critetion(logits, labels)


<그림 11. logits labels 반환>


유사 이미지 representation끼리 유사도가 높게, 다른 이미지 representation끼리는 유사도가 낮게 만들어 주기 위해 info NCR loss를 계산하여 최소화한다. positive pair는 자기 자신(주어진 anchor image)와 증식 이미지이다. 이때 원본 이미지끼리, 증식 이미지끼리 의 유사도는 loss 계산 시 배제한다(그림 8 labels[~mask]에서 대각선 1이 제거 됨으로써). 결국 자기 자신(주어진 anchor 이미지)와 다른 이미지의 유사도를 일일이 계산하기보다 자기 자신과 증식된 이미지만을 positive sample로 선택함으로써 손실 함수처리가 된다.

훈련

 대조 학습으로 훈련을 시행하기위해 아래와 같은 명령을 수행한다. datasets 디렉토리가 필요하고 그 밑에 stl10_binary가 생기는데 아래와 같은 명령어에 맞게 stl10 디렉토리와 symbolic link로 맞추어 주던지 하는 것이 필요하다.


100 epoch 훈련이 끝나면 runs 밑에 일자_job_xx 디렉토리가 생기고 그 밑에 아래 그림 12 와 같은 파일들이 생성된다. Nvidia 2080Ti GPU 4대로 ubuntu20.04, Pytorch 1.10, Pthon3.8, CUDA11.3 환경에서 훈련에 4시간 29분 소요되었다.



<그림 12. 훈련 후 생성되는 파일 들>


성능 평가


훈련을 통해 만들어진 분류기의 정확도를 측정하기위해 학습한 encoder를 고정(freeze)시키고 그 위에 linear classifier를 추가하여 정확도를 측정합니다. 코드는 feature_eval 디렉토리 밑에 mini_batch_logistic_regression_evaluator.ipynb 노트북 코드이다.

우선 아래와 같이 stl10 ResNet-18 공식 데이터세트를 ①과 같이 download=True로 하여 다운로드 받는다. 앞에 훈련에서 사용했던 데이터세트를 사용해도 되지만, 사전 학습 모델을 이용하여 모델이나 데이터세트의 차이에 따른 정확도 측정을 위해 주어진 mini_batch_~ 코드를 최대한 활용해본다. 위의 그림 12와 같은 내용이 ./data 디렉토리 밑에 다운로드 된다.



 
아래와 같이 다운로드 된 디렉토리에서 config.yml을 로드 한다. ①은 현재 torch 1.10, cuda 11.3, python 3.8 환경에서 yaml.load 에서 error가 발생해서 unsafe_load로 변경하였다.



사전 훈련 모델은 아래와 같이 resnet18 모델을 정의한다. ①번과 같이 선언함으로써 weight를 불러오지 않는다. 우리는 저장된 체크포인트를 로드해서 사용할 것이다.



 아래 그림 13의 ①번과 같이 저장되었던 체크포인트 파일을 로드 한다.  ②번과 같이 모델 state_dict backbone. 으로 시작하는 접두사를 제거함으로써 fc.wieght fc.bias 를 제거한다. 하지만 model.named_parameters()에는 fc.weightfc.bias 이름과 구조는 보존하고 있다.


<그림 13. state_dict fc.wieght, fc.bias 제거>


 그리고 아래 그림 14의 ①번과 같이 model.named_parameters fc.weight, fc.bias 를 제외한 나머지들을 모두 False 로 선언함으로써 역전파시 gradient 연산이 일어나지 않게 된다. ②는 model.parmaters중에 gradient enable parameter를 뽑아내는 함수이다.


<그림 14. Gradient freeze 이외에 남은 변수를 넘겨 받기>


아래 그림 15의 ①번과 같이 model summary를 호출하면 ②와 같이 ResNet-18  마지막 layer에 완전연결층이 10 class의 출력을 가지고 있음을 볼 수 있다.


<그림 15. 모델 summary>


완전연결층(FC layer) 훈련 및 모델 평가

 아래 그림 16과 같이 훈련될 gradientenable FC layer 를 훈련한다. epoch100으로 정하고 ①과 같이 모델에 x_batch를 넣어주면 logits가 출력된다. ②와 같이 logitsy_batch와 함께 topl=(1,)를 변수로 top1 accuracy를 호출한다. pytorch에서는 이후에 backward를 해줄 때 gradients 값들을 계속 더해주기 때문에 한번의 학습이 완료되면 gradients를 항상 0으로 만들어주어야 한다. ④ 오차를 역전파(backward)하기 위한 설정. ⑤ 옵티마이저는 parameter, learning rate 및 여러 다른 hyper-parameter를 받아 step() method를 통해 업데이트한다.


<그림 16. FC layer 훈련 및 top-1 정확도 산출>


평가 기준 정의: top-k accuracy

 먼저 top-1 accuracy를 설명해보자. , 고양이, 닭 등등의 서로 다른 6개의 동물들 사진이 있다고 치자. 첫번째 분류 예측에서 6개 중에 4개를 맞추면 67% 정확도다. top-2 accuracy는 각각의 경우에 첫번째와 두번째 예측을 수행한 것을 모두 놓고 몇 개를 맞췄는지 평가하므로 당연히 정확도가 올라간다.

테스트 데이터를 통한 Top1, Top5 정확도 평가

 이어서 아래 그림 17과 같이 테스트 데이터를 로드 하여 정확도 성능을 평가한다. ①은 test_loader로부터 batch 단위로 데이터를 로드 한다. ②에서 batch 단위의 테스트 데이터가 모델에 입력되어 logits를 출력. ③에서 topk=(1,5)를 변수로 logits y_batch를 입력하여 top1, top5 결과를 출력한다. ④를 통해 batch 단위의 결과를 평균 내어 ⑤와 같이 화면에 epoch Top1 Test AccuracyTop 5 결과가 나타난다.


<그림 17. 테스트데이터를 통한 top1, top5 정확도 평가>


성능 결과


 라벨 없는 10만개와 5천개의 stl10 데이터세트 훈련데이터를 입력으로 하여 대조 학습을 통한 nce loss 100회 훈련한 사전 모델을 전이학습을 통하여 로드 하여 성능평가를 위해 라벨이 있는 train test 데이터를 이용하여 마지막 FC 층만 제외한 나머지 층을 훈련을 못하도록 freeze 시켜 놓고 FC 층을 100회 훈련시킨 결과는 아래 그림 18의 붉은 선에 표시된 바와 같이 Top1 정확도는 69.28, Top5 정확도는 98.26 이다.



<그림 18. 선형분류기 학습을 통한 성능 평가>

결언

 본 프로젝트의 목적은 라벨 없는 영상데이터들로 이미지 분류가 가능한지와 어느 정도의 성능을 보여주는지를 살펴보는 것이었다. 대조 학습을 위하여 라벨 없는 stl10 데이터를 훈련하였고 성능 평가를 위해 stl10 데이터의 10class를 보유한 train, test 라벨 있는 데이터를 마지막 층에 선형 분류기를 통하여 성능 평가를 하였다. ResNet-50에 비하여 비교적 구조가 간단한 ResNet-18 구조를 채택하여 official record 74.45에는 못 미치지만 69.28 Top1%를 달성하였다.


 <그림 19. 성능 비교>