요약

소화기(GI track)를 내시경(EGD, Colonoscopy)으로 검사할 때, 대장내시경과 위내시경을 진행합니다. 대장내시경과 위내시경시에 용종 등이 있으면 생검(bx)을 진행하고, 이를 병리검사합니다. 본 논문에서는 생검이후에 병리검사에서의 오류가 있을 수 있는 내용들을 QC하기위해 인공지능을 사용합니다. 매일 분석을 진행하고 분석결과중 인공지능이 예측한 결과랑 판독의가 제시한결과가 다를 경우 리뷰를 다시 진행합니다, 이 논문은 이 방법론을 적용하고 약 3개월간의 내용입니다. 약 7-10배로 슬라이드 조직 판독리뷰가 빨라졌으며, AI로 더블체크를 진행했습니다. 그리고, 인공지능을 도입한 이후 종전대비 휴면에러는 1.2일당 17배의 휴먼에러가 더 많이 검출되었다고 합니다. 

 

Preliminary


- Reference laboratory(위탁검사 실험실): 타 기관으로부터 검사를 받는 위탁 검사실을 의미합니다. 여기서 Reference 은 "참조"가 아닌 수탁/위탁 등을 의미합니다, 예, 전원오거나 가는것도 refer라합니다.

- 씨잰의료재단은 수술로 절제한 검체를 받는 것이 아닌, 내시경 검사등으로 얻어낸 생검(biopsy)을 주로 위탁받습니다. 이런 위탁은 검사실이 없는 1,2차의료병원으로부터 받습니다.

 

Introduction


한국에서는 모든 종류의 암으로 사망하는 사람들 중, 대장암으로 인한 사망이 3위(11.0%), 위암으로 인한 사망이 4위(9.8%)정도 됩니다. 한국에서 이를 위한 스크리닝 검사로 위내시경, 대장내시경을 진행합니다(이를 통틀어 GI endoscopy라고 부름). 그리고, 대장내시경 할때 대부분 용종등이 발견되면, 생검(biopsy, bx)을 하게됩니다. 생검결과는 실험실이 있는 경우 직접이 시행하게되고, 실험실이 없는 경우는 위탁을 하게됩니다. 문제는 위탁을 보낸후, 수탁을 받는 쪽에서서 Human error가 발생할 수 있다는 점입니다. 이런 생검결과는 조직검사(Histopathology)을 하게되는데 이 검사 특성상, 확증적인 진단의 수단이됩니다. 혹시나 발생하는 False negative가 환자의 치료를 놓치는 큰 비용이될 수 있다는 것입니다. 

 

 보통 이런 휴먼에러를 줄이기위해서, 실험실에서는 QC(Quality control)을 자체적으로 진행하는데요. 병리과 선생님당 랜덤으로 몇명씩 샘플을 랜덤으로 뽑아서 리뷰한다거나 하는 식입니다. 근데 이 마저도 꽤 부담이됩니다. 그래서 AI을 이용한 QC을 이용하고자합니다. AI을 이용한 QC방법은 3가지 제한사항이 있는데요.

  1. 첫 째는, 이러한 AI driven QC은 실제로 한다 하더라도, 완전히 병리과정을 대체할 수 없긴합니다. 예를 들어, 위암의 리스크라고 여겨지는 Helicobacter pylori등도 캡쳐가 되어야하는데, 이런건 잡기는 어렵습니다. 또는 위암의 분류는 USS(Updated sydney system)등의 기준에 따라 분류해서 레포트해줘야하는데 이런 검출/분류도 생각보다 쉽지않습니다.
  2. 둘 째는 조직병리 판독 프로세스를 변경해야하는 비용입니다. 대부분에 실험실에서는 조직병리 판독(interpretation)이후에 슬라이드를 스캔하는 형식입니다. 슬라이드를 스캔해야 어찌되었든 이미지를 디지털로 뜰 수 있기에, 이런 프로세스는 병원에서 변경하기가 꽤 비용이 됩니다. 마지막인 세번째는, AI을 이용한 판독자체가 판독자에게 편향을 줄 수 있기 때문입니다. 

그래서, 이 연구는 실증적으로 위의사항을 고려하여 AI driven QC방법론이 실제로 휴먼에러를 더 줄 수 있는지에 대한 연구입니다. 

 

방법론: AI Pipeline


이 연구는 기존에 진단된 조직병리 검사결과를 다시 라벨링하는것부터 시작합니다. 인공지능의 개발과정을 포함해서 총 1,762의 위암생검, 1,509의 대장암생성의 WSI을 가져와서 Training/Validation/Test로 나누었습니다. 그리고나서, 5명의 병리학자들이 기존 진단결과를 리뷰하고 다시 라벨링하는 과정을 거쳤습니다. 그리고 각 슬라이드를 Malignant, Dysplasia, negative for dysplaisa, Uncategorized(그외)로 4가지로 분류했습니다. 실제로는 U은 실무적으로 의미가 없기에 U을 제외한 3종의 분류기를 만들었습니다.

 

그리고 아래의 이미지에 따라 데이터를 처리합니다.

  1. 데이터 파이프라인: MRSX format으로 저장하고, Openlibary으로 핸들링. Openlibary을 이용해서 패치단위(256x256)으로 나눔.**
  2. Annotation: WSI에서 negative 이미지는 따로 Annotation할게 없으니까 그냥 패치로 만들고, Dysplasia랑 malignant만 병변위치까지 Annotation합니다.
  3. 패치 분류기(patch classifier) 학습: DenseNet201로 학습. M, D, N의 분류. WSI classifier의 일부 요소로 사용. + UI제공 목적
  4. WSI 분류기 학습: Patch classifier의 결과를 다시 pooling하는 MIL을 진행한듯(patch classifier의 결과를 사용) + 위치정보를 인댁싱하여 MIL진행하고 결과를 UI에 뿌림. 이 결과도 DenseNet201로 만듬.
  5. 뷰어 개발(SeeDP): Openslide libary OpenSeadragon 3.0.0. 히트맵과 예측결과를 알려줌. (히트맵은 gradient based XAI방법 중 하나를 사용한것같내요)

