Skip to content

Latest commit

ย 

History

History
744 lines (508 loc) ยท 37.5 KB

README.md

File metadata and controls

744 lines (508 loc) ยท 37.5 KB

15. ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๋ชจ์•„๋ณด๊ธฐ

ML Coarse-to-Fine ์ „๋žต๊ณผ Active Learning ๊ธฐ์ดˆ

๋จธ์‹ ๋Ÿฌ๋‹ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค๋•Œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒƒ ํ•˜๋‚˜๋งŒ ๊ผฝ์œผ๋ผ๊ณ  ํ•œ๋‹ค๋ฉด ๋ฐ์ดํ„ฐ๋ผ๊ณ  ๋งํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค๊ณ ์ž ํ•˜๋Š” ๋จธ์‹ ๋Ÿฌ๋‹ ์„œ๋น„์Šค์— ๊ผญ ์•Œ๋งž๋Š” ๋ฐ์ดํ„ฐ์…‹์„ ๋Š˜ ๊ตฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์˜คํžˆ๋ ค ๊ทธ๋Ÿฐ ์ด์ƒ์ ์ธ ๊ฒฝ์šฐ๋Š” ๊ทนํžˆ ๋“œ๋ฌผ๋‹ค๊ณ  ๋ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค. ํ˜„์‹ค ๋ฌธ์ œ์— ๋ถ€๋”ชํ˜”์„ ๋•Œ ์šฐ๋ฆฌ๋Š” ๋ชจ๋ธ์„ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ธ๊ฐ€ ๋ณด๋‹ค ํ›จ์”ฌ ๋งŽ์€ ์‹œ๊ฐ„์„ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์ˆ˜์ง‘, ๊ฐ€๊ณตํ•  ๊ฒƒ์ด๋ƒ์˜ ๋ฌธ์ œ๋กœ ๊ณ ๋ฏผํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค. ์–ธ์ œ๋‚˜ ๊ทธ๋ ‡๋“ฏ ํ™•๋ณดํ•œ ๋ฐ์ดํ„ฐ์˜ ๊ฐฏ์ˆ˜๋Š” ํ„ฑ์—†์ด ๋ถ€์กฑํ•˜๊ณ , ์ด๋ฅผ ๋ฉ”๊พธ๊ธฐ ์œ„ํ•œ ์˜ˆ์‚ฐ์€ ํ™•๋ณด๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉฐ, ์„œ๋น„์Šค ๋”œ๋ฆฌ๋ฒ„๋ฆฌ ํƒ€์ž„์€ ์–ผ๋งˆ ๋‚จ์ง€ ์•Š์€ ํ˜„์‹ค์„ ์šฐ๋ฆฌ๋Š” ์–ด๋–ป๊ฒŒ ํ—ค์ณ ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ์„๊นŒ?

๊ทธ๋ž˜์„œ ์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” ๋จธ์‹ ๋Ÿฌ๋‹ ์—”์ง€๋‹ˆ์–ด๊ฐ€ ๋Š˜ ๊ณ ๋ฏผํ•ด ์˜ค๋Š” ๋ฌธ์ œ, ๋ฐ”๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๋ชจ์œผ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•  ๊ฒƒ์ด๋‹ค.

ํ•™์Šต๋ชฉํ‘œ

  • ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ๋ชจ์•„๋ณด๊ธฐ
  • ๋”ฅ๋Ÿฌ๋‹์ด ์•„๋‹Œ ๋จธ์‹ ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๊ธฐ
  • Keypoints Regressor ์ œ์ž‘ํ•˜๊ธฐ
  • ๋ผ๋ฒจ๋ง ํˆด ๋‹ค๋ค„๋ณด๊ธฐ

์ค€๋น„๋ฌผ

๋ชจ๋ธ ํŒŒ์ผ์„ ๋‹ค์šด๋ฐ›์•„ ์••์ถ•์„ ํ’€์–ด์ค€๋‹ค.

$ wget http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
$ bzip2 -d shape_predictor_68_face_landmarks.dat.bz2

์นด๋ฉ”๋ผ์•ฑ์— ๋‹นํ™ฉํ•œ ํ‘œ์ • ํšจ๊ณผ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด?

๋‹ค์Œ๊ณผ ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

images00.png

์šฐ์„  ๋ˆˆ์„ ์ฐพ์•„์•ผ ํ•œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๋žœ๋“œ๋งˆํฌ(landmark)๋ฅผ ์ด์šฉํ•ด ๋ˆˆ์˜ ์œ„์น˜๋ฅผ ์ฐพ๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋งˆ ์•Œ๊ณ  ์žˆ์„ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ ์ผ๋ฐ˜์ ์ธ ๋žœ๋“œ๋งˆํฌ๋Š” ๋ˆˆ์ด ๋ฐ”๋ผ๋ณด๊ณ  ์žˆ๋Š” ๋ฐฉํ–ฅ๊นŒ์ง€๋Š” ํฌํ•จํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค.

์•„๋ž˜ ์‚ฌ์ง„์ฒ˜๋Ÿผ ์‹œ์„ ์˜ ๋ฐฉํ–ฅ์ด ์™ผ์ชฝ์œผ๋กœ ํ–ฅํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์ •๋ณด๋ฅผ ์ด์šฉํ•˜๋ ค ํ•œ๋‹ค. ๋ˆˆ๋™์ž์˜ ์œ„์น˜๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋” ์„ฌ์„ธํ•œ ํ‘œํ˜„์ด ๊ฐ€๋Šฅํ•  ๊ฒƒ์„ ์˜ˆ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

images01.png

๋ˆˆ๋™์ž๋ฅผ ์ฐพ๋Š” ๋ฐฉ๋ฒ•


dlib๊ณผ ๊ฐ™์€ ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ˆˆ์˜ ์™ธ๊ณฝ์„  ์œ„์น˜๋งŒ ์ฐพ์•„์ค„ ๋ฟ ์‹œ์„ ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ˆˆ๋™์ž๋Š” ์ฐพ์•„์ฃผ์ง€ ์•Š๋Š”๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ˆˆ์˜ ์™ธ๊ณฝ์„  ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•ด ๋ˆˆ์„ ์ฐพ์•„๋‚ด๊ณ  ๊ทธ ๋‚ด๋ถ€์—์„œ ๋ˆˆ๋™์ž๋ฅผ ๊ฒ€์ถœํ•ด์•ผ ํ•œ๋‹ค.

images02.png

๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ˆˆ๋™์ž ๊ฒ€์ถœ ๋ฐ์ดํ„ฐ์…‹์„ ์ฐพ์•„๋ณธ๋‹ค. ๋Œ€์ฒด๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ์…‹์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

images03.png

์ด ๋ฐ์ดํ„ฐ์…‹์€ ๋ถ„๋ช… ๋ˆˆ๋™์ž ๊ฒ€์ถœ๊ณผ ๊ด€๋ จ์ด ์žˆ๋Š” ๋ฐ์ดํ„ฐ์ด์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ๋ชฉํ‘œ๋กœ ํ•˜๋Š” ์ดฌ์˜ ํ™˜๊ฒฝ๊ณผ ๋งŽ์ด ๋‹ค๋ฅด๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•ธ๋“œํฐ ์นด๋ฉ”๋ผ ๊ธฐ๋ฐ˜์˜ ํŒ” ๋„ˆ๋น„ ์ •๋„์˜ ์ดฌ์˜ ํ™˜๊ฒฝ์„ ๊ฐ€์ง€๋Š” ๋ฐ˜๋ฉด ๊ณต๊ฐœ๋œ ๋ฐ์ดํ„ฐ์…‹์€ AR ๊ธฐ๊ธฐ๋ฅผ ์œ„ํ•œ 10cm ์ด๋‚ด์˜ ๊ทผ๊ฑฐ๋ฆฌ ์ดฌ์˜ ํ™˜๊ฒฝ์ด๋‹ค.

์‹ค์ œ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค ๋•Œ์—๋„ ์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ค๊ณ  ์‹ถ์€ ํ™˜๊ฒฝ์— ๊ผญ ๋งž๋Š” ๋ฐ์ดํ„ฐ์…‹์„ ์ฐพ๊ธฐ๋Š” ๋งค์šฐ ์–ด๋ ต๋‹ค. ๋”ฐ๋ผ์„œ ๋จธ์‹ ๋Ÿฌ๋‹ ๊ฐœ๋ฐœ์ž๋Š” ๊ณต๊ฐœ๋œ ๋ฐ์ดํ„ฐ์™€ ๋ชจ๋ธ์ด ๋ชจ๋‘ ์—†์„ ๋•Œ ๋ฌธ์ œ๋ฅผ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ณ ๋ฏผํ•˜๊ณ , ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

๋”ฅ๋Ÿฌ๋‹ ๊ธฐ๋ฐ˜ ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•˜๋ ค๋ฉด ์•„์ฃผ ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ž๋ณธ์ด ํ’๋ถ€ํ•œ ์ƒํ™ฉ์ด๋ผ๋ฉด ๋ฐ์ดํ„ฐ์™€ ์ฃผ๋ณ€ ํ™˜๊ฒฝ์„ ๊ตฌ๋งคํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฒ˜์Œ ์‹œ๋„ํ•˜๋Š” ์—…๋ฌด์— ๋Œ€๊ทœ๋ชจ ์ž๋ณธ์„ ํˆฌ์žํ•˜๊ธฐ๋ž€ ํ˜„์‹ค์ ์œผ๋กœ ๊ต‰์žฅํžˆ ์–ด๋ ต๋‹ค. (์„ฑ๊ณตํ•  ์ˆ˜ ์žˆ์„์ง€, ์„ฑ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์„์ง€ ํ™•์‹ ํ•˜๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ) ๋”ฐ๋ผ์„œ ์ดˆ๊ธฐ ์ปจ์…‰ ์ฆ๋ช… ๋‹จ๊ณ„์—์„œ๋Š” ์†Œ๊ทœ๋ชจ์˜ ์ž๋ณธ๊ณผ ์ธ๋ ฅ์œผ๋กœ ํ”„๋กœํ† ํƒ€์ž…์„ ๋งŒ๋“ค์–ด์•ผํ•˜๋Š”๋ฐ ์ด ๋•Œ ๋”ฅ๋Ÿฌ๋‹์„ ์ ์šฉํ•˜๊ธฐ๊ฐ€ ์‰ฝ์ง€ ์•Š๋‹ค.

