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
๋ค์๊ณผ ๊ฐ์ ํจ๊ณผ๋ฅผ ๊ตฌํํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น?
์ฐ์ ๋์ ์ฐพ์์ผ ํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก ๋๋๋งํฌ(landmark)๋ฅผ ์ด์ฉํด ๋์ ์์น๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ์ ์๋ง ์๊ณ ์์ ๊ฒ์ด๋ค. ํ์ง๋ง ์ผ๋ฐ์ ์ธ ๋๋๋งํฌ๋ ๋์ด ๋ฐ๋ผ๋ณด๊ณ ์๋ ๋ฐฉํฅ๊น์ง๋ ํฌํจํ๊ณ ์์ง ์๋ค.
์๋ ์ฌ์ง์ฒ๋ผ ์์ ์ ๋ฐฉํฅ์ด ์ผ์ชฝ์ผ๋ก ํฅํ๊ณ ์๋ค๋ ์ ๋ณด๋ฅผ ์ด์ฉํ๋ ค ํ๋ค. ๋๋์์ ์์น๋ฅผ ์ ์ ์๋ค๋ฉด ๋ ์ฌ์ธํ ํํ์ด ๊ฐ๋ฅํ ๊ฒ์ ์์ํ ์ ์๋ค.
dlib
๊ณผ ๊ฐ์ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋์ ์ธ๊ณฝ์ ์์น๋ง ์ฐพ์์ค ๋ฟ ์์ ์ ๋ํ๋ด๋ ๋๋์๋ ์ฐพ์์ฃผ์ง ์๋๋ค. ์ฐ๋ฆฌ๋ ๋์ ์ธ๊ณฝ์ ์ ๋ณด๋ฅผ ์ฌ์ฉํด ๋์ ์ฐพ์๋ด๊ณ ๊ทธ ๋ด๋ถ์์ ๋๋์๋ฅผ ๊ฒ์ถํด์ผ ํ๋ค.
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋๋์ ๊ฒ์ถ ๋ฐ์ดํฐ์ ์ ์ฐพ์๋ณธ๋ค. ๋์ฒด๋ก ์๋์ ๊ฐ์ ๋ฐ์ดํฐ์ ์ ์ฐพ์ ์ ์๋ค.
์ด ๋ฐ์ดํฐ์ ์ ๋ถ๋ช ๋๋์ ๊ฒ์ถ๊ณผ ๊ด๋ จ์ด ์๋ ๋ฐ์ดํฐ์ด์ง๋ง ์ฐ๋ฆฌ๊ฐ ๋ชฉํ๋ก ํ๋ ์ดฌ์ ํ๊ฒฝ๊ณผ ๋ง์ด ๋ค๋ฅด๋ค. ์ฐ๋ฆฌ๋ ํธ๋ํฐ ์นด๋ฉ๋ผ ๊ธฐ๋ฐ์ ํ ๋๋น ์ ๋์ ์ดฌ์ ํ๊ฒฝ์ ๊ฐ์ง๋ ๋ฐ๋ฉด ๊ณต๊ฐ๋ ๋ฐ์ดํฐ์ ์ AR ๊ธฐ๊ธฐ๋ฅผ ์ํ 10cm ์ด๋ด์ ๊ทผ๊ฑฐ๋ฆฌ ์ดฌ์ ํ๊ฒฝ์ด๋ค.
์ค์ ์๋น์ค๋ฅผ ๋ง๋ค ๋์๋ ์ฐ๋ฆฌ๊ฐ ๋ง๋ค๊ณ ์ถ์ ํ๊ฒฝ์ ๊ผญ ๋ง๋ ๋ฐ์ดํฐ์ ์ ์ฐพ๊ธฐ๋ ๋งค์ฐ ์ด๋ ต๋ค. ๋ฐ๋ผ์ ๋จธ์ ๋ฌ๋ ๊ฐ๋ฐ์๋ ๊ณต๊ฐ๋ ๋ฐ์ดํฐ์ ๋ชจ๋ธ์ด ๋ชจ๋ ์์ ๋ ๋ฌธ์ ๋ฅผ ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๊ณ ๋ฏผํ๊ณ , ํด๊ฒฐ์ฑ ์ ์ฐพ์ ์ ์์ด์ผ ํ๋ค.
๋ฅ๋ฌ๋ ๊ธฐ๋ฐ ๋ฐฉ๋ฒ์ ์ ์ฉํ๋ ค๋ฉด ์์ฃผ ๋ง์ ๋ฐ์ดํฐ๊ฐ ํ์ํ๋ค. ์๋ณธ์ด ํ๋ถํ ์ํฉ์ด๋ผ๋ฉด ๋ฐ์ดํฐ์ ์ฃผ๋ณ ํ๊ฒฝ์ ๊ตฌ๋งคํ๋ ๋ฐฉ๋ฒ์ผ๋ก ํด๊ฒฐํ ์ ์๋ค. ํ์ง๋ง ์ฒ์ ์๋ํ๋ ์ ๋ฌด์ ๋๊ท๋ชจ ์๋ณธ์ ํฌ์ํ๊ธฐ๋ ํ์ค์ ์ผ๋ก ๊ต์ฅํ ์ด๋ ต๋ค. (์ฑ๊ณตํ ์ ์์์ง, ์ฑ๊ณผ๋ฅผ ๋ผ ์ ์์์ง ํ์ ํ๊ธฐ ์ด๋ ต๊ธฐ ๋๋ฌธ) ๋ฐ๋ผ์ ์ด๊ธฐ ์ปจ์ ์ฆ๋ช ๋จ๊ณ์์๋ ์๊ท๋ชจ์ ์๋ณธ๊ณผ ์ธ๋ ฅ์ผ๋ก ํ๋กํ ํ์ ์ ๋ง๋ค์ด์ผํ๋๋ฐ ์ด ๋ ๋ฅ๋ฌ๋์ ์ ์ฉํ๊ธฐ๊ฐ ์ฝ์ง ์๋ค.
๊ธฐ์กด ๋จธ์ ๋ฌ๋ ๋ฐฉ๋ฒ์ ์ ์ ํ ์ด์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ ์ ๊ฐ๊ณต๋ ์ด๋ ธํ ์ด์ (annotation) ๋๊ตฌ๋ฅผ ๋ง๋ค ์ ์๋ค๋ฉด ๋ฐ๋ก ๋ฅ๋ฌ๋ ๋ฐฉ๋ฒ์ ์ ์ฉํ๋ ๊ฒ๋ณด๋ค ๋น ๋ฅด๊ฒ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด ๋๊ฐ ์ ์๋ค.
์ค๋ ๋ ธ๋์์๋
- ๊ธฐ์กด ๋จธ์ ๋ฌ๋ ๋ฐฉ๋ฒ์ ์ ์ฉํ ๋๋์ ๊ฒ์ถ ๋ชจ๋์ ๋ง๋๋ ๋ฐฉ๋ฒ์ ๋ํด ์ค๋ช ํ๋ค.
- ๋ฅ๋ฌ๋ ๋ฐฉ๋ฒ์ ์ด์ฉํ ๋๋์ ๊ฒ์ถ ๋ชจ๋์ ์ ์ํ๊ณ
- ์์์ ๋ง๋ค์ด์ง ๋ฐ์ดํฐ์ ํจ๊ป ๋์ ํ์ง์ ๋ผ๋ฒจ์ ์ป์ ์ ์๋ ๋ผ๋ฒจ๋ง ํด(labeling tool) ๋ํด ์ค๋ช ํ๋ค.
- ๋ง์ง๋ง์ผ๋ก ์์ ๊ณผ์ ์ ์ด๋ป๊ฒ ํจ์จ์ ์ธ ์์๋ก ์งํํ ์ ์๋์ง ๋ ผ์ํ๋ค.
๋ฅ๋ฌ๋์ ์ ์ฉํ์ง ์๊ณ ๋จธ์ ๋ฌ๋ ๋ฐฉ๋ฒ์ ์ด์ฉํ๋ค๋ ๋ง์ ๊ณง **handcraft feature(์ฌ๋์ด ์ ์ํ ํน์ง)**๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค๋ ๋ง๊ณผ ๊ฐ๋ค. ์ด๋ ๋ชจ๋ธ์ด ์ฌ์ฉํ ํน์ง์ ์ ์ํ๊ธฐ ์ํด์๋ ํด๋น ๋ถ์ผ์ ๋ํ ์ดํด๊ฐ ํ์ํ๋ค. ์ฆ, ๋๋ฉ์ธ ์ ๋ฌธ๊ฐ๊ฐ ์ข์ ๋ชจ๋ธ์ ๋ง๋ค ํ๋ฅ ์ด ๋๋ค.
์ด ๋ฐฉ๋ฒ์ด ์ด๋ป๊ฒ ์ ์ฉ๋ ์ ์๊ณ ์ ํ์ํ์ง ์์๋ฅผ ๋ค์ด๋ณผ๊น ํ๋ค.
2018๋ ์ ์์ธ ํ์ด๋จธ ์น๋งค ์ง๋จ ๋ณด์กฐ ์๋ฃจ์ ์ ๋ง๋ค์๋ค. MRI๋ฅผ ์ดฌ์ํ ํ ๋ ์กฐ์ง์ ๋ถ์ํด์ ์์ธ ํ์ด๋จธ ํ์์ ์ ์๊ตฐ์ ๋ถํฌ๋ฅผ ํ์ ํ๋ ์ ๋ฌด๋ฅผ ์งํํ๋ค. ๋ค์ํ ์น๋งค์ ์ข ๋ฅ๋ฅผ ์ ํ ์ ์์๊ณ ๊ทธ ์ค ํ ์ฌ๋ก๋ฅผ ์ด์ผ๊ธฐํ๋ ค ํ๋ค.
ํ๊ด์ฑ ์น๋งค(Vascular Dementia) ๋ ๋ํ๊ด ๋ฌธ์ ๋ก ๋์กฐ์ง์ด ์์์ ์ ๊ฒ ๋์ด ๋ฐ์ํ๋ ์น๋งค๋ค. ์น๋งค๋ ํ์ฌ ์น๋ฃ๋ฒ์ด ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ณ์ ๋ฏธ๋ฆฌ ์์ธกํ๊ณ ๋๋นํด์ ์งํ์ ๋ฆ์ถ๋ ๋ฐฉ๋ฒ์ด ์ต์ ์ด๋ค. ๊ทธ๋งํผ ์กฐ๊ธฐ ์ง๋จ์ผ๋ก ๋ณ์ ๋ถ๋ฅ์ ์์ธ์ ์ฐพ๋ ๊ฒ์ด ์ค์ํ๋ค. ๋ค๋ฅธ ์์ธ ํ์ด๋จธ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ด ๊ฒฝ์ฐ๋ MRI ์ด๋ฏธ์ง๋ฅผ ํตํด ์ง๋จ์ ๋์ธ ์ ์๋ค. MRI์๋ T1w, T2w, FLAIR ๋ฑ ๋ค์ํ ์ดฌ์ ๋ฐฉ์(protocol)์ด ์๋ค. FLAIR ์ด๋ฏธ์ง๋ฅผ ํ ์ฅ ์ดํด๋ณด์.
์ฒ์๋ณด๋ฉด ์ด๋๊ฐ ์ ์์ด๊ณ ์ด๋๊ฐ ๋ฌธ์ ์ธ์ง ์ ํ ํ์ ํ ์ ์๋ค. ์ด ์ด๋ฏธ์ง์์๋ "ํ๋ฐฑ์ง"์ด ์ด๋์ธ์ง, "๋ฐฑ์ง"์ด ์ด๋์ธ์ง ๊ตฌ๋ถ์ด ์ ๋์ง ์๋๋ค(๋์ ๋์ ๊ฐ ๋ถ๋ถ์ ์ด๋ฆ์ด๋ค). ์ฌ์ค FLAIR ์ด๋ฏธ์ง์์๋ ๋ฐฑ์ง๊ณผ ํ๋ฐฑ์ง์ ๊ตฌ๋ถํ๊ธฐ ์ด๋ ค์ด ๋์ ๋์ฒ์์ก๊ณผ ๊ฐ์ ๋ฌผ์ ๋น๊ต์ ๊ตฌ๋ถํ๊ธฐ ์ฝ๋ค. (What Does Hyperintensity Mean On An Mri Report?) ์๋ ๊ทธ๋ฆผ์ ๋ณด์.
๋นจ๊ฐ์ ์์ญ๊ณผ ๊ฐ์ด ๋์ฒ์์ก ๋ถ๋ถ์ ์ฃผ๋ณ๋ณด๋ค ํฐ ๊ฐ์ผ๋ก ๋ํ๋๊ฒ ๋๋ค. ๋ํ๊ด์ ๋ฌธ์ ๊ฐ ์๊ธฐ๊ฒ ๋๋ฉด ํผ ๋ฑ์ ์ก์ฒด๊ฐ ๋ฐฑ์ง์ ์ค๋ฉฐ๋ค๊ฒ ๋๊ณ ๋์กฐ์ง์ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์๋ค. ๋ฐฑ์ง์ด ๋ณด๋ค ๋ฐ์ ๊ฐ์ผ๋ก ๋ํ๋๋ค๊ณ ํด์ WMH(White Matter Hyperintensity)๋ผ๊ณ ํ๋ค. WMH๊ฐ ์๋ค๊ณ ๋ฐ๋์ ๋ฌธ์ ๊ฐ ์๊ธฐ๋ ๊ฒ์ ์๋์ง๋ง ๋ฌธ์ ๊ฐ ์๊ธด ํ์ ์ค์์ ๋ง์ ์ฌ๋ก๊ฐ WMH๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
๊ทธ๋์ ๋์ํ ์ ์๋๋ค์ WMH๋ฅผ ์ฐพ๋ ๊ฒ์ ์ค์ํ๊ฒ ์๊ฐํ๊ณ ์๋ค. ๊ธ์ด์ด๋ ์๋์ผ๋ก ์ฐพ์์ผ ํ๋๋ฐ ๋ฌธ์ ๋ ๋ผ๋ฒจ์ด ๋ง๋ ํ์ง ์์๋ค. (๋ฌผ๋ก ์ง๊ธ์ ์คํ๋ฐ์ดํฐ๊ฐ ์กฐ๊ธ์ฉ ์๊ธฐ๊ณ ์๋ค.) ์ธ๊ทธ๋ฉํ ์ด์ (segmentation)์ ๋ผ๋ฒจ๋ง(labeing)์ด ์ด๋ ต๊ธฐ ๋๋ฌธ์ ์ด๊ธฐ์๋ ๋ฅ๋ฌ๋์ ์ฌ์ฉํ์ง ์๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด์ผ ํ๋ค.
์ด ๋ฌธ์ ๋ ์๊ฐํด๋ณด๋ฉด ์์ฃผ ์ฝ๊ฒ ์ด๊ธฐ ๋ชจ๋ธ(baseline)์ ๋ง๋ค์ด๋ณผ ์ ์๋ค. WMH์ ๋ป์ ๋ค์ ์ดํด๋ณด๋ฉด WM Hyperintensity, ์ฆ ์ด๋ฆ์ฒ๋ผ ํ์๊ฒ ํ์๋๋ ๋ถ๋ถ์ ๋์ ํฝ์ ๊ฐ์ ๊ฐ์ง๊ณ ์๋ค. ๊ทธ๋ฌ๋ฏ๋ก 255 ๋ฒ์ ๋ด์์ 200 ์ด์์ ๊ฐ์ ๊ฐ์ง๋ ํฝ์ ๋ค๋ง ์ฐพ์๋ด๋ฉด ๊ฐ๋จํ ์ด๊ธฐ ๋ชจ๋ธ์ ๋ง๋ค ์ ์๋ค.
์ด๋ ๊ฒ ์ด๊ธฐ ๋ชจ๋ธ์ ๋ง๋ค๊ณ ์ด ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ํ์ต์์ผ ๋๊ฐ๋ฉด ์ข์ ์ฑ๊ณผ๋ฅผ ์ป์ ์ ์๋ค. ์ด๋ ๊ฒ ๊ทผ์ฌ์ ์ธ(coarse) ๋ฐ์ดํฐ์ ์ ๊ฐ๋จํ ๋ง๋ค๊ณ , ์ด๋ฅผ ์ด์ฉํด ์ด๊ธฐ ๋ชจ๋ธ์ ๋ง๋ ํ ๊ทธ ๋ชจ๋ธ์ ๋์ฑ ์ ๊ตํ๊ฒ ํ๋ จ์์ผ๊ฐ๋ ์ ๋ต์ ML Coarse-to-Fine ์ ๋ต์ด๋ผ๊ณ ํ๋ค.
์ด ์ด์ผ๊ธฐ์์ ์ค์ํ ์ ์
- ํ๊ณ ์ถ์ ๋๋ฉ์ธ์ ์ง์์ ์ตํ ๊ฒ : ํ๊ด์ฑ ์น๋งค์ WMH, MRI ์์ ์ด๋ค ํจํด์ ๋ณด์ด๋์ง
- ๋ฅ๋ฌ๋์ด ์๋ ๋ฐฉ๋ฒ์ ์ ์ฉํ ์ ์๋ ๋ฅ๋ ฅ : Image threshold ๋ฑ ์์์ฒ๋ฆฌ ๊ธฐ๋ฒ
๋ฑ์ ์๊ฐํ๊ณ ์ ์ฉํ ์ ์์ด์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
๋ค์ ์ฐ๋ฆฌ ๋ฌธ์ ๋ก ๋์์์, "๋๋์์๋ ์ด๋ค ํน์ง์ด ์์๊น?"๋ฅผ ๊ณ ๋ฏผํด ๋ณด์. WMH์ ๋ฐ๋๋ก ๋๋์๋ ์ด๋ก๋ค. ์ด๋์ด ๋ถ๋ถ์ ์ค๊ฐ์ ์ฐพ์ผ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
๊ธ์ด์ด๋ ๊ทธ๋ ๊ฒ ์ ๊ทผํ๋ค. (๋ฌผ๋ก ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์๋ค๋ ์ฌ์ค์ ๋ ์ผ๋์ ๋์ด์ผ ํ๋ค.) ๋๋๋งํฌ(landmark)๋ฅผ ์ด์ฉํด์ ๋์ crop ํ๊ณ ๋์์ ๊ฐ์ฅ ์ด๋์ด ๋ถ๋ถ์ ์ค์ฌ์ ์ฐพ๋๋ค. ๋๋์์ ๋น์ด ๋ฐ์ฌ๋๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ ๋ ธ์ด์ฆ(noise) ์ฑ๋ถ์ ์์ ๊ธฐ ์ํด (๋์ฒด์ ์ผ๋ก ๋๋์๊ฐ ์ด๋์ด ๊ฒฝํฅ์ ๋ฐ๋ฅด๊ธฐ ์ํด) ๊ฐ์ฐ์์ ๋ธ๋ฌ(gaussian blur)๋ฅผ ์ ์ฉํ๋ค. ๊ฐ์ฐ์์ ๋ธ๋ฌ์ ๋ํ ์ค๋ช ์ ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ์.
๋ธ๋ฌ ํ ํ๋ฐฑ์ ๋ฐ์ ์์ผฐ๋ค. ์ฌ๊ธฐ์ ๊ฐ์ฅ ๋์ ๊ฐ์ ๊ฐ๋ ํฝ์ ์ ๊ณ ๋ฅด๋ฉด ์๋ ๊ทธ๋ฆผ์ฒ๋ผ ๋์ ์์น๋ฅผ ์ฐพ์ ์ ์๋ค.
'๊ฐ์ฅ ๋์ ๊ฐ'์ ๊ธฐ์ค์ ์ฌ๋ฌ ๋ฐฉํฅ์ผ๋ก ์ ์ํ ์ ์๋ค. 2D ์ด๋ฏธ์ง ์์์ ๋ฐ๋ก (x, y) ์์น๋ฅผ ์ถ์ ํ๋ ๋ฐฉ๋ฒargmax(image)์ด ์์ ์ ์๊ณ ์ ๊ทธ๋ฆผ์์ ์ค๋ฅธ์ชฝ๊ณผ ์๋ ๋ถ๋ถ์ ๋ณด์ด๋ฏ์ด 1์ฐจ์์ผ๋ก ๋์ ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. ์ 2์ฐจ์ ์ด๋ฏธ์ง์์ ๋์ ์ค์ฌ ๋ถ๋ถ ๊ทผ์ฒ ํฝ์ ์ ๊ฑฐ์ ๋ชจ๋ 255๋ก ์ต๋๊ฐ์ ๋ํ๋ธ๋ค. ๋ฐ๋ผ์ ๋๋์๋ฅผ ํน์ ํ๊ธฐ๊ฐ ์ด๋ ต๋ค. ๊ฐ์ฐ์์ ๋ธ๋ฌ๋ฅผ ์ ์ฉํ๋ฉด ๋๋์ ์ค์ฌ์ ํ๊ท ์ผ๋ก ํ๋ ๊ฐ์ฐ์์ ๋ถํฌ๋ฅผ ๋ณผ ์ ์๋ค. ๋ฌผ๋ก ์ต๋๊ฐ 255๋ก truncate ๋์ด ์๊ณ ๋๋์๋ง ๋ฐ์ ๊ฒ์ด ์๋๊ธฐ ๋๋ฌธ์ mixture density์ฒ๋ผ ๋ํ๋์ง๋ค.
์ด๋ 1์ฐจ์์ผ๋ก ๋์ ํด์ ํํํ๋ฉด 255๋ก truncated ๋๋ ๋ฌธ์ ์ ์ฃผ๋ณ ๋ ธ์ด์ฆ์ ์กฐ๊ธ ๋ ๊ฐ๊ฑดํ๊ฒ ๋์ฒํ ์ ์๋ค.
์ด๋ก ์ ์ธ ๋ถ๋ถ์ ์ฝ๋๋ก ๋ํ๋ด ๋ณด์. ์ฌ์ฉํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋์ ๊ฐ๋ค.
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()
๋ ์ค์ฌ์ ์ฐพ๋ ํจ์๋ฅผ ๋ง๋ค ๊ฒ์ด๋ค. ๋จผ์ , ๋ ์ด๋ฏธ์ง๋ฅผ 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()
์ผ์ชฝ ๋๋ ํ์ธํด๋ณธ๋ค.
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()
๋๋์๋ ์ฐพ์์ง๋ง ์ค์ฌ์ด ์๋ ๊ฒฝ์ฐ์ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ ์ฉํด๋ณผ ์ ์๋ค.
๊ธฐ์กด์ ๋จธ์ ๋ฌ๋ ๋ฐฉ๋ฒ๋ค์ ๋๋ฉ์ธ ์ง์์ ์ ์ฉํด์ ๊ฐ๋จํ๊ณ ๋น ๋ฅด๊ฒ ๊ตฌํํ ์ ์๋ ์ฅ์ ์ด ์๋ค. ๋ฐ๋ฉด ์ผ์ ์์ค ์ด์์ ์ฑ๋ฅ์ ๋ง์กฑํ๊ธฐ ์ด๋ ต๋ค. ๋ฐ๋ผ์ ์กฐ๊ธ ๋ชจ์๋ ์ฑ๋ฅ์ผ๋ก ๋๋์ coarseํ ๋ผ๋ฒจ์ ์์งํ ๋ค, ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ๊ฐ์ ํด ๋๊ฐ๋ ํ์ต ์ ๋ต์ ์ฌ์ฉํด์ผ ํ๋ค.
์ด์ ๋ ๋์ ์ฑ๋ฅ์ ์ํด ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ๋ง๋๋ ๊ฒ์ ๊ณ ๋ คํด์ผ ํ๋ค. ์์์๋ ๋๋ฉ์ธ ์ง์์ ํ์ฉํด์ ์์์ ์ผ๋ก ํน์ฑ๋ค์(hand-crafted features) ๋ง๋ค์๋ค๋ฉด ์ด์ ๋ถํฐ๋ ๋๋ฉ์ธ ์ง์ ์์ด ์ ๊ฒฝ๋ง์ด ํน์ง์ ์๋์ผ๋ก ๋ฝ์ ์ ์๋๋ก ์ค๊ณํ๋ค.
์ง๊ธ๊น์ง ์ฐ๋ฆฌ๋ VGG, Resnet ๋ฑ ๊ธฐ๋ณธ(base) ๋ชจ๋ธ์ ์ด๋ฏธ์ง ๋ถ๋ฅ ๋ฌธ์ ๋ฅผ ์ํด ์ฌ์ฉํด ์๋ค. ์ฃผ๋ก ์์ญ ๊ฐ ์ด๋ด์ ํด๋์ค ์ค ํ๋๋ฅผ ์ฐพ๋ ๋ฌธ์ ์ ์ ์ฉํ๋๋ฐ ์ด ๋ชจ๋ธ์ ์ฐ๋ฆฌ์ ๋ชฉํ์ธ ๋๋์๋ก ๋ณํํด ์ฃผ์ด์ผ ํ๋ค.
์ด๋ฏธ์ง ๋ถ๋ฅ ๋ชจ๋ธ์ ์ด๋ฏธ์ง๋ฅผ CNN์ ์ ๋ ฅํด์ ์ต์ข ์ ์ผ๋ก ํด๋น ํด๋์ค์ ์ธ๋ฑ์ค๋ฅผ ์ฐพ์๋ธ๋ค. ์ฆ, ๋ชจ๋ธ์ ์ถ๋ ฅ์ ํด๋์ค๋ฅผ ๋ํ๋ด๋ ๋จ์ผ idx ๊ฐ(๋๋ one-hot vector)์ด ๋ฉ๋๋ค. ๋๋์ ์์น๋ฅผ ์ฐพ๊ธฐ ์ํด์ ์๋์ ๊ฐ์ ๊ตฌ์กฐ๋ก ๋ชจ๋ธ์ ๋ณ๊ฒฝํด์ผ ํ๋ค.
๊ฐ์ฅ ๋จผ์ , ์ถ๋ ฅ์ ๊ฐ์๊ฐ ๋ณ๊ฒฝ๋๋ค. ์ด๋ฏธ์ง ๋ถ๋ฅ ๋ฌธ์ ์์๋ ์ํํธ๋งฅ์ค(softmax)๋ฅผ ํต๊ณผํด 1๊ฐ์ ํด๋์ค ์ธ๋ฑ์ค๋ฅผ ์ถ๋ ฅํ์ง๋ง ๋๋์ ์ค์ฌ ์์น์ธ x, y ์ขํ๋ฅผ ์ถ๋ ฅํด์ผ ํ๋ค. ์ด ๋ ๊ฐ์ ๋ถ๋ฅ ๋ชจ๋ธ์ ์ ์ํ ๋ถ์ฐ์ ๊ฐ์ด ์๋ ์ฐ์ํ ๊ฐ์ด์ด์ผ ํ๋ค. ์ด๋ฐ ๋ฌธ์ ๋ฅผ ํ๊ท(regression) ๋ฌธ์ ๋ผ๊ณ ํ๋ค.
๊ฐ ํ์คํฌ์ ์ถ๋ ฅ ํน์ง
- Image Classification : argmax(softmax)์ ๋ถ์ฐ์ ์ ์ํ ๊ฐ
- Image Localization(regression) : ์ฐ์ํ ์ค์ ๊ฐ
์ํํธ๋งฅ์ค - ํฌ๋ก์ค ์ํธ๋กํผ(cross-entropy) ๋ฐฉ๋ฒ์ ์ด๋ฏธ์ง ํด๋์ค๋ฅผ ๊ตฌ๋ถํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ๊ฐ์ฅ ๋ํ์ ์ธ ์์ค ํจ์์ด๋ค. ํ๊ท์์๋ ์ฌ๋ฌ ๊ฐ์ ๊ฐ์ด ์ฐ์ํ ์ค์๋ก ์ถ๋ ฅ๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ MSE์ ๊ฐ์ ์์ค ํจ์๋ฅผ ๊ณ ๋ คํ ์ ์๋ค.
์ด์ ๋ง๋ ๋ชจ๋ธ์ ํ์ต์ํค๋ฉด ๋๋ค. ๊ทธ๋ฌ๋ ์ค์ ์ ํญ์ ๋ ์ด๋ ต๋ค. ๋ด ๋์ฆ์ ๊ผญ ๋ง๋ ์ปค์คํ ํ์คํฌ์ ๊ฒฝ์ฐ๋ ๋ฐ์ดํฐ๊ฐ ๋๋ถ๋ถ ๋ถ์กฑํ๋ค. ์ค๋ ๊ฐ์์์๋ ๋์ ํ๋ฆฌํฐ์ ๋๋์ ๋ผ๋ฒจ์ ์ป๊ธฐ๊ฐ ๊ฝค ์ด๋ ต๋ค๋ ์ฌ์ค์ ๋๊ผ์ ๊ฒ์ด๋ค.
์ด๋ฐ ๊ฒฝ์ฐ์ ์ ๊ทผํ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ฏธ๋ฆฌ ํ์ต๋ ๊ฐ์ค์น(weight)๋ฅผ ๊ฐ์ง๊ณ ์์ fine tuning ํ๋ ๊ฒ์ด๋ค. ๊ฐ์ ธ์จ ๊ฐ์ค์น๊ฐ ํ์ต๋(pretrained) ํ์คํฌ๊ฐ ๋์ ํ์คํฌ์ ๊ฐ์ ๋๋ฉ์ธ์ด๋ฉด ๋ ์ข๊ฒ ์ง๋ง ์๋์ด๋ ํจ๊ณผ๋ ์๋ค. ๊ทธ๋์ ๋ณดํต์ ์ด๋ฏธ์ง๋ท(ImageNet)์ด๋ COCO ๋ฐ์ดํฐ์ ์ผ๋ก ํ์ตํ ๋ชจ๋ธ ๊ฐ์ค์น๋ฅผ ๊ฐ์ ธ์์ fine tuning ํ๋ค.
์ ๋ฐฉ๋ฒ์ ์ฝ๋๋ก ํํํ๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
- ๊ธฐ๋ณธ ResNet ๋ชจ๋ธ์ ๊ตฌํํ๊ณ
- ImageNet ๋ฐ์ดํฐ์ ์ผ๋ก pretraining ์ ์ด์ฌํ ํ ํ
- ResNet์ fully connected layer ๋ฅผ ์์ ํ๊ณ ํ๊ท ์์ค ํจ์๋ฅผ ๊ตฌํํด์
- ๋๋์ ์์น๋ฅผ ํ์ต์ํต๋๋ค.
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 ๋ชจ๋ธ์ ๊ตฌํํด ์ ๊ณตํ๊ณ ์๋ค.
- ์ฐธ๊ณ : TensorFlow Hub ResNet-50 V2
ํด๋น ๋ชจ๋ธ์ ๊ฐ์ ๋งํฌ์ ์นํ์ด์ง์์ ํ์ธํ ์ ์๋ค. ๋ชจ๋ธ์ 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()
์ด์ ๋จ๊ณ์์ coarse label๋ก ๋ชจ๋ธ์ ์ด๋ ์ ๋ ์์ค๊น์ง ๋ง๋ค์๋ค. ์ด์ fine label์ ์ป์ด์ ๋ชจ๋ธ์ ํฅ์์์ผ์ผ ํ๋ค. ์์ง์ ๋ผ๋ฒจ์ ๋น ๋ฅด๊ฒ ์ป๊ธฐ ์ํด์ ์ด๋ ธํ ์ด์ ํด(annotation tool) ๋๋ **๋ผ๋ฒจ๋ง ํด(labeling tool)**์ ์ฌ์ฉํด์ผ ํ๋ค.
์ ์๋ ค์ง ๋น์ ํ์คํฌ(image classification, object detection, semantic segmentation)๋ ๊ณต๊ฐ๋ ์ด๋ ธํ ์ด์ ๋๊ตฌ๊ฐ ๋ง๋ค.
OpenCV์ CVAT ์ ์ด๋ฏธ์ง ๊ฒ์ถ(object detection) ๋ฑ์ ์ด์ฉํ ์ ์๊ณ ๋ฌด๋ฃ๋ก ๊ณต๊ฐ๋์ด ์๋ค.
imglab ์ด๋ผ๋ ํด๋ ๊ณต๊ฐ๋์ด ์๋๋ฐ, COCO ๋ฐ์ดํฐ์ ํํ๋ก ์ ์ฅํ ์ ์๊ณ ํคํฌ์ธํธ ๋ผ๋ฒจ๋ง(keypoints labeling)๋ ํ ์ ์๋ค.
์ฌ๋ฌ ์ด๋ ธํ ์ด์ ๋๊ตฌ๋ค์ ์ดํด๋ณด๋ฉด ๋ช ๊ฐ์ง ํน์ง์ ์ ์ ์๋ค.
- QT ๋ฑ์ GUI ํ๋ ์์ํฌ๋ฅผ ์ด์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ ์น ๊ธฐ๋ฐ ๋ฐฉ๋ฒ์ผ๋ก ๋๋์ด์ง๋ค.
- ๋จ์ถํค์ ๋ผ๋ฒจ ์ ์ฅ ํฌ๋งท ๋ฑ ํธ์์ฑ์ ํฅ์์ํฌ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ทน์ ์ผ๋ก ์ ์ฉํ๋ค.
๋์ ํธ์์ฑ์ ์์ธ์์ ๊ณต๊ฐํ๊ณ ์์ง๋ง ๋ง์ ์ฌ์ฉํด๋ณด๋ฉด ์ฐ๋ฆฌ๊ฐ ์ํ๋ ํ์คํฌ์ ๋ฑ ๋ง์ง ์๋ ๊ฒฝ์ฐ๊ฐ ๋๋ถ๋ถ ์ด๋ค. (3D ํ๊ฒฝ์์ ์ธ๊ทธ๋ฉํ ์ด์ ํด์ผ ํ๋ ์ผ ๋ฑ)
์ฐ๋ฆฌ๋ ๋๋์์ ์์น๋ฅผ ์ ํํ ์ ์๋ ๋๊ตฌ๊ฐ ํ์ํ๋ค. imglab์๋ ํคํฌ์ธํธ(keypoint) ๋๊ตฌ๊ฐ ์๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํด ๋ณผ ์๋ ์๋ค. ํ์ง๋ง ๋ฌธ์ ๋ COCO ๋ฐ์ดํฐ์ ์์ ๋ผ๋ฒจ๋งํ ์คํ์ผ์ ์ง์ผ์ผํ๊ธฐ ๋๋ฌธ์ 17๊ฐ์ ํคํฌ์ธํธ๋ฅผ ์ ํด์ผ ํ๋ ๊ท์น์ด ์๋ค๋ ์ ์ด๋ค. ์ฐ๋ฆฌ๋ ๋๋์ 1๊ฐ๋ฅผ ์ฐ๊ฑฐ๋ ์ ๋ ์ 2๊ฐ์ ์ ์ด ํ์ํ๋ฐ ์ด ์กฐ๊ฑด์ ๊ผญ ๋ง๋ ๋ผ๋ฒจ๋ง ๋๊ตฌ๋ฅผ ๋ง๋๊ธฐ๋ ์ฝ์ง ์๋ค.
๊ฒฐ๊ตญ ์ผ์ ํ๋ค ๋ณด๋ฉด ์ ๋ง์ ๋ง๋ ๋๊ตฌ๋ฅผ ์ง์ ๋ง๋ค๊ฒ ๋๋ค. ๋ง์นจ ์ ์ ํ ์ ์๊ธฐ๊ฐ ์์ผ๋ ํ๋ฒ ์ฝ์ด๋ณด์.
๋ฌธ์ ๋ ์ด๋ณด์๋ค์ ์น ํ๋ ์์ํฌ๋ GUI ํ๋ก๊ทธ๋๋ฐ์ ์ต์ํ์ง ์๋ค๋ ์ ์ด๋ค. ๋ผ๋ฒจ๋ง ํด์ ์ ์ํ๋ ค ์๊ฐํ๋ค๋ณด๋ฉด QT, MFC, ์ฌ์ง์ด HTML/CSS/JavaScript๋ฅผ ์ตํ๊ณ ์ดํ๋ฆฌ์ผ์ด์ ์์ค๊น์ง ๋ง๋ค ๊ณ ๋ฏผ์ ํ๋ ์ํฉ์ ๋ง์ดํ๊ฒ ๋๋ค. ๋จธ์ ๋ฌ๋ ์์ง๋์ด ์ ์ฅ์์ ๋ฐฐ๋ณด๋ค ๋ฐฐ๊ผฝ์ด ๋ ํฐ ์ํฉ์ด ๋๋ฏ๋ก ์๋นํ ๋ถ๋ด์ ๋๋ ์ ์๋ค.
๋ฐ๋ผ์ ๊ฐ์ฅ ๊ฐ๋จํ๊ณ ํจ์จ์ ์ธ ํํ๋ก ๋ผ๋ฒจ๋ง ํด์ ์ ์ํด์ผ ํ๋ค. ๊ธ์ด์ด๋ ๋ผ๋ฒจ๋ง์ ํ ๋ ๋ ๋จ๊ณ๋ก ๋ผ๋ฒจ๋ง์ ํ๊ณ ์๋ค.
- ๊ธฐ์กด์ ๋ง๋ค์ด์ง ๋ผ๋ฒจ์ด ์ ์์ธกํ๋์ง True / False ๋ถ๋ฅ
- ํด๋น ํ์คํฌ์ ์ด๋ ธํ ์ด์ ํด (์ฐ๋ฆฌ์ ๊ฒฝ์ฐ ํคํฌ์ธํธ ์ด๋ ธํ ์ด์ )
์ค๋ ๋ค๋ฃฐ ๋๋์ ๊ฒ์ถ์ 1, 2๋ฒ ๋ชจ๋ OpenCV๋ง์ ์ด์ฉํด์ ์์ฃผ ๊ฐ๋จํ๊ฒ ๋ง๋ค ์ ์๋ค. ์ด๋ฒ ์๊ฐ์๋ 1๋ฒ์ ๋ง๋ค์ด ๋ณผ ๊ฒ์ด๋ค.
ํ์ด์ฌ๊ณผ 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
์ด๋ฒ ์คํ ์์๋ ์ง๊ธ๊น์ง ๋ง๋ค์ด์จ ํ์ต ์์คํ ์ ํ๋์ ์ ๋ฆฌํด๋ณด๊ณ ํ์ต ์์คํ ์ ์ด๋ป๊ฒ ๋ง๋ค๋ฉด ํจ์จ์ ์ธ์ง, ๋ผ๋ฒจ๋ง์ ์ด๋ค ์์ ์์ ์์ํด์ผ ํ๋์ง ์ดํด๋ณผ ๊ฒ์ด๋ค.
๊ฐ์ฅ ๋จผ์ ์์ ๊ฒ์ถ์ ์ํด ๋ชจ๋ธ๋ค์ ์ค๊ณํ๋ค. ์ ์ฒ๋ฆฌ ํ ํคํฌ์ธํธ ๊ฒ์ถ ๋ชจ๋ธ์ ๋ง๋ค์ด์ ๋๋์ ์์น๋ฅผ ์์ธกํ๋ค.
๋ฐ์ดํฐ๊ฐ ์๋ ์ ๋ฌด ์ด๋ฐ์๋ mean shift์ ๊ฐ์ ๋จธ์ ๋ฌ๋ ๋ฐฉ๋ฒ๋ค์ ์ด์ฉํด์ coarseํ ์์ธก ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค ์ ์์๋ค. ์ด ์์ธก ๊ฒฐ๊ณผ๋ ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ํ์ต ๋ฐ์ดํฐ๋ก ์ฌ์ฉํ ์ ์์๋ค.
coarse dataset์ ๋ผ๋ฒจ ์์ฒด์ ์ ํ๋๊ฐ ๋จ์ด์ง๊ธฐ ๋๋ฌธ์ fineํ ๋ผ๋ฒจ์ ์ป์ ์ ์๋๋ก ๊ฐ์ ์์ผ์ผ ํ๋ค. ๊ฐ์ฅ ๊ฐ๋จํ๊ฒ ๋ผ๋ฒจ๋งํ ์ ์๋ ๋ฐฉ๋ฒ์ ๊ธฐ์กด ๊ฒฐ๊ณผ๊ฐ ์ข๋ค/๋์๋ค
๋ก ๋ถ๋ฅํ๋ ๊ฒ์ด๋ค.
๊ฒฐ๊ณผ๊ฐ ์ข๊ณ ๋์ ๊ฒ์ ๊ธฐ๋กํด ๋๋ฉด ๊ทธ ์์ฒด๋ก๋ ๋ผ๋ฒจ์ด ๋๋ค. ์ด ์ ๋ณด๋ฅผ ์ด์ฉํด์ ์ด๋ฏธ์ง ๋ถ๋ฅ๊ธฐ(classifier)๋ฅผ ๋ง๋ค ์๊ฐ ์๋ค. ์ด ๋ CAM(class activation map)์ ์ถ๊ฐํ๋ฉด ์ด๋๊ฐ ์๋ชป๋์๋์ง ์กฐ๊ธ ๋ ์ฝ๊ฒ ๊ด์ฐฐํ ์ ์๋ค.
๋ง๋ค์ด์ง ์ด๋ฏธ์ง ๋ถ๋ฅ๊ธฐ๋ fine label์ ๋ง๋ค ๋ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ค. ์์ธก ๊ฒฐ๊ณผ๊ฐ '์ข์'์ผ๋ก ๋์จ ๊ฒฐ๊ณผ๋ fineํ ๋ผ๋ฒจ์ด๋ผ ์๊ฐํ๊ณ ํ์ต์ํฌ ์ ์๊ณ ๋ฐ๋ฉด '๋์จ'์ผ๋ก ๋์ค๋ฉด์ CAM ๊ฒฐ๊ณผ๋ ์ข์ง ์๋ค๋ฉด ๋ผ๋ฒจ๋ง์ ํ์ ๋ ํจ๊ณผ์ ์ธ ๋ฐ์ดํฐ์ ์ ๋ง๋ค ์ ์์ ๊ฒ์ด๋ค.
์ ๊ฐ๋ ์ด ๋ฐ๋ก ์กํฐ๋ธ ๋ฌ๋(active learning) ๋ฐฉ๋ฒ๋ก ์ ์์์ด๋ค. ๋ผ๋ฒจ๋ง์ ํ ๋ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ์ ์ ํ ๊ฒ์ธ์ง ๊ณ ๋ฏผํ๊ณ ์ฌ๋์๊ฒ ๋ชจ๋ธ์ด ํผ๋๋ฐฑ์ ์ฃผ๋ ํ์ต๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํ ์ ์๋ค. ์ด๋ ๊ฒ ๋ฝ์์ง ํ๋ณด๊ตฐ์ ์ง์ ๋ผ๋ฒจ๋งํ๋ค.
์ฐ๋ฆฌ๊ฐ ๋ง๋ (์์ผ๋ก ๋ง๋ค) ๋ผ๋ฒจ๋ง ํด์ ์ฌ์ฉํด์ ์์ง์ ๋ผ๋ฒจ๋ก ๋ง๋ค์ด๋ธ๋ค. ๊ธ์ด์ด๋ ์ด ๋ฐ์ดํฐ์ ์ **"fine dataset"**์ด๋ผ ๋ถ๋ฅด๊ณ ์๋ค. ๋ง๋ค์ด์ง ๋ฐ์ดํฐ์ ์ผ๋ก ๋ค์ ํ์ต์ ์ํค๋ฉด ๋ชจ๋ธ ๊ฐ์ ์ ๋ฐ๋ณต๋ฌธ์ด ๋ง๋ค์ด์ง๋ค.
ํ์ตํ๊ณ ๋ค์ ์์ธกํ๋ฉด์ ๋ชจ๋ธ์ ์ฑ๋ฅ์ ํจ์จ์ ์ผ๋ก ๋์ด์ฌ๋ฆฌ๋ ๋ฐฉ๋ฒ์ด๋ค.
์ฌ๋์ด ํ์ต ์์คํ ์ ๊ฐ์ฅ ํจ์จ์ ์ผ๋ก ๊ฐ์ ํ๋ ๋ฐฉ๋ฒ(human-in-the-loop), activeํ๊ฒ ํ์ต ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ๊ณ ๋ผ๋ฒจ์ ๊ฐ์ ์ํค๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์๋ค. ๋ชจ๋ธ ์์ฒด๋ฅผ ์ ์ค๊ณํ๋ ๊ฒ๋ ์ค์ํ์ง๋ง ๋จธ์ ๋ฌ๋ ์์ง๋์ด๋ผ๋ฉด ์ด๋ป๊ฒ ํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๋ชจ์ ์ ์์์ง ์ ๊ณ ๋ฏผํด์ผ ํ๋ค๊ณ ์๊ฐํ๋ค. ์ค๋ ๋ค๋ฃจ์๋ ๋ค์ํ ๋ฐฉ๋ฒ๋ค์ ๋ค์ ๋ ธ๋์ ํ๋ก์ ํธ ์ํ ์ ๋ค์ ํ์ฉํ๊ฒ ๋ ๊ฒ์ด๋ค.