MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„! ์ €๋Š” CROC์˜ CV ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ˜„์žฌ 3๋…„ ๋™์•ˆ CV ๋ถ„์•ผ์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•ด ์™”์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๊ฐ„ ๋™์•ˆ ์šฐ๋ฆฌ๋Š” ๋งŽ์€ ์ผ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์šด์ „ํ•˜๋Š” ๋™์•ˆ ์ˆ ์„ ๋งˆ์‹œ์ง€ ์•Š๊ณ , ๋‹ด๋ฐฐ๋ฅผ ํ”ผ์šฐ์ง€ ์•Š๊ณ , ์ „ํ™”๋ฅผ ํ•˜์ง€ ์•Š๊ณ , ๊ธธ์„ ๋ฐ”๋ผ๋ณด๊ณ , ๊ฟˆ์ด๋‚˜ ๊ตฌ๋ฆ„์„ ๋ณด์ง€ ์•Š๋„๋ก ์šด์ „์ž๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ; ์šฐ๋ฆฌ๋Š” ์ „์šฉ ์ฐจ์„ ์—์„œ ์šด์ „ํ•˜๊ณ  ์—ฌ๋Ÿฌ ์ฃผ์ฐจ ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทผ๋กœ์ž๊ฐ€ ํ—ฌ๋ฉง, ์žฅ๊ฐ‘ ๋“ฑ์„ ์ฐฉ์šฉํ–ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์‹œ์„ค์— ๋“ค์–ด๊ฐ€๊ณ  ์‹ถ์–ดํ•˜๋Š” ์ง์›์„ ์‹๋ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ์„ธ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ด ๋ชจ๋“  ๊ฒƒ์„ ๋ฌด์—‡์„ ์œ„ํ•ด ํ•˜๊ณ  ์žˆ๋Š” ๊ฑธ๊นŒ์š”?

ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ณผ์ •์—์„œ ์šฐ๋ฆฌ๋Š” ๋ถ€๋”ชํžˆ๊ณ , ๋งŽ์€ ์ถฉ๋Œ์„ ๊ฒช๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์ด ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๊ฑฐ๋‚˜ ์•ž์œผ๋กœ ์•Œ๊ฒŒ ๋  ๋ฌธ์ œ๋“ค๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํ™ฉ ๋ชจ๋ธ๋ง

