이미지 로딩 중...

LLM과 파인튜닝 기초 개념 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 19. · 2 Views

LLM과 파인튜닝 기초 개념 완벽 가이드

AI 언어 모델의 동작 원리부터 실무 파인튜닝까지, 초급 개발자를 위한 친절한 설명서입니다. 복잡한 LLM 개념을 일상 생활의 비유로 쉽게 풀어내고, 실전에서 바로 활용할 수 있는 파인튜닝 기법을 배워보세요.


목차

  1. LLM(Large Language Model)의 동작 원리
  2. Pre-training vs Fine-tuning 차이점
  3. Transfer Learning 개념 이해
  4. Full Fine-tuning vs Parameter-Efficient Fine-tuning
  5. 파인튜닝이 필요한 실무 사례
  6. 오픈 LLM의 장단점 분석

1. LLM(Large Language Model)의 동작 원리

시작하며

여러분이 ChatGPT에게 질문을 했을 때, 마치 사람처럼 자연스럽게 대답하는 모습을 보고 놀란 적 있나요? "이 AI는 어떻게 내 질문을 이해하고, 이렇게 정확한 답변을 만들어낼 수 있을까?" 하고 궁금해하셨을 겁니다.

사실 LLM은 마법이 아닙니다. 마치 아이가 책을 많이 읽으면서 언어를 배우는 것처럼, LLM도 엄청난 양의 텍스트 데이터를 학습하면서 언어 패턴을 익힙니다.

하지만 아이와 다른 점은, LLM은 수학적 계산을 통해 단어들 사이의 관계를 '숫자'로 이해한다는 것입니다. 바로 이것이 LLM의 핵심입니다.

단어를 숫자로 변환하고, 그 숫자들 사이의 패턴을 찾아내어 다음에 올 가장 적절한 단어를 예측하는 거대한 수학 모델입니다.

개요

간단히 말해서, LLM은 "다음에 올 단어를 예측하는 초거대 AI 모델"입니다. 마치 여러분이 "오늘 날씨가 참..."이라고 하면 자연스럽게 "좋네요"나 "나쁘네요"를 떠올리는 것처럼요.

LLM이 필요한 이유는 명확합니다. 전통적인 프로그래밍으로는 "모든 질문에 대한 답변"을 미리 코딩할 수 없기 때문입니다.

예를 들어, 고객 상담 챗봇을 만든다고 생각해보세요. 수천 가지 질문 패턴을 일일이 if-else로 처리하는 것은 불가능에 가깝습니다.

전통적인 방법과 비교하면 차이가 명확합니다. 기존에는 규칙 기반으로 "안녕하세요가 입력되면 → 안녕하세요 고객님을 출력"처럼 정해진 응답만 가능했다면, LLM은 문맥을 이해하고 창의적인 답변을 생성할 수 있습니다.

LLM의 핵심 특징은 세 가지입니다. 첫째, 트랜스포머 아키텍처를 사용하여 문장 내 모든 단어를 동시에 고려합니다.

둘째, 수억~수천억 개의 파라미터로 복잡한 언어 패턴을 표현합니다. 셋째, 자기주도 학습으로 라벨 없는 대량의 텍스트에서 배웁니다.

이러한 특징들이 LLM을 "범용 언어 이해 엔진"으로 만들어줍니다.

코드 예제

# LLM의 기본 동작 원리를 간단히 시뮬레이션
import torch
from transformers import GPT2Tokenizer, GPT2LMHeadModel

# 사전 학습된 GPT-2 모델 로드
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
model = GPT2LMHeadModel.from_pretrained('gpt2')

# 입력 텍스트를 숫자(토큰)로 변환
text = "인공지능의 미래는"
input_ids = tokenizer.encode(text, return_tensors='pt')

# 모델이 다음 단어를 예측
with torch.no_grad():
    outputs = model(input_ids)
    predictions = outputs.logits  # 각 단어의 확률 점수

# 가장 높은 점수의 단어 선택
next_token = torch.argmax(predictions[0, -1, :]).item()
predicted_word = tokenizer.decode([next_token])
print(f"다음 단어 예측: {predicted_word}")

설명

이것이 하는 일: 위 코드는 실제 GPT-2 모델을 사용하여 "인공지능의 미래는" 다음에 올 단어를 예측합니다. 마치 자동완성처럼 가장 자연스러운 다음 단어를 찾아내는 과정을 보여줍니다.

첫 번째로, tokenizer가 한국어/영어 텍스트를 숫자 ID로 변환합니다. "인공지능"이라는 단어는 예를 들어 [12345, 67890] 같은 숫자 배열로 바뀝니다.

이렇게 하는 이유는 컴퓨터가 텍스트를 직접 처리할 수 없고, 수학 연산을 위해서는 숫자가 필요하기 때문입니다. 그 다음으로, 모델의 핵심인 트랜스포머가 실행되면서 Self-Attention 메커니즘이 작동합니다.

이 부분이 정말 중요한데, 문장 내 모든 단어가 서로 어떤 관계인지 계산합니다. 예를 들어 "인공지능"과 "미래"가 서로 관련이 깊다는 것을 숫자로 표현합니다.

내부에서는 수천억 번의 행렬 곱셈이 일어나면서 각 단어의 의미와 관계를 파악합니다. 세 번째 단계로, 모델은 모든 가능한 단어(어휘 사전에 있는 5만~10만 개)에 대해 점수를 매깁니다.

"밝다"는 8.5점, "어둡다"는 3.2점처럼요. 마지막으로 torch.argmax가 가장 높은 점수를 받은 단어를 선택하여 최종적으로 예측 결과를 만들어냅니다.

여러분이 이 코드를 사용하면 몇 줄만으로 수십억 달러를 들여 만든 AI 모델의 힘을 체험할 수 있습니다. 실무에서는 이를 확장하여 챗봇, 문서 요약, 코드 생성 등 다양한 애플리케이션을 만들 수 있습니다.

