안녕하세요. 

이번 글에서는 YOLO V3 object detection "TECH REPORT"를 설명하려고 합니다.

 

지금까지 리뷰한 object detection 모델은 어떤 학회나 저널에 제출된 논문들이었습니다.

하지만, YOLO V3 저자는 YOLO V3가 YOLO V2를 약간 업데이트한 버전이라서 논문이 아닌 TECH REPORT 개념으로 작성한다고 언급했습니다.그래서, 현재 어떤 학회에 제출되지 않고 arXiv에만 올라와 있는 상태 입니다.

그렇게 때문에 YOLO V2를 잘 이해하고 있으시다면 어렵지 않게 이해하실 것으로 판단됩니다.

 

그럼, 지금부터 YOLO V3 TECH REPORT를 리뷰해보도록 하겠습니다.  

 

 

Paper: YOLOv3: An incremental Improvement

2018. 04. 08 arXiv  

[영어단어 및 표현 정리]

  • Incremental: Incremental is used to describe something that increases in value or worth, often by a regular amount.

 

 

 

0. Abstract

YOLO V3는 YOLO(V2)의 디자인을 약간씩 변경했다고 언급하고 있습니다. 대표적으로 변경한 부분은 새로운 네트워크 부분인데, 뒤에서 자세히 언급하겠지만 YOLO V2에서 사용했던 darknet19 darknet53으로 발전시켜 YOLO V3의 backbone 네트워크로 사용했습니다.

 

이러한 변경들로 인해 YOLO V2에 비해 모델이 약간 커지긴 했지만 정확성이 높아졌다고 합니다.

  • 320×320 (input resolution) YOLO V3 performance
    • Speed1 (mAP 기준): 22ms ← three times faster than SSD
    • Accuracy1 (mAP 기준): 28.2 mAP ← same as SSD
    • Speed2 (\(AP_{50}\) 기준):: 51ms (on Titan X) ← about four times faster than RetinaNet
    • Accuracy 2 (\(AP_{50}\) 기준):: 57.9 \(AP_{50}\) ← same as RetinaNet

 

 

이 논문에서는 YOLO V3를 mAP가 아닌 \(AP_{50}\)강조하고 있는데요. 이 이유에 대해서는 뒤에서 자세히 설명하도록 하겠습니다.

 

 

[영어단어 및 표현 정리]

  • swell: an old word that basically means fantastic, generally used by old people or hipsters to try to sound hip. 
    • YOLO V3 글 자체가 TECH REPORT다 보니까 슬랭(slang)어를 자주 사용하는 경우가 있습니다. 그래서, 공식사전같은 곳에서 swell의 뜻을 대입해 해석하면 이상해지는 경우가 많죠. 보통 영어 슬랭어는 Urban dictionary 라는 사전을 이용하면 잘 찾을 수 있습니다.

https://www.urbandictionary.com/

 

Urban Dictionary, August 25: milves

plural of milf.

www.urbandictionary.com

 

 

 

 

 

 

1. Introduction

[첫 번째 문단]

역시 official paper가 아니기 때문에 처음에 친숙한 어투로 글 전개를 시작 하는것 같습니다.

 

"가끔 그냥 너도 1년 동안 다른 짓만 할때도 있잖아? 나도 올해에는 research 많이 안하고 트위터만 한 듯... 뭐 물론 GAN 같은 것도 조금 해보긴 했지만...."

"그래도 여력이 조금 남아있어서 YOLO (V2) 성능을 조금 개선시키긴 했어~"

"근데 뭐 막 엄청 interesting한 기법을 쓴건 아니고, 조금씩 변화만 줘서 실험했어~"

 

 

 

[영어단어 및 표현 정리]

  • kinda: (구어) kind of ((발음대로 철자한 것))
  • momentum: If a process or movement gains momentum, it keeps developing or happening more quickly and keeps becoming less likely to stop. (=impetus)

 

 

 

[두 번째 문단]

 

대부분 학회에서는 "Camera ready due"가 있습니다.

학회같은 곳에서 다루는 paper 종류는 두 가지 입니다.

  • Accepted paper
  • Camera-ready paper

아래 그림1을 보면 "Paper Submission Deadline"이라고 나와있을 겁니다. 일반적으로 학회에 제출하여 논문에 accept되면 이를 "Accepted paper"라고 합니다. 

 

그런데, "accepted paper"를 최종 인쇄하기 위해서는 "폰트 종류, 크기", "대소문자" 등의 양식을 다시 통일시켜주어야 합니다. 이때 최종 인쇄를 위해 통일된 양식으로 바꾼 paper를 "Camera-ready paper"라고 보시면 됩니다.

그림1. CVPR (2021) Submission Timeline

 

YOLO V3 저자가 Camera-ready를 하긴했지만, "a source"가 없어서 TECH REPORT로 내기로 했다고 한 것 같네요. (정확히 "a source"가 무엇을 의미하는지는 모르겠습니다....)

 

 

 

[세 번째 문단]

이 tech report는 크게 세 가지 section으로 구성되어 있습니다.

 

  1. Deal: Method (YOLO V3에 대한 전반적인 architecture를 설명)
  2. How we do: Experiment (YOLO V3 결과 해석)
  3. Things we tried that didn't work: Ablation Study 개념
  4. What this all means: Conclusion + 기존 evaluation 방식 불만 제기

 

[영어단어 및 표현 정리]

  • intros: an introduction의 복수형 
  • y'all: you-all의 축약형
  • contemplate: 생각하다

 

 

 

 

 

 

2. Deal

