24.11.11
to do
데일리스크럼 회의록
코드는 각자 따로따로 만들었다.
프로젝트 처음 시작할 때는(수요일까지) 다 강의
OCR같은 경우 강의 다듣기전까진 잘 몰랐다
수요일부터 웬만하면 강의 다 들었으니까 Notion 아이디어 스케치하면서 같이..
강의듣기
Overview
이미지 안에 객체가 존재한다고 했을 때, 해당 객체의 위치 식별부터 클래스를 분류하는 방법에 대해 학습한다.
전처리부터 모델 설계, 학습, 추론의 전체적인 딥러닝 파이프라인 및 경진대회에서 사용하는 방법들을 경험한다.
- FCN
- 가장 근본이 되는 Segmentation Network
- DeconvNet / SegNet
- FCN의 Decoder를 개선
- DeepLab
- FCN의 Receptive Field를 확장
- UNet
- Contracting과 Expanding을 함께하는 Network
- HRNet
- 고해상도 정보를 계속 유지하는 Network
Competition Overview
-
Input : hand bone x-ray 객체가 담긴 이미지가 모델의 인풋으로 사용됩니다. segmentation annotation은 json file로 제공됩니다.
-
Output : 모델은 각 픽셀 좌표에 따른 class를 출력하고, 이를 rle로 변환하여 리턴합니다. 이를 output 양식에 맞게 csv 파일을 만들어 제출합니다.
-
전체 이미지 개수: 800장(Train), 288장(Test)
-
크게 손가락 / 손등 / 팔로 구성되며, 총 29개의 class (뼈 종류)가 존재
'finger-1', 'finger-2', 'finger-3', 'finger-4', 'finger-5', 'finger-6', 'finger-7', 'finger-8', 'finger-9', 'finger-10',
'finger-11', 'finger-12', 'finger-13', 'finger-14', 'finger-15', 'finger-16', 'finger-17', 'finger-18', 'finger-19',
'Trapezium', 'Trapezoid', 'Capitate', 'Hamate', 'Scaphoid', 'Lunate', 'Triquetrum', 'Pisiform', 'Radius', 'Ulna',
각각의 train image에 매칭되는 annotation은 json 파일로 제공되고 있으며, json으로 제공되는 파일에는 다양한 keys가 존재하는데, 그 중 annntations에는 "points", "label"이 있으면 이미지의 어느 영역이 레이블인지 알 수 있습니다.
annotations:
- id : ''
- type : 'poly seg'
- attribute : {}
- points : masking 되어 있는 고유의 좌표 (예시 : 532, 844], [532, 832], ... [418, 747)
- label : 객체가 해당하는 class name (예시 : 'finger-1')
- 이미지 크기 : (2048 x 2048), 3 channel
9강을 참고해서 Semantic Segmentation의 SOTA 모델들을 직접 구현해보거나 7, 9강을 참고해서 segmentation_models.pytorch의 패키지를 이용해서 바로 대회에 참여
1강 Introduction
- 세그멘테이션 개요
2강 Competition Overview (EDA & Metric)
-
Hand Bone Image Dataset
multi-label segmentation이다.
2048 2048 png파일이다.
해당 polygon을 구성하는 point좌표만 제공함으로써 메모리 효율성을 가지는 annotation을 만들 수 있다.
-
EDA
크게 손가락 손등 팔로 구성된다. f-19는 19개의 뼈의 종류가 존재한다는 것이다.
클래스 같은 경우 손가락 뼈는 엄지 손가락 마디부터 순서로 부여했고
다른 뼈들은 이름이 복잡해서 나중에 보도록 한다
팔뼈 파트는 굉장히 큰 pixel 면적을 차지한다.
실제 클래스의 밀도를 보면 팔 뼈 두가지는 굉장히 높은 분산을 가지고 핑거는 분산이 낮다.
사람의 손에 대해 팔뼈 아랫부분이 잘리거나 안잘리거나..실제 이미지에서 finger도 겹치는 부분이 있다는 점을 유의할 것!
한 pixel에 여러가지 class가 등장할 수 있다.
몇몇 클래스들이 많이 겹치는 모습을 볼 수 있다.(진할수록)
손등 파트의 뼈가 겹치는 경우가 많다.
mask만 활용하는 것이 아니라 gender나 다른 특징을 활용하는 방안을 생각할 수 있다. -
평가 Metric
의료 계열에서 많이 사용하는 metric이다.
dice의 식에서 a는 gt, b는 pred이다.
위 식에서는 red class에 대한 dice를 계산해서 0.5가 되는 계산식이다.
그린도 마찬가지로 gt와 pred의 교집합인 3칸 x2 가 분자이고 분모는 두 개 각각의 칸수를 더한다
코드와 함께 살펴보면 입력 이미지가 (배치,채널,height,width)로 들어오면
먼저 t_true와 y_pred에 대해 spatial 차원에 대해 flatten을 진행한다.
그 이후 교집합은 torch.sum함수를 이용해서 계산한다.
분모 파트는 각각에 대해서 크기를 계산한다.이 파트를 그림으로 살펴보면
다이스를 각각의 클래스에 대해 계산을 하는데 이건 C와 연관이 있다.
flatten을 시켜주면 spatial의 차원이 y_pred_f, y_ture_f가 된다.
그 이후에 분모 파트를 먼저 보면 -1에 대해서 torch.sum을 수행하게 되는데 이 의미는 0,1로 구성되어 있는 값에서 1의 개수가 총 몇개인지 합을 구하겠다는 의미이다.분자
교집합의 연산은 위의 코드다. 0과 1을 곱하는 과정에서 0이 하나라도 있으면 0이 된다.
즉 같은 픽셀에 대해 둘다 1인 경우에만 1이 되어 intersection이 되고 그걸 torch.sum으로 더해줘서 최종 분자가 된다. -
Baseline Code
DataLoader
init부터 차례로 살펴보면 init에선 총 4개의 인자를 받는다.
여기선 512,512로 resize한다.
getitem 파트를 보면 item이 들어왔을 때 전처리와 label을 반환한다.
먼저 name을 출력하고 image path를 불러온다.
그다음 opencv의 cv2.imread로 불러오게되면 이미지는 0~255 값을 가지기 때문에 255로 나눠주는 전처리 과정을 거친다.
다음은 이미지를 불러왔으니까 label에 대한 값을 불러온다
label은 폴리건 포인트로 주어지기 때문에 mask로 바꿀 필요가 있다.
각 class에 대해서 annotation을 반복하는데 예를들어 finger 16에 대해서 클래스 인덱스를 추출하면 16은 15다. np.arry로 np.zero 메트릭스를 만들어주고 fillPoly함수를 이용해서 내부 영역을 1의 값으로 채워준다.
클래스 레이블은 zeros를 받기 때문에 전부 0인 상태에서 1 마스크가 생겨서 해당 클래스 인덱스에 1과 0으로 구성된 마스크를 넣어주게되고 finer 0부터15까지 반복한다.
다음으로 transforms를 적용하는 경우이다.
transforms는 not None인 경우만 적용을 하게 된다.
train경우와 그렇지 않은 경우에 대해 나뉘는 것에 대한 주의가 필요하다.
vali에서 실제 테스트와의 차이기를 줄이기 위함이다.
A.resize(512,512)였는데
train일 때는 input을 image와 mask(label)을 받고 validation일 때는 image만 받는다.
result로 train이 아닐 때는(val) 원본 레이블이 들어오게 된다.
반면 train 모드일 때는 결과에 mask가 들어온다.
그 이후에
numpy를 torch tensor로 변환시켜준다.
split은 Group K-fold를 사용한다.
그룹 k-fold를 사용하는 이유는 우리가 사용하는 데이터의 특징과 관련이 있다.
사람 1부터 사람 3까지 있다면 left,right 손이 있다.
동일 인물의 손이 train,val에 같이 들어가는걸 방지할 필요성이 있고 이걸 grop k fold를 통해 구현한다.
실제 코드를 보면
n_split = 5이고 filenames와 labelnames를 train과 val로 나눈다.
그리고 0번을 val dataset으로 사용하는데
group은 사람의 id를 의미한다.
위에서 split된걸 입력으로 받는 dataset을 만들어주고 data loader로 만들어준다.
Model
torchvision 라이브러리를 활용한다.
torchvision의 models를 활용한다. pretrained된 모델은 output class가 우리의 class와 맞지 않으므로 우리가 사용하는 data에 맞게 수정해주어야한다.
실제 model.classifier의 네번째 부분이 다음과 같은 seg의 픽셀와이즈classification을 1x1 conv로 수행하는 파트인데 파트 채널이 21로 되어있는데 우리가 사용하는 dataset의 클래스인 29로 변경해준다.
이렇게 되면 입력이 [512,512,3]으로 들어왔을 때, 우리가 원하는 29 클래스 만큼 나오는 것을 확인할 수 있다.
7강에서는 smp를 사용한다고 한다.
Loss & Optimizer
loss function을 criterion으로 정의하고 optimizer를 optimizer로 정의했을 때,
모델의 inference결과인 outputs와 label인 masks를 입력으로 받아서 loss를 계산할 수 있다.
Train & Val
먼저 모델에 디바이스, 지피유 할당을 해준다음에 정해진 에폭만큼 모델의 학습을 진행한다.
FCN모델 이용해서 out
eval,no_grad 당연하고
(512,512)를 origin size인 원본 마스크로 반환해주는게 첫번째
그리고 두번째로 sigmoid 함수로 0에서 1 범위로 변환하고 특정 threshold 초과는 1로 나머지는 0으로 한다.
세번째론 모든 이미지에 대해 dice 계산을 한다.
모든 클래스에 대해 다이스 값을 가지게 된다.
image0부터 n까지 29개 클래스에 대해 클래스 별 다이스 값의 평균값을 내서 그 값을 클래스별로 얼마가 되는지 최종 메트릭으로 횔용하는걸 볼 수 있다.
학습시키기
각 클래스에 대해서 다이스 값이 계산된다.
val 파트에서의 meandice값을 계산해서 best dice 값을 저장해준다.
Test 파트에서 특이한 점은 output에 대해 RLE라는 인코딩을 사용한다는 점이다.
RLE가 무엇인지 살펴보면 Run-Length-Encoding의 줄임말로 실제 대회에서 submission file size를 줄이기 위해 활용된다.
3강 Semantic Segmentation의 기초와 이해
FCN 논문을 기반으로 Segmentation 태스크가 무엇인지에 대한 이해
- 대표적인 딥러닝을 이용한 세그멘테이션 FCN
- 결론
- 기본과제-1 : FCN8, FCN16, FCN32제출 기한 : 실습은 따로 제출하지 않음
End to End
딥러닝을 이용한 segmentation FCN
딥러닝을 이용해서 (딥러닝 모델인 VGG)
가장 기본적인 FCN을 살펴보면 2015년 CVPR에서 소개되었다.
이후 segmentation 모델에 대해서 가장 baseline이 되었다.
vgg네트워크를 백본으로 사용했다.
backbone은 feature extracter를 담당한다.
agg, alexnet,resnet,efficient 등이 있다.
두번째 특징은 fc layer를 convolution으로 대체했다는 점이다.
2번이 대체되었다.
3번은 이 때 크기가 줄어들었을 텐데 픽셀이 어떤 클래스를 가지는지에 대해 pixel wise prediction을 수행했다.
3x3을 블럭형식으로 사용했고 그 사이사이에 maxpooling을 적용했다.
마지막 단에서는 fc layer 3개를 사용했다.
backbone으로 VGG를 사용했다는 것이 어떤 의미를 가질까?
바로 ! pretrained된 network를 사용할 수 있다는 점이다!
이미 어느정도 학습된 가중치를 사용할 수 있다.
그리고 백본모델을 새로 만들어서 결과튜닝, 파라미터 학습도 다 해야되는데 잘 나온걸 쓰기 때문에 자원의 낭비도 방지할 수 있다.
실제로 논문에선 alex,vgg,google중 성능이 높은 vgg를 백본으로 사용했다고 한다.
베이스라인으로 본 것처럼 resnet을 백본으로하는 fcn인 것을 볼 수 있다.
nn.Linear을 nn.Conv로 바꾼건?
Conv 와 FC의 차이
각 픽셀의 위치 정보를 해치지 않은채로 특징 추출이 가능하다!
fc레이어를 conv레이어로 대체하여 위치 정보를 해치지 않은 채로 특징이 추출되는 것을 확인할 수 있다.
오른쪽은 flatten을 이용해서 이미지를 일자로 펼치고 fc로 특징을 추출하는데 이 과정에서 위치정보가 손실된다.
conv는 정보가 잘 살아남는 반면 fc는 flatten을 거치고 나면 어떤 class를 가지는지 label의 정보밖에 알 수 없는 한계점이 있다.
장점이 더 있다.
파라미터의 변경이 필요없다는 장점이다.
어떤 파라미터의 인자를 입력으로 받는지에 따라 차이점이 있다.
conv는 h,w와 상관이 없기 때문에 512ㅊ512로 학습하나 256x256으로 학습하나 input채널만 고정이 되면 학습이 가능하다.
nn.Linear는 값이 서로 맞지가 않아서 학습이 불가능하게 된다.
위치 정보도 해치지 않고 임의의 정보에 대해서도 학습, Inference가 가능하다는 장점이 있다.
Transposed Convolution
앞서 7x7로 줄어든 이미지를 다시 최종 224x224 크기로 늘려주어야한다.
이렇게 늘려주는 과정을 downsampling의 반대인 upsampling이라고 부른다.
입력이미지를 upsampling하는 과정이다.
각 영역에 대해 겹친 부분은 서메이션과정을 통해 합을 해줘서 최종 output을 도출한다.
왜 Transposed Convolution이라고 불리는 것일까?
예시를 통해 살펴보면 커널을 곱했을 때
동일한 값이 나오는 것을 볼 수 있는데,
이 matrix를 transposed 해서
연산하는 과정에서는 다른 값인 것을 볼 수 있다.
따라서 transposed convolution이라고 말하는게 정확하다
여기서 중요한 점은 3x3 transposed conv이 학습이 가능한 weight로서 학습하는 과정에 따라 더 좋은 output을 만들도록 계속 update되는 값이다.
FCN에서 성능 향상
평가 지표
4~6강에서 기존의 모델은 어떠한 한계점이 있고 이러한 한계점을 어떻게 극복했는지의 위주로 강의
4강 FCN의 한계를 극복한 모델들 1
- FCN의 한계점
- Decoder를 개선한 models
- Skip Connection을 적용한 models
- Receptive Field를 확장시킨 models
- **기본과제-2 : DeconvNet, DilatedNet, SegNet, DeepLabV1
**제출 기한 : 실습은 따로 제출하지 않습니다.
- 객체의 크기가 크거나 작은 경우 예측을 잘 하지 못하는 문제
- Object의 디테일한 모습이 사라지는 문제
DeconvNet
Unpooling: 디테일한 정보를 포착
maxpooling의 위치 정보를 기록함
unpooling pooling에 지워진 경계에 정보를 기록했다가 복원
max pooling에서 위치 정보 추출함
인코더와 디코더는 대칭의 형태로 진행된다.
마지막 1x1 conv로 num_class만큼 채널을 가지도록 output을 생성해준다.
SegNet
가운데 부분 제거해서 속도를 높였다.
sparse한 Matrix를 dense하게 바꾸었다.
Skip connection을 적용한 모델
깊은 레이어에 대해서도 성능을 높게 만들어준다.
FC DenseNet
U-Net
6강에서 살펴 볼 예정
Receptive Field를 확장시킨 모델들
conv -> maxpooling -> conv
효율적으로 receptive field를 넓힐 수 있다.
receptive field는 5x5로 넓어졌ㅈ지만 파라미터 수는 동일하다.(보라색 선 부분은 0으로 패딩된다.)
5강 FCN의 한계를 극복한 모델들 2
- Receptive Field를 확장시킨 models
- 결론
- **기본과제-3 : DeepLabV2, DeepLabV3, DeepLabV3+**제출 기한 : 실습은 따로 제출하지 않습니다.
DeepLab v3
세개만 사용한다.
1x1 conv가 사용된다.
DeepLab v3+
6강 High Performance를 자랑하는 U-Net 계열의 모델들
- U-Net
- U-Net++
- U-Net 3+
- Another version of the U-Net
- 결론
- **심화과제-1 : Unet / Unet++**제출 기한 : 실습은 따로 제출하지 않습니다.
U-Net
64에서 128로 채널을 키운다.
채널을 또 두배 늘린다.
패딩은 0을 주어서 크기는 또 감소시킨다.
이 결과는 enc3_2로 저장해둔다.
다섯번째 인코더는 채널은 그대로 패딩은 0으로 이제 디코더로 넘어오는데 두배만큼 transposed로 채널은 감소하는 것을 확인할 수 있다.
한계점
Dense Skip Connection
같은 레벨의 모든 값을 concat해주는게 차이점이다.
Deep Supervision
U-Net 3+
이후 U-Net 세종류가 있다.