특히 중요한 점은, 이 모델이 "범용적"이라는 것입니다. 같은 모델로 번역도 하고, 질문 답변도 하고, 코드도 생성할 수 있습니다.

실전 팁

💡 처음 학습할 때는 작은 모델(GPT-2, 124M 파라미터)부터 시작하세요. GPT-3나 LLaMA 같은 큰 모델은 수십 GB 메모리가 필요하고 로딩에만 몇 분이 걸립니다.

💡 torch.no_grad()를 반드시 사용하세요. 이것이 없으면 메모리 사용량이 2~3배 증가하며, 추론만 할 때는 gradient 계산이 불필요합니다.

💡 temperature 파라미터로 창의성을 조절할 수 있습니다. 0.7은 안정적, 1.0은 다양한 응답, 1.5는 매우 창의적(때론 이상한) 결과를 냅니다.

💡 실무에서는 max_length와 num_beams를 조정하여 품질과 속도의 균형을 맞추세요. num_beams=5는 5가지 후보를 동시에 고려하여 더 좋은 결과를 냅니다.

💡 GPU가 없다면 CPU로도 작은 모델은 충분히 실행 가능합니다. Colab의 무료 GPU를 활용하면 비용 없이 실험할 수 있습니다.


2. Pre-training vs Fine-tuning 차이점

시작하며

여러분이 AI 모델을 처음부터 직접 학습시키려고 했을 때 이런 상황을 겪어본 적 있나요? "우리 회사 고객 상담 데이터가 1만 건밖에 없는데, 이걸로 ChatGPT 같은 걸 만들 수 있을까?" 하고 막막했던 경험 말이죠.

이런 문제는 실제 개발 현장에서 매우 자주 발생합니다. 좋은 AI를 만들려면 수억 개의 데이터가 필요한데, 대부분의 회사는 그런 데이터를 가지고 있지 않습니다.

게다가 처음부터 학습하려면 수천만 원의 GPU 비용과 몇 달의 시간이 필요합니다. 바로 이럴 때 필요한 것이 Pre-training과 Fine-tuning의 구분입니다.

Pre-training은 "기본기 다지기"이고, Fine-tuning은 "전문 분야 집중 훈련"입니다. 적은 데이터와 비용으로도 강력한 AI를 만들 수 있는 비결이 여기 있습니다.

개요

간단히 말해서, Pre-training은 "거대한 일반 데이터로 언어의 기본을 배우는 단계"이고, Fine-tuning은 "특정 작업에 맞게 미세 조정하는 단계"입니다. 의대생에 비유하면, Pre-training은 의학 기초를 배우는 본과 과정이고, Fine-tuning은 외과, 내과 등 전문의 수련 과정입니다.

이 구분이 왜 중요한지 실무 관점에서 설명하겠습니다. Pre-training은 OpenAI, Google 같은 거대 기업만 할 수 있습니다.

수백억 원의 비용이 들기 때문입니다. 하지만 Fine-tuning은 여러분도 노트북으로 할 수 있습니다.

예를 들어, 의료 챗봇을 만든다면 이미 Pre-train된 GPT 모델을 가져와서 의료 데이터 몇천 건으로 Fine-tuning하면 됩니다. 전통적인 방법과의 비교를 해보겠습니다.

기존 머신러닝에서는 각 작업마다 모델을 처음부터 학습했습니다. 스팸 분류기, 감정 분석기를 따로따로 만들었죠.

이제는 하나의 Pre-trained 모델을 여러 작업에 Fine-tuning하여 재사용할 수 있습니다. Pre-training의 핵심은 "자기주도 학습"입니다.

라벨 없는 텍스트에서 "다음 단어 맞추기" 같은 과제로 스스로 배웁니다. Fine-tuning의 핵심은 "작은 데이터로 큰 효과"입니다.

이미 언어를 아는 모델이 특정 스타일이나 지식만 추가로 배우면 되니까요. 이러한 특징들이 현대 AI 개발의 표준 방법론이 된 이유입니다.

코드 예제

from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments
from datasets import load_dataset

# 1단계: Pre-trained 모델 로드 (이미 언어 기초는 학습된 상태)
model_name = "gpt2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)

# 2단계: Fine-tuning용 데이터 준비 (예: 고객 상담 데이터)
dataset = load_dataset("csv", data_files="customer_support.csv")
tokenized_data = dataset.map(lambda x: tokenizer(x['text'], truncation=True))

# 3단계: Fine-tuning 설정 (적은 epoch로 빠르게)
training_args = TrainingArguments(
    output_dir="./finetuned-model",
    num_train_epochs=3,  # Pre-training은 수백 epoch, Fine-tuning은 3~5 epoch면 충분
    per_device_train_batch_size=4,
    learning_rate=5e-5,  # Pre-training보다 10배 작은 학습률
)

# 4단계: Fine-tuning 실행
trainer = Trainer(model=model, args=training_args, train_dataset=tokenized_data['train'])
trainer.train()  # 몇 시간이면 완료 (Pre-training은 몇 주~몇 달)

설명

이것이 하는 일: 위 코드는 이미 Pre-train된 GPT-2 모델을 가져와서, 여러분의 고객 상담 데이터로 Fine-tuning합니다. 마치 "언어를 아는 AI"를 "우리 회사 스타일로 말하는 AI"로 변신시키는 과정입니다.

첫 번째로, AutoModelForCausalLM.from_pretrained()가 핵심입니다. 이 한 줄이 OpenAI가 수천만 달러를 들여 학습한 모델을 무료로 가져옵니다.

이미 이 모델은 위키피디아, 뉴스, 책 등 수백 GB의 텍스트로 Pre-training되어 있어서, 문법, 상식, 일반 지식을 모두 알고 있습니다. 이렇게 하는 이유는 "바퀴를 재발명하지 않기 위해서"입니다.

