์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐ŸŒ Transformers๋กœ ๋ฒˆ์—ญ AI ์‹ค์Šต
๐Ÿค– AI / ๋จธ์‹ ๋Ÿฌ๋‹ ๊ฐœ๋ฐœ

๐ŸŒ Transformers๋กœ ๋ฒˆ์—ญ AI ์‹ค์Šต

ํ—ˆ๊น…ํŽ˜์ด์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋‚˜๋งŒ์˜ ๋ฒˆ์—ญ AI ๋š๋”ฑ ๋งŒ๋“ค๊ธฐ ๐Ÿ› ๏ธโœจ

๐Ÿ“ ์ž…๋ ฅ ํ…์ŠคํŠธ "์•ˆ๋…•ํ•˜์„ธ์š”, ์˜ค๋Š˜ ๋‚ ์”จ๊ฐ€ ์ •๋ง ์ข‹๋„ค์š”!" ๐Ÿค— Transformers Helsinki-NLP MarianMT ๋ชจ๋ธ โš™๏ธ ๐Ÿง  โœ… ๋ฒˆ์—ญ ๊ฒฐ๊ณผ "Hello, the weather today is really nice!" ๐Ÿš€ ํŒŒ์ด์ฌ ๋ช‡ ์ค„๋กœ ์™„์„ฑํ•˜๋Š” ๋ฒˆ์—ญ AI ํŒŒ์ดํ”„๋ผ์ธ

์•ผ, ์†”์งํžˆ ๋งํ•ด๋ด. ๋ฒˆ์—ญ AI ๋งŒ๋“ ๋‹ค๊ณ  ํ•˜๋ฉด ์™ ์ง€ ์—„์ฒญ ์–ด๋ ค์šธ ๊ฒƒ ๊ฐ™์ง€ ์•Š์•„? ๐Ÿ˜…
๋”ฅ๋Ÿฌ๋‹ ๋…ผ๋ฌธ ์ˆ˜์‹ญ ํŽธ ์ฝ์–ด์•ผ ํ•˜๊ณ , ์ˆ˜๋ฐฑ๋งŒ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ ์ง์ ‘ ๋ชจ์•„์•ผ ํ•˜๊ณ , GPU ์„œ๋ฒ„ ๋ช‡ ๋Œ€ ๋Œ๋ ค์•ผ ํ•  ๊ฒƒ ๊ฐ™์€ ๋А๋‚Œ?

๊ทผ๋ฐ ์‚ฌ์‹ค ํ—ˆ๊น…ํŽ˜์ด์Šค(Hugging Face)์˜ Transformers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์“ฐ๋ฉด, ํŒŒ์ด์ฌ ์ฝ”๋“œ ๋ช‡ ์ค„๋งŒ์œผ๋กœ ์ง„์งœ ๋ฒˆ์—ญ AI๋ฅผ ๋š๋”ฑ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๐ŸŽ‰
์˜ค๋Š˜์€ ๊ทธ ์‹ ์„ธ๊ณ„๋ฅผ ๊ฐ™์ด ํƒํ—˜ํ•ด๋ณด์ž. ์ด๋ก ๋„ ํƒ„ํƒ„ํ•˜๊ฒŒ, ์‹ค์Šต๋„ ๊ผผ๊ผผํ•˜๊ฒŒ โ€” ์™„์ „ ์นœ์ ˆํ•˜๊ฒŒ ์„ค๋ช…ํ•ด์ค„๊ฒŒ. ์ค€๋น„๋์ง€? ๐Ÿ”ฅ


๐Ÿค” Transformers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ญ”๋ฐ?

๋จผ์ € ๊ธฐ๋ณธ๋ถ€ํ„ฐ ์งš๊ณ  ๊ฐ€์ž. Transformers๋Š” ํ—ˆ๊น…ํŽ˜์ด์Šค(Hugging Face)๋ผ๋Š” AI ์Šคํƒ€ํŠธ์—…์ด ๋งŒ๋“  ์˜คํ”ˆ์†Œ์Šค ํŒŒ์ด์ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ.
2018๋…„์— ์ฒ˜์Œ ๋‚˜์™”๊ณ , ์ง€๊ธˆ์€ AI ๊ฐœ๋ฐœ์ž๋“ค ์‚ฌ์ด์—์„œ ์‚ฌ์‹ค์ƒ ํ‘œ์ค€ ๋„๊ตฌ๋กœ ์ž๋ฆฌ์žก์€ ์ƒํƒœ์•ผ.

๐Ÿ“ฆ Transformers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ•ต์‹ฌ ํŠน์ง•

๐Ÿค— ํ—ˆ๊น…ํŽ˜์ด์Šค ์ œ๊ณต PyTorch / TensorFlow ์ง€์› ์ˆ˜์ฒœ ๊ฐœ์˜ ์‚ฌ์ „ํ•™์Šต ๋ชจ๋ธ NLP / ๋น„์ „ / ์˜ค๋””์˜ค ๋ชจ๋‘ ์ปค๋ฒ„

์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•˜๋‚˜๋กœ ๋ฒˆ์—ญ, ์š”์•ฝ, ๊ฐ์„ฑ๋ถ„์„, ์งˆ์˜์‘๋‹ต, ํ…์ŠคํŠธ ์ƒ์„ฑ ๋“ฑ ๊ฑฐ์˜ ๋ชจ๋“  NLP ํƒœ์Šคํฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด.
๊ทธ๋ฆฌ๊ณ  ํ•ต์‹ฌ์€ โ€” ์ด๋ฏธ ํ•™์Šต๋œ ๋ชจ๋ธ(Pre-trained Model)์„ ๊ทธ๋ƒฅ ๊ฐ€์ ธ๋‹ค ์“ธ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ! ๐Ÿ™Œ

์—ฌ๊ธฐ์„œ ์ž ๊น, "Transformer"๋ผ๋Š” ๋‹จ์–ด ์ž์ฒด์— ๋Œ€ํ•ด์„œ๋„ ์•Œ์•„๋‘์ž.
Transformer๋Š” 2017๋…„ ๊ตฌ๊ธ€์ด ๋ฐœํ‘œํ•œ ๋…ผ๋ฌธ "Attention is All You Need"์—์„œ ์ฒ˜์Œ ๋“ฑ์žฅํ•œ ๋”ฅ๋Ÿฌ๋‹ ์•„ํ‚คํ…์ฒ˜์•ผ.
์ด ๊ตฌ์กฐ๊ฐ€ ๋“ฑ์žฅํ•˜๋ฉด์„œ NLP ๋ถ„์•ผ๊ฐ€ ์™„์ „ํžˆ ๋’ค์ง‘์–ด์กŒ๊ณ , BERT, GPT, T5 ๊ฐ™์€ ์ดˆ๊ฑฐ๋Œ€ ์–ธ์–ด๋ชจ๋ธ๋“ค์ด ๋ชจ๋‘ ์ด Transformer ๊ตฌ์กฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ์–ด.

๐Ÿ’ก Tip! Transformer ์•„ํ‚คํ…์ฒ˜์˜ ํ•ต์‹ฌ์€ Self-Attention ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์•ผ.
๋ฌธ์žฅ ๋‚ด ๋‹จ์–ด๋“ค์ด ์„œ๋กœ ์–ผ๋งˆ๋‚˜ ๊ด€๋ จ ์žˆ๋Š”์ง€๋ฅผ ๊ณ„์‚ฐํ•ด์„œ, ๋ฌธ๋งฅ์„ ํ›จ์”ฌ ์ž˜ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜.
์˜ˆ๋ฅผ ๋“ค์–ด "๋‚˜๋Š” ์‚ฌ๊ณผ๋ฅผ ๋จน์—ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋ง›์žˆ์—ˆ๋‹ค."์—์„œ '๊ทธ๊ฒƒ'์ด '์‚ฌ๊ณผ'๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค๋Š” ๊ฑธ ๋ชจ๋ธ์ด ์Šค์Šค๋กœ ํŒŒ์•…ํ•˜๋Š” ๊ฑฐ์•ผ!
๐Ÿ—๏ธ Transformer ๊ธฐ๋ณธ ๊ตฌ์กฐ (๋ฒˆ์—ญ ํƒœ์Šคํฌ ๊ธฐ์ค€) ์ธ์ฝ”๋” (Encoder) Self-Attention Feed Forward Layer Norm ์ž…๋ ฅ ๋ฌธ์žฅ์„ ๋ฒกํ„ฐ๋กœ ๋ณ€ํ™˜ Cross-Attention ์ธ์ฝ”๋” โ†” ๋””์ฝ”๋” ์ •๋ณด ๊ตํ™˜ ๐Ÿ”— ๋””์ฝ”๋” (Decoder) Masked Self-Attention Cross-Attention Feed Forward ๋ฒˆ์—ญ๋œ ๋ฌธ์žฅ์„ ์ˆœ์„œ๋Œ€๋กœ ์ƒ์„ฑ ๋ฒˆ์—ญ AI๋Š” ์ธ์ฝ”๋”-๋””์ฝ”๋” ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•ด ์†Œ์Šค ์–ธ์–ด โ†’ ํƒ€๊ฒŸ ์–ธ์–ด๋กœ ๋ณ€ํ™˜ํ•ด

