LLM_한국어_챗봇_실습

실습 단계

  1. 프롬프트 엔지니어링
    1. 효과적인 챗봇 응답 생성을 위한 프롬프트 최적화 기법
    2. Chain of Thought(CoT), Chain of Density(CoD) 

  2. 경량화 미세튜닝 (LoRA 적용)
    1. LoRA 기법을 활용하여 모델을 사용자의 필요에 맞게 추가 학습
    2. 기존 모델을 직접 전체 학습하는 대신, 적은 연산량으로도 미세튜닝할 수 있도록 설정

  3. 검색 기반 대화 생성 (RAG 적용)
    1. 기존 모델이 가지고 있는 정보만 활용하는 것이 아니라, 외부 문서를 검색하여 최신 정보를 반영할 수 있도록 RAG 기법을 적용
    2. 이를 통해 대화의 정확성과 다양성을 높임

  4. 챗봇 성능 평가
    1. BLEU, BERTScore, 대화 일관성(Coherence) 등의 다양한 평가 지표를 활용하여 챗봇 응답의 품질을 정량적으로 분석
    2. 평가 지표를 적용하여 챗봇이 얼마나 자연스럽고 정확한 응답을 생성하는지 확인

  5. 코드 구성 및 실행
    1. Google Colab 환경에서 원활하게 실행할 수 있도록 환경을 설정
    2. Markdown 설명과 함께 Hugging Face에서 모델을 로드하고, 챗봇의 대화 테스트를 수행

환경설정 및 라이브러리

라이브러리 설치 버전 주요 용도
accelerate 1.4.0         모델 학습 속도 개선(GPU/TPU 최적화 지원)
gcsfs         2023.6.0 Google Cloud Storage 파일 접근 지원
datasets 2.14.5 Hugging Face 데이터셋 로딩 및 전처리 지원
peft         0.4.0          LLM 경량화 파인튜닝 지원 (LoRA 등)
evaluate 0.4.0          모델 평가 및 지표(metric) 관리 지원

실습에 필요한 패키지
  • accelerate:

    • GPU 가속을 위한 도구
    • 분산 학습과 대규모 모델 학습을 더 쉽게 만들어주는 라이브러리
  • peft (Parameter-Efficient Fine-Tuning):

    • 효율적인 파인튜닝을 위한 라이브러리
    • LoRA와 같은 경량화된 학습 방법을 제공
!pip install accelerate==1.4.0
!pip install gcsfs==2023.6.0
!pip install datasets==2.14.5 peft==0.4.0 evaluate==0.4.0

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM, AutoModelForSeq2SeqLM, pipeline
from datasets import load_dataset
from peft import LoraConfig, get_peft_model
import evaluate
import numpy as np

# 모델 및 토크나이저 로드
from transformers import AutoTokenizer, AutoModelForCausalLM

# 모델명 지정
model_name = "torchtorchkimtorch/Llama-3.2-Korean-GGACHI-1B-Instruct-v1"

# Hugging Face에서 토크나이저 및 모델 불러오기
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", torch_dtype=torch.float16)

print("✅ 모델 및 토크나이저 로드 완료")

# 간단한 대화 테스트
prompt = "사용자: 안녕하세요?\n어시스턴트:"
inputs = tokenizer(prompt, return_tensors='pt').to(model.device)

# 모델 응답 생성 (temperature 추가로 더 자연스러운 결과 유도)
outputs = model.generate(**inputs, max_new_tokens=100, do_sample=True, temperature=0.7)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)

# 출력 형식 개선
print(response.split("\n")[-1])  # 어시스턴트의 마지막 응답만 출력


프롬프트 엔지니어링

Chain of Thought (CoT) 기법
모델에게 "그냥 답을 내라"는 대신 추론 과정을 함께 출력하도록 지시함
사용자: 철수에게 사과 3개가 있었고, 영희에게 2개를 주었습니다. 철수에게 남은 사과는 몇 개인가요?
어시스턴트: 문제를 하나씩 단계적으로 해결해 보겠습니다.
  - 단계 1: 철수는 처음에 3개의 사과를 가지고 있었습니다.
  - 단계 2: 철수는 영희에게 2개의 사과를 주었습니다.
  - 단계 3: 따라서, 철수에게 남은 사과는 3 - 2 = 1개입니다.