ML๊ณผ ๊ด€๋ จ๋œ ํ™œ๋™์„ ํ•˜๋Š” ์ Š์€ ํšŒ์‚ฌ N์— ์ทจ์งํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ML(DL, CV) ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋‹ค๊ฐ€ ์–ด๋–ค ์ด์œ ๋กœ ๋‹ค๋ฅธ ์ง์—…์œผ๋กœ ์ „ํ™˜ํ•˜๊ณ  ์ผ๋ฐ˜์ ์œผ๋กœ ํœด์‹์„ ์ทจํ•œ ํ›„ ์šฐ๋ฆฌ ์ž์‹ ์ด๋‚˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ ๋‰ด๋Ÿฐ์œผ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค.

  1. ์ง„์‹ค์˜ ์ˆœ๊ฐ„์ด ์˜ค๋ฉด, ์–ด๋””์—์„œ ๋ฉˆ์ท„๋Š”์ง€, ์–ด๋–ค ํ•˜์ดํผํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‹œ๋„ํ–ˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ๊ฐ€์žฅ ์ค‘์š”ํ•˜๊ฒŒ๋Š” ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ๊ธฐ์–ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ—ค๋“œ, ๊ตฌ์„ฑ, ๋ฉ”๋ชจ์žฅ, ํด๋ผ์šฐ๋“œ์˜ ์ž‘์—… ํ™˜๊ฒฝ ๋“ฑ ๋ชจ๋“  ์‹คํ–‰์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ €์žฅํ•œ ์‚ฌ๋žŒ์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ์˜ต์…˜์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ดํผํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ฝ”๋“œ์— ์ฃผ์„ ์ฒ˜๋ฆฌ๋œ ์ค„๋กœ ์ €์žฅ๋˜์–ด ์žˆ์„ ๋•Œ ์šฐ์—ฐํžˆ ์˜ต์…˜์„ ๋ณด๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ, ์ด๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ™˜์ƒ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋‹น์‹ ์ด ์ž์‹ ์˜ ํ”„๋กœ์ ํŠธ๊ฐ€ ์•„๋‹Œ ํšŒ์‚ฌ๋ฅผ ๋– ๋‚œ ์‚ฌ๋žŒ์˜ ํ”„๋กœ์ ํŠธ๋กœ ๋Œ์•„๊ฐ€์„œ model_1.pb๋ผ๋Š” ์ฝ”๋“œ์™€ ๋ชจ๋ธ์„ ์ƒ์†๋ฐ›์•˜๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ณด์‹ญ์‹œ์˜ค. ๊ทธ๋ฆผ์„ ์™„์„ฑํ•˜๊ณ  ๋ชจ๋“  ๊ณ ํ†ต์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ๋‹น์‹ ๋„ ์ดˆ๋ณด ์ „๋ฌธ๊ฐ€๋ผ๊ณ  ์ƒ์ƒํ•ด ๋ด…์‹œ๋‹ค.
  2. ๊ณ„์†ํ•˜์„ธ์š”. ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์šฐ๋ฆฌ์™€ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“  ์‚ฌ๋žŒ์ด ํ™˜๊ฒฝ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์–ด๋–ค ์ด์œ ๋กœ ๊ทธ๋“ค์€ ๊ทธ๋ฅผ ์šฐ๋ฆฌ์˜ ์ƒ์† ์žฌ์‚ฐ์œผ๋กœ ๋‚จ๊ฒจ ๋‘์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข… ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋˜ํ•œ ์‚ฌ์†Œํ•œ ์ž‘์—…์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๊นŒ?
  3. ๋ชจ๋ธ(์˜ˆ: ์ž๋™์ฐจ ๊ฐ์ง€๊ธฐ)์„ ํ•™์Šตํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๊ฐ€ ๋งค์šฐ ์ข‹์•„์ง€๋Š” ์ง€์ ์— ์ด๋ฅด๋ €์Šต๋‹ˆ๋‹ค. ์ด์ œ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ์‹œ๊ฐ„์ž…๋‹ˆ๋‹ค. car_Detection_v1.pb๋ผ๊ณ  ๋ถ€๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ car_Detection_v2.pb๋ผ๋Š” ๋˜ ๋‹ค๋ฅธ ๊ฒƒ์„ ํ›ˆ๋ จํ•ฉ๋‹ˆ๋‹ค. ์–ผ๋งˆ ํ›„, ์šฐ๋ฆฌ ๋™๋ฃŒ๋‚˜ ์šฐ๋ฆฌ ์ž์‹ ์€ ๋‹ค์–‘ํ•œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ ์  ๋” ๋งŽ์€ ๊ฒƒ์„ ๊ฐ€๋ฅด์นฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋งŽ์€ ์œ ๋ฌผ์ด ํ˜•์„ฑ๋˜๊ณ  ์ด์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํž˜๋“ค๊ฒŒ ์ˆ˜์ง‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ์ง€๊ธˆ์€ ๋” ์ค‘์š”ํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์ด ์ž‘์—…์€ ๋‚˜์ค‘์— ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค).
  4. ์ข‹์•„ ์ด์ œ ๋‹ค ๋๋‚ฌ์–ด! ์šฐ๋ฆฌ์—๊ฒ ๋ชจ๋ธ์ด ์žˆ์–ด์š”! ๋‹ค์Œ ๋ชจ๋ธ ํ•™์Šต์„ ์‹œ์ž‘ํ•˜๊ณ  ์ƒˆ๋กœ์šด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋‚˜์š”? ์•„๋‹ˆ๋ฉด ์ฐจ๋ฅผ ๋งˆ์‹œ๋Ÿฌ ๊ฐˆ ์ˆ˜ ์žˆ๋‚˜์š”? ๊ทธ๋ฆฌ๊ณ  ๋ˆ„๊ฐ€ ๋ฐฐ์น˜ํ•  ๊ฒƒ์ธ๊ฐ€?

๋ฌธ์ œ ์‹๋ณ„

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

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ํ•˜๋‚˜์˜ ๊ฐœ๋ฐœ ์ฃผ๊ธฐ๋ฅผ ๊ฑฐ์ณค๊ณ  ํ•ด๊ฒฐํ•ด์•ผ ํ•  ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ๋‹ค์Œ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

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

