본문 바로가기

프로젝트

무이메이커스_딥러닝을 활용한 객체 인식 프로젝트 (Object Detection) (2/2)

프로젝트 진행 순서 (2/2)

  • 1. Object Detection 개요 (Overview)
  • 2. Custom Image Dataset 만들기 (Annotation)
  • 3. Image 데이터 전처리 (Preprocessing)
  • 4. Detection 딥러닝 모델 선정 (Modeling)
  • 5. 다양한 모델 별 성능 평가 및 시각화 (Evaluation and Visualization)
  • 6. 실생활 적용 (Application)

 

안녕하세요 헬스케어 제품 개발회사 허니컴의 무이메이커스페이스 입니다.

저희는 딥러닝을 접목시킨 제품 개발을 위해 다양한 프로젝트를 수행하고,

이를 활용하여 인공지능을 지닌 다양한 헬스케어 제품을 생산하는데 그 목적이 있습니다.

이번 시간에는 딥러닝을 활용한 객체 인식 프로젝트 2탄을 소개하고자 합니다.

목표는 5가지 종류의 Flower Image 를 구분하는 동시에 해당 위치까지 추정해내는 것이고,

Dataset 으로는 Kaggle 에서 제공되는 Flower Recognition Dataset 을 사용하였습니다.

https://www.kaggle.com/alxmamaev/flowers-recognition

Flowers Recognition

This dataset contains labeled 4242 images of flowers.

www.kaggle.com

총 4242 장으로 구성된 5개 종류의 Flower Dataset

 

4. Detection 모델 선정 (Modeling)

Alexnet 의 등장 이후 Computer Vision 분야에서 CNN 은 지속적으로 발전되어왔고,

Classification 뿐 아니라 Detection 영역에서도 좋은 성능을 보이며 적용되기 시작했습니다.

Overview 에서 이야기했듯이, Region 을 찾고 Feature 를 추출하여 Classification 과 Regression 이 연계되며,

다양한 Region 을 추출해 별도의 Classification 과 Regression 을 수행하는 Detection 접근법을

2-Stage Detector (R-CNN 계열 Detector), 

별도의 Region 추출 없이 Image 자체에서 Classification 과 Regression 을 수행하는 Detection 접근법을

1-Stage Detector (Yolo, SSD 등) 라고 말하며,

정확도가 필요할 경우 2-Stage Detector 를, 실시간이 필요할 경우 1-Stage Detector 를 사용합니다.

1) 2-Stage Detector

R-CNN 의 구조

R-CNN 계열은 Selective Search 를 통해 Region 을 선정한 뒤 CNN 을 통해 모든 Region 들을 Classification 하고

이후 Regression 을 통해 Bounding Box 를 Mapping 하는 과정으로 이뤄집니다.

그러나 초기의 R-CNN 은 몇 천개나 되는 Region 들을 일일히 Classification 해야하므로 속도가 매우 느리고