*MRXS format: multi-file with very complicated proprietary metadata and indexes (https://openslide.org/formats/mirax/

** 패치크기를 키우면 성능엔 도움이 될 수 있지만, UI상으로 그래도 꽤 큰 이미지이게 병변을 확인하긴 어려울 수 있음.

 

데이터 플로우 및 히트맵 예시

 

방법론: QC방법


  1. 단계1: 병리학자가 조직병리를 판독합니다. 이 과정에서는 이 병리이미지가 어느 장기의 검체인지는 모르고, 접수번호만부여받습니다.
  2. 단계2: 3D HISTECH Scanner로  WSI을 스캔하고, MRXS파일을 생성하여 특정 디렉토리에 저장합니다. (아마 메시징 큐역할로) Auto File Watcher 가 MRXS의 생성을 감지하고 복본을 따로 저장합니다. 그리고 SeeDP가 이를 병리번호를 부여하고 저장합니다. 그리고, 레포트의 검체정보의 해더에 있는 키워드에 따라서 인공지능 모델에 요청을 보냅니다(예, GC은 stomach, esopga~, gastro~, CRC은: leum, illeocecal, Cecum같은 해부학적명칭). 요청받은 인공지능 모델은 WSI file을 읽어서 패치 수준, 슬라이드 수준으로 예측하고 이 결과를 DB에 저장합니다. 
  3. 단계3: SeeDP 프로그램에서 판독결과와 예측결과가 일치하는지를 체크하고 다음날에 볼 수 있도록 준비합니다.

 

결과: Daily QC전의 검증, daily QC의 검증


QC운영전의 검증테스트: 실험수준의 결과로는 위암과 대장암에서의 약 96.0%와 95.8% Validation결과를 얻었습니다. 한편. 실제로 도입하기전에 Inhouse dataset으로도 검증도 했습니다. 사전검사(Pre-test)셋을 따로 구축해서 319셋의 대장암, 419셋의 위암데이터셋을 구축했습니다. 이 데이터셋 비율은 임상에서 실무적으로 얻어지는 비율과 동일하게 셋팅했습니다. 이 데이터셋에서도 93.08%, 95.30%의 정확도를 보였습니다. 

 

Daily QC의 검증: 서두에서 얘기했듯이 약 3개월간의 기간동안 전향적으로 연구한 결과를 제시했습니다. 3개월동안에 WSI 분류 성능(정확도)은 약 90.29%로 보였습니다. 이런 인공지능을 이용한 진단보조에서는 False negative가 상당히 중요한데 이 언급도 있습니다. NPV(Negative predictive value, negative로 예측했던 결과중에 실제 negative비율)은 97.20%을 보였습니다. 아마 Threshold을 느슨하게 잡았어도 이 정도 오차를 보일 수 있는데 개선여지가 아직 남은듯합니다. 특히 진짜 FN인경우 CRC에서 한 케이스를 보였습니다. 

 

실제 이 인공지능 모델로 QC을 세달간진행하고, 인공지능QC전 약 33개월의 결과를 함께보여주었습니다. 33개월동안 GC은 5,789의 슬라이드를 봤고, 이는 랜덤샘플한 결과입니다 (약 160.8슬라이드/한달 정도겠구요). 이 경우는 병리판독의의 18개의 불일치를 결과를 보였구요. 이중 16개 케이스는 약간차이나는정도, 2건은 중간정도 판독차이가 있었습니다. 아마 계속 QC해왔던 기관이라 에러율은 딱히없어보였습니다. 한편, 3개월동안의 SeeDP을 용한 QC을 진행한 경우, 3arm 으로 1) 랜덤리뷰, 2)AI +병리과전문의 3) AI only로 각각 평가했습니다. AI +병리과전문의로 오류케이스를 잡는 경우는 1.2일정도 걸렸고, 이를 교정하는데 3.4일내에 끝났습니다. 한편, 원래 프로세스에서는 40.2일이 걸렸습니다. 이는 상당한 생산성향상을 보여줍니다. 더 많은 오류검출과 빠른 엑션이 가능함을 결과로 제시했습니다.

 

결론


1. 실제 임상프로세스에 도입하기 위해서는 임상프로세스의 과정을 크게 바꾸지 않으면서 도입이 필요한데, 큰 변경사항없이 이 과정을 수행했습니다.

2. 연구에서 보여준 것처럼 AI driven QC프로세스는 오검사로 일어날 위협으로 환자안전에 도움을 줄 수 있습니다. 특히, QC 방법으로 인공지능결과와 불일치결과를 확인하면서, 1-2달 걸리던 오진을 빠르게 교정하고 의뢰인(의사)에게 오류없이 알려줄 수 있습니다.

반응형

요약


CNN의 overconfidence 문제를 해결하기위해서, MixPatch라는 방법론을 고안했습니다. 디지털병리 문제 중 WSI을 패치단위로 분석하다기에 종종 과하게 예측되는 경우가 생기기 때문입니다. 저자들은 MixPatch라는 방법론으로 soft label역할을 통해 불확실한 이미지를 추가하는 augmentation 방법론을 제시합니다. 이런 이미지를 추가하여 학습하면서 uncertainty problem을 개선했습니다.

 