์ด ๋ผ์ดํ”„์‚ฌ์ดํด์„ ์‰ฝ๊ณ  ํŽธ๋ฆฌํ•˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์›Œํฌํ”Œ๋กœ์šฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ ๊ฐ™์€๋ฐ์š”? ์ด ๋ฐฉ์‹์„ MLOps๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

MLOps(๊ธฐ๊ณ„ ํ•™์Šต์„ ์œ„ํ•œ DevOps)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ ๊ณผํ•™ ํŒ€๊ณผ IT ํŒ€์ด ํ˜‘๋ ฅํ•˜์—ฌ ๊ธฐ๊ณ„ ํ•™์Šต ๋ชจ๋ธ์— ๋Œ€ํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง, ๊ฒ€์ฆ ๋ฐ ๊ฑฐ๋ฒ„๋„Œ์Šค๋ฅผ ํ†ตํ•ด ๋ชจ๋ธ ๊ฐœ๋ฐœ ๋ฐ ๋ฐฐํฌ ์†๋„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋„ˆ๋Š” ํ•  ์ˆ˜์žˆ๋‹ค. ๋ช…์˜ˆGoogle ์ง์›๋“ค์€ ์ด ๋ชจ๋“  ๊ฒƒ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ? ๊ธฐ์‚ฌ๋ฅผ ๋ณด๋ฉด MLOps๊ฐ€ ์ƒ๋‹นํžˆ ๋ฐฉ๋Œ€ํ•˜๋‹ค๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

๋‚ด ๊ธฐ์‚ฌ์—์„œ๋Š” ํ”„๋กœ์„ธ์Šค์˜ ์ผ๋ถ€๋งŒ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ตฌํ˜„์„ ์œ„ํ•ด MLflow ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด... ์ด๊ฒƒ์€ ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ์ด๋ฏ€๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ ์†Œ๋Ÿ‰์˜ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” ml ํ”„๋ ˆ์ž„์›Œํฌ์™€ ํ†ตํ•ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ธํ„ฐ๋„ท์—์„œ Kubeflow, SageMaker, Trains ๋“ฑ๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ๋„๊ตฌ๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ ํ•„์š”์— ๋” ์ ํ•ฉํ•œ ๋„๊ตฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MLFlow ๋„๊ตฌ ์‚ฌ์šฉ ์˜ˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ MLOps "๊ตฌ์ถ•"