Section2("2. The Deal) 에서는 YOLOv3의 아키텍처에 대해 설명합니다. Secion2 구성을 미리 설명하면 다음과 같습니다.

  • 2.1. Bounding Box Prediction: 제목 그대로 bbox prediction 할 때 사용되는 수식들을 설명합니다 (미리 말씀드리면, 이 부분은 YOLOv2와 동일합니다.
  • 2.2. Class Prediction
  • 2.3. Predicitons Across Scales: darknet-53으로 feature extraction 한 후, bounding box를 찾을 때 다양한 resolution에서 boundinb box를 찾는 방식을 설명합니다. 이 부분이 YOLOv2와 다른 첫 번째 특징입니다.
  • 2.4. Feature Extractor: YOLOv2에서 feature extractor로 사용한 darknet-19를 업그레이드 한, new classifier인 darknet-53을 소개 합니다. 이 부분이 YOLOv2와 다른 두 번재 특징입니다.
  • 2.5. Training: YOLOv3를 어떻게 학습시켰는지 설명합니다.

제가 글을 읽어보면서 순서를 조금 변경시키면 좋겠다고 판단하여, 이 블로그에서는 순서를 아래와 같이 변경하여 설명하려고 합니다.

  • 2.4. Feature Extractor
  • 2.3. Predictions Across Scales
  • 2.2. Class Prediction
  • 2.1. Bounding Box Prediction
  • 2.5. Training

 

 

2-4. Feature Extractor

YOLO V2에서는 feature extractor로써 darknet-19를 사용했었습니다. 아래 그림(테이블)에서 darknet-19를 보면 convolutional layer 19개인 것을 확인할 수 있습니다. YOLO V3에서는 residual connection을 이용하여 layer를 더 deep하게 쌓게 되었고, 그 결과 darknet-53을 만들 수 있게 되었습니다. 아래 그림에서 darknet-53convolutional layer가 총 52개인데, 아마 Avgpool(=average pooling layer) 직전에 1×1×1000 convolutional layer가 생략된 듯 합니다. 이렇게 추측한 이유는 다음과 같습니다.

  • Connected가 softmax 직전에 위치한 것을 보면 logit인 것을 알 수 있습니다. 
  • Connected는 average pooling 결과라고 볼 수 있는데, 아래 그림상으로는 average pooling에 들어가기 직전의 convolutional channel 수 는 1024개 입니다.
  • Average pooling 연산 후 1000개의 neuron을 출력하기 위해서는 입력 직전의 convolutional channel 수가 1000개여야 하기 때문에, 1000개의 채널을 갖는 1×1 convolutional layer가 생략되었다는걸 추측 할 수 있습니다.
  • 즉, 아래 그림의 convolutional layer 총 개수와 Avgpool 직전에 생략된 하나의 1×1 convolutional layer를 더하면 총 convolutional layer 개수가 53개인 것을 확인할 수 있습니다.   
  • (참고로, Size 부분에 "/2"라고 되어 있는 부분은 convolution filter의 stride=2라는 뜻입니다. Pooling이 아닌 conv filter의 stride를 통해 downsampling을 진행했네요)

 

 

Darknet-53을 자세히 도식화하면 다음과 아래 그림과 같이 표현할 수 있습니다. (제가 임의대로 그린거라 틀린부분이 있으면 말씀해주세요!)

 

그림2

 

 

위의 결과표를 보면 darknet-53이 darknet-19보다 좋은 accurcay를 기록하고 있다는걸 알 수 있습니다. ResNet-152보다는 accuracy가 조금 떨어지기는 하지만 더 효율적이라고 하는데, 이 부분은 바로 다음 문단에서 설명하도록 하겠습니다. 

 

 

 

Darknet-53이 ResNet 모델들 보다 efficient하다고 하는 이유는 FPS, BFLOP/s 에 있습니다 (BFLOP의 B는 Billion의 약자입니다. FLOPS에 대한 설명은 아래 글을 참고해주세요!)

 

https://89douner.tistory.com/159

 

4.NVIDIA GPU 아키텍처(feat.FLOPS)

안녕하세요~ 이번글에서는 NVIDIA에서 출시했던 GPU 아키텍처들에 대해 알아볼거에요. 가장 먼저 출시됐던 Tesla 아키텍처를 살펴보면서 기본적인 NVIDIA GPU 구조에 대해서 알아보고, 해당 GPU의 스펙

89douner.tistory.com

 

컴퓨터가 초당 연산할 수 있는 능력을 "BFLOP/s"로 나타내는데, "BFLOP/s"가 높을 수록 GPU가 1초에 더 많은 연산을 실행해준다는 것과 같으니 GPU utilization을 잘 활용한다는 것을 뜻하기도 합니다. 결국, darknet-53이 ResNet-152보다 성능이 약간 떨어지긴 해도 (개인적으로는 0.4%의 오차는 편차에 따라서 큰 의미가 없을 수 있다고 생각하긴 합니다만...), FPS (or GPU utilization)이 월등이 높기 때문에 더 "efficient"하다고 주장하는 것이지요.

 

 

 

 

[영어단어 및 표현 정리]

  • newfangle
    • 형용사로 쓰이는 경우: Eager for novelties; desirous of changing
    • 동사로 쓰이는 경우: To change by introducing novelties

 

 

 

 

2-3. Predictions Across Scales

 

 

위의 두 문단을 정리한 그림을 도식화해서 보여드리겠습니다. (아래 그림에서 "conv[3,3,32,64]/2"라고 되어 있는 부분에서 "/2"가 의미하는 바는 conv filter의 stride가 2라는 뜻힙니다 (즉, conv filter의 stride를 크게 설정함으로써 downsampling을 해주겠다는 뜻이죠))

<그림3 이미지 출처:  https://arxiv.org/ftp/arxiv/papers/1812/1812.10590.pdf>

 

 

 

<그림4 이미지 출처:  https://blog.paperspace.com/how-to-implement-a-yolo-object-detector-in-pytorch/>

 

 

 

우선 저 "We perform the same design~ " 문단은 정확히 무엇을 의미하는 내용들인지 모르겠네요. 

"We still use k-means ~" 문단은 YOLOv3가 학습 전에 bounding box의 aspect ratio를 각 scale마다 어떻게 설정해 줄 지 사전정의한 hyper-parameter 입니다. (제 생각으로는, (10×13), (16×30), (33×23) 이렇게 3개는 small object (52×52 feature map과 관련된 bounding box 정보인듯 합니다. 아니라면 답변주세요!)

 

 

 

 

2-2. Class Prediction

 

우선 위의 문장에서 의미하는 바들을 이해하기 쉽게 풀어서 설명해보도록 하겠습니다.

 

COCO dataset80개의 클래스를 갖고 있습니다. 즉, COCO dataset의 이미지들을 분류하겠다는 것은 80개의 class들을 분류하는 multi-classification task인 것이죠. 그런데, 80개의 클래스들이 모두 서로 전혀관계가 없는 것은 아닙니다. 예를 들어, 80개에 "Person", "Man"이라는 클래스가 포함될 수 도 있는데, 이 두 클래스는 서로 독립적인 클래스가 아니죠. 왜냐하면, "Man"은 "Person"의 부분집합 개념이기 때문입니다. 그래서, '앨론 머스크' 이미지를 classification하면 "Man"이 나올 수 도 있고, "Person"이 나올 수 도 있는 것이죠. (보통 이러한 관계를 지닌 클래스들은 서로 hierarchy한 구조를 갖고 있다고 합니다)

 

일반적으로 classification 방식은 softmax를 취해준 후, cross entropy를 계산하는 경우가 대부분입니다. 그런데, softmax를 취해주면 logit값(=softmax 입력 값: \(z_{i}\))이 제일 높은 하나의 클래스 확률 값만 지나치게 높게 설정해주는 경우가 있습니다. 이렇게 하나의 클래스 확률 값만 높여주는 이유는 입력 이미지에는 하나의 클래스만 있을 것이라는 가정을 하기 때문입니다. 

 

<그림5 이미지 출처: https://gombru.github.io/2018/05/23/cross_entropy_loss/>

 

 

 

그런데, 앞서 설명했듯이 위의 '앨론 머스크' 이미지는 두 가지 클래스(=레이블)를 갖고 있을 수 있다고 했습니다. 즉, muti-label 이미지인 것이죠. 그래서, 이 경우는 multi-label을 모두 정확하게 예측하기 위해서 independent logistic classifiers를 사용합니다. 

 

<그림6>

 

 

 

 

2-1. Bounding Box Prediction

※"2-1.Bounding Box Prediction" 파트는 총 두 문단으로 구성되어 있는데, 여기에서는 문단 순서를 바꾸어 설명하도록 하겠습니다.

 

 

위의 문장을 요약하면 아래 그림으로 표현할 수 있습니다.

YOLOv3는 한 번 연산할 때, feature map의 한 cell당 총 3개의 box에 해당하는 3d-tensor들을 출력합니다. 이론적으로, 한 번 학습 시 생성되는 bounding box 개수는 (10647=52×52×3+26×26×3+13×13×3) 일겁니다. 여기서 IOU가 제일 높은 box의 3d-tensor만 loss function을 위해 사용하게 됩니다. 또한, IOU가 제일 높은 3d-tensor의 objectness score(=confidence score)를 1로 설정해줍니다. (이 과정을 굉장히 간단하게 설명했지만, 실제로 bounding box 후보군을 가려내는 작업은 훨씬 복잡합니다. 이 부분은 코드 구현 부에서 좀 더 자세히 다루도록 하겠습니다)

 

<그림7>

 

YOLOv3에서는 IOU의 threshold를 0.5로 설정하고 있습니다. 그렇기 때문에, 초기에는 10647개 box들의 IOU가 모두 0.5가 넘지 않을 수 도 있습니다. 이 경우에는 아래 YOLO loss에서 objectness loss 부분을 제외한 regression loss, classification loss를 발생시키지 않습니다. (아마, loss를 발생시키지 않는다는 것은 loss 값을 0으로 할당시켜준다는 뜻 같은데, 이 부분은 코드를 리뷰하면서 더 자세히 살펴보도록 하겠습니다. (사실 엄밀히 말하면 아래 수식은 YOLOv1의 loss function입니다. 실제로는 시그마 부분이 좀 변경되어야 할 것 같네요.)

 

<그림8>

 

 

 

 

 

 

이 부분은 YOLOv2와 똑같기 때문에 설명을 더 하지는 않겠습니다. 

(↓↓↓아래 글에서 "3-3) Direct location prediction" 부분을 참고해주세요!↓↓↓)

https://89douner.tistory.com/93

 

10. YOLO V2

안녕하세요~ 이번글에서는 YOLO V1을 업그레이드한 버전인 YOLO V2에 대해서 알아보도록 할거에요. YOLO V2 논문에서는 YOLO V1을 3가지 측면에서 업그레이드 시켜서 논문 제목을 Better, Faster, Stronger이라

89douner.tistory.com

 

 

 

 

 

3. How We Do

[첫 번째 문단]

COCO dataset의 mAP 성능을 살펴보니 SSD variants (SSD513, DSSD513)와 동일한 반면 속도는 3배더 빨랐다고 합니다. 하지만, 여전히 RetinaNet의 mAP 성능을 뛰어넘진 못했네요. (YOLO v3 저자는 mAP 방식의 evaluation 방식이 "weird"하다고 표현했는데, 그 이유는 "5.What This All Means"에서 설명드리도록 하겠습니다) 

 

[영어단어 및 표현 정리]

  • on par with: ~와 동등(대등)한

 

(※아래 "stealing all these tables from [9]" 표현은 RetinaNet 모델 결과는 RetinaNet 논문 [9]에서 그냥 가져온거라고 합니다. RetinaNet을 Scratch로 구현하려면 너무 오래 걸린기 때문에 이렇게 했다고 하네요)

그림?

 

 

 

[두 번째 문단]

하지만, \(AP_{50}\)을 기준으로하면 YOLOv3의 성능은 RetinaNet과 동등해집니다. 하지만, IOU의 threshold를 올리면 AP 성능이 급격히 떨어지는데, 이러한 것으로 보아 YOLOv3 모델이 어떤 객체를 완전히 "fit"(정확)하게 detect하지 못하는걸 알 수 있습니다.

 

그림?+1

 

[영어단어 및 표현 정리]

  • on par with: ~와 동등(대등)한
  • excel at ~ing: ~하는 것이 뛰어나다 

 

 

[세 번째 문단]

위의 그림?(Table 3)을 보면 예전 YOLO(v2) 같은 경우에는 small object에 대한 성능이 매우 안좋았음을 알 수 있습니다. "2.3. Predictions Across Scales"에서 언급된 multi-scale predictions을 이용해 small object에 대한 AP (\(AP_{S})\)를 향상시킬 수 있었습니다. 

하지만, medium, large size objects의 detection 성능 향상 정도가 small object 성능 향상 정도에 미치지 못했다고 합니다. (개인적으로는 뭐... 당연한거 같다는 생각이... YOLO V2에서 multi-scale을 쓰지 않았으면 small object를 아예 놓치는 경우가 있을 수 있을테니, 이런 경우에 mAP를 성능을 크게 깍아먹지 않았었을까라는 생각이 드네요.)

 

 

[영어단어 및 표현 정리]

  • get to the bottom of it: 진상을 규명하다; 진짜 이유를 찾아내다.
    • "get to the bottom of ~"의 본래 뜻은 ~의 바닥까지 본다입니다. 진상을 확인 하는 것도 보이지 않는 밑바닥까지 살펴보는 행위라고 볼 수 있기 때문에, 관용어구로 사용됩니다.

 

 

 

[세 번째 문단]

(논문에서 "see figure 5"라고 했는데, 제가 봤을 땐 오타 같습니다. "see figure 3"이 맞는듯 하네요.)

확실히 mAP보다 mAP-50 지표로 보면 YOLOv3의 성능이 굉장히 좋게 보입니다.

 

mAP-50 기준 결과
mAP 기준 결과

 

 

 

 

 

4. Things We Tried That Didn't Work

이 부분은 오히려 설명을 하는게 YOLOv3를 이해하는데 더 혼동시킬 수 도 있다고 생각하여 따로 글을 올리진 안았습니다. 아래 영상 "24:38~27:00"를 참고하시는게 더 좋을 듯 합니다.

 

 

 

 

 

 

 

5. What This All Means

[첫 번째 문단]

저자는 YOLOv3가 mAP와 \(AP_{50}\) 간의 성능차가 심하게 나는 것을 강조하고 있습니다.

 

 

[두 번째 문단]

mAP 성능이 안좋아서 그런지.... ,mAP를 evaluation 지표로 사용하는 것에 대한 불만을 제기하는데, 그 이유는 아래와 같습니다.

 

"사람도 50% IoU와 30% IoU를 잘 구분하지 못하는데, 즉 20% 차이나는 IOU gap도 구별을 못하는데, 50%, 55%, 60%, ..., 95%씩 나눠서 평가하고 mAP을 구하는게 무슨 의미가 있는거냐"

 

저자는 추가적인 (좀 더 근본적인) 이유도 이야기를 하는데, 그 내용은 뒤에 "6.Rebuttal"에서 설명하도록 하겠습니다.

 

 

[영어단어 및 표현 정리]

  • cryptic: A cryptic remark or message contains a hidden meaning or is difficult to understand.

 

 

 

[세 번째, 네 번째, 다섯 번째 문단]

그리고, 자신이 개발 중인 기술에 대한 근원적인 질문을 합니다.

 

"우리가 object detection 기술을 가졌으니, 그걸로 뭘 할거냐?"

 

이 질문과 함께 자신이 개발한 기술이 privacy를 침해하는 데 사용될 수 있고, 사람을 죽이는 military 목적으로 사용될 수 있다는 것을 우려하고 있습니다. 해당 기술 (Object Detection)은 동물원의 얼룩말 수를 세는 것이나, 자신들의 애완동물을 잘 찾을 수 있는 용도로 사용되어야 한다고 강조합니다. 그리고, 이러한 방향으로 기술이 개발되도록 책임의식을 갖어야 한다고 주장하면서 글을 마무리합니다. (트위터도 끊을 거라고 하네요.. 근데, 2020년에 트위터 내용을 보니 못 끊은건지... 다시 가입한건지..)

 

 

 

 

 

 

6. Rebuttal

Reference 뒷 부분을 보면 "Rebuttal"이라는 section이 있습니다. 일반적으로 저자가 논문이나 자신의 article을 제출하면 reviewer들이 comment를 남깁니다. 그럼, 저자는 해당 comment에 대한 답변을 해야하는데 이러한 답변을 보통 "Rebuttal Letter"라고 부릅니다. 보통 답변을 할 때는 두 가지의 제스처를 취할 수 있습니다.

  • 수락: reviewer들로부터 피드백 받은 comment들 기반으로 잘 내용들을 업데이트 하겠다.
  • 반박: reviewer들이 comment한 것을 동의하기 어려운 경우도 있습니다. 이 때는 동의하지 않는 이유를 설명합니다. 

 

YOLO V3 tech report에서는 저자가 따로 comment 받은 내용과 자신의 rebuttal letter를 "Rebuttal" section으로 만들어 공개했습니다. (첫 번째 문단을 보면 ICCV에 제출한건지......)

첫 번재 문단은 따로 설명하지 않겠습니다. YOLO랑 크게 관련 없는 내용이라....

 

 

[첫 번째 문단 관련 영어단어 및 표현 정리]

  • shouts: shout이 보통 복수형으로 쓰이면 '외침'이라는 뜻으로 쓰이긴 하는데, 슬랭의 의미로 사용할 때는 누군가가 좋은 아이디어를 낼 때 "that's shouts'라고 사용한다고 하네요.
  • heartfelt: 진심어린
  • invariably: 변함없이, 언제나

 

 

[첫 번째 Reviewer: Dan Grossman]

첫 번째로 받은 comment는 "Figure 1, 3"에 대한 지적입니다. "Figure1", "Figure3" 두 그림을 보면 YOLOv3 그래프의 X축이 0부터 시작하지 않습니다. 

 

 

 

그래서, 이러한 comment를 받아들여, 아래와 같은 "Figure 4"를 만들어 제공했습니다.

 

[첫 번째 Reviewer관련 용어]

  • AKA: 일명 ~로 알려진 (as known as ~)
  • throw in ~: ~를 덧 붙이다.

 

 

[두 번째 Reviewer: JudasAdventus]

JudasAdventus라는 사람이 "the arguments against the MSCOCO metrics seem a bit weak."라고 comment 해준 것 같은데, 뭔가.. YOLO v3 저자가 굉장히 기분 안좋은 것 같은 반응을....(제가 해석을 잘 못 하고 있는건지...) 아마, reviewer가 "COCO 데이터 셋은 segmentation 관련 label도 진행하기 때문에 더 정확한 bounding box 정답 좌표를 갖고 있을 것이기 때문에 COCO metric을 쓰는 것에 대한 반문은 "bit weak"하다고 한 것 같습니다. 그러자, 저자는 그런게 문제가 아니라 mAP 쓰는 것에 대한 정당성 자체에 문제를 제기하고 있는 거라고 반문합니다. (그 이유는 아래 문단에서...)

 

 

 

YOLO v3 저자가 지적하는 바는 다음과 같습니다. Objecet detection 모델은 bounding box loss와 classification loss로 구성된 multi-task learning (← classification 학습도 하고, bounding box regression 학습도 하기 때문에 multi-task learning이라고 부름) 을 하는데, 기본적으로 bounding box regression 부분을 지나치게 강조하면 classification 학습이 잘 안될 수 있다는 것이 문제임을 제기합니다. 현실적으로도 물체를 잘 classification하는게 중요한거지 bounding box의 IoU를 50%, 55%, 60% 이런식으로 타이트하게 맞추는게 더 중요하지 않다고 주장하고 있습니다. (예를 들면, 보행자에서 지나가는 물체가 사람임을 인식하는게 중요한거지 사람에 대한 bounding box를 정확히 치는것이 중요하지 않다는 논리인것 같습니다)

 

또한, mAP라는 성능 지표자체가 갖고 있는 치명적인 결함은 다음과 같습니다. 아래 그림에서 누가봐도 "Detection #1"의 결과가 "Detection #2"의 결과보다 좋은거 같은데, 실제 "Detection #1"과 "Detection #2"의 mAP 값이 동일하게 나옵니다. 그 이유는 다음과 같습니다.

 

그 이유는 아래글에서 object detection에서의 precision 개념을 살펴보시면 이해할 수 있으실 겁니다! (간단하게만 말하자면, Detector2의 경우 FN이 많아진 것일 뿐, TP, FP의 개수에는 변함이 없습니다. 그래서, Precision=TP/(TP+FP) 수식 관점에서는 precision은 변하지 않는 것이죠)

https://89douner.tistory.com/76?category=878735 

 

 

 

 

 

 

위와 같은 이유를 들어 저자는 mAP 성능 지표를 쓰는 것이 현실적으로 의미가 있는거냐라는 질문을 다시 한 번 하고 있습니다.

 

 

 

 

 

 

 

 

 

7. Joseph Redmon quits CV research

 

YOLO V1부터 YOLO V3까지 개발해왔던 Joseph Redmon은 2020년이 되자 더 이상 CV (Computer Vision) 연구를 진행하지 않겠다고 선언합니다. 자기가 개발하는 CV 기술들이 군사목적으로 사용되는 것도 원치 않고 privacy 문제도에도 영향을 미치는 것 같다고 합니다 (뭐 드론 같은데에 잘 못 쓰이면 심각한 privacy 문제가 생길 수 있죠). 그래서 YOLO를 더 이상 개발하지 않습니다.

 

 

하지만, Alexey Bochkovskiy라는 러시아 연구원이 이전부터 YOLO 연구를 계속하고 있었기 때문에, Joseph Redmon이 YOLO 개발 중지 선언한 두 달 뒤 (2020.04.23) YOLO V4를 개발하고 논문화합니다. YOLO V4는 다른 글에서 설명하도록 하겠습니다. 

 

 

 

 

 

[참고한 자료]

1. PR-12. YOLOv3 이진원님 발표영상

 

'Deep Learning for Computer Vision > Object Detection (OD)' 카테고리의 다른 글

14. Object Detection Trend (2019~2021.08)  (7) 2021.09.12
11. SSD  (3) 2020.02.06
10. YOLO V2  (4) 2020.02.06
9. YOLO V1  (4) 2020.02.06
8. Faster RCNN  (1) 2020.02.06

안녕하세요.

이번 글에서는 training 과정 visualization 해주는 패키지를 소개하려고 합니다.

 

기본적으로 pytorch에서는 tensorboard를 사용하여 loss, accuracy 등 다양한 metrics와 weight, gradient 값들을 histogram으로 볼 수 있도록 summarywriter라는 가능을 제공하고 있습니다.

 

torch.utils.tensorboard import SummaryWriter

 

(↓↓SummaryWriter 사용법↓)

https://pytorch.org/docs/stable/tensorboard.html

 

torch.utils.tensorboard — PyTorch 1.9.0 documentation

torch.utils.tensorboard Before going further, more details on TensorBoard can be found at https://www.tensorflow.org/tensorboard/ Once you’ve installed TensorBoard, these utilities let you log PyTorch models and metrics into a directory for visualization

pytorch.org

 

 

 

하지만, 이외에 많은 분들이 "Weight and Biases"에서 제공하는 wandb 패키지를 이용해 학습과정들을 visualization하기도 하는데요. 이번 글에서는 wandb 패키지를 이용해 어떻게 visualization 할 수 있는지 살펴보도록 하겠습니다.

 

 

※이전 글에 있는 코드에 wandb 패키지를 적용하는 법을 설명하도록 할테니, 중간중간 코드가 이해안되시는 분들은 꼭 이전 글들을 봐주세요!

 

 

[필자의 개발환경]

OS: Window

가상환경: 아나콘다

딥러닝 프레임워크: Pytorch

IDE: Visual Studio Code

 

 

1. 회원가입 및 wandb 연동하기

1-1. wandb 패키지 설치하기

먼저,  제 경우에는 아나콘다 가상환경VS Code interpreter에 연동시켜 사용하고 있기 때문에 아나콘다에 wandb 패키지설치하도록 하겠습니다.

 

(↓↓ 아나콘다 가상환경에 다양한 패키지 설치 및 VS code 연동 방법↓)

https://89douner.tistory.com/74

 

5. 아나콘다 가상환경으로 tensorflow, pytorch 설치하기 (with VS code IDE, pycharm 연동)

안녕하세요~ 이번시간에는 아나콘다를 통해 2개의 가상환경을 만들고 각각의 가상환경에서 pytorch, tensorflow를 설치하는법을 배워볼거에요~ Pytorch: Python 3.7버전/ CUDA 10.1 버전/ Pytorch=1.4버전 Tensorf..

89douner.tistory.com

 

 

우선 "anaconda wandb"라고 검색하니 아래 사이트가 나옵니다. 해당 사이트에 접속해보겠습니다.

https://anaconda.org/conda-forge/wandb

 

Wandb :: Anaconda.org

 

anaconda.org

 

 

접속하니 아래와 같은 화면이 뜹니다. 아나콘다wandb설치하는 명령어를 알려주네요. 

해당부분을 복사합니다.

그림1

 

 

 

우선 저는 대부분의 패키지(pytorch 등)아나콘다 base라는 가상환경에 설치되어 있기 때문에, base 가상환경복사한 명령어입력하여 설치진행해주겠습니다.

그림2

 

 

1-2. Wandb (Weight and Biases) 회원가입

wandb 패키지이용하려면 "Weight and Biases"회원가입이 되어 있어야 합니다.

그래야 "Weight and Biases" 웹 사이트와 연동하여 visualization 결과들을 살펴볼 수 있기 때문이죠.

 

그럼 "Weight and Biases"에 회원 가입을 해보도록하겠습니다.

 

우선 아래 "Weight and Biases" 사이트접속합니다.

https://wandb.ai/site

 

Weights & Biases – Developer tools for ML

A central dashboard to keep track of your hyperparameters, system metrics, and predictions so you can compare models live, and share your findings.

wandb.ai

 

 

 

접속을 하시면 아래화면이 처음 등장하게됩니다. 그리고 회원가입 버튼 "Sign up"을 클릭해줍니다.

그림3

 

 

그럼 아래와 같이 회원가입 창이 뜹니다. 제 경우에는 github과 연동해서 사용하려 하기 때문에, "Sign up with GitHub"을 클릭해서 사용하도록 하겠습니다.

 

그림4

 

 

 

그리고 "Authorize wandb" 을 클릭해줍니다.

 

그림5

 

 

마지막으로 아래와 같이 계정생성에 필요한 정보를 입력하시면 회원가입이 완료가 됩니다.

그림6

 

 

 

회원가입 후, 로그인을 하시면 아래와 같은 화면이 나타납니다.

그림7

 

 

우선 이 화면은 대기해 놓고 아나콘다 가상환경wandb연동하는 작업부터 하겠습니다.

 

 

 

 

 

 

2. 아나콘다 가상환경과 wandb 연동하기

앞서 언급했듯이 "아나콘다 가상환경을 VS Code interpreter에 연동시켜 사용하고 있고", Weight and Biases 웹 사이트와 연동하여 visualization 결과"를 볼 수 있기 때문에, 아나콘다 가상환경에서 Weight and Biases 웹 사이트와 연동시켜주어야 합니다.

 

연동 방식은 간단합니다.

먼저 아래와 같이 순서를 진행합니다.

  • base 가상환경 프롬프트 열기
  • wandb login 명령어 입력
  • 아래 빨간색 박스 사이트 복사

그림8

 

  • 위에서 복사한 사이트 접속시 아래 화면이 출력 해당 인증키 복사

그림9

 

  • 복사한 인증키 아래 빨간색 밑줄 부분에 붙여넣기하고 엔터 (참고로 저는 복붙이 잘 안돼서 메모장에 복붙한다음 하나씩 인증키를 입력했습니다;;;;)

그림10

 

 

 

연동완료 되었습니다!

그림11

 

 

 

 

3. Project 생성해주기

VS Code에서도 task 마다 별도의 project를 만들게 됩니다. 그렇다면 각각의 task마다 visualization 하려는 정보들도 모두 다르겠죠? 그래서, task 별로 wandb의 visualization project를 만들어 주는것이 좋습니다. (그래야 task 마다 visualization 기록들을 용이하게 관리 할 수 있어요.)

 

그림12

 

 

 

그럼 WandB(=W&B) project생성해보겠습니다. 

먼저 좌측 상단 "Home" 부분에 "Projects"→"Create new project"를 클릭 해주세요

그림7

 

 

 

 

아니면 아래 사이트(="wandb.ai/username")에 직접 접속해서 우측에 있는 "Create new project"를 클릭해주세요.

그림13

 

Project name설정하고 생성해줍니다.

우선 저는 개인용으로 사용할 거라 "private" 버전으로 만들었습니다.

그림14

 

 

 

 

Project생성되면 아래 화면이 출력됩니다.

이제 VS code에서 wandb 패키지로 visualization 관련 코드를 입력하고 실행시키면, 아래 화면에 visualization 결과들이 생성됩니다. 그럼 이제 VS code에서 관련 코드들을 입력해볼까요? 

그림15

 

 

 

3. VS code에 visualization을 위한 wandb 관련 코드 입력하기

제일 먼저 할 것은 wandb 패키지import 시켜주는 것입니다.

현재 "alb_train2.py"에 train 관련 코드가 들어가 있습니다.

 

("alb_train2.py" 파일은 VS code 상에서 UNet segmentation project에 속해있는데, 해당 project가 base 아나콘다 가상환경 interpreter에 연동되어 있습니다. 앞서 base 아나콘다에 wandb 패키지를 설치했기 때문에 에러없이 import wandb 를 수행할 수 있습니다.) 

그림16

 

 

그리고 train_model 함수 부분에 먼저 두 개코드 입력해줍니다.

  • wandb.init()
  • wandb.watch()
def train_model(net, fn_loss, optim, num_epoch):
    wandb.init(project='test', entity='douner89') #추가된 코드
    wandb.watch(net, fn_loss, log="all", log_freq=10) #추가된 코드
    since = time.time()

    best_model_wts = copy.deepcopy(net.state_dict())
    best_loss = 100

 

 

3-1. wandb.init()

먼저, wandb.init() 함수에 대해 설명해보도록 하겠습니다.

 

(↓↓↓ wandb.init() API ↓)

https://docs.wandb.ai/ref/python/init

 

wandb.init

 

docs.wandb.ai

 

 

 

먼저 위의 사이트를 접속한 후, 제일 먼저 눈에 보이는 문장은 아래와 같습니다.

 

"you could add wandb.init() to the beginning of your training script as well as your evaluation script"

 

위와 같은 설명을 토대로 train 함수 첫 번째 부분에 wandb.init() 함수를 구현해놨습니다.

 

wandb.init() 함수 인자들은 아래와 같이 설명이 나와있습니다.

 

그림17

 

 

이 중에서 우선 두 가지 argumetns 설명하도록 하겠습니다.

  • project: 앞서 생성한 project 명 (←"그림14" 참고)
  • entity: 앞서 계정 생성시 설정한 user name (←"그림14" 참고)

해당 project, entity 명을 제대로 입력 해주어야 연동된 weight and biases 사이트에 정보들이 전송이됩니다.

 

 

 

 

 

3-2. wandb.watch()

이번엔 wandb.watch() 함수에 대해서 알아보겠습니다.

 

(↓↓↓ wandb.watch() API ↓↓↓)

https://docs.wandb.ai/ref/python/watch

 

wandb.watch

 

docs.wandb.ai

 

 

해당 API reference를 살펴보면 아래와 같은 문구가 나옵니다.

 

"Hooks into the torch model to collect gradients and the topology."

 

즉, gradient, topology와 관련 정보visualization 해주기 위해 입력해주는 코드라고 하네요.

결국 이 코드로 인해 gradient, topology 값들을 visualization 해줄 수 있게 됩니다. 

 

아래 argument에서 3가지 정도만 설명하겠습니다.

  • models: 딥러닝 모델
  • criterions: loss function
  • log: all이라고 설정하면, gradient, parameters와 관련된 값들을 visualization 해서 볼 수 있습니다.

그림18

 

 

 

3-3. wandb.log()

train_model 함수"#추가된 코드3" 부분을 보면 "wandb.log"라는 코드를 볼 수 있으실 겁니다.

 

(↓↓ wandb.log() API ↓)

https://docs.wandb.ai/ref/python/log

 

wandb.log

 

docs.wandb.ai

 

 

위의 API에서 설명하듯이, wandb.log 함수에 내가 visualization 하고 싶은 argument를 넘겨줄 수 있습니다. 아래 코드에서는 epochtraining lossvisualization 해주기 위해 아래와 같이 입력했습니다.

 

wandb.log({'Epoch': epoch, 'loss': np.mean(loss_arr)})

 

(※wandb.log() API를 보면 알 수 있듯이 다양한 정보들을 visualization (ex: gradient 'histogram', image, etc...) 를 할 수 있으니 참고해주세요)

 

# TRAIN MODE
def train_model(net, fn_loss, optim, num_epoch):
    wandb.init(project='test', entity='douner89') #추가된 코드1
    wandb.watch(net, fn_loss, log="all", log_freq=10) #추가된 코드2
    since = time.time()

    best_model_wts = copy.deepcopy(net.state_dict())
    best_loss = 100

    for epoch in range(st_epoch + 1, num_epoch + 1):
        net.train()
        loss_arr = []
        batch_order=0

        for batch, data in enumerate(loader_train, 1):
            batch_order=batch_order+1
            data['label'] = data['label']/255.0

            input = data['input']
            label = data['label']

            # forward pass
            label = data['label'].to(device)
            input = data['input'].to(device)

            output = net(input)

            # backward pass
            optim.zero_grad()

            loss = fn_loss(output, label)
            loss.backward()

            optim.step()

            # 손실함수 계산
            loss_arr += [loss.item()]

            print("TRAIN: EPOCH %04d / %04d | BATCH %04d / %04d | Batch LOSS %.4f" %
                (epoch, num_epoch, batch, num_batch_train, np.mean(loss_arr)))
        
        print("#############################################################")
        print("TRAIN: EPOCH %04d | Epoch LOSS %.4f" %
                (epoch, np.mean(loss_arr)))
        print("#############################################################")
        wandb.log({'Epoch': epoch, 'loss': np.mean(loss_arr)}) #추가된 코드3



        with torch.no_grad():
            net.eval()
            loss_arr = []

            for batch, data in enumerate(loader_val, 1):
                data['label'] = data['label']/255.0

                # forward pass
                label = data['label'].to(device, dtype=torch.float32)
                input = data['input'].to(device, dtype=torch.float32)

                output = net(input)

                # 손실함수 계산하기
                loss = fn_loss(output, label)

                loss_arr += [loss.item()]

                print("VALID: EPOCH %04d / %04d | BATCH %04d / %04d | LOSS %.4f" %
                        (epoch, num_epoch, batch, num_batch_val, np.mean(loss_arr))) 

            epoch_loss = np.mean(loss_arr)

            # deep copy the model
            if epoch_loss < best_loss:
                best_loss = epoch_loss
                best_model_wts = copy.deepcopy(net.state_dict())

        print()
    
    time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(
        time_elapsed // 60, time_elapsed % 60))
    print('Best val loss: {:4f}'.format(best_loss))
    net.load_state_dict(best_model_wts)
    return net

 

 

 

 

 

4. Visualization 결과보기

다시 weight and biases 사이트 화면으로 돌아오겠습니다.

그림15

 

4-1. wandb.log() 부분 visualization 하기

하지만, 코드를 실행시킨 후, charts 부분을 보면 아래와 같이 wandb.log()에 설정했던 log들이 기록됨을 알 수 있습니다. "wandb.log()"에 epoch과 loss를 설정했기 때문에 epoch, loss값visualization 되는 것을 볼 수 있습니다.

그림19

 

 

 

4-2. wandb.watch() 부분 visualization 하기 (Feat. gradient)

또한, 앞서 "wandb.watch()" 함수를 통해 gradient, parameters 값을 visualization 할 수 있다 언급한 바 있습니다.

 

먼저, gradient 값부터 확인해보겠습니다.

그림20

 

 

아래 그림에서 X, Y축의 의미하는 바는 다음과 같습니다.

  • X축: epoch (필자의 코드에서는 epoch=30으로 설정되어 있음)
  • Y축: gradient

그림21

 

 

 

 

앞서 구현한 model의 변수명을 기반으로 해당 위치에 있는 layer에 전파되는 gradient 값확인해 볼 수 있습니다.

그림22

 

 

 

 

5 epoch에 마우스 포인터를 올려놓으면 해당 epoch 단계에서 얻는 gradient 들의 분포 (histogram) 를 알 수 있습니다.

그림23

 

 

 

그리고 특정 epoch 부분들의 gradient 값디테일하게 보고 싶으면 해당 부분drag 하면 됩니다. 

그림24

 

 

 

또 다른 layer들의 gradient 값을 확인하고 싶다면, 아래 화면우측 하단 빨간색 부분클릭해주시면 됩니다.

그림25

 

 

 

이러한 gradient 값은 다양하게 이용될 수 있지만, 그 중에 가장 대표적인 것이 exploding gradient, vanishing gradient확인해보는 것입니다.

 

예를 들어, conv2 weightgradient 값도 대략 10^5로 굉장히 큰데, conv1 weightgradient 값이 대략 10^7 이면  exploding gradient를 의심해볼 수 있겠죠?

  • 3e+5 →  3*10^5 → 대략 10^5

그림26. 이미지출처:  https://wandb.ai/site/articles/debugging-neural-networks-with-pytorch-and-w-b-using-gradients-and-visualizations

 

(↓↓↓ W&B를 이용해 exploding gradient, vanishing gradient를 보여주는 사례 ↓↓↓)

https://wandb.ai/site/articles/debugging-neural-networks-with-pytorch-and-w-b-using-gradients-and-visualizations

 

Debugging Neural Networks with PyTorch and W&B Using Gradients and Visualizations on Weights & Biases

by Ayush Thakur — Debugging Neural Networks with PyTorch and W&B Using Gradients and Visualizations

wandb.ai

 

 

 

 

 

4-3. wandb.watch() 부분 visualization 하기 (Feat. parameters)

gradient 값 외에, conv filter 값들도 확인해 볼 수 있습니다.

이러한 Conv filter 값들을 통해 유의미한 통계분석도 해볼 수 있겠네요

그림27

 

 

 

 

5. ETC

위에서 설명한 것 외에 다양한 정보들을 visualization 해서 볼 수 있습니다.

 

먼저, 왼쪽 빨간색 박스 부분을 클릭하면 system 즉, hardward (CPU, Memory, GPU) 관련 정보들을 살펴 볼 수 있습니다. 

그림28

 

 

 

아래 빨간색 네모 박스 log 관련 정보를 보여주는 곳인데, 학습 시 vs code기록되는 log 들을 그대로 볼 수 있습니다.

그림29

 

 

 

6. 다른 결과들과 비교하기

실험을 하다보면 다양한 hyper-parameter 조합을 통해 결과를 내야하는 경우가 많습니다.

앞에서는 learning rate 부분을 1e-3으로 설정하고 실행했습니다.

그렇다면 이번에는 le-2로 설정하고 실행해보겠습니다.

 

그림30

 

 

왼쪽 빨간색 네모 부분새로운 process가 실행되는 것을 볼 수 있고, 이전 실험 결과(="solar-toterm-19")와 중첩으로 visualization해서 볼 수 있으니, 비교수월할 수 있겠네요.

그림31

 

 

 

하지만 위와 같은 경우 어떠한 hyper-parameter 조합으로 실험한 결과인지 모르기 때문에, 아래와 같이 해당 hyper-parameter 조합에 대한 정보process name으로 설정해주면 좋습니다.

그림34

 

 

위에서 설명한 방법 외에 다양한 visualization 기능들이 있습니다. 예를 들어, line plot, scatter plot 형태로도 보여 줄 수 있고, GAN 관련한 정보들을 visualization 해줄 수 도 있고, hyper-parameter 중에 중요한게 무엇인지도 알려주는 기능도 있습니다. 이와 관련된 부분은 추후 다루도록 하겠지만, 아래 영상을 보시면 상당 부분 혼자서 하실 수 있을거라 생각됩니다.

 

https://www.youtube.com/watch?v=91HhNtmb0B4 

 

 

 

그 외 참고하면 좋을 사이트를 아래 링크해두겠습니다.

https://theaisummer.com/weights-and-biases-tutorial/

 

A complete Weights and Biases tutorial | AI Summer

Learn about the Weights and Biases library with a hands-on tutorial on the different features and visualizations.

theaisummer.com

 

https://analyticsindiamag.com/hands-on-guide-to-weights-and-biases-wandb-with-python-implementation/

 

 

사실 wandb 패키지의 가장 강력한 기능은 다양한 hyper-parameter 조합을 자동으로 실행해주고 관련 결과들을 visualization 하여 어떤 parameter가 중요한지 보여주는 것입니다. 이러한 기능은 wandb의 sweep을 통해 구현할 수 있는데, 이 부분은 정리가 되는데로 업로드 하겠습니다.

 

감사합니다. 

안녕하세요.

이번 글에서는 pytorch를 이용해 UNet 모델을 구현한 code를 설명할 예정입니다.

 

다양한 딥러닝 기반 segmentation 모델이 있지만, UNet 모델이 가장 기본이 되기 때문에 다루었습니다.

 

소개해 드릴 UNet pytorch 코드는 아래 영상을 기반으로 리뷰했으니 아래 영상도 참고해주세요!

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

 

 

최종코드는 제일 아래에 있으니 참고해주세요!

※대부분 PPT 슬라이드에 설명한 내용을 이미지로 만들어 업로드했기 때문에 글씨가 잘 안보일 수 도 있습니다. 그래서 PPT파일을 따로 첨부하도록 하겠습니다.

 

 

Unet pytorch implementation.pptx
2.52MB

 

 

 

0. UNet() 함수 호출

 

Pytorch에서 UNet 모델을 불러오는 코드는 아래 한 줄로 가능합니다.

 

model = UNet().to(device)

 

위의 코드를 실행시키면 구현해 놓은 UNet class가 로드 됩니다.

 

그림1

 

그럼 구현해 놓은 UNet class를 살펴보도록 하겠습니다.

 

 

 

 

 

1. Contracting Path 구현하기

그림2

 

 

그림3

 

 

 

 

 

2. Expansive Path 구현하기

그림4

 

 

 

그림5

 

 

 

 

 

3. Concatenation 구현하기

그림6

 

 

 

그림7

 

 

 

 

 

 

 

4. 최종코드

class UNet(nn.Module):
    def __init__(self):
        super(UNet, self).__init__()

        def CBR2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True):
            layers = []
            layers += [nn.Conv2d(in_channels=in_channels, out_channels=out_channels,
                                 kernel_size=kernel_size, stride=stride, padding=padding,
                                 bias=bias)]
            layers += [nn.BatchNorm2d(num_features=out_channels)]
            layers += [nn.ReLU()]

            cbr = nn.Sequential(*layers)

            return cbr

        # Contracting path
        self.enc1_1 = CBR2d(in_channels=1, out_channels=64)
        self.enc1_2 = CBR2d(in_channels=64, out_channels=64)

        self.pool1 = nn.MaxPool2d(kernel_size=2)

        self.enc2_1 = CBR2d(in_channels=64, out_channels=128)
        self.enc2_2 = CBR2d(in_channels=128, out_channels=128)

        self.pool2 = nn.MaxPool2d(kernel_size=2)

        self.enc3_1 = CBR2d(in_channels=128, out_channels=256)
        self.enc3_2 = CBR2d(in_channels=256, out_channels=256)

        self.pool3 = nn.MaxPool2d(kernel_size=2)

        self.enc4_1 = CBR2d(in_channels=256, out_channels=512)
        self.enc4_2 = CBR2d(in_channels=512, out_channels=512)

        self.pool4 = nn.MaxPool2d(kernel_size=2)

        self.enc5_1 = CBR2d(in_channels=512, out_channels=1024)

        # Expansive path
        self.dec5_1 = CBR2d(in_channels=1024, out_channels=512)

        self.unpool4 = nn.ConvTranspose2d(in_channels=512, out_channels=512,
                                          kernel_size=2, stride=2, padding=0, bias=True)

        self.dec4_2 = CBR2d(in_channels=2 * 512, out_channels=512)
        self.dec4_1 = CBR2d(in_channels=512, out_channels=256)

        self.unpool3 = nn.ConvTranspose2d(in_channels=256, out_channels=256,
                                          kernel_size=2, stride=2, padding=0, bias=True)

        self.dec3_2 = CBR2d(in_channels=2 * 256, out_channels=256)
        self.dec3_1 = CBR2d(in_channels=256, out_channels=128)

        self.unpool2 = nn.ConvTranspose2d(in_channels=128, out_channels=128,
                                          kernel_size=2, stride=2, padding=0, bias=True)

        self.dec2_2 = CBR2d(in_channels=2 * 128, out_channels=128)
        self.dec2_1 = CBR2d(in_channels=128, out_channels=64)

        self.unpool1 = nn.ConvTranspose2d(in_channels=64, out_channels=64,
                                          kernel_size=2, stride=2, padding=0, bias=True)

        self.dec1_2 = CBR2d(in_channels=2 * 64, out_channels=64)
        self.dec1_1 = CBR2d(in_channels=64, out_channels=64)

        self.fc = nn.Conv2d(in_channels=64, out_channels=1, kernel_size=1, stride=1, padding=0, bias=True)

    def forward(self, x):
        enc1_1 = self.enc1_1(x)
        enc1_2 = self.enc1_2(enc1_1)
        pool1 = self.pool1(enc1_2)

        enc2_1 = self.enc2_1(pool1)
        enc2_2 = self.enc2_2(enc2_1)
        pool2 = self.pool2(enc2_2)

        enc3_1 = self.enc3_1(pool2)
        enc3_2 = self.enc3_2(enc3_1)
        pool3 = self.pool3(enc3_2)
        # print(pool3.size())
        enc4_1 = self.enc4_1(pool3)
        enc4_2 = self.enc4_2(enc4_1)
        pool4 = self.pool4(enc4_2)

        enc5_1 = self.enc5_1(pool4)

        dec5_1 = self.dec5_1(enc5_1)

        unpool4 = self.unpool4(dec5_1)
        cat4 = torch.cat((unpool4, enc4_2), dim=1)
        dec4_2 = self.dec4_2(cat4)
        dec4_1 = self.dec4_1(dec4_2)

        unpool3 = self.unpool3(dec4_1)
        cat3 = torch.cat((unpool3, enc3_2), dim=1)
        dec3_2 = self.dec3_2(cat3)
        dec3_1 = self.dec3_1(dec3_2)

        unpool2 = self.unpool2(dec3_1)
        cat2 = torch.cat((unpool2, enc2_2), dim=1)
        dec2_2 = self.dec2_2(cat2)
        dec2_1 = self.dec2_1(dec2_2)

        unpool1 = self.unpool1(dec2_1)
        cat1 = torch.cat((unpool1, enc1_2), dim=1)
        dec1_2 = self.dec1_2(cat1)
        dec1_1 = self.dec1_1(dec1_2)

        x = self.fc(dec1_1)

        return x

 

 

 

지금까지 UNet을 Pytorch로 구현한 code에 대해서 설명해봤습니다.

다음 글에서는 Pretrained model을 불러와 transfer learning을 적용시키는 코드에 대해 설명하도록 하겠습니다.

 

 

 

[Reference Site]

https://toitoitoi79.tistory.com/97

 

U-net: Convolutional Networks for Biomedical Image Segmentation Pytorch 구현

U-net은 바이오 기술에 사용되는 segmentation 논문입니다. sliding window 방식을 사용하는 CNN 구조와 달리 검증된 patch는 넘기기 때문에 보다 빠른 처리가 가능한 구조 입니다. 해당 포스팅은 구현에 포

toitoitoi79.tistory.com

 

+ Recent posts