๐Ÿ› ๏ธ ํ™˜๊ฒฝ ์„ค์ •๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์ž!

์ž, ์ด์ œ ์ง„์งœ ์‹ค์Šต ๋“ค์–ด๊ฐ€๋ณผ๊ฒŒ. ๋จผ์ € ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์„ค์น˜ํ•ด์•ผ ํ•ด.
ํŒŒ์ด์ฌ 3.8 ์ด์ƒ ํ™˜๊ฒฝ์ด๋ฉด ์ถฉ๋ถ„ํ•˜๊ณ , Google Colab์„ ์“ฐ๋ฉด GPU๋„ ๋ฌด๋ฃŒ๋กœ ์“ธ ์ˆ˜ ์žˆ์–ด์„œ ๊ฐ•์ถ”์•ผ! ๐ŸŽ“

1
ํ•„์ˆ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜
ํ„ฐ๋ฏธ๋„(๋˜๋Š” Colab ์…€)์—์„œ ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด์ค˜.
bash
pip install transformers
pip install torch
pip install sentencepiece
pip install sacremoses
๐Ÿ’ก sentencepiece์™€ sacremoses๋Š” ๋ฒˆ์—ญ ๋ชจ๋ธ์—์„œ ํ…์ŠคํŠธ๋ฅผ ํ† ํฌ๋‚˜์ด์ง•ํ•  ๋•Œ ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ.
ํŠนํžˆ MarianMT ๊ณ„์—ด ๋ฒˆ์—ญ ๋ชจ๋ธ์„ ์“ธ ๋•Œ ํ•„์ˆ˜๋กœ ์„ค์น˜ํ•ด์•ผ ํ•ด!
2
์„ค์น˜ ํ™•์ธ
ํŒŒ์ด์ฌ์—์„œ ์•„๋ž˜ ์ฝ”๋“œ๋กœ ๋ฒ„์ „ ํ™•์ธํ•ด๋ด.
python
import transformers
print(transformers.__version__)
# ์˜ˆ: 4.40.0 ์ด์ƒ์ด๋ฉด OK!
๐Ÿ–ฅ๏ธ ๊ถŒ์žฅ ํ™˜๊ฒฝ

Python 3.8+ transformers 4.30+ torch 2.0+ RAM 4GB ์ด์ƒ

GPU๊ฐ€ ์—†์–ด๋„ CPU๋กœ ์ถฉ๋ถ„ํžˆ ์‹ค์Šต ๊ฐ€๋Šฅํ•ด! ๋‹ค๋งŒ ์†๋„๊ฐ€ ์ข€ ๋А๋ฆด ์ˆ˜ ์žˆ์–ด. ๐Ÿ˜…
Google Colab์—์„œ ๋Ÿฐํƒ€์ž„ ์œ ํ˜•์„ GPU๋กœ ์„ค์ •ํ•˜๋ฉด ํ›จ์”ฌ ๋น ๋ฅด๊ฒŒ ๋Œ์•„๊ฐ€.

๐Ÿš€ ๊ฐ€์žฅ ๋น ๋ฅธ ๋ฐฉ๋ฒ•: pipeline() ํ•จ์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ

ํ—ˆ๊น…ํŽ˜์ด์Šค Transformers์˜ ๊ฝƒ์€ ๋ฐ”๋กœ pipeline() ํ•จ์ˆ˜์•ผ!
๋ชจ๋ธ ๋กœ๋”ฉ, ํ† ํฌ๋‚˜์ด์ง•, ์ถ”๋ก , ๋””์ฝ”๋”ฉ๊นŒ์ง€ โ€” ์ด ๋ชจ๋“  ๊ณผ์ •์„ ๋‹จ ๋ช‡ ์ค„๋กœ ์ฒ˜๋ฆฌํ•ด์ค˜. ์ง„์งœ ๋งˆ๋ฒ• ๊ฐ™๋‹ค๊ณ  ๐Ÿช„

python
from transformers import pipeline

# ํ•œ๊ตญ์–ด โ†’ ์˜์–ด ๋ฒˆ์—ญ ํŒŒ์ดํ”„๋ผ์ธ ์ƒ์„ฑ
translator = pipeline(
    task="translation",
    model="Helsinki-NLP/opus-mt-ko-en"
)

# ๋ฒˆ์—ญ ์‹คํ–‰!
result = translator("์•ˆ๋…•ํ•˜์„ธ์š”! ์˜ค๋Š˜ ๋‚ ์”จ๊ฐ€ ์ •๋ง ์ข‹๋„ค์š”.")
print(result)
# ์ถœ๋ ฅ: [{'translation_text': 'Hello! The weather is really nice today.'}]

์–ด๋•Œ? ์ง„์งœ ์ด๊ฒŒ ๋์ด์•ผ! ๐Ÿ˜ฒ
pipeline() ํ•จ์ˆ˜์— ํƒœ์Šคํฌ ์ด๋ฆ„๊ณผ ๋ชจ๋ธ ์ด๋ฆ„๋งŒ ๋„ฃ์–ด์ฃผ๋ฉด, ํ—ˆ๊น…ํŽ˜์ด์Šค ํ—ˆ๋ธŒ์—์„œ ๋ชจ๋ธ์„ ์ž๋™์œผ๋กœ ๋‹ค์šด๋ฐ›์•„์„œ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด.

๐Ÿ“Œ pipeline()์˜ ์ฃผ์š” ํŒŒ๋ผ๋ฏธํ„ฐ

task: ์ˆ˜ํ–‰ํ•  ํƒœ์Šคํฌ ์ข…๋ฅ˜ (์˜ˆ: "translation", "text-generation", "sentiment-analysis")
model: ์‚ฌ์šฉํ•  ๋ชจ๋ธ ์ด๋ฆ„ (ํ—ˆ๊น…ํŽ˜์ด์Šค ํ—ˆ๋ธŒ์˜ ๋ชจ๋ธ ID)
device: ์‹คํ–‰ ์žฅ์น˜ (0 = GPU ์ฒซ ๋ฒˆ์งธ, -1 = CPU)
max_length: ์ถœ๋ ฅ ์ตœ๋Œ€ ๊ธธ์ด ์„ค์ • ๊ฐ€๋Šฅ

๐ŸŒ ๋‹ค์–‘ํ•œ ์–ธ์–ด ์Œ ๋ฒˆ์—ญ ๋ชจ๋ธ

ํ—ˆ๊น…ํŽ˜์ด์Šค ํ—ˆ๋ธŒ์—๋Š” Helsinki-NLP ๊ทธ๋ฃน์ด ๋งŒ๋“  ์ˆ˜๋ฐฑ ๊ฐœ์˜ ๋ฒˆ์—ญ ๋ชจ๋ธ์ด ์žˆ์–ด.
๋ชจ๋ธ ์ด๋ฆ„ ๊ทœ์น™์€ Helsinki-NLP/opus-mt-{์†Œ์Šค์–ธ์–ด}-{ํƒ€๊ฒŸ์–ธ์–ด} ํ˜•์‹์ด์•ผ.

๐Ÿ—บ๏ธ ์ž์ฃผ ์“ฐ๋Š” ๋ฒˆ์—ญ ๋ชจ๋ธ ๋ชฉ๋ก

ํ•œโ†’์˜ Helsinki-NLP/opus-mt-ko-en

์˜โ†’ํ•œ Helsinki-NLP/opus-mt-en-ko

์˜โ†’์ผ Helsinki-NLP/opus-mt-en-jap

์˜โ†’์ค‘ Helsinki-NLP/opus-mt-en-zh

์˜โ†’ํ”„ Helsinki-NLP/opus-mt-en-fr

์˜โ†’๋… Helsinki-NLP/opus-mt-en-de

์˜โ†’์ŠคํŽ˜์ธ Helsinki-NLP/opus-mt-en-es
python
# ์˜์–ด โ†’ ํ•œ๊ตญ์–ด ๋ฒˆ์—ญ
translator_en_ko = pipeline(
    task="translation",
    model="Helsinki-NLP/opus-mt-en-ko"
)

text = "Artificial intelligence is changing the world rapidly."
result = translator_en_ko(text)
print(result[0]['translation_text'])
# ์ถœ๋ ฅ: ์ธ๊ณต์ง€๋Šฅ์ด ์„ธ์ƒ์„ ๋น ๋ฅด๊ฒŒ ๋ณ€ํ™”์‹œํ‚ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”ฌ ๋” ๊นŠ์ด ํŒŒ๊ณ ๋“ค๊ธฐ: ๋ชจ๋ธ๊ณผ ํ† ํฌ๋‚˜์ด์ € ์ง์ ‘ ๋‹ค๋ฃจ๊ธฐ