MLFlow๋Š” ML ๋ชจ๋ธ์˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ์˜คํ”ˆ ์†Œ์Šค ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค(https://mlflow.org/).

MLflow์—๋Š” ๋„ค ๊ฐ€์ง€ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

  • MLflow ์ถ”์  - ์ด ๊ฒฐ๊ณผ๋ฅผ ๊ฐ€์ ธ์˜จ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ ๊ฒฐ๊ณผ ๊ธฐ๋ก ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.
  • MLflow ํ”„๋กœ์ ํŠธ - ์ฝ”๋“œ๋ฅผ ํŒจํ‚ค์ง•ํ•˜๊ณ  ๋ชจ๋“  ํ”Œ๋žซํผ์—์„œ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • MLflow ๋ชจ๋ธ - ํ”„๋กœ๋•์…˜์— ๋ชจ๋ธ ๋ฐฐํฌ๋ฅผ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค.
  • MLflow Registry - ์ค‘์•™ ์ €์žฅ์†Œ์—์„œ ๋ชจ๋ธ์„ ์ €์žฅํ•˜๊ณ  ํ•ด๋‹น ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MLflow๋Š” ๋‘ ์—”ํ„ฐํ‹ฐ์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

  • ์ถœ์‹œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋“ฑ๋กํ•˜๋ ค๋Š” ๊ต์œก, ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ฐ ์ง€ํ‘œ์˜ ์ „์ฒด ์ฃผ๊ธฐ์ž…๋‹ˆ๋‹ค.
  • ์‹คํ—˜์€ ํ•จ๊ป˜ ์ง„ํ–‰๋˜๋Š” '์ฃผ์ œ'์ž…๋‹ˆ๋‹ค.

์˜ˆ์ œ์˜ ๋ชจ๋“  ๋‹จ๊ณ„๋Š” Ubuntu 18.04 ์šด์˜ ์ฒด์ œ์—์„œ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค.

1. ์„œ๋ฒ„ ๋ฐฐํฌ

ํ”„๋กœ์ ํŠธ๋ฅผ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•˜๊ณ  ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์„œ๋ฒ„๋ฅผ ๋ฐฐํฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. MLflow ์ถ”์  ์„œ๋ฒ„์—๋Š” ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฐฑ์—”๋“œ ์ €์žฅ์†Œ - ๋“ฑ๋ก๋œ ๋ชจ๋ธ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค(4๊ฐœ์˜ DBMS ์ง€์›: mysql, mssql, sqlite ๋ฐ postgresql).
  • ์•„ํ‹ฐํŒฉํŠธ ์ €์žฅ์†Œ - ์•„ํ‹ฐํŒฉํŠธ ์ €์žฅ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค(7๊ฐ€์ง€ ์Šคํ† ๋ฆฌ์ง€ ์˜ต์…˜ ์ง€์›: Amazon S3, Azure Blob Storage, Google Cloud Storage, FTP ์„œ๋ฒ„, SFTP ์„œ๋ฒ„, NFS, HDFS).

๋กœ ์œ ๋ฌผ ๊ฐ€๊ฒŒ ๋‹จ์ˆœํ™”๋ฅผ ์œ„ํ•ด SFTP ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ๊ทธ๋ฃน ๋งŒ๋“ค๊ธฐ
    $ sudo groupadd sftpg
  • ์‚ฌ์šฉ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ทธ ์‚ฌ๋žŒ์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์„ค์ •ํ•˜์„ธ์š”
    $ sudo useradd -g sftpg mlflowsftp
    $ sudo passwd mlflowsftp 
  • ๋ช‡ ๊ฐ€์ง€ ์•ก์„ธ์Šค ์„ค์ • ์กฐ์ •
    $ sudo mkdir -p /data/mlflowsftp/upload
    $ sudo chown -R root.sftpg /data/mlflowsftp
    $ sudo chown -R mlflowsftp.sftpg /data/mlflowsftp/upload
  • /etc/ssh/sshd_config์— ๋ช‡ ์ค„ ์ถ”๊ฐ€
    Match Group sftpg
     ChrootDirectory /data/%u
     ForceCommand internal-sftp
  • ์„œ๋น„์Šค๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์„ธ์š”
    $ sudo systemctl restart sshd

๋กœ ๋ฐฑ์—”๋“œ ์Šคํ† ์–ด postgresql์„ ์‚ฌ์šฉํ•ด๋ณด์ž.

$ sudo apt update
$ sudo apt-get install -y postgresql postgresql-contrib postgresql-server-dev-all
$ sudo apt install gcc
$ pip install psycopg2
$ sudo -u postgres -i
# Create new user: mlflow_user
[postgres@user_name~]$ createuser --interactive -P
Enter name of role to add: mlflow_user
Enter password for new role: mlflow
Enter it again: mlflow
Shall the new role be a superuser? (y/n) n
Shall the new role be allowed to create databases? (y/n) n
Shall the new role be allowed to create more new roles? (y/n) n
# Create database mlflow_bd owned by mlflow_user
$ createdb -O mlflow_user mlflow_db

์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ๋‹ค์Œ Python ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋ณ„๋„์˜ ๊ฐ€์ƒ ํ™˜๊ฒฝ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค).

pip install mlflow
pip install pysftp

์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ด๋ณด์ž

$ mlflow server  
                 --backend-store-uri postgresql://mlflow_user:mlflow@localhost/mlflow_db 
                 --default-artifact-root sftp://mlflowsftp:mlflow@sftp_host/upload  
                --host server_host 
                --port server_port

2. ์ถ”์  ์ถ”๊ฐ€

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