그 다음으로, dataset.map()이 여러분의 고객 상담 데이터를 모델이 이해할 수 있는 형태로 변환합니다. 예를 들어 "배송은 언제 되나요?"라는 텍스트가 [123, 456, 789] 같은 토큰 ID로 바뀝니다.

내부에서는 tokenizer가 특수 토큰([SEP], [CLS] 등)을 추가하고, padding을 맞춰서 배치 처리가 가능하도록 만듭니다. 세 번째 단계에서 TrainingArguments의 세부 설정이 중요합니다.

learning_rate=5e-5는 Pre-training의 1e-4보다 절반 작습니다. 왜냐하면 이미 학습된 가중치를 "살짝만" 조정해야 하기 때문입니다.

너무 크게 바꾸면 Pre-training에서 배운 지식을 잃어버립니다(Catastrophic Forgetting). num_train_epochs=3은 데이터를 3번만 반복한다는 뜻인데, Pre-training의 100+ epoch에 비하면 매우 적습니다.

마지막으로, trainer.train()이 실제 Fine-tuning을 수행하여 최종적으로 "우리 회사 고객 상담 스타일"을 학습한 모델을 만들어냅니다. 내부적으로는 역전파 알고리즘이 작동하면서 모델의 파라미터를 조금씩 수정합니다.

여러분이 이 코드를 사용하면 적은 데이터(수천~수만 건)와 적은 비용(GPU 몇 시간)으로 특화된 AI를 만들 수 있습니다. 실무에서는 법률 문서 분석, 의료 진단 보조, 코드 리뷰 자동화 등 도메인 특화 작업에 이 방법을 많이 사용합니다.

특히 중요한 점은, Fine-tuning 후에도 모델의 일반 언어 능력은 유지된다는 것입니다.

실전 팁

💡 Fine-tuning 시 learning_rate는 Pre-training의 1/10 ~ 1/5로 설정하세요. 너무 크면 이전 지식을 잃고(망각), 너무 작으면 학습이 안 됩니다.

💡 데이터가 1000건 미만이면 overfitting 위험이 큽니다. early_stopping_patience=2를 설정하여 validation loss가 2회 연속 증가하면 학습을 멈추세요.

💡 실무에서는 LoRA, QLoRA 같은 Parameter-Efficient 방법을 사용하면 메모리를 1/10로 줄일 수 있습니다. 전체 모델이 아닌 일부만 Fine-tuning하는 방식입니다.

💡 Fine-tuning 전에 반드시 데이터 품질을 검증하세요. 잘못된 데이터 10%가 섞이면 모델 성능이 30% 이상 떨어집니다.

💡 gradient_accumulation_steps를 사용하면 작은 GPU에서도 큰 배치 효과를 낼 수 있습니다. 4 step마다 업데이트하면 실제 배치 크기의 4배 효과입니다.


3. Transfer Learning 개념 이해

시작하며

여러분이 새로운 외국어를 배울 때 이런 경험을 해보셨나요? "이미 영어를 알고 있으니까, 프랑스어를 배울 때 문법 구조가 비슷해서 훨씬 쉽더라"는 느낌 말이죠.

또는 피아노를 칠 줄 아는 사람이 오르간을 배우면 훨씬 빠르게 배우는 것처럼요. 이런 현상은 머신러닝에서도 똑같이 발생합니다.

한 작업에서 배운 지식이 다른 작업에도 도움이 되는 것을 발견했습니다. 문제는, 전통적인 머신러닝은 각 작업마다 "백지 상태"에서 시작했다는 점입니다.

이미지 분류 모델을 만들었어도, 비슷한 이미지 검색 모델을 만들 때 다시 처음부터 학습해야 했습니다. 바로 이럴 때 필요한 것이 Transfer Learning(전이 학습)입니다.

"다른 작업에서 배운 지식을 재활용"하여 새로운 작업을 빠르고 효과적으로 학습하는 방법입니다. 데이터가 부족하고 컴퓨팅 자원이 제한된 현실에서 가장 실용적인 해법입니다.

개요

간단히 말해서, Transfer Learning은 "이미 학습된 모델의 지식을 다른 작업에 재사용하는 기법"입니다. 마치 수학을 잘하는 사람이 물리학을 배울 때 수학 지식을 활용하는 것과 같습니다.

Transfer Learning이 필요한 이유는 세 가지입니다. 첫째, 데이터 부족 문제 해결입니다.

희귀 질병 이미지가 100장밖에 없어도, ImageNet으로 Pre-train된 모델을 Fine-tuning하면 좋은 성능을 낼 수 있습니다. 둘째, 학습 시간 단축입니다.

처음부터 학습하면 1주일 걸릴 것을 Transfer Learning으로 몇 시간에 끝낼 수 있습니다. 셋째, 성능 향상입니다.

실험 결과, Transfer Learning을 사용한 모델이 처음부터 학습한 모델보다 정확도가 10-30% 더 높습니다. 전통적인 방법과의 비교를 해보겠습니다.

기존에는 각 작업마다 독립된 모델을 만들었습니다. 고양이 분류기, 강아지 분류기를 따로 학습했죠.

이제는 "일반적인 이미지 특징 추출기"를 공유하고, 마지막 분류층만 각 작업에 맞게 바꿉니다. Transfer Learning의 핵심 특징은 두 가지입니다.

첫째, Feature Extraction입니다. Pre-trained 모델의 초기 레이어는 "고정"하고, 출력층만 새로 학습합니다.

둘째, Fine-tuning입니다. 전체 모델을 새 작업에 맞게 "미세 조정"합니다.

이 두 가지를 상황에 맞게 선택하는 것이 실무 핵심입니다.

코드 예제

from transformers import BertModel, BertTokenizer
import torch.nn as nn

# 1단계: BERT Pre-trained 모델 로드 (일반 언어 이해 능력 보유)
bert = BertModel.from_pretrained('bert-base-uncased')
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')