구조가 복잡하다는 단점이 존재하였습니다. (https://arxiv.org/abs/1311.2524)

Fast R-CNN 의 구조

그리하여 개선한 모델이 Fast R-CNN 입니다.

이는 처음부터 Region 을 찾는 것이 아닌, Image 전체를 CNN 에 넣어 Feature Map 을 생성한 후,

Region 을 찾게 되므로 대량 몇 천번의 CNN 계산을 할 필요 없이 단 한번의 CNN 계산으로 Detection 합니다.

따라서 속도의 향상을 가져오게 되었지만, Real-Time 에 적용하기 위해선 근본적인 문제,

Region Proposal 부분에서 계산하는 데 시간 소요가 아직도 크다는 단점이 존재하였습니다.

(https://arxiv.org/abs/1504.08083?context=cs.CV)

Faster R-CNN 의 구조

그리하여 Real-Time 에서도 시행할 수 있도록 개선된 모델이 Faster R-CNN 입니다.

(https://arxiv.org/abs/1506.01497)

이는 Region Proposal 을 위해 아예 Network 를 구성하여 (Region Proposal Network)

CPU 를 사용하는 Selective Search 방법이 아닌, GPU 를 사용한 Network 구조를 통해 Region 을 찾게됩니다.

이 과정에서 Anchor Box 라고 불리우는 Sliding Window 를 사용하고,

생성된 Region 들을 Fast R-CNN 과 마찬가지 과정으로 Classification 과 Regression 을 진행합니다.

cs231n 에 공개된 R-CNN 계열 성능 비교 분석표

속도 면에서 Faster R-CNN 은 높은 성능을 보였지만,

프레임으로 계산하면 최대 7프레임도 되지 못해 Real-Time 이라는 측면에선 접근하기 어렵습니다.

2) 1-Stage Detector

Yolo (https://arxiv.org/abs/1506.02640)

Yolo 의 객체 인식 과정

Yolo 는 하나의 네트워크 구조로 객체 인식을 마칠 수 있는 Real-Time Detection 을 고민한 모델입니다.

R-CNN 계열과 달리 Region 을 추출하지 않으며, Image 전체를 GoogleNet 을 변형한 CNN 구조로 이뤄진

Feature Extractor 에 넣어 그림의 Grid Cell 에 해당되는 Tensor of Prediction 을 추출하고,

해당 Tensor 내에는 Bounding Box 의 갯수와 위치 정보, Confidence Score, 지정된 Class 의 Probability 정보가 담겨있으며, Grid 별로 해당 Tensor 를 이용해 Class-Specific Confidence Score 를 추출합니다.

Yolo 와 다른 객체 인식 모델간의 성능 비교

다음 성능 표를 통해 Yolo 는 R-CNN 에 비해 낮은 mAP 를 보이지만

압도적인 FPS 를 통해 Real-Time 이 가능해짐을 보였습니다.

이후 Logistic Regression 이라던가 Backbone 의 변화 (Darknet53) 등으로 현재 Yolov3 까지 존재합니다.

(https://arxiv.org/abs/1804.02767)

5. 모델 별 성능평가 및 시각화 (Evaluation and Visualization)

1) 2-Stage Detector

다양하게 공개된 R-CNN 모델들이 존재하지만,

저희는 현재 Window 환경에서 Pytorch 를 사용하여 구현중으로,

기존 Linux 바탕의 오픈 소스들을 사용하기에 어려움이 있어 Pytorch 에서 공개된 예제 코드를 바탕으로

작성하여 구현하였습니다. (https://pytorch.org/tutorials/intermediate/torchvision_tutorial.html)

Detection 문제는 Annotation 된 데이터를 구하기 어렵기에,

대부분 기존에 학습된 모델을 불러와 사용하는 경우가 많습니다. (Transfer Learning or Fine Tuning)

저희도 데이터를 준비함에 있어 학습하기 위한 숫자가 적기 때문에 해당 방법을 적용하였고,

Pytorch 에서 제공되는 resnet50 을 이용한 모델을 사용하였습니다.

model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True) 
in_features = model.roi_heads.box_predictor.cls_score.in_features 
model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes) 

# (Git: https://github.com/pytorch/vision/tree/master/references/detection)

또한 해당 예제에서는 다음시간에 다룰 Segmentation 까지 진행하였으므로,

해당 부분을 제외하고 코드를 작성하였습니다.

class Dataset(object):
    def __init__(self, root, transforms):
        self.root = root
        self.transforms = transforms
        self.imgs = list(sorted(os.listdir(os.path.join(root, "Train"))))
        self.boxes = list(sorted(os.listdir(os.path.join(root, "Annotation"))))

    def __getitem__(self, idx):
        # load images ad masks
        img_path = os.path.join(self.root, "Train", self.imgs[idx])
        boxes_path = os.path.join(self.root, "Annotation", self.boxes[idx])
        img = Image.open(img_path).convert("RGB")

        boxes = []
        labels = []
        tree = ET.parse(boxes_path)
        root = tree.getroot()
        num_objs = len(root.findall('object'))
        for member in root.findall('object'):
            value = (
                root.find('folder').text,
                int(member[4][0].text),
                int(member[4][1].text),
                int(member[4][2].text),
                int(member[4][3].text)
            )
            boxes.append(value[1:])

            if value[0] == 'Daisy':
                label = 0
            elif value[0] == 'Dandelion':
                label = 1
            elif value[0] == 'Sunflower':
                label = 2
            elif value[0] == 'Rose':
                label = 3
            elif value[0] == 'Tulip':
                label = 4
            labels.append(label)

        # convert everything into a torch.Tensor
        boxes = torch.as_tensor(boxes, dtype=torch.float32)
        labels = torch.as_tensor(labels, dtype=torch.int64)
        image_id = torch.tensor([idx])

        target = {}
        target["boxes"] = boxes
        target["labels"] = labels
        target["image_id"] = image_id

        if self.transforms is not None:
            img, target = self.transforms(img, target)

        return img, target

    def __len__(self):
        return len(self.imgs)

이후 10번의 Epoch 을 통해 학습을 진행하였고,

Bounding Box 의 정확도가 0.993, Detection 된 id 가 3 이므로 위 코드에서 Rose 를 예측했고,

5장의 사진을 Test 하는데 2.8459초 가 걸렸으므로, 대략 fps 는 2 정도가 되고,

최종적으로 아래 사진과 같이 꽃을 인식하였음을 확인할 수 있었습니다.

R-CNN 을 통해 Object Detection 이 수행된 Image

 

2) 1-Stage Detector

먼저 R-CNN 모델에서 사용된 Annotation 들을 Yolo 형태에 맞춰 변환해주어야 합니다.

xml 형태의 기존 정보들을 txt 로 변환해주기 위해 아래의 오픈소스를 활용하였습니다.

(https://github.com/Isabek/XmlToTxt)

pip install -r requirements.txt
python xmltotxt.py -xml xml -out out

Yolo 형태로 변환하기 위해 해당 classes.txt 내용을 Custom Dataset 에 맞게 변환해줍니다.

Yolo 는 Pytorch 에서 별도로 공개된 오픈소스가 존재하지 않아,

자주 참조되는 Git 을 사용하였습니다. (https://github.com/eriklindernoren/PyTorch-YOLOv3)

해당 Git 에서 소개되는 Custom Dataset 을 구축하고 코드의 일부를 수정하여 사용합니다.

    parser = argparse.ArgumentParser()
    parser.add_argument("--epochs", type=int, default=20, help="number of epochs")
    parser.add_argument("--batch_size", type=int, default=8, help="size of each image batch")
    parser.add_argument("--gradient_accumulations", type=int, default=2, help="number of gradient accums before step")
    parser.add_argument("--model_def", type=str, default="config/yolov3plate.cfg", help="path to model definition file")
    parser.add_argument("--data_config", type=str, default="config/plate.data", help="path to data config file")
    parser.add_argument("--pretrained_weights", type=str, default="weights/darknet53.conv.74", help="if specified starts from checkpoint model")
    parser.add_argument("--n_cpu", type=int, default=8, help="number of cpu threads to use during batch generation")
    parser.add_argument("--img_size", type=int, default=416, help="size of each image dimension")
    parser.add_argument("--checkpoint_interval", type=int, default=1, help="interval between saving model weights")
    parser.add_argument("--evaluation_interval", type=int, default=1, help="interval evaluations on validation set")
    parser.add_argument("--compute_map", default=False, help="if True computes mAP every tenth batch")
    parser.add_argument("--multiscale_training", default=True, help="allow for multi-scale training")
    opt = parser.parse_args()

    dataset = ListDataset(train_path, augment=True, multiscale=opt.multiscale_training)
    dataloader = torch.utils.data.DataLoader(
        dataset,
        batch_size=opt.batch_size,
        shuffle=True,
        pin_memory=True,
        collate_fn=dataset.collate_fn,
    )

* 윈도우 환경이라면 weight 를 불러오는 과정에서 어려움이 있을 수 있습니다.

bash 명령어를 쓰기 위해 윈도우 개발자 모드를 이용해 우분투를 설치해 Bash 명령어를 사용할 수 있도록 합시다.

Yolo 를 통해 Object Detection 이 수행된 Image

Bounding Box 에 표시된 3 은 위 Class 에서 Rose 이므로, 맞는 Object 를 Detection 하였고,

정확도는 0.992, 소요되는 시간은 0:00:00.036 으로 대략 30프레임 정도의 fps 를 보여줍니다.

R-CNN 과 유사한 성능을 보이면서도 실시간성이 가능함을 확인할 수 있었습니다.

그러나 Flower Dataset 에 한하여 이러한 성능이 나타났을 뿐,

무리지어 날아가는 새 떼와 같은 사진에 있어서 Yolo 는 Grid 에 대한 한계가 존재합니다.

따라서 마냥 어떤 모델이 좋다고 단정지을 수 없으며,

제공되는 Dataset 에 맞춰 유동적으로 활용해보고 더 적합한 모델을 사용해야 합니다.

6. 실생활 적용 (Application)

최근 Object Detection 은 자율주행차 영역에서 자주 사용되고 있습니다.

차량 내 블랙박스 모듈에서 사람을 인식하는 부분이라던지, 혹은 도로 교통판을 인식하는 역할을 합니다.

또한 실시간이 가능하기에, 감시카메라에도 적용되며,

숫자나 글씨 학습을 통해 Optical Character Recognition 또한 가능합니다.

해당 영상을 통해 실시간 객체 인식에 대해 확인해보실 수 있습니다.

https://www.youtube.com/watch?v=Cgxsv1riJhI

 

4차 산업혁명을 통한 빅데이터와 인공지능 붐은 다양한 딥러닝의 발전을 가져왔으나,

아직까지 사람들에게 이는 친숙하지 못한 방법론이며 어떠한 데이터냐에 따라 그 변화가 다양하므로 정답이 존재하지 않습니다.

허니컴 메이커스페이스는 데이터에 따라 다양한 방향으로 딥러닝 모델을 적용해보며 '정답' 에 근접한 모델을 생성하고,

이를 사람들이 이해하기 쉽도록 시각화와 같은 방법을 통해 설명해나가고자 합니다.

........

시제품 제작 문의