์˜ˆ๋ฅผ ๋“ค์–ด, ์ €๋Š” ์ž‘์€ github์˜ ํ”„๋กœ์ ํŠธ Keras์— ์žˆ๋Š” ๋ชจ๋“  ๊ฒƒ์„ ๋ถ„ํ• ํ•˜๊ธฐ ์œ„ํ•ด COCO ๋ฐ์ดํ„ฐ ์„ธํŠธ. ์ถ”์ ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด mlflow_training.py ํŒŒ์ผ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฐ€์žฅ ํฅ๋ฏธ๋กœ์šด ์ผ์ด ์ผ์–ด๋‚˜๋Š” ๋ถ€๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

def run(self, epochs, lr, experiment_name):
        # getting the id of the experiment, creating an experiment in its absence
        remote_experiment_id = self.remote_server.get_experiment_id(name=experiment_name)
        # creating a "run" and getting its id
        remote_run_id = self.remote_server.get_run_id(remote_experiment_id)

        # indicate that we want to save the results on a remote server
        mlflow.set_tracking_uri(self.tracking_uri)
        mlflow.set_experiment(experiment_name)

        with mlflow.start_run(run_id=remote_run_id, nested=False):
            mlflow.keras.autolog()
            self.train_pipeline.train(lr=lr, epochs=epochs)

        try:
            self.log_tags_and_params(remote_run_id)
        except mlflow.exceptions.RestException as e:
            print(e)