# 2단계: Transfer Learning - 새로운 작업용 classifier 추가
class SentimentClassifier(nn.Module):
    def __init__(self, bert_model):
        super().__init__()
        self.bert = bert_model  # Pre-trained BERT 재사용
        # BERT의 768차원 출력을 3개 클래스(긍정/중립/부정)로 변환
        self.classifier = nn.Linear(768, 3)

    def forward(self, input_ids, attention_mask):
        # BERT가 문장을 이해 (Transfer된 지식 활용)
        outputs = self.bert(input_ids, attention_mask=attention_mask)
        # 마지막 hidden state로 감정 분류 (새로 배우는 부분)
        logits = self.classifier(outputs.pooler_output)
        return logits

# 3단계: 모델 생성 - BERT 지식 + 감정 분석 능력
model = SentimentClassifier(bert)

설명

이것이 하는 일: 위 코드는 구글이 만든 BERT 모델(위키피디아 전체로 학습)의 언어 이해 능력을 가져와서, 감정 분석이라는 새로운 작업에 적용합니다. 마치 "영어 전문가"를 "영화 리뷰 감정 전문가"로 특화시키는 과정입니다.

첫 번째로, BertModel.from_pretrained()가 Transfer Learning의 핵심입니다. 이 한 줄로 12개 레이어, 110M 파라미터를 가진 거대 모델을 가져옵니다.

이 BERT는 이미 "문맥 이해", "단어 관계 파악", "문법 구조 인식" 능력을 가지고 있습니다. 이렇게 하는 이유는, 이런 기본 능력은 감정 분석에도 똑같이 필요하기 때문입니다.

그 다음으로, SentimentClassifier 클래스가 중요한 역할을 합니다. self.bert는 Pre-trained 모델을 그대로 재사용하고, self.classifier만 새로 만듭니다.

이것이 Transfer Learning의 정석입니다. 이미 잘 학습된 부분(BERT)은 건드리지 않고, 작업 특화 부분(classifier)만 추가합니다.

내부에서 BERT는 "이 리뷰가 어떤 의미인지" 이해하고, classifier는 "그 의미가 긍정적인지 부정적인지" 판단합니다. 세 번째 단계에서 forward() 함수를 보면, 두 단계 처리가 명확합니다.

먼저 self.bert()가 입력 텍스트를 768차원 벡터로 변환합니다. 이 벡터는 "문장의 의미"를 숫자로 표현한 것입니다.

그 다음 self.classifier()가 이 의미 벡터를 받아서 "긍정/중립/부정" 중 하나로 분류합니다. 마지막으로 model = SentimentClassifier(bert)가 실제 Transfer Learning 모델을 생성합니다.

이제 이 모델을 학습시킬 때, BERT 부분은 learning_rate를 낮게(1e-5), classifier 부분은 높게(1e-3) 설정하여 차별화된 학습을 할 수 있습니다. 여러분이 이 코드를 사용하면 감정 분석 데이터 1000건만으로도 90% 이상의 정확도를 달성할 수 있습니다.

처음부터 학습했다면 최소 10만 건이 필요했을 겁니다. 실무에서는 문서 분류, 개체명 인식, 질의응답 등 거의 모든 NLP 작업에 이 방법을 사용합니다.

Transfer Learning 덕분에 소규모 스타트업도 강력한 AI를 만들 수 있게 되었습니다.

실전 팁

💡 데이터가 10000건 미만이면 BERT를 freeze하고 classifier만 학습하세요. 데이터가 충분하면 전체를 Fine-tuning해도 됩니다.

💡 Source domain(Pre-training 데이터)과 Target domain(Fine-tuning 데이터)이 비슷할수록 효과가 큽니다. 의료 작업이면 BioBERT 같은 도메인 특화 모델을 선택하세요.

💡 Discriminative learning rate를 사용하세요. 하위 레이어는 1e-5, 상위 레이어는 1e-4, 새 classifier는 1e-3처럼 점진적으로 올립니다.

💡 실무에서는 Gradual Unfreezing 기법이 효과적입니다. 처음엔 classifier만 학습하고, 나중에 BERT의 상위 레이어를 점진적으로 unfreeze합니다.

💡 Negative Transfer를 조심하세요. Source와 Target이 너무 다르면 오히려 성능이 떨어집니다. 이 경우 레이어 일부만 Transfer하는 것이 좋습니다.


4. Full Fine-tuning vs Parameter-Efficient Fine-tuning

시작하며

여러분이 거대한 LLM 모델을 Fine-tuning하려고 GPU를 확인했을 때 이런 충격을 받은 적 있나요? "GPT-3 크기 모델을 Fine-tuning하려면 GPU 메모리가 80GB 필요하다고?

우리 회사 GPU는 16GB밖에 안 되는데..." 하는 절망감 말이죠. 이런 문제는 실무에서 매우 흔합니다.

LLM이 거대해질수록 Fine-tuning에 필요한 컴퓨팅 자원도 기하급수적으로 증가합니다. 7B 파라미터 모델을 Full Fine-tuning하려면 최소 40GB GPU가 필요하고, 학습 시간만 며칠이 걸립니다.

비용으로 환산하면 한 번 학습에 수백만 원입니다. 바로 이럴 때 필요한 것이 Parameter-Efficient Fine-tuning(PEFT)입니다.

"모델의 일부 파라미터만 효율적으로 학습"하여 메모리를 10분의 1로 줄이면서도 Full Fine-tuning과 비슷한 성능을 내는 혁신적인 방법입니다. 개인 개발자도 노트북으로 거대 모델을 Fine-tuning할 수 있게 만들어준 기술입니다.

개요

간단히 말해서, Full Fine-tuning은 "모델의 모든 파라미터를 업데이트"하는 방식이고, Parameter-Efficient Fine-tuning은 "일부 파라미터만 추가/수정"하는 방식입니다. 집을 리모델링할 때, 전체를 뜯어고치는 것 vs 필요한 부분만 교체하는 것의 차이와 같습니다.