결론: 철수에게 남은 사과는 1개입니다.

Chain of Density(CoD) 기법
처음에는 짧고 핵심적인 응답을 생성
이후 점진적으로 추가 정보를 포함하면서도 응답 길이를 유지하도록 유도
사용자: 관성력이란?
어시스턴트: 물체가 외부 힘이 없을 때 기존 운동 상태를 유지하려는 성질입니다. (1차 응답)
사용자: 좀 더 자세히 설명해 줄 수 있나요?
어시스턴트: 관성력은 뉴턴의 제1법칙(관성의 법칙)과 관련이 있습니다. 예를 들어, 움직이는 자동차가 갑자기 멈추면 탑승자는 계속 앞으로 나아가려 합니다. (2차 응답)

Chain of Draft(CoD) 기법
1단계: 최소한의 핵심 정보를 포함한 초안(Draft) 생성
2단계: 초안을 기반으로 부족한 정보를 보완하여 최적화된 최종 답변 생성
사용자: "AI는 인간에게 어떤 영향을 미칠까요?"
어시스턴트(초안): "AI는 산업, 교육, 의료 등 다양한 분야에서 활용됩니다."
사용자: "좀 더 자세히 설명해줄래?"
어시스턴트(보강): "AI는 산업, 교육, 의료 등 다양한 분야에서 활용되며, 특히 자동화 기술과 데이터 분석을 통해 생산성을 높이고 인간의 노동 부담을 줄이는 데 기여합니다."


기법 / Chain of Density (CoD)                  / Chain of Draft (CoDft)
목적 / 정보를 점진적으로 확장                 / 초안을 생성하고 보강
방식 / 기존 답변을 포함해 추가 설명 요청  / 초안(draft)을 생성 후 보강 요청
예시  / "좀 더 자세히 설명해줘."                / "이전 답변을 더 구체적으로 설명해줘."
출력  / 더 풍부한 설명이 추가됨                / 초안에서 점진적으로 보강됨

LoRA를 활용한 모델 경량 미세튜닝

이미 학습된 기본 weight는 고정시키고, weight를 추가하여 학습시킨다.

대화 데이터셋 사용: KoAlpaca (Alpaca를 한국어로 변환. )
이때의 대화 데이터셋은 어떤 질문을 주로 했고 어떤 답변의 포맷을 했는지 확인해야 한다.

최근 업데이트: QLoRA, MoRA

1) 대화 데이터셋 준비

dataset = load_dataset("royboy0416/ko-alpaca")
print(dataset)
print("예시 샘플:", dataset["train"][0])

def format_qa(example):
    instr = example["instruction"].strip()
    out = example["output"].strip()
    text = f"질문: {instr}\n답변: {out}"
    return {"text": text}

train_data = dataset["train"].map(format_qa)
print("포맷된 예시:", train_data[0]["text"])
# 포맷된 예시: 질문: 건강을 유지하기 위한 세 가지 팁을 알려주세요.
#            답변: 세 가지 팁은 아침식사를 꼭 챙기며, 충분한 수면을 취하고, 적극적으로 운동을 하는 것입니다.



(2) 사전훈련 모델 및 LoRA 설정

from peft import LoraConfig, get_peft_model

# LoRA 설정 구성
lora_config = LoraConfig(
    r=8,            # 랭크(rank) 값, loRA 행렬의 차원
    lora_alpha=16,  # 로라 학습률 스케일러(alpha)
    target_modules=["q_proj", "v_proj"],  # LoRA 적용 대상 모듈 (모델 종류에 맞게 설정)
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"  # 언어모델(자동완성) 유형
)
model = get_peft_model(model, lora_config)
print("LoRA 적용 완료:", type(model))


(3) 모델 미세튜닝 (학습)

# 토큰화 함수: 텍스트 -> input ids (모델 입력용 토큰 시퀀스)
def tokenize_function(example):
    return tokenizer(example["text"], truncation=True)

tokenized_dataset = train_data.map(tokenize_function, batched=True, remove_columns=["instruction", "input", "output", "text"])

from transformers import TrainingArguments, Trainer, DataCollatorForLanguageModeling

training_args = TrainingArguments(
    output_dir="chatbot-lora-checkpoints",
    per_device_train_batch_size=4,
    num_train_epochs=1,
    logging_steps=100,
    save_steps=500,
    fp16=True,  # GPU 반정밀도 사용
    optim="adamw_torch",  # 옵티마이저 설정
    report_to="none"      # (보고 비활성화)
)