pipeline()์ด ํŽธํ•˜๊ธด ํ•œ๋ฐ, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋” ์„ธ๋ฐ€ํ•œ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•  ๋•Œ๊ฐ€ ๋งŽ์•„.
๊ทธ๋Ÿด ๋•Œ๋Š” ๋ชจ๋ธ(Model)๊ณผ ํ† ํฌ๋‚˜์ด์ €(Tokenizer)๋ฅผ ์ง์ ‘ ๋ถˆ๋Ÿฌ์™€์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์จ์•ผ ํ•ด.

๐Ÿ’ก ํ† ํฌ๋‚˜์ด์ €(Tokenizer)๋ž€?
ํ…์ŠคํŠธ๋ฅผ ๋ชจ๋ธ์ด ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์ˆซ์ž(ํ† ํฐ ID)๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋„๊ตฌ์•ผ.
์˜ˆ๋ฅผ ๋“ค์–ด "์•ˆ๋…•ํ•˜์„ธ์š”"๋ผ๋Š” ๋‹จ์–ด๊ฐ€ [1234, 5678, 9012] ๊ฐ™์€ ์ˆซ์ž ๋ฐฐ์—ด๋กœ ๋ฐ”๋€Œ๋Š” ๊ฑฐ์ง€.
๋ฒˆ์—ญ ๋ชจ๋ธ๋งˆ๋‹ค ์ž๊ธฐ๋งŒ์˜ ํ† ํฌ๋‚˜์ด์ €๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์„œ, ๋ฐ˜๋“œ์‹œ ๊ฐ™์€ ๋ชจ๋ธ์˜ ํ† ํฌ๋‚˜์ด์ €๋ฅผ ์จ์•ผ ํ•ด!
python
from transformers import MarianMTModel, MarianTokenizer

# ๋ชจ๋ธ ์ด๋ฆ„ ์„ค์ •
model_name = "Helsinki-NLP/opus-mt-ko-en"

# ํ† ํฌ๋‚˜์ด์ €์™€ ๋ชจ๋ธ ๋กœ๋“œ
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)

# ๋ฒˆ์—ญํ•  ํ…์ŠคํŠธ
texts = [
    "์˜ค๋Š˜์€ ์ •๋ง ์ข‹์€ ๋‚ ์ด์—์š”.",
    "ํŒŒ์ด์ฌ์œผ๋กœ AI๋ฅผ ๋งŒ๋“œ๋Š” ๊ฑด ์ƒ๊ฐ๋ณด๋‹ค ์‰ฌ์›Œ์š”!"
]

# ํ† ํฌ๋‚˜์ด์ง• (ํ…์ŠคํŠธ โ†’ ํ† ํฐ ID)
inputs = tokenizer(
    texts,
    return_tensors="pt",   # PyTorch ํ…์„œ ํ˜•์‹
    padding=True,          # ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ํŒจ๋”ฉ
    truncation=True,       # ์ตœ๋Œ€ ๊ธธ์ด ์ดˆ๊ณผ ์‹œ ์ž๋ฅด๊ธฐ
    max_length=512
)

print("ํ† ํฐ ID ์˜ˆ์‹œ:", inputs['input_ids'][0][:10])
# ์ถœ๋ ฅ: tensor([  234,  1234,  5678, ...])
python
# ๋ชจ๋ธ๋กœ ๋ฒˆ์—ญ ์ƒ์„ฑ
import torch

with torch.no_grad():  # ์ถ”๋ก  ์‹œ ๊ทธ๋ž˜๋””์–ธํŠธ ๊ณ„์‚ฐ ๋ถˆํ•„์š”
    translated_tokens = model.generate(
        **inputs,
        max_length=512,
        num_beams=4,        # ๋น” ์„œ์น˜: 4๊ฐœ ํ›„๋ณด ํƒ์ƒ‰
        early_stopping=True
    )

# ํ† ํฐ ID โ†’ ํ…์ŠคํŠธ๋กœ ๋””์ฝ”๋”ฉ
translated_texts = tokenizer.batch_decode(
    translated_tokens,
    skip_special_tokens=True  # [PAD], [EOS] ๊ฐ™์€ ํŠน์ˆ˜ ํ† ํฐ ์ œ๊ฑฐ
)

for original, translated in zip(texts, translated_texts):
    print(f"์›๋ฌธ: {original}")
    print(f"๋ฒˆ์—ญ: {translated}")
    print("---")
โšก num_beams ํŒŒ๋ผ๋ฏธํ„ฐ ์ดํ•ดํ•˜๊ธฐ

num_beams=1: Greedy Search โ€” ๋งค ์Šคํ…๋งˆ๋‹ค ๊ฐ€์žฅ ํ™•๋ฅ  ๋†’์€ ๋‹จ์–ด ํ•˜๋‚˜๋งŒ ์„ ํƒ. ๋น ๋ฅด์ง€๋งŒ ํ’ˆ์งˆ ๋‚ฎ์Œ.

num_beams=4: Beam Search โ€” 4๊ฐœ์˜ ํ›„๋ณด ๊ฒฝ๋กœ๋ฅผ ๋™์‹œ์— ํƒ์ƒ‰. ๋” ์ž์—ฐ์Šค๋Ÿฌ์šด ๋ฒˆ์—ญ ๊ฒฐ๊ณผ.

num_beams=8: ๋” ๋งŽ์€ ํ›„๋ณด ํƒ์ƒ‰. ํ’ˆ์งˆ์€ ์˜ฌ๋ผ๊ฐ€์ง€๋งŒ ์†๋„๊ฐ€ ๋А๋ ค์ ธ.

์ผ๋ฐ˜์ ์œผ๋กœ 4~6 ์ •๋„๊ฐ€ ํ’ˆ์งˆ๊ณผ ์†๋„์˜ ๊ท ํ˜•์ด ์ข‹์•„! ๐ŸŽฏ
๐Ÿ”„ ๋ฒˆ์—ญ AI ์ฒ˜๋ฆฌ ํ๋ฆ„ (์ƒ์„ธ) โ‘  ์ž…๋ ฅ ์›๋ฌธ ํ…์ŠคํŠธ ํ•œ๊ตญ์–ด ๋ฌธ์žฅ โ‘ก ํ† ํฌ๋‚˜์ด์ง• ํ…์ŠคํŠธ โ†’ ์ˆซ์ž [234, 567, ...] โ‘ข ๋ชจ๋ธ ์ถ”๋ก  MarianMT Encoder-Decoder Beam Search โ‘ฃ ๋””์ฝ”๋”ฉ ์ˆซ์ž โ†’ ํ…์ŠคํŠธ ์˜์–ด ํ† ํฐ ๋ณ€ํ™˜ โ‘ค ์ถœ๋ ฅ ๋ฒˆ์—ญ ๊ฒฐ๊ณผ ์˜์–ด ๋ฌธ์žฅ ์ „์ฒด ๊ณผ์ •์ด ์ž๋™ํ™”๋˜์–ด ์žˆ์–ด์„œ pipeline()์œผ๋กœ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ! ์ง์ ‘ ์ œ์–ดํ•  ๋•Œ๋Š” ๊ฐ ๋‹จ๊ณ„๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์–ด ๐ŸŽ›๏ธ

๐ŸŽฏ ์‹ค์ „ ํ”„๋กœ์ ํŠธ: ๋‹ค๊ตญ์–ด ๋ฒˆ์—ญ๊ธฐ ๋งŒ๋“ค๊ธฐ

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

python
from transformers import pipeline
from typing import Optional