์—ฌ๊ธฐ์„œ self.remote_server๋Š” mlflow.tracking ๋ฉ”์†Œ๋“œ์— ๋Œ€ํ•œ ์ž‘์€ ๋ž˜ํผ์ž…๋‹ˆ๋‹ค. MlflowClient(ํŽธ์˜๋ฅผ ์œ„ํ•ด ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ—˜์„ ๋งŒ๋“ค๊ณ  ์„œ๋ฒ„์—์„œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์œผ๋กœ, ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋ณ‘ํ•ฉํ•ด์•ผ ํ•˜๋Š” ์œ„์น˜(mlflow.set_tracking_uri(self.tracking_uri))๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ž๋™ ๋กœ๊น… mlflow.keras.autolog()๋ฅผ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ MLflow Tracking์€ TensorFlow, Keras, Gluon XGBoost, LightGBM, Spark์— ๋Œ€ํ•œ ์ž๋™ ๋กœ๊น…์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฐพ์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ ์–ธ์ œ๋“ ์ง€ ๋ช…์‹œ์ ์œผ๋กœ ๋กœ๊น…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ›ˆ๋ จ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์›๊ฒฉ ์„œ๋ฒ„์— ํƒœ๊ทธ์™€ ์ž…๋ ฅ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

๋ช‡ ์ค„๋งŒ ์žˆ์œผ๋ฉด ๋‹ค๋ฅธ ๋ชจ๋“  ์‚ฌ๋žŒ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ชจ๋“  ์ถœ์‹œ์— ๋Œ€ํ•œ ์ •๋ณด์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ์›ํ•œ?

3. ํ”„๋กœ์ ํŠธ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค

์ด์ œ ํ”„๋กœ์ ํŠธ๋ฅผ ์‰ฝ๊ฒŒ ์‹œ์ž‘ํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด MLproject ๋ฐ conda.yaml ํŒŒ์ผ์„ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
MLํ”„๋กœ์ ํŠธ

name: flow_segmentation
conda_env: conda.yaml

entry_points:
  main:
    parameters:
        categories: {help: 'list of categories from coco dataset'}
        epochs: {type: int, help: 'number of epochs in training'}

        lr: {type: float, default: 0.001, help: 'learning rate'}
        batch_size: {type: int, default: 8}
        model_name: {type: str, default: 'Unet', help: 'Unet, PSPNet, Linknet, FPN'}
        backbone_name: {type: str, default: 'resnet18', help: 'exampe resnet18, resnet50, mobilenetv2 ...'}

        tracking_uri: {type: str, help: 'the server address'}
        experiment_name: {type: str, default: 'My_experiment', help: 'remote and local experiment name'}
    command: "python mlflow_training.py 
            --epochs={epochs}
            --categories={categories}
            --lr={lr}
            --tracking_uri={tracking_uri}
            --model_name={model_name}
            --backbone_name={backbone_name}
            --batch_size={batch_size}
            --experiment_name={experiment_name}"

MLflow ํ”„๋กœ์ ํŠธ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ์†์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ด๋ฆ„ - ํ”„๋กœ์ ํŠธ ์ด๋ฆ„
  • ํ™˜๊ฒฝ - ๋‚ด ๊ฒฝ์šฐ conda_env๋Š” Anaconda๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ํ•˜๊ณ  ์ข…์†์„ฑ ์„ค๋ช…์ด conda.yaml ํŒŒ์ผ์— ์žˆ์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • ์ง„์ž…์  - ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ๊ณผ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค(ํ›ˆ๋ จ์„ ์‹œ์ž‘ํ•  ๋•Œ ๋ชจ๋“  ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์ž๋™์œผ๋กœ ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค).

conda.yaml

name: flow_segmentation
channels:
  - defaults
  - anaconda
dependencies:
  - python==3.7
  - pip:
    - mlflow==1.8.0
    - pysftp==0.2.9
    - Cython==0.29.19
    - numpy==1.18.4
    - pycocotools==2.0.0
    - requests==2.23.0
    - matplotlib==3.2.1
    - segmentation-models==1.0.1
    - Keras==2.3.1
    - imgaug==0.4.0
    - tqdm==4.46.0
    - tensorflow-gpu==1.14.0

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

4. ํ›ˆ๋ จ์„ ์‹œ์ž‘ํ•˜์ž

ํ”„๋กœ์ ํŠธ๋ฅผ ๋ณต์ œํ•˜๊ณ  ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

git clone https://github.com/simbakot/mlflow_example.git
cd mlflow_example/

์‹คํ–‰ํ•˜๋ ค๋ฉด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

pip install mlflow
pip install pysftp

์™œ๋ƒํ•˜๋ฉด conda_env๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์—์„œ๋Š” Anaconda๊ฐ€ ์ปดํ“จํ„ฐ์— ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋‚˜ ํ•„์š”ํ•œ ๋ชจ๋“  ํŒจํ‚ค์ง€๋ฅผ ์ง์ ‘ ์„ค์น˜ํ•˜๊ณ  ์‹œ์ž‘ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

๋ชจ๋“  ์ค€๋น„ ๋‹จ๊ณ„๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉฐ ๊ต์œก์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์—์„œ:

$ mlflow run -P epochs=10 -P categories=cat,dog -P tracking_uri=http://server_host:server_port .

๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์ž๋™์œผ๋กœ conda ํ™˜๊ฒฝ์ด ์ƒ์„ฑ๋˜๊ณ  ํ›ˆ๋ จ์ด ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.
์œ„์˜ ์˜ˆ์—์„œ๋Š” ํ›ˆ๋ จ์„ ์œ„ํ•œ ์‹œ๋Œ€ ์ˆ˜, ์ฆ‰ ๋ถ„๋ฅ˜ํ•˜๋ ค๋Š” ๋ฒ”์ฃผ๋ฅผ ์ „๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค(์ „์ฒด ๋ชฉ๋ก์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). ์—ฌ๊ธฐ์—) ๋ฐ ์›๊ฒฉ ์„œ๋ฒ„์˜ ์ฃผ์†Œ์ž…๋‹ˆ๋‹ค.
๊ฐ€๋Šฅํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ „์ฒด ๋ชฉ๋ก์€ MLproject ํŒŒ์ผ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

5. ํ•™์Šต ๊ฒฐ๊ณผ ํ‰๊ฐ€

๊ต์œก์„ ๋งˆ์นœ ํ›„ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์„œ๋ฒ„ ์ฃผ์†Œ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. http://server_host:server_port

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

์—ฌ๊ธฐ์—๋Š” ๋ชจ๋“  ์‹คํ—˜ ๋ชฉ๋ก(์™ผ์ชฝ ์ƒ๋‹จ)๊ณผ ์‹คํ–‰ ์ •๋ณด(๊ฐ€์šด๋ฐ)๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ์ถœ์‹œ์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ์ •๋ณด(๋งค๊ฐœ๋ณ€์ˆ˜, ์ง€ํ‘œ, ์•„ํ‹ฐํŒฉํŠธ ๋ฐ ์ผ๋ถ€ ์ถ”๊ฐ€ ์ •๋ณด)๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