Introduction


조직병리진단시에 병리학자들이 많은 시간을 써야함에 따라서 약 3~9%의 휴먼에러가 발생합니다. 이 에러율을 줄이기위해서 딥러닝으로 QC역할로서 진행합니다. CNN기반으로 WSI을 분석하다보면, 사이즈가 너무 큰데 화소수를 줄이자니 성능이 나빠져, 작은 이미지인 패치단위로 잘라서 분석하고 집계하는 방식을 취합니다. 그러다보니 결국 패치를 분류하는 분류기의 성능에 직결되게 됩니다. 따라서, 패치 분류기를 훈련시켜야 좋을지 고민이 되는 부분입니다.

패치에서 암인지 아닌지를 분류하는 것과 같이 패치만 보고 예측하는 것을 패치수준(Patch level)분류라고하는데요. 패치수준(patch level)의 분류기를 잘 학습시키위해 여러 방법론이 있었는데, data augmentation(color,distortion, stain normalizaion)등이 주로있었습니다. 패치에 사용되는 CNN이 좀더 다양한 현실의 문제를 학습하기를 바라는 것이죠. 하지만, 이런 과정을 거쳐도 결국 실제로 사용하려면 예측점수가 중요한데, uncertainity prediction은 아직 안다뤄졌습니다.

이 문제가 중요한 이유는 병리이미지의 양성패치(abnormal, 병리적소견이 있는) 양성의 조직영상으로만 채워지지 않습니다. 즉, 일부는 양성, 일부는 음성으로 채워져있습니다. 하지만, 실제로 학습할 때는 병리학자 선생님들께서 5%의 양성, 95%의 음성이 섞인 패치를 주시기보다는 엄청 심각한, 예를 들어 95%가 비정상 세포인 이미지를 주시기 마련입니다. 그러다보니, 자연스럽게 모델은 매우 심각한 케이스만 양성으로 분류하게되며, 실제 있을만한 양성+음성의 세포조합인 패치는 학습이 안되어있게됩니다. 즉, 한 패치에서도 양성/음성비율이 다른 문제 Mixed-regision variation 특성을 가지게 됩니다. 그 결과, 양성이 매우적은 경우에도 마치 학습해서 봤던 것처럼 강하게 예측(over confidence)로 예측하게됩니다. 이런 상황은 딥러닝을 이용한 디지털병리에서 실제 사용하기에 매우 까다로운 문제가 됩니다.

이 논문에서는 실제로 이렇게 있을만한 mixed-variation property을 만들어내 soft-label dataset으로 활용하기 위함입니다

 

방법론: Mixed-Patch


이 방법론은 미니배치로 사용하는 패치를 Augmetnation하고 label도 augmented label(soft label)을 사용하는 것이 핵심입니다. 논문에서는 x_mixed, y_mixed라고 표현했습니다. 이 Augmentation된 이미지를 mini-patch라고 일컫습니다. 미니 패치는 원래 패치이미지를 다시 작은이미지로 split하고, 랜덤으로 섞고, 선택해서 조합(concat)하여 패치사이즈와 같게 학습되는 형식입니다.  예를들어, 패치이미지가 128x128이었다면, 이 논문에서는 64x64의 미니패치들을 만들고, 이를 4개를 접합(concat)하여 또다른 하나의 패치를 만드는 형식으로 진행한 것입니다. 이를 x_mixed라고합니다.

한편, 라벨은 소프트라벨을 주려고 했기에, 양성(비정상)으로부터 만들어진 미니패치가 있다면 0.5~1.0사이의 라벨을 주려고했습니다. 0.5~1.0사이의 수치중 mini 패치의 비율을 사용했습니다.

 

학습과정에서는 손실함수를 2가지로 나눕니다. 원래이미지와 Augmentation이미지에 적용할 각각의 손실함수입니다. 식 (1)은 원래 이미지에서 KL divergence입니다. (2)식은 Augmented된 이미지(Mixed-patch)에 대한 KL divergence입니다. 식 (3)은 (1)과 (2)의 가중합입니다. (1)과 (2)의 데이터셋 비중이 다르기에 이를 적절한 r로 처리하구요. (1)식은 BCE가아닌 (2)과 같은 KL로 학습했습니다.

결과: 동일한 네트워크로 Mixed Patch의 성능이 유리함.


이 논문에서는 MixedPatch의 효과를 평가하기위해 베이스라인, LS(label smoothing), cut, cut mix, mix patch을 보여줍니다. 앞의 4개의 방법론은 밴치마크로 사용됩니다.

