아롱이 탐험대

얼굴 나이 인식기 개발 - 5 detect code (Using EfficientNet with Pytorch) 본문

Project/pytorch

얼굴 나이 인식기 개발 - 5 detect code (Using EfficientNet with Pytorch)

ys_cs17 2020. 9. 18. 11:34
반응형

Review

이번 시간에는 지난번에 이어서 trained weight를 가지고 detect 하는 code를 작성해보자.

 

전체 코드

https://github.com/yunseokddi/pytorch_dev/blob/master/facial_age_classifier/EfficientNet_ver/detect.py

 

detect 코드 자체는 크게 matplotlib, opecv, pillow를 통해 output image에 대한 결과를 시각화할 수 있다.

이번 시간에는 opecv를 통해 detect 결과에 대해 출력해보자.

 

detect.py

import torch
import cv2
import argparse

from efficientnet_pytorch import EfficientNet

parser = argparse.ArgumentParser()
parser.add_argument("--data", type=str, default='./sample/sample13.jpg')
opt = parser.parse_args()

필요한 module을 import 하고, 여러 이미지들을 detect 하기 위해 parser를 통해 이미지를 변경할 수 있도록 구성하였다.

 

age_dict = {0:'1~5', 1:'6~10', 2:'11~15', 3:'16~20',4 :'21~25', 5:'26~30', 6:'31~35', 7:'36~40', 8:'41~45',
            9:'46~50', 10:'51~55', 11:'56~60', 12:'61~65', 13:'66~70', 14:'71~'}

data_dir = opt.data
weight_path = 'weights/class_15_weights/best_weights_acc78.pth'

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

기본적으로 쓰이는 global variable이다. age_dict의 경우는 output 결과가 index로 나오기 때문에 초반에 설정했던 15개의 class를 각각 index로 mapping 하였다.

 

model = EfficientNet.from_pretrained('efficientnet-b3', num_classes=15)
model.load_state_dict(torch.load(weight_path))
model.to(device)

model.eval()

다음은 model선언 부이다. 학습할 때와 다른 점은 load_state_dict를 통해 우리가 학습 시킨 weight를 불러오는 과정이다.

또한 model을 eval로 선언하면서  weight update를 하지 않는다.

 

inputs = cv2.imread(data_dir)
inputs = cv2.resize(inputs, (200,200))
ori_img = inputs.copy()
inputs = inputs[:, :, ::-1].transpose((2, 0, 1)).copy()
inputs = torch.from_numpy(inputs).float().div(255.0).unsqueeze(0)
inputs = inputs.cuda()

다음은 model에 들어가기 전 input image에 대한 처리 과정이다.

우선 image를 opencv를 사용하여 읽은 후 학습시 input size였던 200*200으로 resize 해준다.

ori_img는 추후 출력을 위해 미리 copy를 해둔다.

그러고 나서 transpose를 진행하는데 이는 opencv와 pytorch의 input 형식이 다르기 때문이다.

opencv는 image를 (width, height, channel)로 처리하는 반면 pytorch는 (channel, width, height)로 처리한다.

그다음은 numpy image를 255로 나누고, torch tensor로 변환시켜준다. 여기서 unsqueeze를 진행하는데 그 이유는 model에 input으로 들어갈 때 train시에는 (batch, channel, width, height)로 들어가지만, detect시에는 image 1개에 대한 처리를 하기 때문에 batch 부분을 unsqueeze(0)을 통해 1로 한 차원 더 늘려준다.

따라서 최종적인 input shape는 (1,3,200,200)이 된다.

 

outputs = model(inputs)
_, preds = torch.max(outputs, 1)

cv2.putText(ori_img, str(age_dict[preds.item()]),(75, 15), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.5, color=(0,0,0))
cv2.imshow('result', ori_img)
cv2.waitKey(0)

마지막으로 model에 input을 넣어 output을 추출한 뒤 어느 class에서 확률이 가장 높은지 torch.max를 통해 해당 index를 뽑아낸다. index는 참고로 preds이다.

그리고 해당 결과를 출력하기 위해 putText를 통해 age text를 그리고, image를 출력한다.

 

INPUT: python3 detect.py --data "본인의 IMAGE PATH"

실험 결과 대부분의 image에 대한 acc가 높다. 하지만 문제점이 2가지 존재한다.

우선 학습 데이터 자체가 서양인 얼굴을 기준으로 하였기 때문에 동양인 얼굴의 나이 인식률은 매우 낮다.

또한 10대 후반~20대 후반까지의 얼굴들은 사람의 따라 노안, 동안인 경우가 많아 이 부분에서 정확도가 낮은 편이다.

이를 해결하기 위해서는 동양인 얼굴에 대한 dataset을 구해야 하지만 현재까지 찾아본 결과 open dataset은 존재하지 않았다. 또한 동안, 노안인 얼굴의 대해서는 현재까지도 얼굴 나이 관련 논문이 나오는 추세여서 아직은 해결되지 않은 것 같다.하지만 EfficientNet의 강력함을 확실하게 느낄 수 있었던 project였다는 부분에서 의의를 두고 싶다.

 

반응형
Comments