LLM (2)

Myeongsu Moon·2025년 1월 24일

제로베이스

목록 보기
68/95
post-thumbnail

Chapter 2 한글로 튜닝된 LLaMa 모델로 챗봇 만들기

LLaMa

  • LLaMa3
    -> LLaMa(Large Language Model Meta AI) 모델은 Meta(옛 페이스북)에서 개발한 대규모 언어 모델 시리즈
    -> 기존에 널리 사용되던 거대 언어 모델(예: GPT 계열, BERT, RoBERTa 등)은 주로 클로즈드 소스 형태로 제공되 거나, 특정 기업의 API 형태로만 접근 가능한 경우가 많음
    -> LLaMa는 연구자들과 개발자들이 더욱 쉽게 활용하고 실험할 수 있도록 일부 모델 가중치와 코드를 공개적으로 배포하여 오픈소스 생태계 발전에 기여하고자 하는 취지에서 탄생
    -> 고성능, 경량화: 대규모 파라미터(수십 억 개 이상)를 가진 모델임에도 효율적인 훈련 및 추론이 가능하도록 최적화
    -> 다양한 파라미터 크기: 연구 용도나 배포 환경에 따라 선택적으로 활용할 수 있도록 다양한 규모(7B, 13B, 30B, 65B 등)의 모델을 제공
    -> 광범위한 언어 처리 능력: 질의응답, 번역, 글 작성, 코드 도움 등 다양한 자연어 처리 태스크를 효과적으로 수행
!pip install -q transformers==4.40.0 accelerate gradio
import os
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

model_id = 'beomi/Llama-3-Open-Ko-8B-Instruct-preview'
  • 평가모드로 모델 세팅
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    torch_dtype="auto",
    device_map="auto",
)
model.eval()
  • 포롬프트와 인스트럭션
PROMPT = '''친절한 챗봇으로서 상대방의 요청에 최대한 친절하게 답하자.모든 대답은 한국어로 대답해줘.'''
instruction = "Python에서 입력된 두개의 문자열을 합쳐서 출력 하는 함수(def)를 만들어줘"

messages = [
    {"role": "system", "content": f"{PROMPT}"},
    {"role": "user", "content": f"{instruction}"}
  • "system" 역할:
    -> 시스템 메시지는 모델의 전체적인 행동 지침, 컨텍스트, 스타일 등을 제시.
    -> 예를 들어 PROMPT 라는 시스템 메시지에는 모델이 대화를 진행할 때 따라야 할 규칙이나 제약사항, 그 리고 전체적인 대화의 주제를 제시
    -> 이후 사용자와의 대화 도중에도 모델은 시스템 메시지에 제시된 가이드라인을 참고하여 응답을 생성
    -> 꼭 그 역할을 지키는것은 아님

  • "user" 역할:
    -> 사용자 메시지는 모델이 실제로 응답을 생성해야 하는 지시
    -> 사용자가 명령이나 질문을 던지는 형태로, 이를 통해 모델은 현재 대화 차례에서 무엇에 답해야 하는지 를 파악

  • messages를 모델이 이해할 수 있는 입력 형식으로 변환

input_ids = tokenizer.apply_chat_template(
    messages,
    add_generation_prompt=True,
    return_tensors="pt"
).to(model.device)
  • 모델의 텍스트 생성 종료 조건
terminators = [
    tokenizer.eos_token_id,
    tokenizer.convert_tokens_to_ids("<|eot_id|>")
]
  • 추론
outputs = model.generate(
    input_ids,
    max_new_tokens=512,
    eos_token_id=terminators,
    do_sample=True,
    temperature=1,
    top_p=0.9,
)

-> input_ids 로부터 최대 512 토큰의 새로운 텍스트를 샘플링 방식으로 생성
-> eos_token_id 로 지정한 terminators 토큰을 만나면 출력을 멈추며,
-> temperature=1 과 top_p=0.9 는 생성 시의 랜덤성과 다양성을 조절
--> 1보다 작으면 모델이 더 보수적으로, 높은 확률의 토큰을 선호하게 되고,
--> 1보다 크면 더 다양한(확률이 낮은) 토큰도 선택하는 경향이 커짐
--> top_p=0.9 는 누클리어스 샘플링(Nucleus Sampling) 기법을 적용하는 파라미터
--> 모델이 다음 단어를 선택할 때 전체 확률 분포 중 상위 90%의 누적 확률을 차지하는 토큰들만 후보로 삼 도록 제한
--> 아주 낮은 확률을 가진 토큰들은 거의 선택되지 않아 출력 품질을 유지
--> 단순히 가장 확률이 높은 단어만 택하는 것보다 더 다양한 응답을 생성

  • 결과
from pprint import pprint

response = outputs[0][input_ids.shape[-1]:]
pprint(tokenizer.decode(response, skip_special_tokens=True))

GRADIO를 사용해 챗봇 구현

  • Gradio는 머신러닝(특히 딥러닝) 모델을 웹 인터페이스 형태로 빠르고 손쉽게 공유하고 시연할 수 있도록 도와 주는 Python 라이브러리

  • 복잡한 웹 서버나 프론트엔드 구현 없이도 간단한 함수 호출만으로 웹 브라우저에서 모델의 입력/출력 인터페이 스(텍스트 박스, 이미지 업로드, 음성 녹음 등)를 생성

  • 메시지를 만드는 함수

def build_messages(PROMPT, chat_history, input_text):
    messages = [{"role": "system", "content": f"{PROMPT}"}]

    for message in chat_history:
        user_msg, assistant_msg = message
        messages.append({"role": "user", "content": user_msg})
        messages.append({"role": "assistant", "content": assistant_msg})

    messages.append({"role": "user", "content": input_text})
    return messages
  • 모델 추론을 위해 토큰 반환 함수
def get_input_ids(tokenizer, model, messages):
    input_ids = tokenizer.apply_chat_template(
        messages,
        add_generation_prompt=True,
        return_tensors="pt"
    ).to(model.device)
    return input_ids
  • 종료 조건
def get_terminators(tokenizer):
    terminators = [
        tokenizer.eos_token_id,
        tokenizer.convert_tokens_to_ids("<|eot_id|>")
    ]
    return terminators
  • 추론 함수
def generate_outputs(model, input_ids, terminators):
    outputs = model.generate(
        input_ids,
        max_new_tokens=512,
        eos_token_id=terminators,
        do_sample=True,
        temperature=1,
        top_p=0.9,
    )
    return outputs
  • 출력 결과 정리
def decode_response(tokenizer, outputs, input_ids):
    response_ids = outputs[0][input_ids.shape[-1]:]
    response = tokenizer.decode(response_ids, skip_special_tokens=True)
    return response
  • 함수들로 채팅이 가능하도록 history 정리
def generate_response(input_text, chat_history):
    messages = build_messages(PROMPT, chat_history, input_text)
    input_ids = get_input_ids(tokenizer, model, messages)
    terminators = get_terminators(tokenizer)
    outputs = generate_outputs(model, input_ids, terminators)
    response = decode_response(tokenizer, outputs, input_ids)

    chat_history.append((input_text, response))
    return "", chat_history
  • gradio를 사용해서 채팅창 생성
import gradio as gr

with gr.Blocks() as demo:
    chatbot = gr.Chatbot(height=600)
    msg = gr.Textbox()
    clear = gr.Button("Clear")

    msg.submit(generate_response, [msg, chatbot], [msg, chatbot])
    clear.click(lambda: None, None, chatbot, queue=False)

demo.launch()

이 글은 제로베이스 데이터 취업 스쿨의 강의 자료 일부를 발췌하여 작성되었습니다

0개의 댓글