๊ธฐ์กด ๋จธ์‹ ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•์„ ์ ์ ˆํžˆ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์ž˜ ๊ฐ€๊ณต๋œ ์–ด๋…ธํ…Œ์ด์…˜(annotation) ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋ฐ”๋กœ ๋”ฅ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋น ๋ฅด๊ฒŒ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด ๋‚˜๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.

์˜ค๋Š˜ ๋…ธ๋“œ์—์„œ๋Š”

  • ๊ธฐ์กด ๋จธ์‹ ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•œ ๋ˆˆ๋™์ž ๊ฒ€์ถœ ๋ชจ๋“ˆ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•œ๋‹ค.
  • ๋”ฅ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•œ ๋ˆˆ๋™์ž ๊ฒ€์ถœ ๋ชจ๋“ˆ์„ ์ œ์ž‘ํ•˜๊ณ 
  • ์•ž์—์„œ ๋งŒ๋“ค์–ด์ง„ ๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ ๋†’์€ ํ’ˆ์งˆ์˜ ๋ผ๋ฒจ์„ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๋ผ๋ฒจ๋ง ํˆด(labeling tool) ๋Œ€ํ•ด ์„ค๋ช…ํ•œ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ ์•ž์˜ ๊ณผ์ •์„ ์–ด๋–ป๊ฒŒ ํšจ์œจ์ ์ธ ์ˆœ์„œ๋กœ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋…ผ์˜ํ•œ๋‹ค.

๋Œ€๋Ÿ‰์˜ Coarse Point Label ๋ชจ์•„๋ณด๊ธฐ

(1) ๋„๋ฉ”์ธ์˜ ํŠน์ง•์„ ํŒŒ์•…ํ•˜์ž


๋”ฅ๋Ÿฌ๋‹์„ ์ ์šฉํ•˜์ง€ ์•Š๊ณ  ๋จธ์‹ ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•œ๋‹ค๋Š” ๋ง์€ ๊ณง **handcraft feature(์‚ฌ๋žŒ์ด ์ •์˜ํ•œ ํŠน์ง•)**๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๋ง๊ณผ ๊ฐ™๋‹ค. ์ด๋•Œ ๋ชจ๋ธ์ด ์‚ฌ์šฉํ•  ํŠน์ง•์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ•ด๋‹น ๋ถ„์•ผ์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ์ฆ‰, ๋„๋ฉ”์ธ ์ „๋ฌธ๊ฐ€๊ฐ€ ์ข‹์€ ๋ชจ๋ธ์„ ๋งŒ๋“ค ํ™•๋ฅ ์ด ๋†’๋‹ค.

์ด ๋ฐฉ๋ฒ•์ด ์–ด๋–ป๊ฒŒ ์ ์šฉ๋  ์ˆ˜ ์žˆ๊ณ  ์™œ ํ•„์š”ํ•œ์ง€ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณผ๊นŒ ํ•œ๋‹ค.

2018๋…„์— ์•Œ์ธ ํ•˜์ด๋จธ ์น˜๋งค ์ง„๋‹จ ๋ณด์กฐ ์†”๋ฃจ์…˜์„ ๋งŒ๋“ค์—ˆ๋‹ค. MRI๋ฅผ ์ดฌ์˜ํ•œ ํ›„ ๋‡Œ ์กฐ์ง์„ ๋ถ„์„ํ•ด์„œ ์•Œ์ธ ํ•˜์ด๋จธ ํ™˜์ž์™€ ์ •์ƒ๊ตฐ์˜ ๋ถ„ํฌ๋ฅผ ํŒŒ์•…ํ•˜๋Š” ์—…๋ฌด๋ฅผ ์ง„ํ–‰ํ–ˆ๋‹ค. ๋‹ค์–‘ํ•œ ์น˜๋งค์˜ ์ข…๋ฅ˜๋ฅผ ์ ‘ํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ  ๊ทธ ์ค‘ ํ•œ ์‚ฌ๋ก€๋ฅผ ์ด์•ผ๊ธฐํ•˜๋ ค ํ•œ๋‹ค.

ํ˜ˆ๊ด€์„ฑ ์น˜๋งค(Vascular Dementia) ๋Š” ๋‡Œํ˜ˆ๊ด€ ๋ฌธ์ œ๋กœ ๋‡Œ์กฐ์ง์ด ์†์ƒ์„ ์ž…๊ฒŒ ๋˜์–ด ๋ฐœ์ƒํ•˜๋Š” ์น˜๋งค๋‹ค. ์น˜๋งค๋Š” ํ˜„์žฌ ์น˜๋ฃŒ๋ฒ•์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ๋ณ‘์„ ๋ฏธ๋ฆฌ ์˜ˆ์ธกํ•˜๊ณ  ๋Œ€๋น„ํ•ด์„œ ์ง„ํ–‰์„ ๋Šฆ์ถ”๋Š” ๋ฐฉ๋ฒ•์ด ์ตœ์„ ์ด๋‹ค. ๊ทธ๋งŒํผ ์กฐ๊ธฐ ์ง„๋‹จ์œผ๋กœ ๋ณ‘์˜ ๋ถ„๋ฅ˜์™€ ์›์ธ์„ ์ฐพ๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค. ๋‹ค๋ฅธ ์•Œ์ธ ํ•˜์ด๋จธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด ๊ฒฝ์šฐ๋„ MRI ์ด๋ฏธ์ง€๋ฅผ ํ†ตํ•ด ์ง„๋‹จ์„ ๋„์šธ ์ˆ˜ ์žˆ๋‹ค. MRI์—๋Š” T1w, T2w, FLAIR ๋“ฑ ๋‹ค์–‘ํ•œ ์ดฌ์˜ ๋ฐฉ์‹(protocol)์ด ์žˆ๋‹ค. FLAIR ์ด๋ฏธ์ง€๋ฅผ ํ•œ ์žฅ ์‚ดํŽด๋ณด์ž.

images04.png

์ฒ˜์Œ๋ณด๋ฉด ์–ด๋””๊ฐ€ ์ •์ƒ์ด๊ณ  ์–ด๋””๊ฐ€ ๋ฌธ์ œ์ธ์ง€ ์ „ํ˜€ ํŒŒ์•…ํ•  ์ˆ˜ ์—†๋‹ค. ์ด ์ด๋ฏธ์ง€์—์„œ๋Š” "ํšŒ๋ฐฑ์งˆ"์ด ์–ด๋””์ธ์ง€, "๋ฐฑ์งˆ"์ด ์–ด๋””์ธ์ง€ ๊ตฌ๋ถ„์ด ์ž˜ ๋˜์ง€ ์•Š๋Š”๋‹ค(๋‘˜์€ ๋‡Œ์˜ ๊ฐ ๋ถ€๋ถ„์˜ ์ด๋ฆ„์ด๋‹ค). ์‚ฌ์‹ค FLAIR ์ด๋ฏธ์ง€์—์„œ๋Š” ๋ฐฑ์งˆ๊ณผ ํšŒ๋ฐฑ์งˆ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์–ด๋ ค์šด ๋Œ€์‹  ๋‡Œ์ฒ™์ˆ˜์•ก๊ณผ ๊ฐ™์€ ๋ฌผ์€ ๋น„๊ต์  ๊ตฌ๋ถ„ํ•˜๊ธฐ ์‰ฝ๋‹ค. (What Does Hyperintensity Mean On An Mri Report?) ์•„๋ž˜ ๊ทธ๋ฆผ์„ ๋ณด์ž.

images05.png

๋นจ๊ฐ„์ƒ‰ ์˜์—ญ๊ณผ ๊ฐ™์ด ๋‡Œ์ฒ™์ˆ˜์•ก ๋ถ€๋ถ„์€ ์ฃผ๋ณ€๋ณด๋‹ค ํฐ ๊ฐ’์œผ๋กœ ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋œ๋‹ค. ๋‡Œํ˜ˆ๊ด€์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋˜๋ฉด ํ”ผ ๋“ฑ์˜ ์•ก์ฒด๊ฐ€ ๋ฐฑ์งˆ์— ์Šค๋ฉฐ๋“ค๊ฒŒ ๋˜๊ณ  ๋‡Œ์กฐ์ง์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ๋ฐฑ์งˆ์ด ๋ณด๋‹ค ๋ฐ์€ ๊ฐ’์œผ๋กœ ๋‚˜ํƒ€๋‚œ๋‹ค๊ณ  ํ•ด์„œ WMH(White Matter Hyperintensity)๋ผ๊ณ  ํ•œ๋‹ค. WMH๊ฐ€ ์žˆ๋‹ค๊ณ  ๋ฐ˜๋“œ์‹œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด ํ™˜์ž ์ค‘์—์„œ ๋งŽ์€ ์‚ฌ๋ก€๊ฐ€ WMH๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋‡Œ์˜ํ•™ ์„ ์ƒ๋‹˜๋“ค์€ WMH๋ฅผ ์ฐพ๋Š” ๊ฒƒ์„ ์ค‘์š”ํ•˜๊ฒŒ ์ƒ๊ฐํ•˜๊ณ  ์žˆ๋‹ค. ๊ธ€์“ด์ด๋„ ์ž๋™์œผ๋กœ ์ฐพ์•„์•ผ ํ–ˆ๋Š”๋ฐ ๋ฌธ์ œ๋Š” ๋ผ๋ฒจ์ด ๋งˆ๋•…ํ•˜์ง€ ์•Š์•˜๋‹ค. (๋ฌผ๋ก  ์ง€๊ธˆ์€ ์˜คํ”ˆ๋ฐ์ดํ„ฐ๊ฐ€ ์กฐ๊ธˆ์”ฉ ์ƒ๊ธฐ๊ณ  ์žˆ๋‹ค.) ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜(segmentation)์€ ๋ผ๋ฒจ๋ง(labeing)์ด ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ์ดˆ๊ธฐ์—๋Š” ๋”ฅ๋Ÿฌ๋‹์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” ์ƒ๊ฐํ•ด๋ณด๋ฉด ์•„์ฃผ ์‰ฝ๊ฒŒ ์ดˆ๊ธฐ ๋ชจ๋ธ(baseline)์„ ๋งŒ๋“ค์–ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. WMH์˜ ๋œป์„ ๋‹ค์‹œ ์‚ดํŽด๋ณด๋ฉด WM Hyperintensity, ์ฆ‰ ์ด๋ฆ„์ฒ˜๋Ÿผ ํ•˜์–—๊ฒŒ ํ‘œ์‹œ๋˜๋Š” ๋ถ€๋ถ„์€ ๋†’์€ ํ”ฝ์…€ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ 255 ๋ฒ”์œ„ ๋‚ด์—์„œ 200 ์ด์ƒ์˜ ๊ฐ’์„ ๊ฐ€์ง€๋Š” ํ”ฝ์…€๋“ค๋งŒ ์ฐพ์•„๋‚ด๋ฉด ๊ฐ„๋‹จํ•œ ์ดˆ๊ธฐ ๋ชจ๋ธ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