๊ฐ ์ง€ํ‘œ์— ๋Œ€ํ•ด ๋ณ€๊ฒฝ ๋‚ด์—ญ์„ ๊ด€์ฐฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

์ €๊ฒƒ๋“ค. ํ˜„์žฌ๋Š” "์ˆ˜๋™" ๋ชจ๋“œ์—์„œ ๊ฒฐ๊ณผ๋ฅผ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ MLflow API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™ ๊ฒ€์ฆ์„ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

6. ๋ชจ๋ธ ๋“ฑ๋ก

๋ชจ๋ธ์„ ๋ถ„์„ํ•˜๊ณ  ์ „ํˆฌ ์ค€๋น„๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋‹ค๊ณ  ํŒ๋‹จํ•œ ํ›„ ๋“ฑ๋ก์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ฐœ์‚ฌ๋ฅผ ์„ ํƒํ•˜๊ณ (์ด์ „ ๋‹จ๋ฝ์— ํ‘œ์‹œ๋จ) ๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค.

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

๋ชจ๋ธ์— ์ด๋ฆ„์„ ์ง€์ •ํ•˜๋ฉด ๋ฒ„์ „์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ชจ๋ธ์„ ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ ์ €์žฅํ•˜๋ฉด ๋ฒ„์ „์ด ์ž๋™์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ๋ฉ๋‹ˆ๋‹ค.

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

๊ฐ ๋ชจ๋ธ์— ๋Œ€ํ•ด ์„ค๋ช…์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์„ธ ๊ฐ€์ง€ ์ƒํƒœ(์Šคํ…Œ์ด์ง•, ํ”„๋กœ๋•์…˜, ๋ณด๊ด€๋จ) ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ดํ›„์— API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์ƒํƒœ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋ฒ„์ „ ๊ด€๋ฆฌ์™€ ํ•จ๊ป˜ ์ถ”๊ฐ€์ ์ธ ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

์šฐ๋ฆฌ๋Š” ๋˜ํ•œ ๋ชจ๋“  ๋ชจ๋ธ์— ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

๊ทธ๋ฆฌ๊ณ  ๊ทธ๋“ค์˜ ๋ฒ„์ „

MLOps - ์š”๋ฆฌ์ฑ…, 1์žฅ

์ด์ „ ๋‹จ๋ฝ์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ชจ๋“  ์ž‘์—…์€ API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

7. ๋ชจ๋ธ ๋ฐฐํฌ

์ด ๋‹จ๊ณ„์—์„œ๋Š” ์ด๋ฏธ ํ›ˆ๋ จ๋œ(keras) ๋ชจ๋ธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ ๋ฐฉ๋ฒ•์˜ ์˜ˆ:

class SegmentationModel:
    def __init__(self, tracking_uri, model_name):

        self.registry = RemoteRegistry(tracking_uri=tracking_uri)
        self.model_name = model_name
        self.model = self.build_model(model_name)

    def get_latest_model(self, model_name):
        registered_models = self.registry.get_registered_model(model_name)
        last_model = self.registry.get_last_model(registered_models)
        local_path = self.registry.download_artifact(last_model.run_id, 'model', './')
        return local_path

    def build_model(self, model_name):
        local_path = self.get_latest_model(model_name)

        return mlflow.keras.load_model(local_path)

    def predict(self, image):
        image = self.preprocess(image)
        result = self.model.predict(image)
        return self.postprocess(result)

    def preprocess(self, image):
        image = cv2.resize(image, (256, 256))
        image = image / 255.
        image = np.expand_dims(image, 0)
        return image

    def postprocess(self, result):
        return result