class MultilingualTranslator:
    """๋‹ค๊ตญ์–ด ๋ฒˆ์—ญ๊ธฐ ํด๋ž˜์Šค"""
    
    # ์ง€์› ์–ธ์–ด ์Œ ์ •์˜
    SUPPORTED_MODELS = {
        ('ko', 'en'): 'Helsinki-NLP/opus-mt-ko-en',
        ('en', 'ko'): 'Helsinki-NLP/opus-mt-en-ko',
        ('en', 'fr'): 'Helsinki-NLP/opus-mt-en-fr',
        ('en', 'de'): 'Helsinki-NLP/opus-mt-en-de',
        ('en', 'es'): 'Helsinki-NLP/opus-mt-en-es',
        ('en', 'ja'): 'Helsinki-NLP/opus-mt-en-jap',
        ('en', 'zh'): 'Helsinki-NLP/opus-mt-en-zh',
        ('fr', 'en'): 'Helsinki-NLP/opus-mt-fr-en',
        ('de', 'en'): 'Helsinki-NLP/opus-mt-de-en',
    }
    
    def __init__(self):
        self.loaded_models = {}  # ์บ์‹œ: ํ•œ ๋ฒˆ ๋กœ๋“œํ•œ ๋ชจ๋ธ ์žฌ์‚ฌ์šฉ
    
    def translate(
        self,
        text: str,
        source_lang: str,
        target_lang: str,
        max_length: int = 512
    ) -> Optional[str]:
        """
        ํ…์ŠคํŠธ๋ฅผ ๋ฒˆ์—ญํ•˜๋Š” ๋ฉ”์ธ ํ•จ์ˆ˜
        
        Args:
            text: ๋ฒˆ์—ญํ•  ํ…์ŠคํŠธ
            source_lang: ์†Œ์Šค ์–ธ์–ด ์ฝ”๋“œ (์˜ˆ: 'ko', 'en')
            target_lang: ํƒ€๊ฒŸ ์–ธ์–ด ์ฝ”๋“œ (์˜ˆ: 'en', 'fr')
            max_length: ์ตœ๋Œ€ ์ถœ๋ ฅ ๊ธธ์ด
        
        Returns:
            ๋ฒˆ์—ญ๋œ ํ…์ŠคํŠธ ๋˜๋Š” None (์ง€์›ํ•˜์ง€ ์•Š๋Š” ์–ธ์–ด ์Œ)
        """
        lang_pair = (source_lang, target_lang)
        
        # ์ง€์› ์—ฌ๋ถ€ ํ™•์ธ
        if lang_pair not in self.SUPPORTED_MODELS:
            print(f"โŒ '{source_lang}' โ†’ '{target_lang}' ๋ฒˆ์—ญ์€ ์ง€์›ํ•˜์ง€ ์•Š์•„์š”.")
            return None
        
        model_name = self.SUPPORTED_MODELS[lang_pair]
        
        # ๋ชจ๋ธ ์บ์‹œ ํ™•์ธ (์ด๋ฏธ ๋กœ๋“œ๋œ ๋ชจ๋ธ์€ ์žฌ์‚ฌ์šฉ)
        if model_name not in self.loaded_models:
            print(f"โณ ๋ชจ๋ธ ๋กœ๋”ฉ ์ค‘: {model_name}")
            self.loaded_models[model_name] = pipeline(
                task="translation",
                model=model_name,
                max_length=max_length
            )
            print(f"โœ… ๋ชจ๋ธ ๋กœ๋“œ ์™„๋ฃŒ!")
        
        translator = self.loaded_models[model_name]
        result = translator(text, max_length=max_length)
        return result[0]['translation_text']
    
    def get_supported_pairs(self):
        """์ง€์›ํ•˜๋Š” ์–ธ์–ด ์Œ ๋ชฉ๋ก ์ถœ๋ ฅ"""
        print("๐ŸŒ ์ง€์›ํ•˜๋Š” ๋ฒˆ์—ญ ์–ธ์–ด ์Œ:")
        for (src, tgt) in self.SUPPORTED_MODELS.keys():
            print(f"  {src} โ†’ {tgt}")


# ์‚ฌ์šฉ ์˜ˆ์‹œ
translator = MultilingualTranslator()

# ํ•œ๊ตญ์–ด โ†’ ์˜์–ด
result1 = translator.translate(
    "์žฌ๋Šฅ๋„ท์—์„œ AI ๋ฒˆ์—ญ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์‹ถ์–ด์š”!",
    source_lang='ko',
    target_lang='en'
)
print(f"๋ฒˆ์—ญ ๊ฒฐ๊ณผ: {result1}")

# ์˜์–ด โ†’ ํ”„๋ž‘์Šค์–ด
result2 = translator.translate(
    "Machine learning is fascinating!",
    source_lang='en',
    target_lang='fr'
)
print(f"๋ฒˆ์—ญ ๊ฒฐ๊ณผ: {result2}")
๐Ÿง  ์ฝ”๋“œ ํ•ต์‹ฌ ํฌ์ธํŠธ ์ •๋ฆฌ

๋ชจ๋ธ ์บ์‹ฑ: ํ•œ ๋ฒˆ ๋กœ๋“œํ•œ ๋ชจ๋ธ์„ ๋”•์…”๋„ˆ๋ฆฌ์— ์ €์žฅํ•ด์„œ ์žฌ์‚ฌ์šฉํ•ด. ๋งค๋ฒˆ ๋‹ค์šด๋กœ๋“œํ•˜๋ฉด ์‹œ๊ฐ„์ด ๋„ˆ๋ฌด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ฑฐ๋“ !

ํƒ€์ž… ํžŒํŒ…: Optional[str] ๊ฐ™์€ ํƒ€์ž… ํžŒํŠธ๋ฅผ ์จ์„œ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์„ ๋†’์˜€์–ด.

ํด๋ž˜์Šค ์„ค๊ณ„: ๋ฒˆ์—ญ๊ธฐ๋ฅผ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค๋ฉด ์—ฌ๋Ÿฌ ์–ธ์–ด ์Œ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ํ›จ์”ฌ ํŽธํ•ด.

๐Ÿ“Š ๋ฒˆ์—ญ ํ’ˆ์งˆ ํ‰๊ฐ€: BLEU ์Šค์ฝ”์–ด ์ดํ•ดํ•˜๊ธฐ

๋ฒˆ์—ญ AI๋ฅผ ๋งŒ๋“ค์—ˆ์œผ๋ฉด "์ด ๋ฒˆ์—ญ์ด ์–ผ๋งˆ๋‚˜ ์ข‹์€๊ฐ€?"๋ฅผ ์ธก์ •ํ•ด์•ผ๊ฒ ์ง€? ๐Ÿค”
๋ฒˆ์—ญ ํ’ˆ์งˆ ํ‰๊ฐ€์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์“ฐ์ด๋Š” ์ง€ํ‘œ๊ฐ€ ๋ฐ”๋กœ BLEU(Bilingual Evaluation Understudy) ์Šค์ฝ”์–ด์•ผ.

๐Ÿ“ BLEU ์Šค์ฝ”์–ด๋ž€?

๊ธฐ๊ณ„ ๋ฒˆ์—ญ ๊ฒฐ๊ณผ์™€ ์‚ฌ๋žŒ์ด ์ž‘์„ฑํ•œ ์ฐธ์กฐ ๋ฒˆ์—ญ(Reference Translation)์„ ๋น„๊ตํ•ด์„œ ์œ ์‚ฌ๋„๋ฅผ 0~1 ์‚ฌ์ด ์ ์ˆ˜๋กœ ๋‚˜ํƒ€๋‚ด๋Š” ์ง€ํ‘œ์•ผ.

๊ณ„์‚ฐ ์›๋ฆฌ: n-gram(์—ฐ์†๋œ n๊ฐœ์˜ ๋‹จ์–ด) ๋‹จ์œ„๋กœ ์–ผ๋งˆ๋‚˜ ๊ฒน์น˜๋Š”์ง€ ์ธก์ •ํ•ด.

์˜ˆ๋ฅผ ๋“ค์–ด ๊ธฐ๊ณ„ ๋ฒˆ์—ญ: "The cat sat on the mat"
์ฐธ์กฐ ๋ฒˆ์—ญ: "The cat is sitting on the mat"
โ†’ ๊ฒน์น˜๋Š” ๋‹จ์–ด๋“ค์˜ ๋น„์œจ์„ ๊ณ„์‚ฐํ•ด์„œ ์ ์ˆ˜๋ฅผ ๋งค๊ฒจ!

์ ์ˆ˜ ํ•ด์„:
0.0 ~ 0.1 โ†’ ๊ฑฐ์˜ ์“ธ๋ชจ์—†๋Š” ๋ฒˆ์—ญ ๐Ÿ˜ข
0.1 ~ 0.3 โ†’ ์–ด๋А ์ •๋„ ์ดํ•ด ๊ฐ€๋Šฅ
0.3 ~ 0.5 โ†’ ๊ฝค ์ข‹์€ ๋ฒˆ์—ญ ๐Ÿ‘
0.5 ์ด์ƒ โ†’ ์ „๋ฌธ๊ฐ€ ์ˆ˜์ค€ ๋ฒˆ์—ญ ๐Ÿ†
python
# BLEU ์Šค์ฝ”์–ด ๊ณ„์‚ฐ ์‹ค์Šต
# ๋จผ์ € sacrebleu ์„ค์น˜: pip install sacrebleu

import sacrebleu

# ๊ธฐ๊ณ„ ๋ฒˆ์—ญ ๊ฒฐ๊ณผ (hypothesis)
hypothesis = ["The weather today is really nice."]

# ์‚ฌ๋žŒ์ด ์ž‘์„ฑํ•œ ์ฐธ์กฐ ๋ฒˆ์—ญ (reference)
reference = ["The weather is very nice today."]

# BLEU ์Šค์ฝ”์–ด ๊ณ„์‚ฐ
bleu = sacrebleu.corpus_bleu(hypothesis, [reference])
print(f"BLEU ์Šค์ฝ”์–ด: {bleu.score:.2f}")
# ์ถœ๋ ฅ: BLEU ์Šค์ฝ”์–ด: 42.35 (0~100 ์Šค์ผ€์ผ๋กœ๋„ ํ‘œํ˜„ ๊ฐ€๋Šฅ)
โš ๏ธ BLEU์˜ ํ•œ๊ณ„
BLEU๋Š” ๋‹จ์–ด ๊ฒน์นจ๋งŒ ๋ณด๊ธฐ ๋•Œ๋ฌธ์—, ์˜๋ฏธ๋Š” ๊ฐ™์ง€๋งŒ ํ‘œํ˜„์ด ๋‹ค๋ฅธ ๋ฒˆ์—ญ์€ ๋‚ฎ์€ ์ ์ˆ˜๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด.
์˜ˆ๋ฅผ ๋“ค์–ด "I'm happy" = "I feel joyful"์€ ์˜๋ฏธ๊ฐ€ ๊ฐ™์ง€๋งŒ BLEU ์ ์ˆ˜๋Š” ๋‚ฎ๊ฒŒ ๋‚˜์™€.
๊ทธ๋ž˜์„œ ์ตœ๊ทผ์—๋Š” COMET, BERTScore ๊ฐ™์€ ๋” ๋ฐœ์ „๋œ ํ‰๊ฐ€ ์ง€ํ‘œ๋„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด!