images06.png

์ด๋ ‡๊ฒŒ ์ดˆ๊ธฐ ๋ชจ๋ธ์„ ๋งŒ๋“ค๊ณ  ์ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ํ•™์Šต์‹œ์ผœ ๋‚˜๊ฐ€๋ฉด ์ข‹์€ ์„ฑ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๊ทผ์‚ฌ์ ์ธ(coarse) ๋ฐ์ดํ„ฐ์…‹์„ ๊ฐ„๋‹จํžˆ ๋งŒ๋“ค๊ณ , ์ด๋ฅผ ์ด์šฉํ•ด ์ดˆ๊ธฐ ๋ชจ๋ธ์„ ๋งŒ๋“  ํ›„ ๊ทธ ๋ชจ๋ธ์„ ๋”์šฑ ์ •๊ตํ•˜๊ฒŒ ํ›ˆ๋ จ์‹œ์ผœ๊ฐ€๋Š” ์ „๋žต์„ ML Coarse-to-Fine ์ „๋žต์ด๋ผ๊ณ  ํ•œ๋‹ค.

์ด ์ด์•ผ๊ธฐ์—์„œ ์ค‘์š”ํ•œ ์ ์€

  1. ํ’€๊ณ  ์‹ถ์€ ๋„๋ฉ”์ธ์˜ ์ง€์‹์„ ์ตํž ๊ฒƒ : ํ˜ˆ๊ด€์„ฑ ์น˜๋งค์™€ WMH, MRI ์—์„œ ์–ด๋–ค ํŒจํ„ด์„ ๋ณด์ด๋Š”์ง€
  2. ๋”ฅ๋Ÿฌ๋‹์ด ์•„๋‹Œ ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ : Image threshold ๋“ฑ ์˜์ƒ์ฒ˜๋ฆฌ ๊ธฐ๋ฒ•

๋“ฑ์„ ์ƒ๊ฐํ•˜๊ณ  ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

(2) ๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ


๋‹ค์‹œ ์šฐ๋ฆฌ ๋ฌธ์ œ๋กœ ๋Œ์•„์™€์„œ, "๋ˆˆ๋™์ž์—๋Š” ์–ด๋–ค ํŠน์ง•์ด ์žˆ์„๊นŒ?"๋ฅผ ๊ณ ๋ฏผํ•ด ๋ณด์ž. WMH์™€ ๋ฐ˜๋Œ€๋กœ ๋ˆˆ๋™์ž๋Š” ์–ด๋‘ก๋‹ค. ์–ด๋‘์šด ๋ถ€๋ถ„์˜ ์ค‘๊ฐ„์„ ์ฐพ์œผ๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

images07.png

๊ธ€์“ด์ด๋Š” ๊ทธ๋ ‡๊ฒŒ ์ ‘๊ทผํ–ˆ๋‹ค. (๋ฌผ๋ก  ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋Š˜ ์—ผ๋‘์— ๋‘์–ด์•ผ ํ•œ๋‹ค.) ๋žœ๋“œ๋งˆํฌ(landmark)๋ฅผ ์ด์šฉํ•ด์„œ ๋ˆˆ์„ crop ํ•˜๊ณ  ๋ˆˆ์—์„œ ๊ฐ€์žฅ ์–ด๋‘์šด ๋ถ€๋ถ„์˜ ์ค‘์‹ฌ์„ ์ฐพ๋Š”๋‹ค. ๋ˆˆ๋™์ž์— ๋น›์ด ๋ฐ˜์‚ฌ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ ๋…ธ์ด์ฆˆ(noise) ์„ฑ๋ถ„์„ ์—†์• ๊ธฐ ์œ„ํ•ด (๋Œ€์ฒด์ ์œผ๋กœ ๋ˆˆ๋™์ž๊ฐ€ ์–ด๋‘์šด ๊ฒฝํ–ฅ์„ ๋”ฐ๋ฅด๊ธฐ ์œ„ํ•ด) ๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ(gaussian blur)๋ฅผ ์ ์šฉํ–ˆ๋‹ค. ๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ์— ๋Œ€ํ•œ ์„ค๋ช…์€ ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

๋ธ”๋Ÿฌ ํ›„ ํ‘๋ฐฑ์„ ๋ฐ˜์ „์‹œ์ผฐ๋‹ค. ์—ฌ๊ธฐ์„œ ๊ฐ€์žฅ ๋†’์€ ๊ฐ’์„ ๊ฐ–๋Š” ํ”ฝ์…€์„ ๊ณ ๋ฅด๋ฉด ์•„๋ž˜ ๊ทธ๋ฆผ์ฒ˜๋Ÿผ ๋ˆˆ์˜ ์œ„์น˜๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

images08.png

'๊ฐ€์žฅ ๋†’์€ ๊ฐ’'์˜ ๊ธฐ์ค€์€ ์—ฌ๋Ÿฌ ๋ฐฉํ–ฅ์œผ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค. 2D ์ด๋ฏธ์ง€ ์ƒ์—์„œ ๋ฐ”๋กœ (x, y) ์œ„์น˜๋ฅผ ์ถ”์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•argmax(image)์ด ์žˆ์„ ์ˆ˜ ์žˆ๊ณ  ์œ„ ๊ทธ๋ฆผ์—์„œ ์˜ค๋ฅธ์ชฝ๊ณผ ์•„๋ž˜ ๋ถ€๋ถ„์— ๋ณด์ด๋“ฏ์ด 1์ฐจ์›์œผ๋กœ ๋ˆ„์ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์œ„ 2์ฐจ์› ์ด๋ฏธ์ง€์—์„œ ๋ˆˆ์˜ ์ค‘์‹ฌ ๋ถ€๋ถ„ ๊ทผ์ฒ˜ ํ”ฝ์…€์€ ๊ฑฐ์˜ ๋ชจ๋‘ 255๋กœ ์ตœ๋Œ€๊ฐ’์„ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๋”ฐ๋ผ์„œ ๋ˆˆ๋™์ž๋ฅผ ํŠน์ •ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค. ๊ฐ€์šฐ์‹œ์•ˆ ๋ธ”๋Ÿฌ๋ฅผ ์ ์šฉํ•˜๋ฉด ๋ˆˆ๋™์ž ์ค‘์‹ฌ์„ ํ‰๊ท ์œผ๋กœ ํ•˜๋Š” ๊ฐ€์šฐ์‹œ์•ˆ ๋ถ„ํฌ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋ฌผ๋ก  ์ตœ๋Œ€๊ฐ’ 255๋กœ truncate ๋˜์–ด ์žˆ๊ณ  ๋ˆˆ๋™์ž๋งŒ ๋ฐ์€ ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— mixture density์ฒ˜๋Ÿผ ๋‚˜ํƒ€๋‚˜์ง„๋‹ค.

์ด๋•Œ 1์ฐจ์›์œผ๋กœ ๋ˆ„์ ํ•ด์„œ ํ‘œํ˜„ํ•˜๋ฉด 255๋กœ truncated ๋˜๋Š” ๋ฌธ์ œ์™€ ์ฃผ๋ณ€ ๋…ธ์ด์ฆˆ์— ์กฐ๊ธˆ ๋” ๊ฐ•๊ฑดํ•˜๊ฒŒ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

(3) ๊ตฌํ˜„ : ๋ˆˆ ์ด๋ฏธ์ง€ ์–ป๊ธฐ


์ด๋ก ์ ์ธ ๋ถ€๋ถ„์„ ์ฝ”๋“œ๋กœ ๋‚˜ํƒ€๋‚ด ๋ณด์ž. ์‚ฌ์šฉํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

import matplotlib.pylab as plt
import tensorflow as tf
import os
from os.path import join
from glob import glob
from tqdm import tqdm
import numpy as np
import cv2
import math
import dlib

์ด๋ฏธ์ง€๋ฅผ ์ค€๋น„ํ•œ๋‹ค.

import os
img_path = os.getenv('HOME')+'/aiffel/coarse_to_fine/images/image.jpg'
img = cv2.imread(img_path)
print (img.shape)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()

์ง€๊ธˆ๊นŒ์ง€ ํ•ด์˜จ ๋ฐฉ๋ฒ•๋Œ€๋กœ ์–ผ๊ตด๊ณผ ๋žœ๋“œ๋งˆํฌ๋ฅผ ๊ฒ€์ถœํ•œ๋‹ค.

img_bgr = img.copy()

detector_hog = dlib.get_frontal_face_detector() # detector ์„ ์–ธ
dlib_model_path = os.getenv('HOME')+'/aiffel/coarse_to_fine/models/shape_predictor_68_face_landmarks.dat'
landmark_predictor = dlib.shape_predictor(dlib_model_path)

