1. WIDER FACE 데이터셋
- 오늘 우리가 Face Detection 모델의 학습을 위해 다루게 될 데이터셋은 바로 WIDER FACE 데이터셋이다.
- 빠른 인퍼런스 타임을 위해 사용할 YOLO, SSD 같은 single stage model을 학습시키는 것은 흔히 COCO 데이터셋 같은 것이 사용된다.
- 하지만 오늘 우리가 추구하는 "먼 거리에 흩어져 있는 다수의 사람 얼굴을 빠르게 detect 하는 모델"을 만들기 위해서는 "보다 넓은 공간에 있는 다수의 사람이 등장하는 이미지 데이터셋"이 필요하다.
- WIDER FACE 데이터셋은 이런 용도로 활용하기 적합한 데이터셋이다.
- WIDER FACE 데이터셋 홈페이지에 들어가서 데이터들을 다운 받았다. train, val, test, face_split 데이터가 있고 총 4GB 가량 크기의 데이터셋이다.
- WIDER Face Dataset의 전체 이미지 개수와 얼굴 개수는 각각 32,203개의 이미지와 393,703개의 얼굴 데이터가 존재한다.
- WIDER Face Dataset에서 train / validation / test의 구성 비율은 각각 40% / 10% / 50%로 구성되어 있다.
2. 데이터셋 전처리 (1) 분석
- WIDER FACE Bounding Box
1) WIDER FACE 데이터셋은 Dace detection을 위한 데이터셋이므로 입력데이터는 이미지 파일이 있고, Ground Truth(GT)는 Bounding box 정보로 되어 있다.
2) 이전 스텝에서 다운 받은 파일은 4개의 디렉토리로 이루어져 있는데, WIDER_xxx로 되어있는 3개 디렉토리(train, val, test)에는 입력용 이미지 파일만 들어있다.
3) 이 디렉토리보다 구체적으로 분석해야할 것은 face_split 디렉토리 내에 있는 2개의 파일 안에 포함되어 있는 Bounding box 정보이다.
4) 코드 실습을 통해 파일의 데이터가 어떻게 구성되어 있는지 확인했다.
5) 그리고 함수를 만들어서 bounding box 정보를 파싱해서 리스트로 추출했다.
3. 데이터셋 전처리 (2) tf_example 생성
- tfrecord 만들기
1) 오늘 다루게 될 대용량 데이터셋의 처리속도 향상을 위해서 전처리 작업을 통해 tfrecord 데이터셋으로 변환할 필요가 있다.
2) 1개 데이터 단위를 이루는 tf.trian.Example 인스턴스를 생성하는 메소드를 만든다.
3) 이제 전처리를 위해 필요한 메소드들이 어느정도 갖춰졌다.
4) 데이터셋의 이미지파일, 그리고 bounding box를 파싱한 정보를 모아 방금 만든 make_example 메소드를 통해 만든 example을 serialize하여 바이너리 파일로 생성한다.
5) 위 과정을 코드 실습을 통해 구현했다. 이전 스텝에서 여기까지의 전처리 과정은 tf_dataset_preprocess라는 파일에 정리했다.
4. 모델 구현 (1) priors box
- SSD의 prior box
1) SSD 모델의 가장 중요한 특징 중 하나는 prior box(또는 anchor box)를 필요로 한다는 점이다.
2) prior box란 object가 존재할 만한 다양한 크기의 box의 좌표 및 클래스 정보를 일정 개수만큼 미리 고정해 둔 것이다.
3) ground truth에 해당하는 bounding box와의 IoU를 계산하여 일정 이상(0.5) 곂치는 prior box를 선택하는 방식이 RCNN 계열의 sliding window 방식보다 훨씬 속도가 빠르면서 유사한 정도의 정확도를 얻을 수 있다는 장점이 있다.
4) 코드를 통해 이번 프로젝트에 활용할 config 정보를 모아서 dict 구조로 정리했다.
5) 그리고 코드를 통해 config 중 prior(anchor) box 생성과 관련된 것들을 따로 확인했다.
6) 위 그림에서 보는 것 처럼 prior box를 생성하기 위해서는 먼저 기준이 되는 feature map을 생성한다. 그림에서는 8x8, 4x4의 예가 나오지만, 프로젝트에서는 4가지 유형의 feature map을 생성하게 된다.
7) 어떤 유형을 생성하는지 그리고 feature map별로 순회를 하면서 prior box를 생성하는 것을 코드로 실습했다.
8) 이번 스텝에서 본 prior_box 생성 과정을 make_prior_box라는 파일에 정리했다. 그리고 prior_box를 생성하는 최종 메소드인 prior_box()를 코드 실습을 통해 만들었다.
5. 모델 구현 (2) SSD
- SSD model 빌드하기
1) 이제 본격적으로 SSD 모델을 생성해볼 차례이다. 이번 스텝은 코드 실습을 통해 이루어졌다.
2) 우선은 SSD 모델 내부에서 사용하는 레이어들을 구현했다.
3) 레이어들을 준비하고, 본격적으로 SSD model를 생성했다.
4) 이번 스텝에서 해본 SSD model 생성 과정을 tf_build_ssd_model이라는 파일에 정리했다.
6. 모델 학습 (1) Augmentation, Prior 적용
- augmentation
1) 이제 모델 구성까지 완료했다.
2) 그러나 본격적으로 train을 진행하기 전에 몇 가지 더 남아있다.
3) 이전 스텝에서 구성한 tfrecordset 형태의 데이터셋은 아직 Data augmentation이 적용되지 않았다.
4) Object detection에서 사용하는 다양한 augmentation 기법을 적용해 주면 좀 더 성능향상을 기대할 수 있을 것이다.
5) augmentation을 위해 tf.data.TFRecordDataset.map() 내에서 호출할 메소드들은 아래와 같다.
(1) _crop
(2) _pad_to_square
(3) _resize
(4) _flip
(5) _distort
6) 코드를 통해 구현했다.
- Prior box 적용
1) SSD 모델의 특이점 중 하나가 prior box를 사용한다는 점을 앞에서 설명했다.
2) prior box 정보는 데이터셋에 반영되어야 한다.
3) 이 스텝에서 만든 메소드들은 prior box와 bounding box 사이의 IoU, 다른 말로는 jaccard index를 측정하기 위한 것이다.
4) 이후 이 메소드를 활용해 어떻게 데이터셋을 추가로 가공하는지 살펴보자.
5) jaccard index를 계산하는 메소드를 코드로 구현해봤다.
6) encode_tf는 이를 이용해서 ftrecord 데이터셋의 라벨을 가공하는 메소드이다. 내용을 정리하면 아래와 같다.
(1) jaccard 메소드를 이용해 label의 ground truth bbox와 가장 overlap 비율이 높은 matched prior를 구한다.
(2) _encode_bbox 메소드를 통해 bbox의 scale을 동일하게 보장한다.
(3) 전체 prior box에 대해 일정 threshold 이상 overlap되는 ground truth bounding box 존재 여부(positive / negative)를 concat하여 새로운 label로 업데이트 한다.
7) 코드를 통해 구현했다.
- load_dataset
1) 위에서 구현한 두 가지 메소드를 이전 스텝에서 생성한 tfrecord 데이터셋에 적용하여 SSD 학습을 위한 데이터셋을 생성하는 최종 메소드인 load_dataset을 구현한다.
(1) _trainsform_data : augmentation과 prior box label을 적용하여 기존의 dataset을 변환하는 메소드
(2) _parse_tfrecord : tfrecord에 _transform_data를 적용하는 함수 클로저 생성
(3) load_tfrecord_dataset : tf.data.TFRecordDataset.map()에 _parse_tfrecord을 적용하는 실제 데이터셋 변환 메인 메소드
(4) load_dataset : load_tfrecord_dataset을 통해 train, validation 데이터셋을 생성하는 최종 메소드
2) 코드를 통해 구현했다.
3) 이번 스텝에서 한 load_dataset 메소드 구현체를 tf_dataloader라는 파일에 정리했다.
7. 모델 학습 (2) Train
- Learning rate scheduler
1) 본격적으로 train에 들어가기 전에 두 가지 더 준비할 것이 남았다.
2) 그 중 하나가 Learning rate scheduler이다.
3) 이번에는 구간별로 learning rate가 일정하게 유지하면서 감소하는 PiecewiseConstantDecay를 상속받아, 초기시점에 WarmUp 부분을 추가한 PiecewuseConstantWarmUpDecay를 활용하겠다.
4) 코드를 통해 구현했다.
- Hard negative mining
1) Object Detection 모델 학습 시 자주 사용되는 Hard negative mining이라는 기법이 있다.
2) 학습과정에서 label은 negative인데 confidence가 높게 나오는 샘플을 재학습하면 positive와 negative의 모호한 경계선상에 분포한 false negative 오류에 강해진다는 장점이 있다.
3) 실제로 confidence가 높은 샘플을 모아 training을 다시 수행하기보다는, 그런 샘플들에 대한 loss만 따로 모아 계산해주는 방식으로 반영할 수 있다.
4) 구현된 hard_negative_mining 메소드와 이 메소드를 통해 얻은 샘플을 통해 얻은 localization loss를 기존의 classification loss에 추가로 반영하는 MultiBoxLoss 계산 메소드를 확인해보자.
- Training
1) 이제 본격적으로 모델 학습을 진행한다.
2) 배치사이즈, epoch 수 등 학습에 대한 기본설정은 config dict 내용에 이미 넣었다.
3) 이번 스텝에 소개한 모델 학습 과정을 train이라는 파일에 정리했다.
8. Inference (1) NMS
- NMS 구현하기
1) Grid cell을 사용하는 Object detection의 inference 단계에서 하나의 object가 여러 개의 prior box에 걸쳐져 있을 때 가장 확률이 높은 1개의 prior box 하나로 줄여주는 NMS(non-max suppression)이 필요하다.
2) 이를 만드는 것을 코드로 실습했다.
9. Inference (2) 사진에서 얼굴 찾기
- 사진에서 여러 개의 얼굴을 찾아보자.
1) 이제 마무리 단계이다.
2) SSD 모델을 통해 우리는 Multi-face detection 기능을 확보했다.
3) 얼마나 잘 했는지 확인할 필요가 있다.
4) inference와 화면 출력을 위한 몇가지 기능을 추가했다. 그리고 여러 사람의 얼굴이 포함된 이미지를 준비하고 성능을 확인해봤다.
5) 이번 스텝에서 한 과정을 inference라는 파일에 정리했다.
6) 나는 인터넷에 있는 씨스타 사진으로 해봤는데 4명의 얼굴을 잘 찾았다.
10. 프로젝트 : 스티커를 붙여주자
- 드디어 딥러닝 모델을 이용해 스티커앱을 개선해서 이미지 속 다수의 사람에게 스티커를 붙여줄 수 있게 되었다.
- 이제 지금까지 만든 작품을 통해 스티커를 붙여보자.
- Step 1. 스티커 구하기 혹은 만들기
1) 예전에 3번째 프로젝트를 할 때 왕관 또는 고양이 수염 혹은 기타 이미지를 통해 스티커를 붙여봤었다.
2) 이 때 사용했던 스티커를 사용해도 되고, 다른 이미지를 사용해도 된다.
- Step 2. SSD 모델을 통해 얼굴 bounding box 찾기
1) 위에서 실습코드를 진행하며 필요한 모델을 이미 생성했다.
2) 잘 훈련된 해당 모델을 통해 적절한 얼굴 bounding box를 찾아보자.
3) inference 파일을 적극 참고하면 도움이 될 것이다.
- Step 3. dlib을 이용한 landmark 찾기
1) 검출된 bounding box 별로 dlib을 이용해 face landmark를 찾을 수 있다.
2) inference파일에서 show_image 메소드를 사용할 부분을 잘 수정하면 가능할 것이라 한다.
3) 나는 3번째 프로젝트를 할 때 사용한 코드도 참고하여 실습했다.
- Step 4. 스티커 합성 사진 생성하기
1) 이제 선택한 인물사진에 스티커를 합성해보자.
2) 이미지에 너무 많은 사람 얼굴이 포함되어 있거나, 검출된 얼굴이 너무 작으면 스티커를 합성했을 때 어울리지 않을 것이다.
3) 따라서 어느정도 검출된 얼굴 크기가 크고(근접샷처럼 너무 커도 문제이다), 3~5명의 사람이 적당할 것이다. 그래서 씨스타 사진을 선택했던 것 같다.
4) 1명의 얼굴에 스티커를 붙여주는 방법은 3번째 프로젝트를 할 때 이미 해봤다. 이를 응용하면 여러 사람에게 스티커를 붙일 수 있을 것이다.
- 이 노드에 마지막에는 다른 노드와 달리 "그동안 수고많으셨습니다!!!" 이라는 말이 적혀있다.
- 앞으로 하나 남은 것으로 알고 있다. 여기서는 마지막에서 두번째 프로젝트이지만, 이 전까지는 이 프로젝트가 아마 마지막 프로젝트였던 것 같다.
'공부 > AIFFEL' 카테고리의 다른 글
Going Deeper(CV)_DJ 20 : 행동 스티커 만들기 (0) | 2021.05.07 |
---|---|
Going Deeper(CV)_DJ 19 : 사람의 몸짓을 읽어보자. (0) | 2021.05.06 |
Going Deeper(CV)_DJ 16 : 불안한 시선 이펙트 추가하기 (0) | 2021.05.03 |
Going Deeper(CV)_DJ 15 : 내 거친 생각과 불안한 눈빛과 그걸 지켜보는 카메라앱 (0) | 2021.04.29 |
Going Deeper(CV)_DJ 14 : 카메라 스티커앱을 개선하자! (0) | 2021.04.27 |