# ๐Ÿง—โ€โ™‚๏ธ ๊ฐœ๋ฐœ ๊ณผ์ • ๋ฐ ๋ฌธ์ œ ํ•ด๊ฒฐ (Development Journey) ์ด ๋ฌธ์„œ์—์„œ๋Š” Emotion Diary ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ๊ฒช์—ˆ๋˜ ์ฃผ์š” ๊ธฐ์ˆ ์  ๋„์ „ ๊ณผ์ œ์™€ ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๊ณผ์ •์„ ์ƒ์„ธํžˆ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. --- ### 1. ๋Œ€์šฉ๋Ÿ‰ AI ๋ชจ๋ธ ๊ด€๋ฆฌ ๋ฐ ๋ฐฐํฌ ์ „๋žต ์ˆ˜๋ฆฝ - **๋ฌธ์ œ์ **: 1GB๊ฐ€ ๋„˜๋Š” AI ๋ชจ๋ธ ํŒŒ์ผ์„ Git LFS๋กœ ๊ด€๋ฆฌํ–ˆ์œผ๋‚˜, Hugging Face Spaces์˜ 1GB ์ €์žฅ ๊ณต๊ฐ„ ํ•œ๊ณ„(Storage limit reached)์™€ LFS ํŒŒ์ผ-ํฌ์ธํ„ฐ ๋ถˆ์ผ์น˜(LFS pointer does not exist) ๋“ฑ ๋ฐฐํฌ ๊ณผ์ •์—์„œ ์ง€์†์ ์ธ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. - **ํ•ด๊ฒฐ ๊ณผ์ •**: ๋ชจ๋ธ๊ณผ ์•ฑ ์ฝ”๋“œ์˜ ์™„์ „ํ•œ ๋ถ„๋ฆฌ ์ „๋žต์„ ์ฑ„ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. - ๋Œ€์šฉ๋Ÿ‰ ๋ชจ๋ธ์€ Hugging Face Hub์— ๋ณ„๋„๋กœ ์—…๋กœ๋“œํ•˜์—ฌ ๋ฒ„์ „ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. - GitHub ์ €์žฅ์†Œ์—์„œ๋Š” Git LFS ์ถ”์ ์„ ์™„์ „ํžˆ ์ œ๊ฑฐํ•˜๊ณ  ์ˆœ์ˆ˜ ์•ฑ ์ฝ”๋“œ๋งŒ ๊ด€๋ฆฌํ•˜๋„๋ก ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค. - GitHub Actions ์›Œํฌํ”Œ๋กœ์šฐ(`sync-to-hub.yml`)์˜ `lfs` ์˜ต์…˜์„ `false`๋กœ ์„ค์ •ํ•˜์—ฌ, ๋ฐฐํฌ ์‹œ์—๋Š” ์•ฑ ์ฝ”๋“œ๋งŒ Spaces๋กœ ํ‘ธ์‹œํ•˜๋„๋ก ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. - **๊ฒฐ๋ก **: Spaces ์•ฑ ์‹คํ–‰ ์‹œ์ ์—์„œ `emotion_engine.py`๊ฐ€ Hub๋กœ๋ถ€ํ„ฐ ๋ชจ๋ธ์„ ๋‹ค์šด๋กœ๋“œํ•˜๋„๋ก ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ €์žฅ ๊ณต๊ฐ„ ๋ฌธ์ œ๋ฅผ ๊ทผ๋ณธ์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ณ , ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‹œ ๋ชจ๋ธ์„ ๋‹ค์‹œ ์—…๋กœ๋“œํ•  ํ•„์š”๊ฐ€ ์—†๋Š” ํšจ์œจ์ ์ธ ๋ฐฐํฌ ํŒŒ์ดํ”„๋ผ์ธ์„ ์™„์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. --- ### 2. CI/CD ํŒŒ์ดํ”„๋ผ์ธ์˜ ๋ถ„์‚ฐ ํ™˜๊ฒฝ ์ธ์ฆ ๋ฌธ์ œ ํ•ด๊ฒฐ - **๋ฌธ์ œ์ **: ๋กœ์ปฌ์—์„œ `git push`๋กœ ํŠธ๋ฆฌ๊ฑฐ๋œ GitHub Actions๊ฐ€ Hugging Face Spaces์— ์ ‘๊ทผํ•  ๋•Œ `Invalid credentials` ์ธ์ฆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Spaces์˜ Secret๊ณผ GitHub Actions์˜ Secret ์—ญํ• ์— ๋Œ€ํ•œ ํ˜ผ๋™ ๋•Œ๋ฌธ์ด์—ˆ์Šต๋‹ˆ๋‹ค. - **ํ•ด๊ฒฐ ๊ณผ์ •**: '๋ฐฐํฌ ๋กœ๋ด‡(GitHub Actions)'๊ณผ '๋นŒ๋“œ ๋กœ๋ด‡(Spaces)'์˜ ๊ฐœ๋…์œผ๋กœ ์—ญํ• ์„ ๋ช…ํ™•ํžˆ ๋ถ„๋ฆฌํ•˜์—ฌ ์ ‘๊ทผํ–ˆ์Šต๋‹ˆ๋‹ค. - **GitHub Actions Secret (`HF_TOKEN`)**: '๋ฐฐํฌ ๋กœ๋ด‡'์ด Hugging Face ์ €์žฅ์†Œ(Repository)์— ์ฝ”๋“œ๋ฅผ ํ‘ธ์‹œํ•  ๋•Œ ํ•„์š”ํ•œ `write` ๊ถŒํ•œ ํ† ํฐ์„ ๋“ฑ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. - **Hugging Face Spaces Secret (`HF_TOKEN`)**: '๋นŒ๋“œ ๋กœ๋ด‡'์ด ๋‚ด๋ถ€์ ์œผ๋กœ LFS ํŒŒ์ผ ์ฒ˜๋ฆฌ๋‚˜ ๋‹ค๋ฅธ private ์ €์žฅ์†Œ์— ์ ‘๊ทผํ•  ๋•Œ ํ•„์š”ํ•œ ํ† ํฐ์„ ๋“ฑ๋กํ–ˆ์Šต๋‹ˆ๋‹ค. (์ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜๋ฉด์„œ Spaces Secret์˜ ํ•„์š”์„ฑ์€ ๋‚ฎ์•„์กŒ์Šต๋‹ˆ๋‹ค.) - **๊ฒฐ๋ก **: ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์‹คํ–‰ ํ™˜๊ฒฝ์—์„œ ํ•„์š”ํ•œ ์ธ์ฆ ์ •๋ณด๋ฅผ ๋ช…ํ™•ํžˆ ๋ถ„๋ฆฌํ•˜๊ณ  ์˜ฌ๋ฐ”๋ฅธ ๊ถŒํ•œ์˜ ํ† ํฐ์„ ์ œ๊ณตํ•จ์œผ๋กœ์จ CI/CD ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ธ์ฆ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. --- ### 3. Flask ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์กฐ ์„ค๊ณ„ ๋ฐ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜ ๋””๋ฒ„๊น… - **๋ฌธ์ œ์ **: ๊ฐœ๋ฐœ ์ดˆ๊ธฐ, ๋ชจ๋“  ๋กœ์ง์ด ๋‹ด๊ธด ๋‹จ์ผ ํŒŒ์ผ ๊ตฌ์กฐ(`app.py`)๋กœ ์ธํ•ด ์ˆœํ™˜ ์ฐธ์กฐ(Circular Import) ๋ฐ `ModuleNotFoundError`๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, API๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค AI ๋ชจ๋ธ์„ ๋กœ๋”ฉํ•˜์—ฌ ์‘๋‹ต ์†๋„๊ฐ€ ๋งค์šฐ ๋А๋ ธ์Šต๋‹ˆ๋‹ค. - **ํ•ด๊ฒฐ ๊ณผ์ •**: Flask์˜ **Application Factory ํŒจํ„ด**์„ ๋„์ž…ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ์žฌ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค. - `src/__init__.py`์˜ `create_app` ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์•ฑ์˜ ๋ชจ๋“  ๊ตฌ์„ฑ์š”์†Œ(DB, ๋ธ”๋ฃจํ”„๋ฆฐํŠธ, ์„ค์ •)๋ฅผ ์กฐ๋ฆฝํ•˜๋„๋ก ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค. - ์•ฑ์ด ์‹œ์ž‘๋˜๋Š” ์‹œ์ (`create_app` ๋‚ด๋ถ€)์—์„œ AI ๋ชจ๋ธ์„ ๋‹จ ํ•œ ๋ฒˆ๋งŒ ๋กœ๋“œํ•˜์—ฌ `app` ๊ฐ์ฒด์— ์ €์žฅ(`app.emotion_classifier`)ํ–ˆ์Šต๋‹ˆ๋‹ค. - **๊ฒฐ๋ก **: ๊ฐ API ์š”์ฒญ์—์„œ๋Š” `current_app` ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ๋ฏธ๋ฆฌ ๋กœ๋“œ๋œ ๋ชจ๋ธ์„ ์ฐธ์กฐํ•˜๊ฒŒ ํ•˜์—ฌ, ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์„ฑ๊ณผ ์‘๋‹ต ์†๋„๋ฅผ ๊ทน๋Œ€ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๊ณ  ์•ˆ์ •์ ์ธ ๋ฐฑ์—”๋“œ ๊ตฌ์กฐ๋ฅผ ์™„์„ฑํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. --- ### 4. ๋ชจ๋ธ ์„ฑ๋Šฅ ํ•˜๋ฝ ๋ฐ ์ •ํ™•๋„ ๊ฐœ์„  ๊ณผ์ • - **๋ฌธ์ œ์ **: ๊ฐœ๋ฐœ ๊ณผ์ •์—์„œ ์›๋ณธ ํ•™์Šต ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์‹ค๋˜์–ด ๋ชจ๋ธ์„ ์žฌํ•™์Šตํ•˜์ž, ์ •ํ™•๋„๊ฐ€ ์ดˆ๊ธฐ ๋ชจ๋ธ๋ณด๋‹ค ํ˜„์ €ํžˆ ๋‚ฎ์•„์ง€๋Š” ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ์Šต๋‹ˆ๋‹ค. - **ํ•ด๊ฒฐ ๊ณผ์ •**: ์„ฑ๋Šฅ์„ ๋ณต์›ํ•˜๊ณ  ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์ฒด๊ณ„์ ์œผ๋กœ ์‹คํ—˜ํ–ˆ์Šต๋‹ˆ๋‹ค. - **ํ˜ผ๋™ ํ–‰๋ ฌ(Confusion Matrix) ๋ถ„์„**: ๋ชจ๋ธ์ด ์–ด๋–ค ๊ฐ์ •๋“ค์„ ์„œ๋กœ ํ˜ผ๋™ํ•˜๋Š”์ง€ ํŒŒ์•…ํ•˜์—ฌ ๋ฌธ์ œ์˜ ์›์ธ์„ ์ง„๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. - **๋ ˆ์ด๋ธ” ์žฌ๊ตฌ์„ฑ (Label Remapping)**: ์„ธ๋ถ„ํ™”๋œ ๊ฐ์ • ๋ ˆ์ด๋ธ”์„ 6๊ฐœ ๋˜๋Š” 4๊ฐœ์˜ ์ฃผ์š” ๊ฐ์ •์œผ๋กœ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ๋ถ„๋ฅ˜ ๋ฌธ์ œ์˜ ๋ณต์žก๋„๋ฅผ ์กฐ์ ˆํ–ˆ์Šต๋‹ˆ๋‹ค. - **๋ฐ์ดํ„ฐ ๋ถˆ๊ท ํ˜• ํ•ด์†Œ**: ์†Œ์ˆ˜ ํด๋ž˜์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฆ๊ฐ•ํ•˜๋Š” ์˜ค๋ฒ„์ƒ˜ํ”Œ๋ง(Oversampling) ๋ฐ ๊ฐ ํด๋ž˜์Šค์— ๋‹ค๋ฅธ ์ค‘์š”๋„๋ฅผ ๋ถ€์—ฌํ•˜๋Š” ์ˆ˜๋™ ํด๋ž˜์Šค ๊ฐ€์ค‘์น˜(Manual Class Weights)๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. - **์ „์ด ํ•™์Šต(Transfer Learning) ๊ฐ•ํ™”**: ๊ฐ์„ฑ ๋ถ„์„์— ํŠนํ™”๋œ NSMC(Naver Movie Corpus) ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ 1์ฐจ ์‚ฌ์ „ ํ•™์Šตํ•œ ๋ชจ๋ธ์„ ๊ธฐ๋ฐ˜์œผ๋กœ, ์ตœ์ข… ๊ฐ์ • ๋ฐ์ดํ„ฐ์— 2์ฐจ ๋ฏธ์„ธ์กฐ์ •(Fine-tuning)์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. - **๊ฒฐ๋ก **: ์—ฌ๋Ÿฌ ์‹คํ—˜ ๊ฒฐ๊ณผ, 'ํ•œ๊ตญ์–ด ๊ฐ์„ฑ๋Œ€ํ™” ๋ง๋ญ‰์น˜' ๋ฐ์ดํ„ฐ์˜ ๋ ˆ์ด๋ธ”์„ 6๊ฐœ์˜ ์ฃผ์š” ๊ฐ์ •์œผ๋กœ ๋งคํ•‘ํ•˜๊ณ , ๋ฐ์ดํ„ฐ ๋ถˆ๊ท ํ˜• ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด **์ˆ˜๋™์œผ๋กœ ํด๋ž˜์Šค ๊ฐ€์ค‘์น˜๋ฅผ ์ •๊ตํ•˜๊ฒŒ ์กฐ์ •**ํ•˜์—ฌ ํ•™์Šตํ•˜๋Š” ๋ฐฉ์‹์ด ์•ฝ 80%์˜ ์ •ํ™•๋„๋ฅผ ํšŒ๋ณตํ•˜๋ฉฐ ๊ฐ€์žฅ ์•ˆ์ •์ ์ด๊ณ  ํšจ๊ณผ์ ์ž„์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.