왜 이 구분이 중요한지 실무 관점에서 설명하겠습니다. Full Fine-tuning은 최고 성능을 내지만, 7B 모델 기준 40GB GPU 메모리와 며칠의 학습 시간이 필요합니다.

반면 LoRA(PEFT의 대표 기법)는 같은 모델을 16GB GPU에서 몇 시간 만에 학습할 수 있습니다. 예를 들어, 의료 챗봇을 만들 때 Full Fine-tuning은 클라우드 비용 300만 원, LoRA는 30만 원이면 가능합니다.

전통적인 방법과 비교하면 차이가 극명합니다. 기존 Full Fine-tuning에서는 70억 개 파라미터를 모두 저장해야 했다면, LoRA는 추가 파라미터 몇백만 개만 저장합니다.

원본 모델은 고정해두고, 작은 "어댑터"만 끼워 넣는 방식입니다. PEFT의 핵심 특징은 세 가지입니다.

첫째, Low-Rank Adaptation입니다. 큰 행렬 업데이트를 작은 두 행렬의 곱으로 근사합니다.

둘째, Frozen Backbone입니다. 원본 모델은 절대 건드리지 않습니다.

셋째, Modularity입니다. 여러 작업에 대해 여러 어댑터를 만들어 필요할 때 갈아 끼울 수 있습니다.

이러한 특징들이 현대 LLM Fine-tuning의 표준이 된 이유입니다.

코드 예제

from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model, TaskType

# 1단계: 거대 모델 로드 (예: 7B 파라미터 LLaMA)
model_name = "meta-llama/Llama-2-7b-hf"
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

# 2단계: LoRA 설정 - 원본 70억 개 대신 파라미터 약 400만 개만 학습
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=8,  # Low-rank 차원 (작을수록 메모리 절약)
    lora_alpha=32,  # Scaling factor
    lora_dropout=0.1,
    target_modules=["q_proj", "v_proj"]  # Attention 부분만 적용
)

# 3단계: PEFT 모델 생성 - 원본 모델 + LoRA 어댑터
peft_model = get_peft_model(model, lora_config)

# 학습 가능한 파라미터 확인
trainable_params = sum(p.numel() for p in peft_model.parameters() if p.requires_grad)
total_params = sum(p.numel() for p in peft_model.parameters())
print(f"학습 파라미터: {trainable_params:,} / 전체: {total_params:,}")
print(f"비율: {100 * trainable_params / total_params:.2f}%")  # 보통 0.1~1%

설명

이것이 하는 일: 위 코드는 70억 개 파라미터를 가진 LLaMA 모델에 LoRA를 적용하여, 실제로는 약 400만 개(0.05%)만 학습합니다. 마치 거대한 기계에서 핵심 부품 몇 개만 교체하여 새로운 기능을 추가하는 것과 같습니다.

첫 번째로, AutoModelForCausalLM.from_pretrained()가 7B 모델을 로드합니다. 이 모델은 메모리에 약 14GB(float16 기준)를 차지합니다.

Full Fine-tuning이라면 여기에 Optimizer state, gradient 등이 추가되어 총 40-50GB가 필요합니다. 이렇게 많은 이유는, 각 파라미터마다 momentum, variance 등의 추가 정보를 저장하기 때문입니다.

그 다음으로, LoraConfig의 핵심 파라미터들이 메모리 절약의 비밀입니다. r=8이 가장 중요한데, 이것은 "Low-Rank"의 차원입니다.

원래 4096x4096 행렬을 업데이트하려면 1600만 개 파라미터가 필요하지만, LoRA는 4096x8과 8x4096 두 개의 작은 행렬(총 6만5천 개)로 근사합니다. 내부에서는 W = W_original + (A × B) 공식으로 작동합니다.

target_modules=["q_proj", "v_proj"]는 Attention의 Query와 Value 부분만 수정한다는 뜻입니다. 세 번째 단계에서 get_peft_model()이 마법을 일으킵니다.

원본 모델의 파라미터는 모두 requires_grad=False로 고정하고, 새로운 LoRA 레이어만 requires_grad=True로 설정합니다. 따라서 역전파 시 gradient가 LoRA 부분에만 흐르고, 메모리 사용량이 극적으로 감소합니다.

마지막 부분의 출력을 보면 놀라운 결과를 확인할 수 있습니다. 보통 "학습 파라미터: 4,194,304 / 전체: 6,738,415,616 (0.06%)"처럼 나옵니다.

즉, 전체의 0.06%만 학습하면서도 Full Fine-tuning의 95% 성능을 달성합니다. 여러분이 이 코드를 사용하면 개인 노트북(16GB GPU)으로도 거대 LLM을 Fine-tuning할 수 있습니다.

실무에서는 고객사별 맞춤 챗봇을 만들 때, 각 고객사마다 작은 LoRA 어댑터만 만들어서 관리합니다. 원본 모델 하나에 어댑터 100개를 끼워서 100개 회사의 챗봇을 운영하는 식입니다.

메모리는 원본 모델 + 작은 어댑터만 차지하므로 매우 효율적입니다.

실전 팁

💡 r(rank) 값은 4~16 사이에서 시작하세요. 4는 극도로 효율적, 16은 성능 중시입니다. 실험 결과 8이 가장 균형 잡힌 선택입니다.

💡 lora_alpha는 보통 r의 2배로 설정합니다. r=8이면 lora_alpha=16이 표준입니다. 이 비율이 학습 안정성을 결정합니다.

💡 target_modules 선택이 중요합니다. "q_proj", "v_proj"만 해도 충분하지만, 성능을 더 원하면 "k_proj", "o_proj", "gate_proj"도 추가하세요.

💡 QLoRA를 사용하면 메모리를 더욱 줄일 수 있습니다. 4-bit quantization + LoRA 조합으로 7B 모델을 6GB GPU에서도 학습 가능합니다.