์—ฌ๊ธฐ์„œ self.registry๋Š” ํŽธ์˜์ƒ mlflow.tracking.MlflowClient์— ๋Œ€ํ•œ ์ž‘์€ ๋ž˜ํผ์ž…๋‹ˆ๋‹ค. ์š”์ ์€ ์›๊ฒฉ ์„œ๋ฒ„์— ์•ก์„ธ์Šคํ•˜์—ฌ ๊ทธ๊ณณ์—์„œ ์ง€์ •๋œ ์ด๋ฆ„๊ณผ ์ตœ์‹  ์ƒ์‚ฐ ๋ฒ„์ „์„ ๊ฐ€์ง„ ๋ชจ๋ธ์„ ์ฐพ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ์œผ๋กœ ์•„ํ‹ฐํŒฉํŠธ๋ฅผ ./model ํด๋”์— ๋กœ์ปฌ๋กœ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ์ด ๋””๋ ‰ํ„ฐ๋ฆฌ mlflow.keras.load_model(local_path)์—์„œ ๋ชจ๋ธ์„ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. CV(ML) ๊ฐœ๋ฐœ์ž๋Š” ์‰ฝ๊ฒŒ ๋ชจ๋ธ์„ ๊ฐœ์„ ํ•˜๊ณ  ์ƒˆ ๋ฒ„์ „์„ ๊ฒŒ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก ์ ์œผ๋กœ

๋‚˜๋Š” ๋‹ค์Œ์„ ํ—ˆ์šฉํ•˜๋Š” ์‹œ์Šคํ…œ์„ ์ œ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ML ๋ชจ๋ธ, ํ•™์Šต ์ง„ํ–‰ ์ƒํ™ฉ ๋ฐ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์ค‘์•™์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์‹ ์†ํ•˜๊ฒŒ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋ธ ์ž‘์—… ์ง„ํ–‰ ์ƒํ™ฉ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ  ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋ธ์˜ ์ƒํƒœ๋ฅผ ๋ฒ„์ „ํ™”ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฒฐ๊ณผ ๋ชจ๋ธ์„ ๋ฐฐํฌํ•˜๋Š” ๊ฒƒ์€ ์‰ฝ์Šต๋‹ˆ๋‹ค.

์ด ์˜ˆ๋Š” ์žฅ๋‚œ๊ฐ์ด๋ฉฐ ๊ฒฐ๊ณผ ํ‰๊ฐ€ ๋ฐ ๋ชจ๋ธ ๋“ฑ๋ก ์ž๋™ํ™”(๊ฐ๊ฐ 5๋ฒˆ ๋ฐ 6๋ฒˆ)๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ์ž์ฒด ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•œ ์ถœ๋ฐœ์  ์—ญํ• ์„ ํ•˜๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ ์„ธํŠธ์˜ ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ฒƒ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ œ๊ฐ€ ๋งํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ์š”์ ์€ ์ „์ฒด์ ์œผ๋กœ MLOps๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. MLflow๋Š” ๋ชฉ์ ์„ ์œ„ํ•œ ์ˆ˜๋‹จ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ํ‘œ์‹œํ•˜์ง€ ์•Š์€ ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์ ์–ด์ฃผ์„ธ์š”.
๊ท€ํ•˜์˜ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์‹œ์Šคํ…œ์— ๋ฌด์—‡์„ ์ถ”๊ฐ€ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?
๋ฌธ์ œ์˜ ์ „๋ถ€ ๋˜๋Š” ์ผ๋ถ€๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์–ด๋–ค ๋„๊ตฌ์™€ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?

์ถ”์‹ : ๋ช‡ ๊ฐ€์ง€ ๋งํฌ๋ฅผ ๋‚จ๊ฒจ ๋‘๊ฒ ์Šต๋‹ˆ๋‹ค.
github ํ”„๋กœ์ ํŠธ - https://github.com/simbakot/mlflow_example
MLํ”Œ๋กœ์šฐ - https://mlflow.org/
์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋‚ด ์—…๋ฌด ์ด๋ฉ”์ผ - [์ด๋ฉ”์ผ ๋ณดํ˜ธ]

์šฐ๋ฆฌ ํšŒ์‚ฌ๋Š” ์ •๊ธฐ์ ์œผ๋กœ IT ์ „๋ฌธ๊ฐ€๋ฅผ ์œ„ํ•œ ๋‹ค์–‘ํ•œ ์ด๋ฒคํŠธ๋ฅผ ๊ฐœ์ตœํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ์Šคํฌ๋ฐ” ์‹œ๊ฐ„์œผ๋กœ 8์›” 19์ผ 00:XNUMX์— ์˜จ๋ผ์ธ ํ˜•์‹์œผ๋กœ CV ๋ชจ์ž„์ด ์žˆ์„ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๊ด€์‹ฌ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ฐธ๊ฐ€ํ•˜๊ณ  ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— .

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€