베이스라인은 그냥학습하는 방법론을; LS은 학습시 confidence에대한 정규화를 하는방법론(https://analytics4everything.tistory.com/263, 포스팅참고하세요), cut, cut mix은 각각 다른 부분은 잘라내어 덛대거나 덛대지않거나하는 차이입니다. 추가로 cutmix은 mislabel을 줍니다. 예를 들어, 정상이미지에 비정상일부이미지를 잘라붙이는 방법론입니다.

분류성능상에서는 MixPatch가 가장좋았고, calibration plot을 그려봐도 cutmix와 유사하게 비슷한 성능을 보입니다.

 

종합적으로 정확도, 민/특, AUROC, ECE가 가장 우수한것이 MixedPatch였내요.

 

결론


요약하면, 실제 WSI이미지에서 Ground truth로 annotation케이스와 real-case을 줄이기위해서 data augmentation전략(MixedPatch)을 사용하고, 이에 맞게 손실함수를 각각 원본데아터+증강데이터를 혼합하여 학습한 방법입니다. 

반응형

요약


- 뉴털네트워크를 이용할때, 엔트로피(entropy)가 낮은 경우를 패널티를 줘서 over-confidencence 문제를 해소를 보임.

- 2가지 패널티 방법론을 제시: 라벨스무딩, Confidence penality

- 이미지 분류, 언어모델, 번역, 등의 다양한 문제에서의 이 방법론을 적용하여 해소됨을 보임.

 
 

Figure 1. 논문에서 제시한 2가지 방법론을 사용한 경우의 MNIST 데이터에서의 model confidence 분포. 첫번째그림에서는 예측값의 분포가 0아니면 1이 었는데, 컨피던스의 정규화과정을 거치면서 무조건 0,1이기보다는 중간값을 제시하여 불확실성에 대한 수치를 반영함.

 

사전지식(Preliminary)


*엔트로피가 낮다= 0 또는 1로만 모델이 분류하여 예측이 이분화(dichotomy)된 것을 의미합니다. 하지만, 세상의 모든예측이 확실할수만은 없죠.
* 엔트로피의 정의는 다음을 참고하세요.
 

 

방법론(method)


- H은 엔트로피를 의미해서 모델이 반환하는 값을 이용해서 다음의 식을 계산합니다.

$L(\theta) = - \sum logp_{\theta}(y|x) - H(p_{\theta}( y|x ))$

이 수식이 의미하는 것은 Loss = (negative log-likelihood) - (beta * negative entropy) 입니다. 즉, 손실값 = 오분류 오차 - (가중치 * 분포도)을 의미하는 것이죠. 추가로 beta 가 들어가 있는데, beta을 줘서 너무 강하게 한쪽으로만 에측하지 않도록 패널티을 추가하는 형식입니다.

 

- 방법론 1. Annealing 과 Threhold방법론

힌지 손실함수(Hinge loss)을 사용하는 방식입니다.

$L(\theta) = - \sum logp_{\theta}(y|x) - \beta max(0, \tau - H((p_{\theta}(y|x) ))$

위 식에서는 엔트로피가 타우($\tau$)보다 큰 경우만 패널티를 주는 수식으로 변경했습니다. 이렇게하는 이유는 지도학습의 경우에는 학습 초반에 빨리 파라미터가 수렴하는 것이 좋은데, 이럴려면 초반에는 패널티가 좀 적어야하고, 학습후반에 패널티를 키워야합니다.즉, 패널티를 초반에는 안주고, 후반에는 줘야합니다. 따라서, 이를 구현하기위해서 힌지로스(=>max(0, tau - 함수값))을 써서 다음과 같이 구현했습니다.
 
- 방법론 2. 라벨 스무딩(Label smoothing)
사전 라벨의 분포를 사용하는 방법입니다. 사전 라벨이 균일하다면, 예측된 라벨의 분포도 균일하길 바라바면서 KL Divergence로 두 분포의 거리를 패널티로 주는 방법입니다.
 
  $L(\theta) = - \sum logp_{\theta}(y|x) - D_{KL}(u \|\|H((p_{\theta}(y|x) ))$

 

실험(Experiments) 및 결과(Results)


실험으로는 이미지 분류를 진행했고 MNIST에서는 오차율이 약간 크게나왔습니다. (Table 1). 하지만 그레디언트의 크기자체는 다른 방법론보다 작아진 것을 볼 수 있는데요.이는 더 빨리 수렴했음을 의미합니다.(FIgure 1)

 

언어모델에서도 이 방법론을 적용했는데요. 여전히 다른 모델이 성능이 좋지만, Zaremba et al (2014)의 모델을 그대로 적용한 경우 confidence penalty가 가장 낮았습니다(Table 3)

 

결론

- 정리하면 이 논문에서는 "모델의 신뢰도(model confidence)"을 정규화하는 방법 2가지을 제시했습니다: confidence penality, label smoothing). 이 두 방법론은 지도학습에서 향상된 성능을 보였습니다.

 

반응형

 

요약


SimCLR을 이미지 데이터을 더 잘 구별하기위한, 대조적학습 (Constrative learning)을 이용한 사전학습 프레임워크*입니다. SimCLR은 비슷한 같은 데이터 증강(Data augmentation)을 이용하는데, 같은 데이터 소스로 부터 생성된 이미지는 가깝게, 다른 이미지소스로 부터 생성된 이미지는 멀게 학습하는 metric learning 방법입니다. 즉 이미지의 유사성/이질성을 학습하는 방법론입니다. 이 방법론을 사전학습으로 사용하면, 시각적표현을 더 잘학습할 수 있고, 지도학습 등에서의 적은 파라미터로도 더 높은 구별성능을 낼 수 있습니다. 

*프레임워크: 세부적인 방법론만 바꿔가면서 동일한 목적을 달성할 수 있도록하는 큰 틀을 의미합니다.

 

Introduction


- 비전관련 학습은 크게 생성이나, 구분문제(discrimitive approach)로 나뉩니다. 생성도 역시 2가질로 나뉘는데 모델을 학습하는 방법과, 픽셀수준까지 학습하는 방법으로 나뉩니다. 다만, 픽셀수준까지 생성하는것은 매우 비용이 많이듭니다. 한편, 분류문제(discrimitive approach)은 목적함수등을 이용해서 지도학습을 하게되며, 사전학습문제(pretext task)을 이용해서 라벨없는 데이터를 학습하기도합니다. Pretext task을 어떻게 꾸리냐에 따라 다르긴한데, 대부분 사람마다 다른 경험적인(heuristic)한 방법입니다. 그러다보니, 일반화성능에 미치지 못할 수 있습니다. 하지만 최근 들어서는 contrastive learning이 pretext task에 기여할 수 있다는 논문이 주류로 뜹니다.

- 저자들은 Contrastive learning을 할 수 있는 방법론을 하나 제시합니다. 그리고, Constrative learning을 잘하기 위한 주요요소들을 제시합니다.

1. 여러가지 data augmentation 방법을 함께 이용하는 것이  매우 중요함.
2. Augmentation 후에 learnable 비선형변환의 표현이 표현 성능이 더 좋음
3. Contrastive corss entropy을 사용하면 더 좋음
4. 큰 사이즈의 배치사이즈와 긴 훈련시간을 사용하면 좋음

 

Methods


  • Contrastive learning framework - 목적: 같은 데이터에 다른 방법의 Augmentation을 사용하여 비선형매핑을 하더라도 동일함 이미지로 표현됨

구성요소

  • Data augmentation: 한 이미지로부터 각각 다른 데이터증강방법을 이용해서 (x_i), (x_j)을 생성합니다. 이 두 이미지를 positive 데이터로 만듭니다. 위의 그림에서 t~T에해당하는 것이 data augmentation 방법입니다. 그 결과는 $\tilde{x}_{i}$, $ \tilde{x}_{j}$에 해당합니다.
  • Base encoder: 인코더 $f()$. 이 인코더를 통과한 이후 d차원의 벡터를 만들어 냅니다.
  • Projection head: $g()$. base encoder가 생성한 벡터를 비선형변환을 하는 MLP을 의미합니다. 그 결과 벡터 $z$가 생산됩니다.
  • contrastive loss function: negative + positive 이미지가 포함되었을때, x_i을 모델에 입력한 경우 x_j을 선별하는 과정을 목적 정의 되었습니다. 이 논문에서는 미니배치를 N개로 두었습니다. N개의 이미지로부터 각각 2개씩 데이터증강을 하니 총 2N의 데이터포인트가 생깁니다. 이 2N에서 positive을 하나 i라고하면 i와 짝이되는 j 은 positive이고 그외는 negative가됩니다. 2(N-1)이 negative pair가 됩니다. 예를 들어, 5개의 이미지를 미니배치라고하면 각각의 5개로 만들어낸 10개는 유사도: sim(u, v). 두 벡터 u, v가 들어오는 경우 $u^{T}v / ||u||||v||$을 하는 과정으로 cosimilarity을 의미합니다. 위의 유사도를 이용해서 아래의 손실함수를 정의합니다. 

Equation 1. SimCLR에서 사용하는 loss function

 

 

전체적인 SimCLR의 알고리즘은 아래와 같습니다. 그리고, 이를 시각화하면 아래와 같은 메트릭스 연산을 하는 것과 동일합니다.

1. 알고리즘의 첫번째 단계로는 각 이미지를 Augmentation하는 것입니다. N개의 이미지가 배치사이즈라고하면 각 N개의 이미지를 2개씩 각각 다른 방법론으로 augmentation 시킵니다.

2. 유사도 메트릭스를 생성합니다. $_{i,j}$가 유사도 메트릭스에 해당하고, i와 i은 같은 이미지이므로 1이어야하고, i와 바로 +1차이나는 j도 같은 이미지로부터 augmentation 된것이니(=1단계:Augmentation), 같은 이미지로 유사도가 1이어야합니다.

 

3. 손실함수 계산: 유사도 메트릭스 $s_{i,j}$에 대해서 i,j의 순서를 바꿔가면서 손실함수를 계산합니다. 분모는 한 행을 의미하고, 분자는 i또는 j에 대해서 계산합니다.

 

 

Result


사전작업(Pre-text)을 학습하는 경우, 이 모델을 fix하고 linear 모델만 단 경우는 여러 데이터셋에서 성능의 우위를 가리기어렵지만, 이를 함께 fine-tuning하는 경우 지도학습모다 더 좋은 성능을 기대할 수 있었습니다.

다른 모델과의 비교에서도 동일한 파라미터내에서는 더 잘 시각적인 표현을 학습해서 예측을 잘한 결과를 보여주고 있습니다 (Figure 6). 또한, ImageNet에서도 라벨이 거의 없는 이미지에 대해서도 Top 5예측성능이 우수하게 나오고있습니다.

 

두 번째 결과로는, "한 이미지로부터 두 Augmentation을 해야하는데, 어떤 조합으로 하는게 좋을까?"를 실험적으로 증명합니다. Augmentation 방법로는 아래의 10가지 말고도 여러가지 방법론이 있습니다. Data augmentation 단계에서 하는게 좋을 지 고민을 해야합니다. 

 

이 고민에 대해서 실험적으로 여러 짝으로 진행해보았고, 그 결과로 컬러왜곡(color distortion)과 Crop의 조합이 가장좋았습니다. 

컬러 왜곡이 중요한 이유를 추가적으로 설명했는데, 랜덤크롭한 영상의 이미지가 비슷한 컬러를 보여주기 때문에, 컬러만 가지고 구분이 될 수 있다는 내용을 언급합니다. 그렇기에 이것을 좀더 어렵게하더라도, 더 잘 맞추기위해(=일반화 성능향상) 컬러 왜곡을 하는 것이 중요하다고 합니다.

이러한 컬러 왜곡을 더 강하게 줄 수록, 비지도학습에서의 성능이 더 향상된다고합니다. 지도학습보다 더 좋은 성능이다라는 것이 아니라, 컬러왜곡을 지도학습과 비지도학습에 둘다 적용할때, 강도를 세게했을때는 SimCLR에서 더 효과가 좋았다라는 것입니다.

 

에폭이 적을때는 배치사이즈가 더 큰 사이즈로하는 것이 좋지만, 충분히 학습시킬 수 있는 epoch이라면 배치아시즈가 그렇게 영향을 주는 것 같지 않습니다. 이는 배치사이즈마다 샘플링을 각각 다르게하니, 시각적인 학습을 충분히 더 할 수 있음에도 100에폭밖에 학습을 못해서 충분히 학습이 안된것처럼 보입니다. Constrative learning에서는 더 큰 사이즈의 배치를 넣으면 negative가 엄청 많아지기에, 더 빨리 학습의 수렴을 유도하는것으로 해석해볼 수 있습니다(=더 빠른 이미지의 구별능력)

 

pytorch구현


파이토치에서 augmentation된 이미지 i, j의 유사도를 구하는 방법은 아래와 같습니다. 

  1. 유사도 메트릭스 ($s_{i,j}$) 내에 각 행에는 2개의 positive 샘플이 있습니다. 하나는 자기자신이고, 나머지는 augmentation된 이미지 2장이 같은 origin이라는 positive sample pair입니다.
  2. 자기자신(i=j)인 인덱스만 지워줍니다. 이 지운 결과는 벡터로 나옵니다.
  3. 벡터에서 positive만 따로 가져오고, 나머지 negative을 따로 구한 후 ,concat 합니다. positive와 negative순서로 concat합니다.
  4. 이 때, 라벨은 positive sample은 항상 0번컬럼에 존재하기에 np.zeros(2N)으로 만듭니다. 왜냐하면 torch.nn.CrossEntropy 구현체에서는 라벨에는 항상 정답라벨의 클레스번호가 들어가기 때문입니다. 정답라벨이 항상 0이기에, 그냥 np.zeros()로 들어갑니다.

 

위 내용을 이용해 구현한 코드는 아래에 있습니다.

 

Conclusion


SimCLR 프레임워크는 Constrative learning을 이용해서 self-supervised learning을 진행하고 다운스트림테스크에서 더 나은 성능을 보여주었습니다. 그리고, 그 각 세부요소들 중에, 어떤 조합/하이퍼 파라미터가 좋은지 결과를 함께 보여주었습니다. 

반응형

 

요약


마르코브 랜덤필드(Markov random field, MRF)은 이산확률변수사이에 상호의존성을 표현하는 그래프모델입니다. 주요한 특징은 무방향성(Undirected)이며 인접한 경우에만 상호작용하는(pairwise interaction)하는 그래프의 성질을 지니고 있습니다. 관찰된 데이터로부터 알려지지 않은 변수를 추론하기위해서 주로 사용되며, 특히 이미지에서는 이미지 복원, 이미지 세그멘테이션, 객체인식 등에 주로 쓰입니다.

 

그림1. 마르코프 랜덤 필드의 예시(Pairwise random feild)

 

 

 

마르코브 랜덤 필드 정의(MRF, Markov random fields)


마르코브 랜덤필드는 마르코브 속성을 가진 그래프를 의미합니다. 이산확률변수(노드)사이의 상호의존성(edge)을 표현하는 그래프 모댈입니다. 이 노드 사이에서는 무방향성(undirect, 무향)입니다.

  • 일반적인 Markov network (=마르코브 속성(Markov property)가 있어야함)
  • 그래프모형이기에 노드(node)와 엣지(edge)가 존재하며, node은 확률변수, edge은 확률변수사이에 종속성을 의미함.

 

그림 표현

  • 검정색원(filled circle)은 관찰된 상태의 노드를 의미
  • 흰 원(empty circle)은 관찰되지 않은 상태의 노드를 의미

위의 그림1은 마르코브 랜덤필드의 흔한 예시입니다. 격자형으로 마르코브 속성을 가집니다. 쉽게 말해서 각 노드들이 확률변수 일때, 변수들 변수들간의 상호 의존성이 존재한다는 것입니다. 마르코브 속성은 현재상태가 과거상태에만 의존한다는 것인데, 이전 과거의 T상태전까지(T memory markcov라고도 함)영향을 받을 수 있음을 의미합니다. 위의 격자모형의 그래프에서는 상호의존성을 인접한 노드에서 받을 수 있습니다. 좀 더 나아가서 인접한 노드라고하지만, 이 인접한 노드들은 주변의 인접한 노드가 또 있기에(2칸 떨어진) 이전 T상태전까지 영향을 받는것처럼 생각할 수도 있습니다(하지만 2칸떨어진 노드가 직접영향을 주는 것은 절대아닙니다. 그럴거면 2칸 떨어진 노드에 직접 연결되어있어야합니다.).

 

만일 노드 3개(A, B, C)가 주어져있고, 노드A가 C을 통하지 않으면 B로갈 경로가 없다고하면 다음과 같이 표기합니다. 만일 이러한 경로가 있으면 이 노드들의 구성은 dependent한것입니다.

$X_A \perp X_B \,|\, X_C$

 

 

수식표현

  • $x_{i}$: 확률변수. 노드를 의미. 변수라고도하고 node라도 합니
  • $\psi(x_{i}, x_{j})$: 관찰되지않은 노드($x_{i}$)와 관찰되지 않은노드($x_{j}$)의 종속성을 의미. 발음은 프사이라고 합니다. 이 종속성은 메트릭스로도 표현할 수 있습니다. 통상 대칭인 정방행렬(symmetric, square matrix)여서 노드 i에서 j로 가거나 노드 j에서 노드i로 가는 것이 동일한 종속성입니다. 하지만, 이 두 노드 사이가 비대칭이어도 상관없습니다. 영문표기로는 compatible function라고합니다.
  • $\phi(x_{i}, y_{j})$: 관찰되지않은 노드($x_{i}$)와 관찰된 노드($y_{j}$)의 종속성을 의미합니다. 위의 표기와 다르게 한쪽이 관찰되지 않을 때 쓰는 notation입니다. 영문표기로는 evidence for x라고 합니다. 이미 y은 결정되어있으니 x을 구하기위한 근거라는 것이죠.
  • $N_{n}=\{m \in \mathbb{N} \,|\, (n,m) \in \varepsilon\}$: 노드 n의 엣지로 연결된 노드의 집합 (=노드N의 이웃집합)
  • $P(X_{n} \| X_{N_{n}})$: 노드n의 인접한노드(=로컬 조건부확률)로만 알고있으면$ X_{n}$의 확률을 알 수 있음을 의미합니다. 마르코브 속성을 의미합니다. [1]

 

 

마르코브 랜덤 필드의 예시


아래의 그림은 MRF의 예시입니다. 4개의 노드가 존재합니다. 3개의 노드($x_{1}, x_{2}, x_{3}$)은 관찰되지 않은 노드이고, 유일하게 node 4($y_{2}$)만 관찰된 노드입니다.

 

위 MRF을 수식으로 표현해보겠습니다.

  • 노드: 관찰되지 않은 노드1은 $x_{1}$, ..., 노드3은 $x_{3}$입니다.  반면 관찰된 노드4은 $y_{4}$입니다.
  • MRF은 각 노드사이의 종속성을 표현한다고 했습니다. 각 노드의 종속성을 아래와 같이  표현할 수 있습니다.

 

에너지함수(energy function)와 포탠셜(Potential)


마르코브 랜덤필드의 확률분포는 에너지함수를 사용하여 계산할 수 있습니다. 즉, 이런 마르코브랜덤 필드가 나오려면 어떤 확률분포였겠드냐를 의미합니다. 여기서 에너지함수라는 것을사용하는데,에너지함수는 다음과 같은 아이디에 기반합니다.

  • 높은 에너지를 가지고 있는 상태는 불안정하니 낮은 확률을 갖는다는 것
  • 에너지함수는 확률변수의 집합의 각 상태에 대한 에너지값을 부여하며, 에너지가 낮을수록 높은확률

 

깁스 분포(Gibbs distribution)을 이용해서 마르코브 랜덤필드를 정의해보겠습니다. (깁스 분포는 결합확률분포가 각 확률변수의 조건부 독립적이어서 곱한것을 의미)

 

$P(X)= \frac {1}{Z} \prod _{c\in C} \phi_{c} (x_{c})$

여기서 C은 maximal clique을 의미합니다. 즉 이 그래프에서 클리크에 속하는 모든 노드들의 확률을 다 하나하나 곱하면 전체 그래프가 될 수 있다는 것을 의미합니다. 그리고 여기서 Z은 보통 정규화 상수인데, 이 그래프에서는 다음과 같이 표현합니다.

$Z=\sum_{x}\prod _{c \in C}\phi_{c}(x_{c})$

 

이 그래프에서 $phi_{c}(x_{c})$을 다음과 같이 쓸 수 있습니다. 보통 여기서 T은 온도(temperature)라고해서 1을 쓰씁니다. 

$\phi_{c}(x_{c})=e^{-1 \frac{1}{T}V_{c}(x_{c})}$

 

각각 Z랑 $phi_{c}(x_{c})$을 알고있으니, 깁스분포에 대입해보면, 아래와 같고, 지수의 승을 덧셈으로 표현할 수 있으니까 결국 두번째식까지 얻어낼 수 있습니다. 

$P(x)=\frac{1}{Z}\prod _{c \in C} e^{-\frac{1}{T}V_{c}(x_{c})}$

$P(X)=\frac{1}{Z}e^{-\frac{1}{T}\sum_{c \in C}V_{c}(x_{c})}$

이때, $\sum_{c \in C}V_{c}(x_{c})$을 보통  $U(x)$라고하고, 에너지라고합니다. 그리고 V은 클리크 포탠셜(clique potential)이라고합니다.

 

 

마르코브 랜덤 필드와 베이지안 네트워크의 차이


마르코브랜덤필드는 베이지안 네트워크와 유사합니다. 표로 정리하면 아래와 같은 차이점이 있습니다.

  마르코브 랜덤 필드 베이지안 네트워크
정의 확률 변수 간의 조건부 독립 관계를 나타내는 무방향 그래프 확률 변수의 조건부 독립 관계를 나타내는 방향성 있는 그래프(Acyclic)
방향 Undirected Directed
두 노드의 확률 compatible function ψ_ij (x_i,x_j) Conditional probability p(x_i |x_j)
변수타입 이산 이산, 연속
순환가능 가능 불가능

 

 

 

 

Python example


MRF의 예시

import networkx as nx
import matplotlib.pyplot as plt

# 그래프 생성
G = nx.Graph()

# 노드 추가
nodes = ["x1", "x2", "x3", "y2"]
G.add_nodes_from(nodes)

# 간선 추가 및 가중치 설정
edges = [("x1", "x2", 0.9), ("x2", "x3", 0.1), ("y2", "x2", 0.1)]
G.add_weighted_edges_from(edges)

# 각 노드에 확률 변수 값을 할당 (예: 이진 랜덤 변수)
for node in G.nodes:
    G.nodes[node]['value'] = 0  # 초기값을 0 또는 1로 설정

# 노드 위치 지정
pos = {
    "x1": (-1, 0),  # 왼쪽에 위치
    "x2": (0, 0),  # 6시 방향에 위치
    "x3": (1, 0),   # 오른쪽에 위치
    "y2": (0, 1)    # 12시 방향에 위치
}

# 그래프 시각화
nx.draw(G, pos, with_labels=True, font_weight='bold', node_size=800, node_color='lightblue', font_color='black')

plt.show()

 

MRF을 이용한 iterated conditional modes(ICM)을 적용

import cv2
import numpy as np
from PIL import Image

# 이미지 불러오기
image = cv2.imread('/home/heon/repositories/detection_models/sample.png', cv2.IMREAD_GRAYSCALE)
image = cv2.resize(image, (128, 128))


noisy_image = image + np.random.normal(0, 15, image.shape).astype(np.uint8)
binary_image = cv2.threshold(noisy_image, 100, 255, cv2.THRESH_BINARY)[1]

Image.fromarray(image)
Image.fromarray(noisy_image)
Image.fromarray(binary_image)

def calculate_cost(y_p, x_p, alpha, beta, neighbors, y_k):
    cost = alpha * (1 - (y_p == x_p))
    for q in neighbors:
        cost += beta * (1 - (y_p == y_k[q]))
    return cost

def icm_reconstruction(observed_image, alpha, beta, max_iterations):
    height, width = observed_image.shape
    y_k = np.copy(observed_image)  # Initialize the restored image as the observed image.
    
    neighbors = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]
    
    for _ in range(max_iterations):
        updated_y = np.copy(y_k)
        
        for i in range(1, height - 1):
            for j in range(1, width - 1):
                current_pixel = observed_image[i, j]
                best_cost = float('inf')
                best_pixel_value = None
                
                for y_p in [0, 1]:
                    cost = calculate_cost(y_p, current_pixel, alpha, beta, neighbors, y_k)
                    # print(i,j,cost, best_cost)
                    if cost < best_cost:
                        best_cost = cost
                        best_pixel_value = y_p
                updated_y[i, j] = best_pixel_value
        
        if np.array_equal(updated_y, y_k):
            break
        
        y_k = updated_y
    
    return y_k

 

Reference


[1]https://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/AV0809/ORCHARD/#:~:text=A%20Markov%20Random%20Field%20(MRF,the%20set%20of%20nodes%20S.

반응형

요약


FastAPI middleware은 어플리케이션의 요청 및 응답처리과정중에 중간에 위치하여, 여러 작업을 수행할 수 있는 요청->동작 사이, 응답->동작사이에 여러 기능을 수행
주로 요청 및 응답을 변형하거나(예, 암호화), 인증, 로깅및 모니터링, 예외처리등을 수행.
ASGI (Asynchronous Server Gateway Interface) 프로토콜을 따르는 웹 애플리케이션에서 비동기 요청을 처리하기 위해, request._receive속성에 설정하도록함


fastAPI의 미들웨어는 @app.middleware("http")와같이 함수위의 데코레이터로 사용가능합니다.
async def set_body(request: Request, body: bytes) 함수는 원래 요청 객체에 바이트로 된 본문을 설정하기 위해 사용됩니다. 
아래의 함수 내에서 async def receive() -> Message 함수를 정의하고, 이 함수는 request 객체의 _receive 속성으로 설정됩니다. 
따라서 ASGI 프레임워크는 요청을 수신할 때 이 _receive 함수를 호출하여 요청 객체의 본문을 설정하여 로깅할 수 있습니다.

async def set_body(request: Request, body: bytes):
    async def receive() -> Message:
        return {"type": "http.request", "body": body}

    request._receive = receive


@app.middleware("http")
async def log_request_payload(request: Request, call_next):
    payload = await request.body()
    await set_body(request, payload)
    request.app.state.logger.debug(f"Request payload: {payload.decode()}")
    response = await call_next(request)
    return response

 



아래의 call_next의 인자가 callable로 (reqeust)을다시 인자로 받아야하는데, FastAPI.reqeust은 아래와 같이 구성되어있습니다.
request._receive 속성이 property로 설정되어있고 타입이 empty_receive라 Courutine의 타입을 받게되어있습니다.
그래서 async def로 정의한 함수를 넣어주도록하고, 그 메시지의 형태를 stream내애 얻어지는 형태랑 유사하게 받도록합니다.

class Request(HTTPConnection):
    _form: typing.Optional[FormData]

    def __init__(
        self, scope: Scope, receive: Receive = empty_receive, send: Send = empty_send
    ):
        super().__init__(scope)
        assert scope["type"] == "http"
        self._receive = receive
        self._send = send
        self._stream_consumed = False
        self._is_disconnected = False
        self._form = None

    @property
    def method(self) -> str:
        return self.scope["method"]

    @property
    def receive(self) -> Receive:
        return self._receive

    async def stream(self) -> typing.AsyncGenerator[bytes, None]:
        if hasattr(self, "_body"):
            yield self._body
            yield b""
            return
        if self._stream_consumed:
            raise RuntimeError("Stream consumed")
        self._stream_consumed = True
        while True:
            message = await self._receive()
            if message["type"] == "http.request":
                body = message.get("body", b"")
                if body:
                    yield body
                if not message.get("more_body", False):
                    break
            elif message["type"] == "http.disconnect":
                self._is_disconnected = True
                raise ClientDisconnect()
        yield b""
반응형

+ Recent posts