img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
dlib_rects = detector_hog(img_rgb, 1) # (image, num of img pyramid)

list_landmarks = []
for dlib_rect in dlib_rects:
    points = landmark_predictor(img_rgb, dlib_rect)
    list_points = list(map(lambda p: (p.x, p.y), points.parts()))
    list_landmarks.append(list_points)

for dlib_rect in dlib_rects:
    l = dlib_rect.left()
    t = dlib_rect.top()
    r = dlib_rect.right()
    b = dlib_rect.bottom()
    cv2.rectangle(img_rgb, (l,t), (r,b), (0,255,0), 2, lineType=cv2.LINE_AA)

for landmark in list_landmarks:
    for idx, point in enumerate(list_points):
        cv2.circle(img_rgb, point, 2, (255, 255, 0), -1) # yellow

plt.imshow(img_rgb)
plt.show()

๋žœ๋“œ๋งˆํฌ๋ฅผ ์ด์šฉํ•ด์„œ ๋ˆˆ ์œ„์น˜๋งŒ cropํ•œ๋‹ค. dlib์˜ ๋žœ๋“œ๋งˆํฌ ์ž๋ฃŒํ˜•์€ 68๊ฐœ์˜ ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

def eye_crop(bgr_img, landmark):
    # dlib eye landmark: 36~41 (6), 42~47 (6)
    np_left_eye_points = np.array(landmark[36:42])
    np_right_eye_points = np.array(landmark[42:48])

    np_left_tl = np_left_eye_points.min(axis=0)
    np_left_br = np_left_eye_points.max(axis=0)
    np_right_tl = np_right_eye_points.min(axis=0)
    np_right_br = np_right_eye_points.max(axis=0)

    list_left_tl = np_left_tl.tolist()
    list_left_br = np_left_br.tolist()
    list_right_tl = np_right_tl.tolist()
    list_right_br = np_right_br.tolist()
    
    left_eye_size = np_left_br - np_left_tl
    right_eye_size = np_right_br - np_right_tl
    
    ### if eye size is small
    if left_eye_size[1] < 5:
        margin = 1
    else:
        margin = 6
    
    img_left_eye = bgr_img[np_left_tl[1]-margin:np_left_br[1]+margin, np_left_tl[0]-margin//2:np_left_br[0]+margin//2]
    img_right_eye = bgr_img[np_right_tl[1]-margin:np_right_br[1]+margin, np_right_tl[0]-margin//2:np_right_br[0]+margin//2]

    return [img_left_eye, img_right_eye]

landmark์˜ ์˜ค์ฐจ๋กœ ๋ˆˆ์„ ๊ฒ€์ถœํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ ๋‹นํ•œ margin ๊ฐ’์„ ์„ค์ •ํ•œ๋‹ค. ์‹ค์ œ๋กœ ๋ˆˆ์„ cropํ•ด ๋ณด์ž.

img_left_eye, img_right_eye = eye_crop(img_bgr, list_landmarks[0])

print (img_left_eye.shape)
plt.imshow(cv2.cvtColor(img_right_eye, cv2.COLOR_BGR2RGB))
plt.show()

images09.png

(4) ๊ตฌํ˜„ : ๋ˆˆ๋™์ž ์ฐพ๊ธฐ


๋ˆˆ ์ค‘์‹ฌ์„ ์ฐพ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค. ๋จผ์ €, ๋ˆˆ ์ด๋ฏธ์ง€๋ฅผ low pass filter๋ฅผ ์ด์šฉํ•ด์„œ smoothing ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” bilateralFilter๋ฅผ ์ด์šฉํ–ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ 1์ฐจ์› ๊ฐ’์œผ๋กœ ๋ˆ„์ ์‹œํ‚จ ํ›„ y ์ถ• ๊ธฐ์ค€์œผ๋กœ ์ตœ๋Œ€๊ฐ’์„ ์ฐพ์•„์„œ center_y ์ขŒํ‘œ๋ฅผ ๋จผ์ € ์–ป์–ด๋‚ธ๋‹ค. (y ์ถ•์€ x ์ถ•์— ๋น„ํ•ด ์ƒ๋Œ€์ ์œผ๋กœ ๋ณ€ํ™”๊ฐ€ ์ ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค)

x์ถ•์€ 1์ฐจ์› max point๋ฅผ ๊ธฐ์ค€์œผ๋กœ mean shift๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. ์–‘ ๋๋‹จ์— ์ˆ˜๋ ดํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•œ ํ›„ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

def findCenterPoint(gray_eye, str_direction='left'):
    if gray_eye is None:
        return [0, 0]

    # smoothing
    filtered_eye = cv2.bilateralFilter(gray_eye, 7, 75, 75)
    filtered_eye = cv2.bilateralFilter(filtered_eye, 7, 75, 75)
    filtered_eye = cv2.bilateralFilter(filtered_eye, 7, 75, 75)

    # 2D images -> 1D signals
    row_sum = 255 - np.sum(filtered_eye, axis=0)//gray_eye.shape[0]
    col_sum = 255 - np.sum(filtered_eye, axis=1)//gray_eye.shape[1]

    # normalization & stabilization
    def vector_normalization(vector):
        vector = vector.astype(np.float32)
        vector = (vector-vector.min())/(vector.max()-vector.min()+1e-6)*255
        vector = vector.astype(np.uint8)
        vector = cv2.blur(vector, (5,1)).reshape((vector.shape[0],))
        vector = cv2.blur(vector, (5,1)).reshape((vector.shape[0],))            
        return vector
    row_sum = vector_normalization(row_sum)
    col_sum = vector_normalization(col_sum)

    def findOptimalCenter(gray_eye, vector, str_axis='x'):
        axis = 1 if str_axis == 'x' else 0
        center_from_start = np.argmax(vector)
        center_from_end = gray_eye.shape[axis]-1 - np.argmax(np.flip(vector,axis=0))
        return (center_from_end + center_from_start) // 2

    center_x = findOptimalCenter(gray_eye, row_sum, 'x')
    center_y = findOptimalCenter(gray_eye, col_sum, 'y')

    inv_eye = (255 - filtered_eye).astype(np.float32)
    inv_eye = (255*(inv_eye - inv_eye.min())/(inv_eye.max()-inv_eye.min())).astype(np.uint8)

    resized_inv_eye = cv2.resize(inv_eye, (inv_eye.shape[1]//3, inv_eye.shape[0]//3))
    init_point = np.unravel_index(np.argmax(resized_inv_eye),resized_inv_eye.shape)

    x_candidate = init_point[1]*3 + 1
    for idx in range(10):
        temp_sum = row_sum[x_candidate-2:x_candidate+3].sum()
        if temp_sum == 0:
            break
        normalized_row_sum_part = row_sum[x_candidate-2:x_candidate+3].astype(np.float32)//temp_sum
        moving_factor = normalized_row_sum_part[3:5].sum() - normalized_row_sum_part[0:2].sum()
        if moving_factor > 0.0:
            x_candidate += 1
        elif moving_factor < 0.0:
            x_candidate -= 1
    
    center_x = x_candidate

    if center_x >= gray_eye.shape[1]-2 or center_x <= 2:
        center_x = -1
    elif center_y >= gray_eye.shape[0]-1 or center_y <= 1:
        center_y = -1
    
    return [center_x, center_y]

์™ผ์ชฝ, ์˜ค๋ฅธ์ชฝ ๋‘ ๋ˆˆ ์ด๋ฏธ์ง€์— ๋Œ€ํ•ด ์œ„ ํ•จ์ˆ˜๋“ค์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

def detectPupil(bgr_img, landmark):
    if landmark is None:
        return

    img_eyes = []
    img_eyes = eye_crop(bgr_img, landmark)

    gray_left_eye = cv2.cvtColor(img_eyes[0], cv2.COLOR_BGR2GRAY)
    gray_right_eye = cv2.cvtColor(img_eyes[1], cv2.COLOR_BGR2GRAY)

    if gray_left_eye is None or gray_right_eye is None:
        return 

    left_center_x, left_center_y = findCenterPoint(gray_left_eye,'left')
    right_center_x, right_center_y = findCenterPoint(gray_right_eye,'right')

    return [left_center_x, left_center_y, right_center_x, right_center_y, gray_left_eye.shape, gray_right_eye.shape]

๊ฒฐ๊ณผ๋ฅผ ๋ฝ‘์•„๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ขŒํ‘œ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

left_center_x, left_center_y, right_center_x, right_center_y, le_shape, re_shape = detectPupil(img_bgr, list_landmarks[0])
print ((left_center_x, left_center_y), (right_center_x, right_center_y), le_shape, re_shape)

์˜ค๋ฅธ์ชฝ ๋ˆˆ์„ ์ด๋ฏธ์ง€๋กœ ์ถœ๋ ฅํ•ด๋ณด์ž.

show = img_right_eye.copy()
    
show = cv2.circle(show, (right_center_x, right_center_y), 3, (0,255,255), -1)

plt.imshow(cv2.cvtColor(show, cv2.COLOR_BGR2RGB))
plt.show()

images10.png

์™ผ์ชฝ ๋ˆˆ๋„ ํ™•์ธํ•ด๋ณธ๋‹ค.

show = img_left_eye.copy()
    
show = cv2.circle(show, (left_center_x, left_center_y), 3, (0,255,255), -1)

plt.imshow(cv2.cvtColor(show, cv2.COLOR_BGR2RGB))
plt.show()

images11.png

๋ˆˆ๋™์ž๋Š” ์ฐพ์•˜์ง€๋งŒ ์ค‘์‹ฌ์ด ์•„๋‹Œ ๊ฒฝ์šฐ์— ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ์กด์˜ ๋จธ์‹ ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•๋“ค์€ ๋„๋ฉ”์ธ ์ง€์‹์„ ์ ์šฉํ•ด์„œ ๊ฐ„๋‹จํ•˜๊ณ  ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ๋ฐ˜๋ฉด ์ผ์ • ์ˆ˜์ค€ ์ด์ƒ์˜ ์„ฑ๋Šฅ์„ ๋งŒ์กฑํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ๋”ฐ๋ผ์„œ ์กฐ๊ธˆ ๋ชจ์ž๋ž€ ์„ฑ๋Šฅ์œผ๋กœ ๋Œ€๋Ÿ‰์˜ coarseํ•œ ๋ผ๋ฒจ์„ ์ˆ˜์ง‘ํ•œ ๋’ค, ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ๊ฐœ์„ ํ•ด ๋‚˜๊ฐ€๋Š” ํ•™์Šต ์ „๋žต์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

ํ‚คํฌ์ธํŠธ ๊ฒ€์ถœ ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ ๋งŒ๋“ค๊ธฐ

์ด์ œ ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ์œ„ํ•ด ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค. ์•ž์—์„œ๋Š” ๋„๋ฉ”์ธ ์ง€์‹์„ ํ™œ์šฉํ•ด์„œ ์ˆ˜์ž‘์—…์œผ๋กœ ํŠน์„ฑ๋“ค์„(hand-crafted features) ๋งŒ๋“ค์—ˆ๋‹ค๋ฉด ์ด์ œ๋ถ€ํ„ฐ๋Š” ๋„๋ฉ”์ธ ์ง€์‹ ์—†์ด ์‹ ๊ฒฝ๋ง์ด ํŠน์ง•์„ ์ž๋™์œผ๋กœ ๋ฝ‘์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„ํ•œ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์šฐ๋ฆฌ๋Š” VGG, Resnet ๋“ฑ ๊ธฐ๋ณธ(base) ๋ชจ๋ธ์„ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ ๋ฌธ์ œ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•ด ์™”๋‹ค. ์ฃผ๋กœ ์ˆ˜์‹ญ ๊ฐœ ์ด๋‚ด์˜ ํด๋ž˜์Šค ์ค‘ ํ•˜๋‚˜๋ฅผ ์ฐพ๋Š” ๋ฌธ์ œ์— ์ ์šฉํ–ˆ๋Š”๋ฐ ์ด ๋ชจ๋ธ์„ ์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ์ธ ๋ˆˆ๋™์ž๋กœ ๋ณ€ํ˜•ํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

images12.png

์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ ๋ชจ๋ธ์€ ์ด๋ฏธ์ง€๋ฅผ CNN์— ์ž…๋ ฅํ•ด์„œ ์ตœ์ข…์ ์œผ๋กœ ํ•ด๋‹น ํด๋ž˜์Šค์˜ ์ธ๋ฑ์Šค๋ฅผ ์ฐพ์•„๋‚ธ๋‹ค. ์ฆ‰, ๋ชจ๋ธ์˜ ์ถœ๋ ฅ์€ ํด๋ž˜์Šค๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋‹จ์ผ idx ๊ฐ’(๋˜๋Š” one-hot vector)์ด ๋ฉ๋‹ˆ๋‹ค. ๋ˆˆ๋™์ž ์œ„์น˜๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ๋ชจ๋ธ์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค.

images13.png

๊ฐ€์žฅ ๋จผ์ €, ์ถœ๋ ฅ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค. ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜ ๋ฌธ์ œ์—์„œ๋Š” ์†Œํ”„ํŠธ๋งฅ์Šค(softmax)๋ฅผ ํ†ต๊ณผํ•ด 1๊ฐœ์˜ ํด๋ž˜์Šค ์ธ๋ฑ์Šค๋ฅผ ์ถœ๋ ฅํ–ˆ์ง€๋งŒ ๋ˆˆ๋™์ž ์ค‘์‹ฌ ์œ„์น˜์ธ x, y ์ขŒํ‘œ๋ฅผ ์ถœ๋ ฅํ•ด์•ผ ํ•œ๋‹ค. ์ด ๋•Œ ๊ฐ’์€ ๋ถ„๋ฅ˜ ๋ชจ๋ธ์˜ ์ •์ˆ˜ํ˜• ๋ถˆ์—ฐ์† ๊ฐ’์ด ์•„๋‹Œ ์—ฐ์†ํ˜• ๊ฐ’์ด์–ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํšŒ๊ท€(regression) ๋ฌธ์ œ๋ผ๊ณ  ํ•œ๋‹ค.

๊ฐ ํƒœ์Šคํฌ์˜ ์ถœ๋ ฅ ํŠน์ง•

  • Image Classification : argmax(softmax)์˜ ๋ถˆ์—ฐ์† ์ •์ˆ˜ํ˜• ๊ฐ’
  • Image Localization(regression) : ์—ฐ์†ํ˜• ์‹ค์ˆ˜ ๊ฐ’

์†Œํ”„ํŠธ๋งฅ์Šค - ํฌ๋กœ์Šค ์—”ํŠธ๋กœํ”ผ(cross-entropy) ๋ฐฉ๋ฒ•์€ ์ด๋ฏธ์ง€ ํด๋ž˜์Šค๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ์†์‹ค ํ•จ์ˆ˜์ด๋‹ค. ํšŒ๊ท€์—์„œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฐ’์ด ์—ฐ์†ํ˜• ์‹ค์ˆ˜๋กœ ์ถœ๋ ฅ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— MSE์™€ ๊ฐ™์€ ์†์‹ค ํ•จ์ˆ˜๋ฅผ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ๋‹ค.

images14.png

์ด์ œ ๋งŒ๋“  ๋ชจ๋ธ์„ ํ•™์Šต์‹œํ‚ค๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹ค์ „์€ ํ•ญ์ƒ ๋” ์–ด๋ ต๋‹ค. ๋‚ด ๋‹ˆ์ฆˆ์— ๊ผญ ๋งž๋Š” ์ปค์Šคํ…€ ํƒœ์Šคํฌ์˜ ๊ฒฝ์šฐ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋Œ€๋ถ€๋ถ„ ๋ถ€์กฑํ•˜๋‹ค. ์˜ค๋Š˜ ๊ฐ•์˜์—์„œ๋„ ๋†’์€ ํ€„๋ฆฌํ‹ฐ์˜ ๋ˆˆ๋™์ž ๋ผ๋ฒจ์„ ์–ป๊ธฐ๊ฐ€ ๊ฝค ์–ด๋ ต๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋Š๊ผˆ์„ ๊ฒƒ์ด๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋ฏธ๋ฆฌ ํ•™์Šต๋œ ๊ฐ€์ค‘์น˜(weight)๋ฅผ ๊ฐ€์ง€๊ณ  ์™€์„œ fine tuning ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ฐ€์ ธ์˜จ ๊ฐ€์ค‘์น˜๊ฐ€ ํ•™์Šต๋œ(pretrained) ํƒœ์Šคํฌ๊ฐ€ ๋‚˜์˜ ํƒœ์Šคํฌ์™€ ๊ฐ™์€ ๋„๋ฉ”์ธ์ด๋ฉด ๋” ์ข‹๊ฒ ์ง€๋งŒ ์•„๋‹ˆ์–ด๋„ ํšจ๊ณผ๋Š” ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ณดํ†ต์€ ์ด๋ฏธ์ง€๋„ท(ImageNet)์ด๋‚˜ COCO ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ ํ•™์Šตํ•œ ๋ชจ๋ธ ๊ฐ€์ค‘์น˜๋ฅผ ๊ฐ€์ ธ์™€์„œ fine tuning ํ•œ๋‹ค.

images15.png

์œ„ ๋ฐฉ๋ฒ•์„ ์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. ๊ธฐ๋ณธ ResNet ๋ชจ๋ธ์„ ๊ตฌํ˜„ํ•˜๊ณ 
  2. ImageNet ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ pretraining ์„ ์—ด์‹ฌํžˆ ํ•œ ํ›„
  3. ResNet์˜ fully connected layer ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ํšŒ๊ท€ ์†์‹ค ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด์„œ
  4. ๋ˆˆ๋™์ž ์œ„์น˜๋ฅผ ํ•™์Šต์‹œํ‚ต๋‹ˆ๋‹ค.

1 ~ 3๋ฒˆ๊นŒ์ง€ ์ง์ ‘ ์ž‘์—…ํ•˜๋ ค๋ฉด ImageNet ํ›ˆ๋ จ์ด ๋งค์šฐ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ๊ฝค ๋ฒˆ๊ฑฐ๋กœ์šด ์ž‘์—…์ด๋‹ค. ํ•˜์ง€๋งŒ ํ…์„œํ”Œ๋กœ์šฐ์—์„œ tensorflow_hub ๋ฅผ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ImageNet์œผ๋กœ ํ•™์Šต๋œ ๋ชจ๋ธ์„ ๊ฐ€์ง€๊ณ  ์˜ค๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.

!pip install tensorflow_hub # ์„ค์น˜๋˜์–ด ์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ ์ฃผ์„ ํ•ด์ œ
import tensorflow_hub as hub
from tensorflow.keras import layers
from tensorflow.keras import models
from tensorflow.keras.callbacks import LearningRateScheduler

tensorflow_hub ๋ฅผ import ํ•œ๋‹ค. hub ์—๋Š” VGG ๋„คํŠธ์›Œํฌ ์™ธ์—๋„ ๋งŽ์€ ๋ชจ๋ธ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

๋งŽ์€ ๋ชจ๋ธ๋“ค์ด ์‚ฌ์šฉ ์„ค๋ช…๊ณผ ํ•จ๊ป˜ ์ œ๊ณต๋œ๋‹ค. ๊ทธ ์ค‘ ResNet-50์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

๋งˆ์นจ tensorflow_hub ์—์„œ ์ ์ ˆํ•œ ResNet-50 ๋ชจ๋ธ์„ ๊ตฌํ˜„ํ•ด ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

ํ•ด๋‹น ๋ชจ๋ธ์€ ๊ฐ™์€ ๋งํฌ์˜ ์›นํŽ˜์ด์ง€์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋ธ์€ resnet50, ํ•™์Šต๋œ dataset ์€ ImageNet ์ด๋ผ๋Š” ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

TensorFlow Hub ๋ชจ๋ธ์„ ์ฝ”๋“œ๋กœ ๋ถˆ๋Ÿฌ์˜จ๋‹ค. tensorflow_hub ์—์„œ ResNet์˜ ํŠน์„ฑ ์ถ”์ถœ๊ธฐ ๋ถ€๋ถ„์„ ๋ฐฑ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

''' tf hub feature_extractor '''
feature_extractor_url = "https://tfhub.dev/google/imagenet/resnet_v2_50/feature_vector/4"
feature_extractor_layer = hub.KerasLayer(feature_extractor_url,
                                         input_shape=(80,120,3))

์ขŒํ‘œ๋ฅผ ํ•™์Šตํ•  ์ˆ˜ ์žˆ๋„๋ก Dense ๋ ˆ์ด์–ด๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

num_classes = 6

feature_extractor_layer.trainable = False
model = tf.keras.Sequential([
    feature_extractor_layer,
    #layers.Dense(1024, activation='relu'),
    #layers.Dropout(0.5),
    layers.Dense(num_classes, activation='sigmoid'),
])

๋ชจ๋ธ์˜ ๊ตฌ์กฐ๋ฅผ ํ™•์ธํ•œ๋‹ค.

model.summary()

๋ผ๋ฒจ๋ง ํˆด (1) ์†Œ๊ฐœ

์ด์ „ ๋‹จ๊ณ„์—์„œ coarse label๋กœ ๋ชจ๋ธ์„ ์–ด๋Š ์ •๋„ ์ˆ˜์ค€๊นŒ์ง€ ๋งŒ๋“ค์—ˆ๋‹ค. ์ด์ œ fine label์„ ์–ป์–ด์„œ ๋ชจ๋ธ์„ ํ–ฅ์ƒ์‹œ์ผœ์•ผ ํ•œ๋‹ค. ์–‘์งˆ์˜ ๋ผ๋ฒจ์„ ๋น ๋ฅด๊ฒŒ ์–ป๊ธฐ ์œ„ํ•ด์„  ์–ด๋…ธํ…Œ์ด์…˜ ํˆด(annotation tool) ๋˜๋Š” **๋ผ๋ฒจ๋ง ํˆด(labeling tool)**์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

์ž˜ ์•Œ๋ ค์ง„ ๋น„์ „ ํƒœ์Šคํฌ(image classification, object detection, semantic segmentation)๋Š” ๊ณต๊ฐœ๋œ ์–ด๋…ธํ…Œ์ด์…˜ ๋„๊ตฌ๊ฐ€ ๋งŽ๋‹ค.

OpenCV์˜ CVAT ์€ ์ด๋ฏธ์ง€ ๊ฒ€์ถœ(object detection) ๋“ฑ์— ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ณ  ๋ฌด๋ฃŒ๋กœ ๊ณต๊ฐœ๋˜์–ด ์žˆ๋‹ค.

imglab ์ด๋ผ๋Š” ํˆด๋„ ๊ณต๊ฐœ๋˜์–ด ์žˆ๋Š”๋ฐ, COCO ๋ฐ์ดํ„ฐ์…‹ ํ˜•ํƒœ๋กœ ์ €์žฅํ•  ์ˆ˜ ์žˆ๊ณ  ํ‚คํฌ์ธํŠธ ๋ผ๋ฒจ๋ง(keypoints labeling)๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์—ฌ๋Ÿฌ ์–ด๋…ธํ…Œ์ด์…˜ ๋„๊ตฌ๋“ค์„ ์‚ดํŽด๋ณด๋ฉด ๋ช‡ ๊ฐ€์ง€ ํŠน์ง•์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

  1. QT ๋“ฑ์˜ GUI ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์›น ๊ธฐ๋ฐ˜ ๋ฐฉ๋ฒ•์œผ๋กœ ๋‚˜๋ˆ„์–ด์ง„๋‹ค.
  2. ๋‹จ์ถ•ํ‚ค์™€ ๋ผ๋ฒจ ์ €์žฅ ํฌ๋งท ๋“ฑ ํŽธ์˜์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ ๊ทน์ ์œผ๋กœ ์ ์šฉํ•œ๋‹ค.

๋†’์€ ํŽธ์˜์„ฑ์„ ์•ž์„ธ์›Œ์„œ ๊ณต๊ฐœํ•˜๊ณ  ์žˆ์ง€๋งŒ ๋ง‰์ƒ ์‚ฌ์šฉํ•ด๋ณด๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ํƒœ์Šคํฌ์— ๋”ฑ ๋งž์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋Œ€๋ถ€๋ถ„ ์ด๋‹ค. (3D ํ™˜๊ฒฝ์—์„œ ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ํ•ด์•ผ ํ•˜๋Š” ์ผ ๋“ฑ)

์šฐ๋ฆฌ๋Š” ๋ˆˆ๋™์ž์˜ ์œ„์น˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๋„๊ตฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. imglab์—๋Š” ํ‚คํฌ์ธํŠธ(keypoint) ๋„๊ตฌ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜๋Š” ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋ฌธ์ œ๋Š” COCO ๋ฐ์ดํ„ฐ์…‹์—์„œ ๋ผ๋ฒจ๋งํ•œ ์Šคํƒ€์ผ์„ ์ง€์ผœ์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— 17๊ฐœ์˜ ํ‚คํฌ์ธํŠธ๋ฅผ ์ •ํ•ด์•ผ ํ•˜๋Š” ๊ทœ์น™์ด ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ˆˆ๋™์ž 1๊ฐœ๋ฅผ ์ฐ๊ฑฐ๋‚˜ ์–‘ ๋ˆˆ ์˜† 2๊ฐœ์˜ ์ ์ด ํ•„์š”ํ•œ๋ฐ ์ด ์กฐ๊ฑด์— ๊ผญ ๋งž๋Š” ๋ผ๋ฒจ๋ง ๋„๊ตฌ๋ฅผ ๋งŒ๋‚˜๊ธฐ๋Š” ์‰ฝ์ง€ ์•Š๋‹ค.

๊ฒฐ๊ตญ ์ผ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์ž…๋ง›์— ๋งž๋Š” ๋„๊ตฌ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค๊ฒŒ ๋œ๋‹ค. ๋งˆ์นจ ์ ์ ˆํ•œ ์ œ์ž‘๊ธฐ๊ฐ€ ์žˆ์œผ๋‹ˆ ํ•œ๋ฒˆ ์ฝ์–ด๋ณด์ž.

๋ฌธ์ œ๋Š” ์ดˆ๋ณด์ž๋“ค์€ ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ GUI ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ์ต์ˆ™ํ•˜์ง€ ์•Š๋‹ค๋Š” ์ ์ด๋‹ค. ๋ผ๋ฒจ๋ง ํˆด์„ ์ œ์ž‘ํ•˜๋ ค ์ƒ๊ฐํ•˜๋‹ค๋ณด๋ฉด QT, MFC, ์‹ฌ์ง€์–ด HTML/CSS/JavaScript๋ฅผ ์ตํžˆ๊ณ  ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ˆ˜์ค€๊นŒ์ง€ ๋งŒ๋“ค ๊ณ ๋ฏผ์„ ํ•˜๋Š” ์ƒํ™ฉ์„ ๋งž์ดํ•˜๊ฒŒ ๋œ๋‹ค. ๋จธ์‹ ๋Ÿฌ๋‹ ์—”์ง€๋‹ˆ์–ด ์ž…์žฅ์—์„œ ๋ฐฐ๋ณด๋‹ค ๋ฐฐ๊ผฝ์ด ๋” ํฐ ์ƒํ™ฉ์ด ๋˜๋ฏ€๋กœ ์ƒ๋‹นํ•œ ๋ถ€๋‹ด์„ ๋Š๋‚„ ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ํšจ์œจ์ ์ธ ํ˜•ํƒœ๋กœ ๋ผ๋ฒจ๋ง ํˆด์„ ์ œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค. ๊ธ€์“ด์ด๋Š” ๋ผ๋ฒจ๋ง์„ ํ•  ๋•Œ ๋‘ ๋‹จ๊ณ„๋กœ ๋ผ๋ฒจ๋ง์„ ํ•˜๊ณ  ์žˆ๋‹ค.

  1. ๊ธฐ์กด์— ๋งŒ๋“ค์–ด์ง„ ๋ผ๋ฒจ์ด ์ž˜ ์˜ˆ์ธกํ•˜๋Š”์ง€ True / False ๋ถ„๋ฅ˜
  2. ํ•ด๋‹น ํƒœ์Šคํฌ์˜ ์–ด๋…ธํ…Œ์ด์…˜ ํˆด (์šฐ๋ฆฌ์˜ ๊ฒฝ์šฐ ํ‚คํฌ์ธํŠธ ์–ด๋…ธํ…Œ์ด์…˜)

์˜ค๋Š˜ ๋‹ค๋ฃฐ ๋ˆˆ๋™์ž ๊ฒ€์ถœ์€ 1, 2๋ฒˆ ๋ชจ๋‘ OpenCV๋งŒ์„ ์ด์šฉํ•ด์„œ ์•„์ฃผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฒˆ ์‹œ๊ฐ„์—๋Š” 1๋ฒˆ์„ ๋งŒ๋“ค์–ด ๋ณผ ๊ฒƒ์ด๋‹ค.

๋ผ๋ฒจ๋ง ํˆด (2) ์ง์ ‘ ์ œ์ž‘ํ•˜๊ธฐ

ํŒŒ์ด์ฌ๊ณผ OpenCV๋งŒ์„ ์ด์šฉํ•ด์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ„ฐ๋ฏธ๋„ ๋ช…๋ น์œผ๋กœ ์•„์ฃผ ์‰ฝ๊ฒŒ ์‹คํ–‰ ํ•  ์ˆ˜ ์žˆ๋Š” ์–ด๋…ธํ…Œ์ด์…˜ ๋„๊ตฌ๋ฅผ ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค. ์ด๋ฒˆ์— ๋งŒ๋“ค ์–ด๋…ธํ…Œ์ด์…˜ ๋„๊ตฌ๋Š” ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์— ๋“ค์–ด์žˆ๋Š” ๋งŽ์€ ์ด๋ฏธ์ง€๋“ค์— ๋Œ€ํ•ด True/False Binary Classification์„ ์œ„ํ•œ ๋ผ๋ฒจ๋ง์„ ํ•ด์ฃผ๋Š” ๋„๊ตฌ์ด๋‹ค. ํŒŒ์ผ๋ช…์€ my_labeler_1st.py๋กœ ํ•œ๋‹ค.

# ์šฐ๋ฆฌ๊ฐ€ ์ œ์ž‘ํ•˜๊ณ ์ž ํ•˜๋Š” ๋ผ๋ฒจ๋ง ํˆด์˜ ์‚ฌ์šฉ๋ฒ•
$ python my_labeler_1st.py [imgpath or dir] [mask path or dir]

๋‹จ์ถ•ํ‚ค๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋งคํ•‘ํ•œ๋‹ค.

esc : program off 
n : next image
p : previous image
f : true tag & next image
d : false tag & next image
s : save
v : current label show

์›๋ณธ ์ด๋ฏธ์ง€์™€ ํ‚คํฌ์ธํŠธ ์œ„์น˜์— ๋ผ๋ฒจ๋ง์ด ๋˜์–ด์žˆ๋Š” ์ •๋‹ต์„ ๋ชจ๋‘ ์ด๋ฏธ์ง€ ํ˜•ํƒœ๋กœ ์ €์žฅํ•ด๋‘์—ˆ๋‹ค. ๋‹ต์ด ๋งž๋Š”์ง€ ์•Œ๊ธฐ ์œ„ํ•ด์„œ img_path ์™€ mask_path ์—์„œ ๊ฐ ์ด๋ฏธ์ง€๋ฅผ ์ฝ๋Š”๋‹ค.

import os
from os.path import join
from glob import glob
import cv2
import numpy as numpy
import argparse
import numpy as np
import json
from pprint import pprint

args = argparse.ArgumentParser()

# hyperparameters
args.add_argument('img_path', type=str, nargs='?', default=None)
args.add_argument('mask_path', type=str, nargs='?', default=None)

config = args.parse_args()

์ฝ์€ ์ด๋ฏธ์ง€๋“ค์€ ์ ์ ˆํ•œ blend_mask() ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ํ™”๋ฉด์— ์ถœ๋ ฅํ•  ์ด๋ฏธ์ง€๋กœ ๋งŒ๋“ ๋‹ค.

def blend_mask(img_orig, img_mask, alpha=0.3):
    '''
    alpha : alpha blending ratio. 0 ~ 1
    '''
    imgBlack = np.zeros(img_mask.shape, dtype=np.uint8)
    mask = (img_mask / img_mask.max()) * 255
    mask = mask.astype(np.uint8)

    if len(np.unique(mask)) > 2:
        # multi channel mask
        mask_color = cv2.applyColorMap(mask, cv2.COLORMAP_JET)
        mask_white = cv2.merge((mask,mask,mask))
        mask_color = np.where(mask_white != 0, mask_color, 0)
    else:
        # 1 channel mask
        mask_color = cv2.merge((imgBlack, mask, mask))

    img_show = cv2.addWeighted(img_orig, 0.9, mask_color, alpha, 0.0)
    return img_show

alpha ๊ฐ’์€ ์•ŒํŒŒ ๋ธ”๋ Œ๋”ฉ(alpha-blending) ๊ธฐ๋ฒ•์˜ ๋ธ”๋ Œ๋”ฉ ์ƒ์ˆ˜๋‹ค.

์ด๋ฏธ์ง€, ์˜ˆ์ƒ ๋ผ๋ฒจ์˜ ๊ฒฝ๋กœ์— ๋ฌธ์ œ๊ฐ€ ์—†๋Š”์ง€ ์ฒดํฌํ•œ๋‹ค. img_path ๊ฐ€ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ž…๋ ฅ๋˜๋Š” ๊ฒฝ์šฐ(os.path.isdir(config.img_path)), ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์— ์žˆ๋Š” ์ด๋ฏธ์ง€ ์ „์ฒด ์ธ๋ฑ์Šค๋ฅผ ์ฐพ๊ณ  ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€๋ฅผ ์ฝ๋Š”๋‹ค. ๋งˆ์Šคํฌ๋กœ๋Š”, mask_path ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ฝ์–ด์ง„ ์ด๋ฏธ์ง€์™€ ๊ฐ™์€ ์ด๋ฆ„์„ ๊ฐ–๋Š” ๋ผ๋ฒจ ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ง€๊ณ  ์˜ฌ ์˜ˆ์ •์ด๋‹ค.

def check_dir():
    flg_mask = True
    if config.mask_path is None \
        or len(config.mask_path) == 0 \
        or config.mask_path == '':
        print ('[*] mask file not exist')
        flg_mask = False

    if config.img_path is None \
        or len(config.img_path) == 0 \
        or config.img_path == '' \
        or os.path.isdir(config.img_path):
        root = os.path.realpath('./')
        if os.path.isdir(config.img_path):
            root = os.path.realpath(config.img_path)
        img_list = sorted(glob(join(root, '*.png')))
        img_list.extend(sorted(glob(join(root, '*.jpg'))))
        config.img_path = img_list[0]

    img_dir = os.path.dirname(os.path.realpath(config.img_path))
    mask_dir = os.path.dirname(os.path.realpath(config.mask_path)) if flg_mask else None
    mask_dir = os.path.realpath(config.mask_path) if flg_mask and os.path.isdir(config.mask_path) else mask_dir

    return img_dir, mask_dir, flg_mask

๋‹ค์Œ ์ด๋ฏธ์ง€๋กœ ๋„˜์–ด๊ฐ€๋Š” ํ•จ์ˆ˜๋‹ค. ํ‚ค์›Œ๋“œ๋กœ ์ž…๋ ฅ๋œ pos ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ ์ˆœ์„œ(idx)๋ฅผ ํ•˜๋‚˜์”ฉ ์กฐ์ ˆํ•œ๋‹ค. idx ๊ฐ€ ๋ฆฌ์ŠคํŠธ ํฌ๊ธฐ ์ด์ƒ์œผ๋กœ ๋  ๋•Œ ์ˆœ์„œ๋ฅผ ๋‹ค์‹œ 0์œผ๋กœ ์กฐ์ •ํ•œ๋‹ค.

def move(pos, idx, img_list):
    if pos == 1:
        idx += 1
        if idx == len(img_list):
            idx = 0
    elif pos == -1:
        idx -= 1
        if idx == -1:
            idx = len(img_list) - 1
    return idx

๋ฉ”์ธ์ด ๋˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค. img_list ์˜ ์ด๋ฏธ์ง€๋“ค์„ ํ•˜๋‚˜์”ฉ ์ฝ์œผ๋ฉด์„œ json_file์— ๋ผ๋ฒจ์„ ํ•˜๋‚˜์”ฉ ์ž…๋ ฅํ•œ๋‹ค. ํ˜„์žฌ ์ด๋ฏธ์ง€ ์ˆœ์„œ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋„๋ก ์ถœ๋ ฅํ•˜๊ณ  p ์™€ f ๋ฅผ ์ž…๋ ฅํ•  ๋•Œ dict_label ์— ์ •๋‹ต์„ ์ž…๋ ฅํ•˜๋„๋ก ๋งŒ๋“ ๋‹ค. s ๋ฅผ ๋ˆ„๋ฅด๋ฉด json ํŒŒ์ผ ํ˜•ํƒœ๋กœ ์ €์žฅํ•œ๋‹ค.

def blend_view():
    cv2.namedWindow('show', 0)
    cv2.resizeWindow('show', 500, 500)

    img_dir, mask_dir, flg_mask = check_dir()

    fname, ext = os.path.splitext(config.img_path)
    img_list = [os.path.basename(x) for x in sorted(glob(join(img_dir,'*%s'%ext)))]

    dict_label = {}
    dict_label['img_dir'] = img_dir
    dict_label['mask_dir'] = img_dir
    dict_label['labels'] = []

    json_path = os.getenv('HOME')+'/aiffel/coarse_to_fine/annotation.json'
    json_file = open(json_path, 'w', encoding='utf-8')

    idx = img_list.index(os.path.basename(config.img_path))
    while True:
        start = cv2.getTickCount()
        fname = img_list[idx]
        mname = fname
        orig = cv2.imread(join(img_dir, fname), 1)

        img_show = orig
        if flg_mask:
            mask = cv2.imread(join(mask_dir, mname), 0) 
            img_show = blend_mask(orig, mask)

        time = (cv2.getTickCount() - start) / cv2.getTickFrequency() * 1000

        print (f'[INFO] ({idx+1}/{len(img_list)}) {fname}... time: {time:.3f}ms')

        cv2.imshow('show', img_show)

        key = cv2.waitKey(0)
        if key == 27:   # Esc to Stop and Save Json result.
            return -1
        if key == ord('n'):
            idx = move(1, idx, img_list)
        elif key == ord('p'):
            idx = move(-1, idx, img_list)
        elif key == ord('f'):
            dict_label['labels'].append({'name':fname, 'class':1})
            idx = move(1, idx, img_list)
            print (f'[INFO] {fname}, class: true')
        elif key == ord('d'):
            dict_label['labels'].append({'name':fname, 'class':0})
            idx = move(1, idx, img_list)
            print (f'[INFO] {fname}, class: False')
        elif key == ord('v'):
            print ()
            pprint (dict_label)
            print ()
        elif key == ord('s'):
            json.dump(dict_label, json_file, indent=2)
            print (f'[INFO] < {json_path} > saved!')
    json_file.close()

if __name__ == '__main__':
    blend_view()

๊ฐ€๋ณ๊ณ  ๋น ๋ฅธ ๋ผ๋ฒจ๋ง ํˆด์„ ๋งŒ๋“ค์—ˆ๋‹ค. ๋จธ์‹ ๋Ÿฌ๋‹ ์—…๋ฌด์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋งŒํผ, ํ•„์š”ํ•˜๋‹ค๋ฉด ๋ผ๋ฒจ๋ง ํˆด์„ ๋งŒ๋“ค์–ด ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์œ„์™€ ๊ฐ™์€ ๋งŒ๋“ค์–ด๋ณธ ๋ผ๋ฒจ๋ง ํˆด ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์œ„์™€ ๊ฐ™์ด ์ฒจ๋ถ€ํ•˜์˜€๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ์‹คํ–‰ํ•ด ๋ณด๋ฉด์„œ ๋ผ๋ฒจ๋ง์„ ์ง์ ‘ ์ˆ˜ํ–‰ํ•ด ๋ณด์ž. img_path๋Š” ์ด๋ฏธ์ง€๊ฐ€ ๋‹ด๊ฒจ ์žˆ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ž„์˜๋กœ ๋ถ€์—ฌํ•˜๋ฉด ๋œ๋‹ค. ์•„๋ž˜ ์˜ˆ์‹œ๋Š” ~/aiffel/coarse_to_fine/images ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ์ด๋‹ค.

# ๋ผ๋ฒจ๋ง ์ˆ˜ํ–‰
python my_labeler_1st.py ./images

์ •์˜ํ•œ ๋‹จ์ถ•ํ‚ค ์ •๋ณด๋ฅผ ๊ธฐ์–ตํ•˜์ž. f๋‚˜ d๋ฅผ ์ด์šฉํ•ด์„œ ๋ผ๋ฒจ์„ ๋ถ€์—ฌํ•˜๊ณ , s๋ฅผ ๋ˆŒ๋Ÿฌ ์ €์žฅํ•œ ํ›„ esc๋ฅผ ๋ˆŒ๋Ÿฌ ํŒŒ์ผ์— ์ €์žฅํ•œ ํ›„ ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•œ๋‹ค. ์œ„ ์†Œ์Šค์ฝ”๋“œ์—์„œ ์ง€์ •ํ•œ ๋Œ€๋กœ, ๋ผ๋ฒจ๋ง ํŒŒ์ผ์€ ~/aiffel/coarse_to_fine/annotation.json์œผ๋กœ ์ €์žฅ๋œ๋‹ค.

esc : program off 
n : next image
p : previous image
f : true tag & next image
d : false tag & next image
s : save
v : current label show

Human-in-the-loop & Active Learning

์ด๋ฒˆ ์Šคํ…์—์„œ๋Š” ์ง€๊ธˆ๊นŒ์ง€ ๋งŒ๋“ค์–ด์˜จ ํ•™์Šต ์‹œ์Šคํ…œ์„ ํ•œ๋ˆˆ์— ์ •๋ฆฌํ•ด๋ณด๊ณ  ํ•™์Šต ์‹œ์Šคํ…œ์„ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค๋ฉด ํšจ์œจ์ ์ธ์ง€, ๋ผ๋ฒจ๋ง์„ ์–ด๋–ค ์‹œ์ ์—์„œ ์‹œ์ž‘ํ•ด์•ผ ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณผ ๊ฒƒ์ด๋‹ค.

๊ฐ€์žฅ ๋จผ์ € ์‹œ์„  ๊ฒ€์ถœ์„ ์œ„ํ•ด ๋ชจ๋ธ๋“ค์„ ์„ค๊ณ„ํ–ˆ๋‹ค. ์ „์ฒ˜๋ฆฌ ํ›„ ํ‚คํฌ์ธํŠธ ๊ฒ€์ถœ ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด์„œ ๋ˆˆ๋™์ž ์œ„์น˜๋ฅผ ์˜ˆ์ธกํ–ˆ๋‹ค.

1. Coarse Dataset ๋งŒ๋“ค๊ธฐ


๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ์—…๋ฌด ์ดˆ๋ฐ˜์—๋Š” mean shift์™€ ๊ฐ™์€ ๋จธ์‹ ๋Ÿฌ๋‹ ๋ฐฉ๋ฒ•๋“ค์„ ์ด์šฉํ•ด์„œ coarseํ•œ ์˜ˆ์ธก ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ด ์˜ˆ์ธก ๊ฒฐ๊ณผ๋Š” ๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์— ํ•™์Šต ๋ฐ์ดํ„ฐ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

images16.png

2. Fine Dataset ๋งŒ๋“ค๊ธฐ


coarse dataset์€ ๋ผ๋ฒจ ์ž์ฒด์˜ ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— fineํ•œ ๋ผ๋ฒจ์„ ์–ป์„ ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ์„ ์‹œ์ผœ์•ผ ํ•œ๋‹ค. ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ผ๋ฒจ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๊ธฐ์กด ๊ฒฐ๊ณผ๊ฐ€ ์ข‹๋‹ค/๋‚˜์˜๋‹ค ๋กœ ๋ถ„๋ฅ˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

images17.png

๊ฒฐ๊ณผ๊ฐ€ ์ข‹๊ณ  ๋‚˜์œ ๊ฒƒ์„ ๊ธฐ๋กํ•ด ๋‘๋ฉด ๊ทธ ์ž์ฒด๋กœ๋„ ๋ผ๋ฒจ์ด ๋œ๋‹ค. ์ด ์ •๋ณด๋ฅผ ์ด์šฉํ•ด์„œ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜๊ธฐ(classifier)๋ฅผ ๋งŒ๋“ค ์ˆ˜๊ฐ€ ์žˆ๋‹ค. ์ด ๋•Œ CAM(class activation map)์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์–ด๋””๊ฐ€ ์ž˜๋ชป๋˜์—ˆ๋Š”์ง€ ์กฐ๊ธˆ ๋” ์‰ฝ๊ฒŒ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ๋“ค์–ด์ง„ ์ด๋ฏธ์ง€ ๋ถ„๋ฅ˜๊ธฐ๋Š” fine label์„ ๋งŒ๋“ค ๋•Œ ํšจ๊ณผ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ์ธก ๊ฒฐ๊ณผ๊ฐ€ '์ข‹์Œ'์œผ๋กœ ๋‚˜์˜จ ๊ฒฐ๊ณผ๋Š” fineํ•œ ๋ผ๋ฒจ์ด๋ผ ์ƒ๊ฐํ•˜๊ณ  ํ•™์Šต์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ณ  ๋ฐ˜๋ฉด '๋‚˜์จ'์œผ๋กœ ๋‚˜์˜ค๋ฉด์„œ CAM ๊ฒฐ๊ณผ๋„ ์ข‹์ง€ ์•Š๋‹ค๋ฉด ๋ผ๋ฒจ๋ง์„ ํ–ˆ์„ ๋•Œ ํšจ๊ณผ์ ์ธ ๋ฐ์ดํ„ฐ์…‹์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

3. Active Learning


์œ„ ๊ฐœ๋…์ด ๋ฐ”๋กœ ์•กํ‹ฐ๋ธŒ ๋Ÿฌ๋‹(active learning) ๋ฐฉ๋ฒ•๋ก ์˜ ์‹œ์ž‘์ด๋‹ค. ๋ผ๋ฒจ๋ง์„ ํ•  ๋•Œ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ์„ ์ •ํ•  ๊ฒƒ์ธ์ง€ ๊ณ ๋ฏผํ•˜๊ณ  ์‚ฌ๋žŒ์—๊ฒŒ ๋ชจ๋ธ์ด ํ”ผ๋“œ๋ฐฑ์„ ์ฃผ๋Š” ํ•™์Šต๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋ฝ‘์•„์ง„ ํ›„๋ณด๊ตฐ์„ ์ง์ ‘ ๋ผ๋ฒจ๋งํ•œ๋‹ค.

images18.png

์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“ (์•ž์œผ๋กœ ๋งŒ๋“ค) ๋ผ๋ฒจ๋ง ํˆด์„ ์‚ฌ์šฉํ•ด์„œ ์–‘์งˆ์˜ ๋ผ๋ฒจ๋กœ ๋งŒ๋“ค์–ด๋‚ธ๋‹ค. ๊ธ€์“ด์ด๋Š” ์ด ๋ฐ์ดํ„ฐ์…‹์„ **"fine dataset"**์ด๋ผ ๋ถ€๋ฅด๊ณ  ์žˆ๋‹ค. ๋งŒ๋“ค์–ด์ง„ ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ ๋‹ค์‹œ ํ•™์Šต์„ ์‹œํ‚ค๋ฉด ๋ชจ๋ธ ๊ฐœ์„ ์˜ ๋ฐ˜๋ณต๋ฌธ์ด ๋งŒ๋“ค์–ด์ง„๋‹ค.

images19.png

ํ•™์Šตํ•˜๊ณ  ๋‹ค์‹œ ์˜ˆ์ธกํ•˜๋ฉด์„œ ๋ชจ๋ธ์˜ ์„ฑ๋Šฅ์„ ํšจ์œจ์ ์œผ๋กœ ๋Œ์–ด์˜ฌ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

images20.png

์‚ฌ๋žŒ์ด ํ•™์Šต ์‹œ์Šคํ…œ์— ๊ฐ€์žฅ ํšจ์œจ์ ์œผ๋กœ ๊ฐœ์ž…ํ•˜๋Š” ๋ฐฉ๋ฒ•(human-in-the-loop), activeํ•˜๊ฒŒ ํ•™์Šต ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ถœํ•˜๊ณ  ๋ผ๋ฒจ์„ ๊ฐœ์„ ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜๋‹ค. ๋ชจ๋ธ ์ž์ฒด๋ฅผ ์ž˜ ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•˜์ง€๋งŒ ๋จธ์‹ ๋Ÿฌ๋‹ ์—”์ง€๋‹ˆ์–ด๋ผ๋ฉด ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๋ชจ์„ ์ˆ˜ ์žˆ์„์ง€ ์ž˜ ๊ณ ๋ฏผํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค. ์˜ค๋Š˜ ๋‹ค๋ฃจ์—ˆ๋˜ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•๋“ค์€ ๋‹ค์Œ ๋…ธ๋“œ์˜ ํ”„๋กœ์ ํŠธ ์ˆ˜ํ–‰ ์‹œ ๋‹ค์‹œ ํ™œ์šฉํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.