โšก ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ฟ€ํŒ ๋ชจ์Œ

๋ฒˆ์—ญ AI๋ฅผ ์‹ค์ œ ์„œ๋น„์Šค์— ์“ฐ๋ ค๋ฉด ์†๋„์™€ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ๋„ ์ค‘์š”ํ•ด.
๋ช‡ ๊ฐ€์ง€ ์‹ค์šฉ์ ์ธ ์ตœ์ ํ™” ๋ฐฉ๋ฒ•์„ ์•Œ๋ ค์ค„๊ฒŒ! ๐Ÿš€

1๏ธโƒฃ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ(Batch Processing)

์—ฌ๋Ÿฌ ๋ฌธ์žฅ์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋ฉด ํ›จ์”ฌ ๋น ๋ฅด๊ฒŒ ๋ฒˆ์—ญํ•  ์ˆ˜ ์žˆ์–ด.

python
from transformers import pipeline

translator = pipeline(
    "translation",
    model="Helsinki-NLP/opus-mt-ko-en",
    device=0  # GPU ์‚ฌ์šฉ (์—†์œผ๋ฉด -1)
)

# โŒ ๋น„ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•: ํ•˜๋‚˜์”ฉ ๋ฒˆ์—ญ
texts = ["์•ˆ๋…•ํ•˜์„ธ์š”", "์˜ค๋Š˜ ๋‚ ์”จ๊ฐ€ ์ข‹์•„์š”", "ํŒŒ์ด์ฌ์€ ์žฌ๋ฏธ์žˆ์–ด์š”"]
results_slow = [translator(text) for text in texts]

# โœ… ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•: ๋ฐฐ์น˜๋กœ ํ•œ ๋ฒˆ์— ๋ฒˆ์—ญ
results_fast = translator(
    texts,
    batch_size=8  # ํ•œ ๋ฒˆ์— 8๊ฐœ์”ฉ ์ฒ˜๋ฆฌ
)

print("๋ฐฐ์น˜ ๋ฒˆ์—ญ ๊ฒฐ๊ณผ:")
for text, result in zip(texts, results_fast):
    print(f"  {text} โ†’ {result[0]['translation_text']}")

2๏ธโƒฃ ๋ชจ๋ธ ์–‘์žํ™”(Quantization)

๋ชจ๋ธ ํฌ๊ธฐ๋ฅผ ์ค„์—ฌ์„œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ๋‚ฎ์ถ”๊ณ  ์†๋„๋ฅผ ๋†’์ด๋Š” ๊ธฐ๋ฒ•์ด์•ผ.

python
import torch
from transformers import MarianMTModel, MarianTokenizer

model_name = "Helsinki-NLP/opus-mt-ko-en"
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)

# ๋™์  ์–‘์žํ™” ์ ์šฉ (CPU์—์„œ ํšจ๊ณผ์ )
quantized_model = torch.quantization.quantize_dynamic(
    model,
    {torch.nn.Linear},  # Linear ๋ ˆ์ด์–ด๋งŒ ์–‘์žํ™”
    dtype=torch.qint8   # 8๋น„ํŠธ ์ •์ˆ˜๋กœ ๋ณ€ํ™˜
)

# ๋ชจ๋ธ ํฌ๊ธฐ ๋น„๊ต
import os
torch.save(model.state_dict(), 'original_model.pt')
torch.save(quantized_model.state_dict(), 'quantized_model.pt')

original_size = os.path.getsize('original_model.pt') / 1024 / 1024
quantized_size = os.path.getsize('quantized_model.pt') / 1024 / 1024

print(f"์›๋ณธ ๋ชจ๋ธ ํฌ๊ธฐ: {original_size:.1f} MB")
print(f"์–‘์žํ™” ๋ชจ๋ธ ํฌ๊ธฐ: {quantized_size:.1f} MB")
print(f"ํฌ๊ธฐ ๊ฐ์†Œ: {(1 - quantized_size/original_size)*100:.1f}%")
๐Ÿ’พ ์–‘์žํ™”์˜ ํšจ๊ณผ

์ผ๋ฐ˜์ ์œผ๋กœ FP32(32๋น„ํŠธ ๋ถ€๋™์†Œ์ˆ˜์ ) โ†’ INT8(8๋น„ํŠธ ์ •์ˆ˜)๋กœ ์–‘์žํ™”ํ•˜๋ฉด:

๐Ÿ“ฆ ๋ชจ๋ธ ํฌ๊ธฐ: ์•ฝ 75% ๊ฐ์†Œ
โšก ์ถ”๋ก  ์†๋„: CPU์—์„œ 2~4๋ฐฐ ํ–ฅ์ƒ
๐ŸŽฏ ๋ฒˆ์—ญ ํ’ˆ์งˆ: ์•ฝ๊ฐ„ ์ €ํ•˜๋˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„ ํ—ˆ์šฉ ๊ฐ€๋Šฅํ•œ ์ˆ˜์ค€

3๏ธโƒฃ ๊ธด ํ…์ŠคํŠธ ์ฒ˜๋ฆฌ: ์ฒญํฌ ๋ถ„ํ• 

๋ฒˆ์—ญ ๋ชจ๋ธ์€ ๋ณดํ†ต ์ตœ๋Œ€ 512 ํ† ํฐ๊นŒ์ง€๋งŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด.
๊ธด ๋ฌธ์„œ๋ฅผ ๋ฒˆ์—ญํ•  ๋•Œ๋Š” ์ ์ ˆํžˆ ๋ถ„ํ• ํ•ด์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ด.

python
def translate_long_text(text, translator, max_chunk_length=400):
    """
    ๊ธด ํ…์ŠคํŠธ๋ฅผ ๋ฌธ์žฅ ๋‹จ์œ„๋กœ ๋ถ„ํ• ํ•ด์„œ ๋ฒˆ์—ญํ•˜๋Š” ํ•จ์ˆ˜
    """
    # ๋ฌธ์žฅ ๋‹จ์œ„๋กœ ๋ถ„ํ•  (๋งˆ์นจํ‘œ, ๋А๋‚Œํ‘œ, ๋ฌผ์Œํ‘œ ๊ธฐ์ค€)
    import re
    sentences = re.split(r'(?<=[.!?])\s+', text)
    
    chunks = []
    current_chunk = []
    current_length = 0
    
    for sentence in sentences:
        sentence_length = len(sentence)
        
        if current_length + sentence_length > max_chunk_length:
            if current_chunk:
                chunks.append(' '.join(current_chunk))
            current_chunk = [sentence]
            current_length = sentence_length
        else:
            current_chunk.append(sentence)
            current_length += sentence_length
    
    if current_chunk:
        chunks.append(' '.join(current_chunk))
    
    # ๊ฐ ์ฒญํฌ ๋ฒˆ์—ญ ํ›„ ํ•ฉ์น˜๊ธฐ
    translated_chunks = []
    for i, chunk in enumerate(chunks):
        print(f"์ฒญํฌ {i+1}/{len(chunks)} ๋ฒˆ์—ญ ์ค‘...")
        result = translator(chunk)
        translated_chunks.append(result[0]['translation_text'])
    
    return ' '.join(translated_chunks)


# ์‚ฌ์šฉ ์˜ˆ์‹œ
long_text = """
์ธ๊ณต์ง€๋Šฅ์€ ํ˜„๋Œ€ ์‚ฌํšŒ์—์„œ ๋งค์šฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
ํŠนํžˆ ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ ๋ถ„์•ผ์—์„œ ํฐ ๋ฐœ์ „์ด ์ด๋ฃจ์–ด์กŒ์Šต๋‹ˆ๋‹ค.
๋ฒˆ์—ญ, ์š”์•ฝ, ์งˆ์˜์‘๋‹ต ๋“ฑ ๋‹ค์–‘ํ•œ ํƒœ์Šคํฌ์—์„œ ์ธ๊ฐ„ ์ˆ˜์ค€์˜ ์„ฑ๋Šฅ์„ ๋ณด์ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์•ž์œผ๋กœ๋„ AI ๊ธฐ์ˆ ์€ ๊ณ„์† ๋ฐœ์ „ํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค.
"""

from transformers import pipeline
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ko-en")
result = translate_long_text(long_text.strip(), translator)
print("๋ฒˆ์—ญ ๊ฒฐ๊ณผ:")
print(result)