💡 여러 어댑터를 관리할 때는 adapter_name을 명확히 지정하세요. "customer_a", "customer_b"처럼 구분하면 나중에 load_adapter()로 쉽게 전환할 수 있습니다.


5. 파인튜닝이 필요한 실무 사례

시작하며

여러분이 ChatGPT API를 사용해서 회사 업무를 자동화하려다가 이런 문제를 겪어본 적 있나요? "고객 상담 답변을 생성하는데, 우리 회사 톤앤매너랑 너무 달라요.

그리고 전문 용어를 자꾸 틀리게 이해해요." 하는 답답함 말이죠. 이런 문제는 실제로 매우 흔합니다.

일반 LLM은 "평균적인" 언어를 배웠기 때문에, 특정 회사의 스타일, 도메인 지식, 업무 규칙을 정확히 따르지 못합니다. 예를 들어, 법률 회사에서 계약서를 검토하는 AI를 만든다면, GPT-4도 법률 전문가만큼 정확하지 않습니다.

바로 이럴 때 필요한 것이 파인튜닝입니다. "우리 회사만의 데이터"로 모델을 특화시켜서, 정확도와 일관성을 획기적으로 높일 수 있습니다.

실무에서 어떤 상황에 파인튜닝이 필수인지, 구체적인 사례로 알아보겠습니다.

개요

간단히 말해서, 파인튜닝은 "일반 LLM을 우리 업무에 특화된 전문가로 만드는 과정"입니다. 마치 일반 의대 졸업생을 심장외과 전문의로 훈련시키는 것과 같습니다.

파인튜닝이 필요한 대표적인 실무 상황은 다섯 가지입니다. 첫째, 도메인 특화 지식이 필요할 때입니다.

의료, 법률, 금융처럼 전문 용어와 규칙이 중요한 분야에서는 일반 LLM의 정확도가 60-70%밖에 안 됩니다. 파인튜닝하면 90% 이상으로 향상됩니다.

둘째, 톤앤매너 일관성이 중요할 때입니다. 고객 상담 챗봇이 매번 다른 말투로 답변하면 고객 경험이 나빠집니다.

셋째, 최신 정보나 내부 데이터를 활용해야 할 때입니다. LLM의 학습 cutoff 이후 데이터나 회사 내부 문서는 파인튜닝으로만 반영할 수 있습니다.

전통적인 방법과 비교하면 차이가 명확합니다. 기존에는 Prompt Engineering으로 해결하려고 했습니다.

"당신은 친절한 상담사입니다. 다음 규칙을 따르세요..." 같은 긴 프롬프트를 매번 보냈죠.

하지만 이 방법은 일관성이 떨어지고, 토큰 비용이 많이 듭니다. 파인튜닝하면 짧은 프롬프트로도 원하는 스타일과 지식을 얻을 수 있습니다.

실무 파인튜닝의 핵심은 "비용 대비 효과"입니다. 파인튜닝 비용이 100만 원이라면, API 호출 비용 절감이나 품질 향상으로 그 이상의 가치를 만들어야 합니다.

또한 "데이터 품질"이 결정적입니다. 잘못된 데이터 100건으로 파인튜닝하면 모델이 오히려 나빠집니다.

이러한 실무 고려사항들을 이해하는 것이 성공의 열쇠입니다.

코드 예제

from openai import OpenAI
import json

client = OpenAI()

# 실무 사례 1: 고객 상담 톤앤매너 학습용 데이터 준비
training_data = [
    {
        "messages": [
            {"role": "system", "content": "당신은 친절하고 전문적인 고객 상담사입니다."},
            {"role": "user", "content": "배송이 언제 오나요?"},
            {"role": "assistant", "content": "안녕하세요! 주문하신 상품은 내일 오후 2시경 도착 예정입니다. 배송 추적은 문자로 안내드렸으니 확인 부탁드립니다. 😊"}
        ]
    },
    # ... 최소 50-100개의 실제 상담 대화
]

# JSONL 형식으로 저장 (OpenAI Fine-tuning 요구 형식)
with open("customer_support_train.jsonl", "w", encoding="utf-8") as f:
    for item in training_data:
        f.write(json.dumps(item, ensure_ascii=False) + "\n")

# 실무 사례 2: Fine-tuning 작업 생성
file = client.files.create(file=open("customer_support_train.jsonl", "rb"), purpose="fine-tune")
job = client.fine_tuning.jobs.create(
    training_file=file.id,
    model="gpt-4o-mini-2024-07-18",
    hyperparameters={"n_epochs": 3}  # 3 epoch면 충분 (과적합 방지)
)

print(f"Fine-tuning 작업 ID: {job.id}")
# 완료 후 사용: client.chat.completions.create(model="ft:gpt-4o-mini-...")

설명

이것이 하는 일: 위 코드는 실제 고객 상담 대화 데이터를 사용하여 GPT 모델을 회사 스타일에 맞게 파인튜닝합니다. 마치 "일반 상담원"을 "우리 회사 베테랑 상담원"으로 훈련시키는 과정입니다.

첫 번째로, training_data의 구조가 매우 중요합니다. "messages" 형식은 실제 대화 흐름을 그대로 반영합니다.

system 메시지는 역할 정의, user는 고객 질문, assistant는 이상적인 답변입니다. 이렇게 하는 이유는, 모델이 "이런 질문에는 이렇게 답해야 한다"는 패턴을 학습하기 때문입니다.

예를 들어, "😊" 이모지 사용, "안녕하세요!" 같은 인사, "부탁드립니다" 같은 정중한 표현이 반복되면 모델이 이 스타일을 체득합니다. 그 다음으로, JSONL 형식 저장이 필수입니다.

각 줄이 하나의 완전한 JSON 객체여야 합니다. ensure_ascii=False는 한글이 깨지지 않도록 합니다.