# Data collator 설정 (자동으로 배치 내 시퀀스 패딩 및 causal LM용 레이블 생성)
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset,
    data_collator=data_collator
)

trainer.train()


(4) 튜닝 후 챗봇 성능 확인

# 튜닝된 모델로 답변 생성
test_prompt = "질문: 기본 색은 무엇인가요?\n답변:"
inputs = tokenizer(test_prompt, return_tensors='pt', return_token_type_ids=False).to(model.device)  # token_type_ids 제거
output_ids = model.generate(**inputs, max_new_tokens=100)
print(tokenizer.decode(output_ids[0], skip_special_tokens=True))


양자화

8-bit 양자화: 파라미터의 각 자료형(8bit로)을 단순하게 만든다.

대화 기록 및 RAG를 활용한 답변 생성

(1) 대화 히스토리 활용하기
  • 히스토리 리스트 만들기
  • 사용자 질문 + 프롬프트를 자연어 모델에 입력하고 답변 받기
  • 입력값과 답변을 히스토리 리스트에 저장
  • 이 히스토리를 RAG에 활용

(2) RAG (Retrieval-Augmented Generation) 적용
  • 딕셔너리 생성(key, 설명)
  • 질문 내용 중에 key가 있는지 확인
  • 설명을 가져와서 프롬프트에 함께 넣어줌
  • 프롬프트: 딕셔너리설명 + 프롬프트엔지니어링 + 사용자질문

챗봇 성능 평가

BLEU: 단어 중복률
원래 기계번역 성능 평가를 위해 고안된 n-그램 정밀도 기반 점수입니다. 모델의 답변과 하나 이상의 레퍼런스(기준) 답변 사이의 표면적 단어 중복률을 측정합니다​. 값이 0에 가까우면 전혀 겹치지 않음을, 100에 가까우면 완전히 동일함을 의미합니다. 대화 응답은 정답이 여러 가지일 수 있으므로 BLEU는 참고용으로만 사용됩니다.

BERTScore: 의미적 유사
BERT 등의 사전훈련 언어모델 임베딩을 활용하여 모델 응답과 참조 응답 간의 의미적 유사도를 측정하는 지표입니다​. 단어 매칭에 의존하지 않고 문장 의미 유사도를 평가하므로, BLEU처럼 단어가 정확히 일치하지 않아도 의미가 비슷하면 높은 점수를 줄 수 있습니다. 대화 응답의 유연한 평가에 유용합니다.

Coherence: 일관성
대화의 흐름 상 응답이 문맥에 잘 맞고 일관적인지를 나타내는 개념적인 지표입니다. 자동 평가로 정량화하기는 어렵지만, 예를 들어 이전 대화와 모순되지 않거나, 적절히 연결되는지를 측정하려는 시도가 있습니다. 간단한 방법으로는 문맥-응답 간 임베딩 유사도나 언어 모델의 다음 발화 예측 확률 등을 활용할 수 있지만, 여전히 사람 평가에 많이 의존합니다. (일관성 평가는 구체적 수치보다는 qualitative하게, 예시 대화 등을 검토하여 판단하는 경우가 많습니다.)

!pip install sacrebleu bert-score
import evaluate
bleu = evaluate.load("sacrebleu")
bertscore = evaluate.load("bertscore")

# 예시 모델 응답과 레퍼런스 정답 준비
predictions = [
    "기본 색은 빨강, 파랑, 노랑입니다.",    # 모델의 답변 1
    "스티브 잡스는 애플의 창업자입니다."    # 모델의 답변 2
]
references = [
    ["기본 색상은 빨강, 파랑, 노랑이다."],  # 정답 예시 1 (동일 의미, 표현만 약간 다름)
    ["스티브 잡스는 Apple사의 공동 창립자이다."]  # 정답 예시 2
]

# BLEU 계산
bleu_result = bleu.compute(predictions=predictions, references=references)
print("BLEU 점수:", bleu_result["score"])

# BERTScore 계산 (한국어 설정)
bert_result = bertscore.compute(predictions=predictions, references=[ref[0] for ref in references], lang="ko")
print("BERTScore F1:", bert_result["f1"])





댓글 쓰기

다음 이전