๐ŸŒŸ ํŒŒ์ธํŠœ๋‹: ๋‚˜๋งŒ์˜ ๋ฒˆ์—ญ ๋ชจ๋ธ ๋งŒ๋“ค๊ธฐ

๊ธฐ์กด ๋ชจ๋ธ์„ ๊ทธ๋Œ€๋กœ ์“ฐ๋Š” ๊ฒƒ๋„ ์ข‹์ง€๋งŒ, ํŠน์ • ๋„๋ฉ”์ธ(์˜ํ•™, ๋ฒ•๋ฅ , IT ๋“ฑ)์— ํŠนํ™”๋œ ๋ฒˆ์—ญ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด
ํŒŒ์ธํŠœ๋‹(Fine-tuning)์„ ํ•ด์•ผ ํ•ด!
์‚ฌ์ „ํ•™์Šต๋œ ๋ชจ๋ธ์„ ๋‚ด ๋ฐ์ดํ„ฐ๋กœ ์ถ”๊ฐ€ ํ•™์Šต์‹œํ‚ค๋Š” ๊ฑฐ์•ผ. ๐ŸŽ“

๐Ÿ“š ํŒŒ์ธํŠœ๋‹์— ํ•„์š”ํ•œ ๊ฒƒ๋“ค

๋ณ‘๋ ฌ ์ฝ”ํผ์Šค (์›๋ฌธ-๋ฒˆ์—ญ๋ฌธ ์Œ) GPU (์ตœ์†Œ 8GB VRAM ๊ถŒ์žฅ) datasets ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ Seq2SeqTrainer

๋ณ‘๋ ฌ ์ฝ”ํผ์Šค๋ž€ ์›๋ฌธ๊ณผ ๋ฒˆ์—ญ๋ฌธ์ด ์Œ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๋ฐ์ดํ„ฐ์…‹์ด์•ผ.
์˜ˆ: "์•ˆ๋…•ํ•˜์„ธ์š”" โ†” "Hello" ์ด๋Ÿฐ ์‹์œผ๋กœ ์ˆ˜๋งŒ~์ˆ˜๋ฐฑ๋งŒ ์Œ์ด ํ•„์š”ํ•ด.
python
from transformers import (
    MarianMTModel,
    MarianTokenizer,
    Seq2SeqTrainer,
    Seq2SeqTrainingArguments,
    DataCollatorForSeq2Seq
)
from datasets import Dataset
import pandas as pd

# 1. ํ•™์Šต ๋ฐ์ดํ„ฐ ์ค€๋น„ (์˜ˆ์‹œ: IT ๋„๋ฉ”์ธ ๋ฒˆ์—ญ ๋ฐ์ดํ„ฐ)
train_data = {
    'ko': [
        "ํŒŒ์ด์ฌ์€ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ž…๋‹ˆ๋‹ค.",
        "๋”ฅ๋Ÿฌ๋‹ ๋ชจ๋ธ์„ ํ•™์Šต์‹œํ‚ค๋ ค๋ฉด GPU๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.",
        "API๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ธํ„ฐํŽ˜์ด์Šค์˜ ์•ฝ์ž์ž…๋‹ˆ๋‹ค.",
        # ... ์‹ค์ œ๋กœ๋Š” ์ˆ˜์ฒœ~์ˆ˜๋งŒ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•ด!
    ],
    'en': [
        "Python is an object-oriented programming language.",
        "A GPU is needed to train deep learning models.",
        "API stands for Application Programming Interface.",
    ]
}

df = pd.DataFrame(train_data)
dataset = Dataset.from_pandas(df)

# 2. ๋ชจ๋ธ๊ณผ ํ† ํฌ๋‚˜์ด์ € ๋กœ๋“œ
model_name = "Helsinki-NLP/opus-mt-ko-en"
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)

# 3. ๋ฐ์ดํ„ฐ ์ „์ฒ˜๋ฆฌ ํ•จ์ˆ˜
def preprocess_function(examples):
    inputs = tokenizer(
        examples['ko'],
        max_length=128,
        truncation=True,
        padding=False
    )
    
    with tokenizer.as_target_tokenizer():
        targets = tokenizer(
            examples['en'],
            max_length=128,
            truncation=True,
            padding=False
        )
    
    inputs['labels'] = targets['input_ids']
    return inputs

# ๋ฐ์ดํ„ฐ์…‹ ์ „์ฒ˜๋ฆฌ
tokenized_dataset = dataset.map(
    preprocess_function,
    batched=True,
    remove_columns=['ko', 'en']
)

# 4. ํ•™์Šต ์„ค์ •
training_args = Seq2SeqTrainingArguments(
    output_dir="./my-ko-en-translator",
    num_train_epochs=3,
    per_device_train_batch_size=8,
    warmup_steps=100,
    weight_decay=0.01,
    logging_dir="./logs",
    logging_steps=10,
    save_strategy="epoch",
    predict_with_generate=True,
    fp16=True,  # ํ˜ผํ•ฉ ์ •๋ฐ€๋„ ํ•™์Šต (GPU ํ•„์š”)
    learning_rate=5e-5,
)

# 5. ๋ฐ์ดํ„ฐ ์ฝœ๋ ˆ์ดํ„ฐ ์„ค์ •
data_collator = DataCollatorForSeq2Seq(
    tokenizer,
    model=model,
    padding=True
)

# 6. ํŠธ๋ ˆ์ด๋„ˆ ์ƒ์„ฑ ๋ฐ ํ•™์Šต ์‹œ์ž‘
trainer = Seq2SeqTrainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset,
    data_collator=data_collator,
    tokenizer=tokenizer,
)

print("๐Ÿš€ ํŒŒ์ธํŠœ๋‹ ์‹œ์ž‘!")
trainer.train()
print("โœ… ํŒŒ์ธํŠœ๋‹ ์™„๋ฃŒ!")

# 7. ํŒŒ์ธํŠœ๋‹๋œ ๋ชจ๋ธ ์ €์žฅ
trainer.save_model("./my-ko-en-translator-final")
tokenizer.save_pretrained("./my-ko-en-translator-final")
๐Ÿ’ก ํŒŒ์ธํŠœ๋‹ ๊ฟ€ํŒ!
๋ฐ์ดํ„ฐ๊ฐ€ ์ ์„ ๋•Œ๋Š” ํ•™์Šต๋ฅ (learning_rate)์„ ๋‚ฎ๊ฒŒ ์„ค์ •ํ•ด์•ผ ํ•ด. (1e-5 ~ 5e-5 ๊ถŒ์žฅ)
๋„ˆ๋ฌด ๋†’์œผ๋ฉด ๊ธฐ์กด์— ํ•™์Šต๋œ ์ง€์‹์„ ์žŠ์–ด๋ฒ„๋ฆฌ๋Š” Catastrophic Forgetting์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด!
๊ทธ๋ฆฌ๊ณ  Early Stopping์„ ํ™œ์šฉํ•ด์„œ ๊ณผ์ ํ•ฉ์„ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•ด.
๐ŸŽ“ ํŒŒ์ธํŠœ๋‹(Fine-tuning) ๊ฐœ๋…๋„ ์‚ฌ์ „ํ•™์Šต ๋ชจ๋ธ Helsinki-NLP opus-mt-ko-en ์ˆ˜๋ฐฑ๋งŒ ๋ฌธ์žฅ์œผ๋กœ ํ•™์Šต๋จ ์ผ๋ฐ˜ ๋ฒˆ์—ญ ๋Šฅ๋ ฅ ๋ณด์œ  ๐Ÿง  ๋‚ด ๋„๋ฉ”์ธ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€ ํ•™์Šต ๐Ÿ”ฅ ํŒŒ์ธํŠœ๋‹ ์ค‘ Epoch 1/3 Loss: 2.34 โ†’ 0.87 ๊ฐ€์ค‘์น˜ ์—…๋ฐ์ดํŠธ ๋„๋ฉ”์ธ ์ ์‘ ์ค‘... โš™๏ธ ํŒŒ์ธํŠœ๋‹ ์™„๋ฃŒ! ๋‚˜๋งŒ์˜ ๋ฒˆ์—ญ ๋ชจ๋ธ ๐ŸŽ‰ IT ๋„๋ฉ”์ธ ๋ฒˆ์—ญ ํŠนํ™” ์ „๋ฌธ ์šฉ์–ด ์ •ํ™•๋„ ํ–ฅ์ƒ ๋„๋ฉ”์ธ ํŠนํ™” ํ‘œํ˜„ ํ•™์Šต ์‚ฌ์ „ํ•™์Šต ๋ชจ๋ธ์˜ ์ง€์‹์„ ์œ ์ง€ํ•˜๋ฉด์„œ ๋‚ด ๋ฐ์ดํ„ฐ๋กœ ์ถ”๊ฐ€ ํ•™์Šต! ์ฒ˜์Œ๋ถ€ํ„ฐ ํ•™์Šตํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ์ ์€ ๋ฐ์ดํ„ฐ์™€ ์‹œ๊ฐ„์œผ๋กœ ๊ฐ€๋Šฅํ•ด ๐Ÿš€