내부에서 OpenAI API는 이 파일을 읽어서 각 대화 예시로 모델을 학습시킵니다. 데이터 개수는 최소 50개, 이상적으로는 100-500개입니다.

1000개 이상은 과적합 위험이 있습니다. 세 번째 단계에서 client.files.create()가 데이터를 OpenAI 서버에 업로드합니다.

purpose="fine-tune"은 이 파일이 파인튜닝용임을 명시합니다. 그 다음 client.fine_tuning.jobs.create()가 실제 학습 작업을 시작합니다.

hyperparameters의 n_epochs=3은 데이터를 3번 반복 학습한다는 뜻입니다. 너무 많으면 과적합되고, 너무 적으면 학습이 덜 됩니다.

마지막으로, 학습이 완료되면(보통 10분-1시간) "ft:gpt-4o-mini-..."로 시작하는 모델 ID를 받습니다. 이후부터는 이 ID로 API를 호출하면, 여러분의 회사 스타일로 답변하는 맞춤형 모델을 사용할 수 있습니다.

여러분이 이 코드를 사용하면 실제로 다음과 같은 효과를 얻을 수 있습니다. 첫째, API 비용 절감입니다.

긴 프롬프트가 필요 없어져서 토큰 사용량이 30-50% 줄어듭니다. 둘째, 응답 품질 향상입니다.

실험 결과, 파인튜닝된 모델이 사용자 만족도 평가에서 20-30% 더 높은 점수를 받습니다. 셋째, 일관성 확보입니다.

같은 질문에 매번 비슷한 스타일로 답변하여 브랜드 이미지를 유지합니다. 실무에서는 의료 진단 보조, 법률 문서 검토, 코드 리뷰 자동화, 교육 콘텐츠 생성 등 정확도와 일관성이 중요한 모든 분야에 활용됩니다.

실전 팁

💡 데이터 품질이 양보다 100배 중요합니다. 잘못된 답변 10개가 섞이면 모델이 혼란스러워합니다. 전문가가 검수한 고품질 데이터 50개가 검수 안 된 500개보다 낫습니다.

💡 Validation set을 반드시 준비하세요. 전체 데이터의 10-20%를 따로 떼어놔서 과적합 여부를 확인합니다. Validation loss가 증가하면 학습을 멈춰야 합니다.

💡 실무에서는 A/B 테스트가 필수입니다. 기존 모델 vs 파인튜닝 모델을 실제 사용자에게 랜덤으로 보여주고, 어느 쪽 만족도가 높은지 측정하세요.

💡 파인튜닝 비용 계산: OpenAI GPT-4o-mini 기준 1000 토큰당 $0.30입니다. 100개 예시 × 평균 200 토큰 = 20,000 토큰 × 3 epoch = 약 $18입니다. API 절감 효과와 비교하세요.

💡 지속적인 업데이트가 중요합니다. 처음 파인튜닝 후 3-6개월마다 새로운 대화 데이터를 추가하여 재학습하세요. 고객 질문 패턴과 회사 정책은 계속 변하기 때문입니다.


6. 오픈 LLM의 장단점 분석

시작하며

여러분이 AI 프로젝트를 시작하면서 이런 고민을 해보신 적 있나요? "OpenAI API를 쓸까, 아니면 LLaMA 같은 오픈소스 모델을 직접 운영할까?" 매달 API 비용 청구서를 보면서 "이 돈이면 서버를 사는 게 나을 것 같은데..." 하는 생각 말이죠.

이런 선택의 갈림길은 모든 AI 개발자가 직면하는 문제입니다. OpenAI, Anthropic 같은 상용 API는 편리하지만 비용이 계속 나가고, 데이터가 외부로 나간다는 불안감이 있습니다.

반면 LLaMA, Mistral 같은 오픈 LLM은 무료지만 서버 관리, 모델 최적화 등 기술적 허들이 높습니다. 바로 이럴 때 필요한 것이 오픈 LLM의 장단점을 명확히 이해하는 것입니다.

어떤 상황에서는 오픈 LLM이 압도적으로 유리하고, 어떤 경우는 API가 훨씬 합리적입니다. 실무 관점에서 냉정하게 분석해보겠습니다.

개요

간단히 말해서, 오픈 LLM은 "소스 코드와 가중치가 공개되어 누구나 사용/수정/배포할 수 있는 AI 모델"입니다. 마치 오픈소스 소프트웨어처럼, Linux vs Windows의 선택과 비슷합니다.

오픈 LLM의 필요성은 세 가지 핵심 가치에 있습니다. 첫째, 비용 절감입니다.

API는 사용량에 비례하여 비용이 증가하지만, 오픈 LLM은 초기 인프라 비용만 들면 무제한 사용 가능합니다. 예를 들어, 월 1000만 건 요청이라면 API는 월 500만 원, 자체 서버는 월 100만 원(GPU 임대)입니다.

둘째, 데이터 보안입니다. 의료, 금융 데이터는 법적으로 외부 API에 보낼 수 없는 경우가 많습니다.

셋째, 커스터마이징 자유도입니다. 모델 구조를 직접 수정하거나 특수한 최적화를 적용할 수 있습니다.

하지만 단점도 명확합니다. 첫째, 기술적 난이도가 높습니다.

GPU 서버 세팅, 모델 최적화(quantization, vLLM 등), 스케일링 등 DevOps 지식이 필요합니다. 둘째, 성능 격차입니다.

GPT-4o나 Claude 3.5 Sonnet에 비하면 오픈 LLM(LLaMA 3.1 70B)의 품질이 10-20% 낮습니다. 셋째, 유지보수 부담입니다.

모델 업데이트, 보안 패치, 모니터링을 직접 해야 합니다. 오픈 LLM의 핵심 특징을 정리하면, "통제권과 책임의 트레이드오프"입니다.

모든 것을 자유롭게 할 수 있지만, 모든 책임도 여러분에게 있습니다. API는 그 반대입니다.

이 트레이드오프를 이해하고 프로젝트 특성에 맞게 선택하는 것이 실무 핵심입니다.