๐ŸŒ ์›น API๋กœ ๋ฐฐํฌํ•˜๊ธฐ: FastAPI ์—ฐ๋™

๋ฒˆ์—ญ ๋ชจ๋ธ์„ ๋งŒ๋“ค์—ˆ์œผ๋ฉด ์‹ค์ œ๋กœ ์„œ๋น„์Šค๋กœ ๋ฐฐํฌํ•ด์•ผ๊ฒ ์ง€? ๐Ÿš€
FastAPI๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฒˆ์—ญ AI๋ฅผ REST API๋กœ ๋น ๋ฅด๊ฒŒ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์–ด.
์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ AI ๋ฒˆ์—ญ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด!

bash
pip install fastapi uvicorn
python (main.py)
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from transformers import pipeline
from typing import Optional
import time

app = FastAPI(
    title="๋ฒˆ์—ญ AI API",
    description="Transformers ๊ธฐ๋ฐ˜ ๋‹ค๊ตญ์–ด ๋ฒˆ์—ญ ์„œ๋น„์Šค",
    version="1.0.0"
)

# ์š”์ฒญ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ์ •์˜
class TranslationRequest(BaseModel):
    text: str
    source_lang: str = "ko"
    target_lang: str = "en"
    max_length: Optional[int] = 512

# ์‘๋‹ต ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ์ •์˜
class TranslationResponse(BaseModel):
    original_text: str
    translated_text: str
    source_lang: str
    target_lang: str
    processing_time: float

# ์ง€์› ๋ชจ๋ธ ๋งคํ•‘
MODELS = {
    "ko-en": "Helsinki-NLP/opus-mt-ko-en",
    "en-ko": "Helsinki-NLP/opus-mt-en-ko",
    "en-fr": "Helsinki-NLP/opus-mt-en-fr",
    "en-de": "Helsinki-NLP/opus-mt-en-de",
}

# ๋ชจ๋ธ ์บ์‹œ
model_cache = {}

def get_translator(source_lang: str, target_lang: str):
    """๋ชจ๋ธ ๋กœ๋“œ ๋ฐ ์บ์‹ฑ"""
    key = f"{source_lang}-{target_lang}"
    
    if key not in MODELS:
        raise HTTPException(
            status_code=400,
            detail=f"์ง€์›ํ•˜์ง€ ์•Š๋Š” ์–ธ์–ด ์Œ: {source_lang} โ†’ {target_lang}"
        )
    
    if key not in model_cache:
        model_cache[key] = pipeline(
            "translation",
            model=MODELS[key]
        )
    
    return model_cache[key]

@app.get("/")
async def root():
    return {"message": "๋ฒˆ์—ญ AI API์— ์˜ค์‹  ๊ฑธ ํ™˜์˜ํ•ด์š”! ๐ŸŽ‰"}

@app.get("/supported-languages")
async def get_supported_languages():
    """์ง€์›ํ•˜๋Š” ์–ธ์–ด ์Œ ๋ชฉ๋ก ๋ฐ˜ํ™˜"""
    return {
        "supported_pairs": list(MODELS.keys()),
        "total": len(MODELS)
    }

@app.post("/translate", response_model=TranslationResponse)
async def translate(request: TranslationRequest):
    """ํ…์ŠคํŠธ ๋ฒˆ์—ญ ์—”๋“œํฌ์ธํŠธ"""
    
    if not request.text.strip():
        raise HTTPException(
            status_code=400,
            detail="๋ฒˆ์—ญํ•  ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
        )
    
    if len(request.text) > 5000:
        raise HTTPException(
            status_code=400,
            detail="ํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ๊ธธ์–ด์š”. 5000์ž ์ดํ•˜๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."
        )
    
    start_time = time.time()
    
    translator = get_translator(request.source_lang, request.target_lang)
    result = translator(
        request.text,
        max_length=request.max_length
    )
    
    processing_time = time.time() - start_time
    
    return TranslationResponse(
        original_text=request.text,
        translated_text=result[0]['translation_text'],
        source_lang=request.source_lang,
        target_lang=request.target_lang,
        processing_time=round(processing_time, 3)
    )

# ์„œ๋ฒ„ ์‹คํ–‰: uvicorn main:app --reload --port 8000
๐Ÿงช API ํ…Œ์ŠคํŠธ ๋ฐฉ๋ฒ•

์„œ๋ฒ„ ์‹คํ–‰ ํ›„ http://localhost:8000/docs์— ์ ‘์†ํ•˜๋ฉด
FastAPI๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ฃผ๋Š” Swagger UI์—์„œ ๋ฐ”๋กœ API๋ฅผ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์–ด!

๋˜๋Š” curl ๋ช…๋ น์–ด๋กœ๋„ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•ด:
curl -X POST "http://localhost:8000/translate" -H "Content-Type: application/json" -d '{"text":"์•ˆ๋…•ํ•˜์„ธ์š”","source_lang":"ko","target_lang":"en"}'

๐Ÿ” ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์™€ ํ•ด๊ฒฐ๋ฒ•

์‹ค์Šตํ•˜๋‹ค ๋ณด๋ฉด ๋ถ„๋ช…ํžˆ ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋‚˜๊ฒŒ ๋  ๊ฑฐ์•ผ. ๋ฏธ๋ฆฌ ์•Œ์•„๋‘๋ฉด ๋‹นํ™ฉํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์–ด! ๐Ÿ˜Ž

โŒ ์˜ค๋ฅ˜ 1: OSError: Can't load tokenizer

์›์ธ: sentencepiece ๋˜๋Š” sacremoses๊ฐ€ ์„ค์น˜๋˜์ง€ ์•Š์Œ
ํ•ด๊ฒฐ: pip install sentencepiece sacremoses ์‹คํ–‰
โŒ ์˜ค๋ฅ˜ 2: CUDA out of memory

์›์ธ: GPU ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ
ํ•ด๊ฒฐ:
- ๋ฐฐ์น˜ ํฌ๊ธฐ(batch_size) ์ค„์ด๊ธฐ
- torch.cuda.empty_cache() ์‹คํ–‰
- ๋ชจ๋ธ์„ CPU๋กœ ์ด๋™: model.to('cpu')
- ํ˜ผํ•ฉ ์ •๋ฐ€๋„(fp16) ์‚ฌ์šฉ
โŒ ์˜ค๋ฅ˜ 3: ๋ฒˆ์—ญ ๊ฒฐ๊ณผ๊ฐ€ ์ด์ƒํ•˜๊ฑฐ๋‚˜ ๋นˆ ๋ฌธ์ž์—ด

์›์ธ: ์ž…๋ ฅ ํ…์ŠคํŠธ๊ฐ€ ๋„ˆ๋ฌด ์งง๊ฑฐ๋‚˜, ์–ธ์–ด ๊ฐ์ง€ ์‹คํŒจ
ํ•ด๊ฒฐ:
- ์ตœ์†Œ 5๋‹จ์–ด ์ด์ƒ์˜ ๋ฌธ์žฅ ์ž…๋ ฅ
- max_length ํŒŒ๋ผ๋ฏธํ„ฐ ๋Š˜๋ฆฌ๊ธฐ
- num_beams ๊ฐ’ ์กฐ์ • (4~6 ๊ถŒ์žฅ)
โŒ ์˜ค๋ฅ˜ 4: ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ๋„ˆ๋ฌด ๋А๋ฆผ

์›์ธ: ๋„คํŠธ์›Œํฌ ์†๋„ ๋˜๋Š” ํ—ˆ๊น…ํŽ˜์ด์Šค ์„œ๋ฒ„ ์ƒํƒœ
ํ•ด๊ฒฐ:
- ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •: TRANSFORMERS_CACHE๋กœ ์บ์‹œ ๊ฒฝ๋กœ ์ง€์ •
- ๋ชจ๋ธ์„ ๋กœ์ปฌ์— ๋ฏธ๋ฆฌ ์ €์žฅ: model.save_pretrained('./local-model')
- ๋กœ์ปฌ ๋ชจ๋ธ ๋กœ๋“œ: pipeline("translation", model="./local-model")
โš ๏ธ ์ฃผ์˜! ํ—ˆ๊น…ํŽ˜์ด์Šค ๋ชจ๋ธ์€ ์ฒ˜์Œ ์‹คํ–‰ ์‹œ ์ž๋™์œผ๋กœ ๋‹ค์šด๋กœ๋“œ๋˜๋Š”๋ฐ,
MarianMT ๋ชจ๋ธ ํ•˜๋‚˜๊ฐ€ ๋ณดํ†ต 300MB ~ 1GB ์ •๋„ ๋ผ.
์ธํ„ฐ๋„ท ์—ฐ๊ฒฐ์ด ํ•„์š”ํ•˜๊ณ , ๋””์Šคํฌ ๊ณต๊ฐ„๋„ ์ถฉ๋ถ„ํžˆ ํ™•๋ณดํ•ด๋‘ฌ์•ผ ํ•ด!