코드 예제

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# 오픈 LLM 장점 활용 예시: 로컬에서 무제한 사용
model_name = "meta-llama/Llama-3.1-8B-Instruct"

# 1단계: 모델 다운로드 및 로드 (한 번만 하면 됨, API는 매번 요청)
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.float16,  # 메모리 절약 (32bit → 16bit)
    device_map="auto"  # 자동으로 GPU에 분산 배치
)

# 2단계: 커스터마이징 - API로는 불가능한 제어
# 예: 특정 토큰 확률 직접 조작 (민감 정보 생성 방지)
def generate_with_custom_logic(prompt):
    inputs = tokenizer(prompt, return_tensors="pt").to("cuda")

    # 생성 파라미터 완전 제어 (API는 제한적)
    outputs = model.generate(
        **inputs,
        max_new_tokens=200,
        temperature=0.7,
        top_p=0.9,
        do_sample=True,
        repetition_penalty=1.2,  # 반복 방지
        pad_token_id=tokenizer.eos_token_id
    )

    return tokenizer.decode(outputs[0], skip_special_tokens=True)

# 3단계: 무제한 로컬 추론 (비용 = 전기세만)
result = generate_with_custom_logic("LLM 파인튜닝의 핵심은")
print(result)

설명

이것이 하는 일: 위 코드는 Meta의 LLaMA 3.1 모델을 로컬 서버에서 직접 실행하여, API 없이 무제한으로 텍스트를 생성합니다. 마치 "자기 집 텃밭에서 채소 키우기" vs "슈퍼에서 채소 사기"의 차이와 같습니다.

첫 번째로, AutoModelForCausalLM.from_pretrained()가 모델 전체를 여러분의 서버에 다운로드합니다. 8B 모델은 약 16GB(float16 기준)를 차지합니다.

이것이 오픈 LLM의 핵심 장점입니다. 한 번 다운로드하면 영원히 무료로 사용 가능합니다.

API라면 매번 요청마다 비용이 발생하죠. torch_dtype=torch.float16은 메모리를 절반으로 줄이는 기법으로, 정확도 손실은 1% 미만이지만 속도는 2배 빨라집니다.

그 다음으로, device_map="auto"가 자동으로 모델을 여러 GPU에 분산 배치합니다. 예를 들어 70B 모델을 4개의 A100 GPU에 나눠서 올립니다.

이런 세밀한 제어는 API로는 불가능합니다. 내부에서 Accelerate 라이브러리가 각 레이어를 분석하여 최적의 배치를 결정합니다.

세 번째 단계의 generate_with_custom_logic()이 오픈 LLM의 진가를 보여줍니다. repetition_penalty=1.2는 같은 단어 반복을 억제하고, temperature, top_p는 창의성을 조절합니다.

API도 이런 파라미터를 제공하지만, 오픈 LLM은 더 나아가 "특정 토큰 금지", "로짓 직접 수정", "디코딩 알고리즘 교체" 등 무한한 커스터마이징이 가능합니다. 예를 들어, 의료 AI라면 "환자 이름" 같은 민감 정보가 생성되지 않도록 해당 토큰의 확률을 0으로 만들 수 있습니다.

마지막으로, 이 모든 과정의 비용이 "GPU 전기세"만 든다는 점이 핵심입니다. AWS p3.2xlarge 인스턴스(V100 GPU)가 시간당 $3인데, 100만 건 요청을 처리할 수 있습니다.

OpenAI API라면 100만 건에 $600 정도 듭니다. 요청량이 많을수록 오픈 LLM이 압도적으로 저렴합니다.

여러분이 이 코드를 사용하면 다음과 같은 실무 이점이 있습니다. 첫째, 스케일 경제입니다.

스타트업 초기에는 API가 저렴하지만, DAU 10만 명 이상 서비스라면 자체 인프라가 10배 저렴합니다. 둘째, 데이터 주권입니다.

EU의 GDPR, 한국의 개인정보보호법을 100% 준수하려면 데이터를 외부에 보낼 수 없습니다. 셋째, 실험 자유도입니다.

새로운 디코딩 알고리즘, 커스텀 파인튜닝 기법을 마음껏 시도할 수 있습니다. 실무에서는 B2B SaaS(고객 데이터 보안 중요), 대용량 배치 처리(비용 절감 중요), AI 연구(커스터마이징 중요) 등에 오픈 LLM을 선호합니다.

실전 팁

💡 vLLM 라이브러리를 사용하면 추론 속도가 10-20배 빨라집니다. PagedAttention으로 메모리 효율도 2배 향상됩니다. 프로덕션 배포 시 필수입니다.

💡 모델 선택 기준: 7B는 단일 GPU(A100 40GB), 13B는 듀얼 GPU, 70B는 4-8 GPU 필요합니다. 비용과 성능을 고려하여 최소 크기를 선택하세요. 실험 결과 13B면 대부분 작업에 충분합니다.

💡 Quantization은 필수입니다. GPTQ나 AWQ로 4-bit 양자화하면 메모리가 1/4로 줄고, 속도는 2배 빨라지며, 정확도 손실은 2-3%입니다. bitsandbytes 라이브러리 활용하세요.

💡 오픈 LLM vs API 결정 기준: 월 요청 100만 건 미만이면 API, 100만 건 이상이면 오픈 LLM, 1000만 건 이상이면 무조건 오픈 LLM이 저렴합니다. 엑셀로 비용 시뮬레이션 해보세요.

💡 라이선스 주의사항: LLaMA는 상업적 사용 가능(단, MAU 7억 이상 제한), Mistral은 Apache 2.0(완전 자유), Falcon은 상업용 별도 라이선스 필요. 변호사와 확인 필수입니다.


#LLM#파인튜닝#Transfer Learning#Parameter-Efficient#Pre-training#AI,LLM,머신러닝,파인튜닝,NLP

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.