๐Ÿ“ˆ ๋” ๋‚˜์•„๊ฐ€๊ธฐ: ์ตœ์‹  ๋ฒˆ์—ญ ๋ชจ๋ธ๋“ค

MarianMT ์™ธ์—๋„ ํ—ˆ๊น…ํŽ˜์ด์Šค์—๋Š” ๋‹ค์–‘ํ•œ ๋ฒˆ์—ญ ๋ชจ๋ธ๋“ค์ด ์žˆ์–ด.
๊ฐ๊ฐ์˜ ํŠน์ง•์„ ์•Œ์•„๋‘๋ฉด ์ƒํ™ฉ์— ๋งž๋Š” ๋ชจ๋ธ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽฏ

๐Ÿ† ์ฃผ์š” ๋ฒˆ์—ญ ๋ชจ๋ธ ๋น„๊ต

1. Helsinki-NLP/MarianMT
- ํŠน์ง•: ๊ฐ€๋ณ๊ณ  ๋น ๋ฆ„, ๋‹ค์–‘ํ•œ ์–ธ์–ด ์Œ ์ง€์›
- ์ ํ•ฉ: ๋น ๋ฅธ ํ”„๋กœํ† ํƒ€์ดํ•‘, ๋ฆฌ์†Œ์Šค ์ œํ•œ ํ™˜๊ฒฝ
- ํฌ๊ธฐ: ~300MB

2. facebook/mbart-large-50-many-to-many-mmt
- ํŠน์ง•: 50๊ฐœ ์–ธ์–ด ์ง€์›, ๋†’์€ ๋ฒˆ์—ญ ํ’ˆ์งˆ
- ์ ํ•ฉ: ๋‹ค๊ตญ์–ด ์„œ๋น„์Šค, ๊ณ ํ’ˆ์งˆ ๋ฒˆ์—ญ
- ํฌ๊ธฐ: ~2.4GB

3. Helsinki-NLP/opus-mt-tc-big-ko-en
- ํŠน์ง•: ํ•œโ†’์˜ ํŠนํ™”, ๋” ํฐ ๋ชจ๋ธ๋กœ ๋†’์€ ํ’ˆ์งˆ
- ์ ํ•ฉ: ํ•œ๊ตญ์–ด ๋ฒˆ์—ญ ํ’ˆ์งˆ์ด ์ค‘์š”ํ•œ ๊ฒฝ์šฐ
- ํฌ๊ธฐ: ~1.2GB

4. google/mt5-base
- ํŠน์ง•: ๊ตฌ๊ธ€์˜ ๋‹ค๊ตญ์–ด T5 ๋ชจ๋ธ, ํŒŒ์ธํŠœ๋‹์— ์ ํ•ฉ
- ์ ํ•ฉ: ์ปค์Šคํ…€ ๋ฒˆ์—ญ ๋ชจ๋ธ ๊ฐœ๋ฐœ
- ํฌ๊ธฐ: ~580MB
python
# mBART ๋ชจ๋ธ๋กœ ๋‹ค๊ตญ์–ด ๋ฒˆ์—ญ ์˜ˆ์‹œ
from transformers import MBartForConditionalGeneration, MBart50TokenizerFast

model = MBartForConditionalGeneration.from_pretrained(
    "facebook/mbart-large-50-many-to-many-mmt"
)
tokenizer = MBart50TokenizerFast.from_pretrained(
    "facebook/mbart-large-50-many-to-many-mmt"
)

# ์†Œ์Šค ์–ธ์–ด ์„ค์ • (ํ•œ๊ตญ์–ด)
tokenizer.src_lang = "ko_KR"

article_ko = "์ธ๊ณต์ง€๋Šฅ ๊ธฐ์ˆ ์ด ๋น ๋ฅด๊ฒŒ ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค."

encoded_ko = tokenizer(article_ko, return_tensors="pt")

# ํƒ€๊ฒŸ ์–ธ์–ด: ์˜์–ด
generated_tokens = model.generate(
    **encoded_ko,
    forced_bos_token_id=tokenizer.lang_code_to_id["en_XX"]
)

translation = tokenizer.batch_decode(
    generated_tokens,
    skip_special_tokens=True
)
print(translation[0])
# ์ถœ๋ ฅ: Artificial intelligence technology is developing rapidly.
๐Ÿ’ก ์–ด๋–ค ๋ชจ๋ธ์„ ์„ ํƒํ•ด์•ผ ํ• ๊นŒ?
- ๋น ๋ฅธ ์†๋„ + ๊ฐ€๋ฒผ์šด ํ™˜๊ฒฝ โ†’ MarianMT
- ๋†’์€ ํ’ˆ์งˆ + ๋‹ค๊ตญ์–ด โ†’ mBART-50
- ํ•œ๊ตญ์–ด ํŠนํ™” โ†’ opus-mt-tc-big-ko-en
- ์ปค์Šคํ…€ ํŒŒ์ธํŠœ๋‹ โ†’ mT5 ๋˜๋Š” mBART

์žฌ๋Šฅ๋„ท์—์„œ AI ๋ฒˆ์—ญ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค๋ฉด, ์„œ๋น„์Šค ๊ทœ๋ชจ์™€ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ ๋ชจ๋ธ์„ ์„ ํƒํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ด!

๐ŸŽ‰ ์˜ค๋Š˜ ๋ฐฐ์šด ๊ฒƒ ์ด์ •๋ฆฌ!

์™€, ์ •๋ง ๋งŽ์€ ๊ฑธ ๋ฐฐ์› ์ง€? ๐Ÿ˜„ ๋งˆ์ง€๋ง‰์œผ๋กœ ์˜ค๋Š˜ ํ•ต์‹ฌ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ!

1
Transformers ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ดํ•ด
ํ—ˆ๊น…ํŽ˜์ด์Šค์˜ Transformers๋Š” ์ˆ˜์ฒœ ๊ฐœ์˜ ์‚ฌ์ „ํ•™์Šต ๋ชจ๋ธ์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ.
2
pipeline()์œผ๋กœ ๋น ๋ฅธ ๋ฒˆ์—ญ
pipeline("translation", model="...") ํ•œ ์ค„๋กœ ๋ฒˆ์—ญ AI๋ฅผ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด.
3
๋ชจ๋ธ + ํ† ํฌ๋‚˜์ด์ € ์ง์ ‘ ์ œ์–ด
MarianMTModel๊ณผ MarianTokenizer๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ๋ฉด ๋” ์„ธ๋ฐ€ํ•œ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•ด.
4
์„ฑ๋Šฅ ์ตœ์ ํ™”
๋ฐฐ์น˜ ์ฒ˜๋ฆฌ, ์–‘์žํ™”, ์ฒญํฌ ๋ถ„ํ•  ๋“ฑ์œผ๋กœ ์‹ค์ œ ์„œ๋น„์Šค์— ์ ํ•ฉํ•œ ์„ฑ๋Šฅ์„ ๋‚ผ ์ˆ˜ ์žˆ์–ด.
5
ํŒŒ์ธํŠœ๋‹์œผ๋กœ ๋„๋ฉ”์ธ ํŠนํ™”
Seq2SeqTrainer๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŠน์ • ๋„๋ฉ”์ธ์— ํŠนํ™”๋œ ๋ฒˆ์—ญ ๋ชจ๋ธ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.
6
FastAPI๋กœ ์„œ๋น„์Šค ๋ฐฐํฌ
๋ฒˆ์—ญ ๋ชจ๋ธ์„ REST API๋กœ ๋ฐฐํฌํ•ด์„œ ์‹ค์ œ ์„œ๋น„์Šค๋กœ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.
๐Ÿš€ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‚˜์•„๊ฐ€๋ ค๋ฉด?

โ‘  ํ—ˆ๊น…ํŽ˜์ด์Šค ํ—ˆ๋ธŒ(huggingface.co)์—์„œ ๋‹ค์–‘ํ•œ ๋ฒˆ์—ญ ๋ชจ๋ธ ํƒ์ƒ‰ํ•ด๋ณด๊ธฐ
โ‘ก ์ž์‹ ๋งŒ์˜ ๋„๋ฉ”์ธ ๋ฐ์ดํ„ฐ๋กœ ํŒŒ์ธํŠœ๋‹ ์‹คํ—˜ํ•ด๋ณด๊ธฐ
โ‘ข BLEU, COMET ๋“ฑ ๋‹ค์–‘ํ•œ ํ‰๊ฐ€ ์ง€ํ‘œ๋กœ ๋ชจ๋ธ ์„ฑ๋Šฅ ์ธก์ •ํ•ด๋ณด๊ธฐ
โ‘ฃ Docker + FastAPI๋กœ ๋ฒˆ์—ญ ์„œ๋น„์Šค ์ปจํ…Œ์ด๋„ˆํ™”ํ•ด๋ณด๊ธฐ
โ‘ค ํ—ˆ๊น…ํŽ˜์ด์Šค Spaces์— ๋ฌด๋ฃŒ๋กœ ๋ฐ๋ชจ ์•ฑ ๋ฐฐํฌํ•ด๋ณด๊ธฐ ๐ŸŽˆ
๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0