LLM Fine-tuning 실습 프로젝트 - Part 7

[LLM Inference]

Contents

  1. Inference - transformers
  2. Inference - vllm


1. Inference - transformers

(1) Import Packages

from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import os


(2) Load Model

Training할 것이 아니기 때문에, eval 모드로 설정한다 (.eval())

tokenizer = AutoTokenizer.from_pretrained("google/gemma-2-9b-it")
model = AutoModelForCausalLM.from_pretrained("google/gemma-2-9b-it",
                                             device_map="auto")

model.eval()
model.generation_config.max_new_tokens = 2048


(3) Input 예시

input text를 tokenizer를 통해 토큰으로 변환해준다.

  • 정수 integer id 값을 가지는 것을 확인할 수 있음
input_text='what is your name?'

input_ids= tokenizer(input_text,return_tensors='pt').to('cuda')
input_ids
{'input_ids': tensor([[     2,   5049,    603,    861,   1503, 235336]], device='cuda:0'), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1]], device='cuda:0')}


(4) Output 예시

출력값 또한 정수 integer id 값을 가지는 것을 확인할 수 있음

outputs=model.generate(**input_ids)
The 'max_batch_size' argument of HybridCache is deprecated and will be removed in v4.46. Use the more precisely named 'batch_size' argument instead.
Starting from v4.46, the `logits` model output will have the same type as the model (except at train time, where it will always be FP32)


outputs
tensor([[     2,   5049,    603,    861,   1503, 235336,    109,   2926,   1503,
            603, 137061, 235265,    590,   1144,    671,   2174, 235290,  30316,
          16481,  20409, 235265,    107,    108,      1]], device='cuda:0')


(5) 전체 과정

input_text='안녕하세요!'
input_ids = tokenizer(input_text, return_tensors='pt').to('cuda')
print(input_ids.input_ids)
tensor([[     2, 238179, 243415, 204551, 235341]], device='cuda:0')


outputs = model.generate(input_ids=input_ids.input_ids,
                       return_dict_in_generate=True,
                       output_scores=True,
                       temperature=0.05,
                       top_k=10,
                       top_p= 0.9,
                       do_sample=True
                       )


각 단어에 대한 predicted probability 또한 확인할 수 있다

logits = outputs.scores


참고) outputs.sequences는, input text ( = 안녕하세요 ) 또한 담고 있다.

print(tokenizer.batch_decode(outputs.sequences,skip_special_tokens=True)[0])
안녕하세요! 

오늘은 

**"내가 좋아하는 옷 스타일"**

에 대해 이야기해보려고 합니다. 

저는 옷을 통해 자신감을 표현하고 싶어하는 편이에요. 

따라서 옷 스타일은 

...


(6) 기타: pipeline

from transformers import pipeline

pipe = pipeline(model=model, 
                task='text-generation',
               tokenizer=tokenizer)

input_text = '대한민국의 수도는?'
pipe(input_text)
[{'generated_text': '대한민국의 수도는?\n\n정답: 서울\n'}]


2. Inference - vllm

(1) Import Packages

import vllm
from vllm import LLM, SamplingParams
from typing import List
from vllm.outputs import RequestOutput


(2) Load Model

base_model= 'google/gemma-2-9b-it' # SFT모델이 여기에 들어가야함 => 저장된 SFT 절대경로로 지정
gpu_num= 4
max_token: int = 4096
model = LLM(model=base_model, tensor_parallel_size=gpu_num, max_model_len=max_token,
            gpu_memory_utilization=0.8)


(3) 생성을 위한 parameter 설정

sampling_params = SamplingParams(
    top_k=5, 
    top_p=1, 
    max_tokens=max_token, 
    temperature=1, 
    best_of=13, 
    n=6, 
    stop=['<|endoftext|>', '</s>', '<|im_end|>', '<|end_of_text|>']
)

파라미터 설명
top_k=5 다음 단어를 예측할 때 확률이 높은 상위 5개 후보 중에서만 샘플링 (일반적으로 작은 값일수록 보수적인 생성)
top_p=1 Nucleus Sampling (Top-p): 누적 확률이 1.0 이하인 단어들 중에서 샘플링 (여기서는 사실상 활성화되지 않음)
max_tokens=max_token 한 번에 생성할 최대 토큰 수를 지정 (변수 max_token 값에 따라 다름)
temperature=1 모델이 단어를 선택할 때의 랜덤성(샘플링의 다양성)을 조절하는 온도 값 (1이면 기본 설정, 높을수록 창의적, 낮을수록 보수적)
best_of=13 총 13개의 시도를 수행하여 가장 좋은 결과를 선택 (일반적으로 더 높은 값은 더 좋은 결과를 줄 수 있음)
n=6 한 번의 요청에서 6개의 출력을 생성 (여러 개의 응답을 동시에 얻음)


(4) Input 예시

prompts= ['이름이 뭐야?', '세종대왕은 몇살이야?','너무 졸려 근데 일이 많아...']


(5) Output 예시

outputs: List[RequestOutput] = model.generate(prompts, sampling_params)


(6) 결과 확인하기

outputs[0].prompt
'이름이 뭐야?'


outputs[0].outputs
[CompletionOutput(index=0, text='\n\n', token_ids=(108, 107, 108, 1), cumulative_logprob=None, logprobs=None, finish_reason=stop, stop_reason=None),
 CompletionOutput(index=1, text=' \n', token_ids=(235248, 108, 107, 1), cumulative_logprob=None, logprobs=None, finish_reason=stop, stop_reason=None),
 CompletionOutput(index=2, text='\n\n저는 지혜입니다. 대규모 언어 모델입니다.\n', token_ids=(109, 238721, 236214, 34805, 242166, 47555, 235265, 26801, 240753, 237551, 171754, 236770, 162570, 47555, 235265, 107, 108, 1), cumulative_logprob=None, logprobs=None, finish_reason=stop, stop_reason=None),
 CompletionOutput(index=3, text=' \n\n이름이 뭐예요? \n\n어떤 이름이 좋아요? \n\n저는 이름이 뭐라고 하세요? \n\n\n이 외에도 다양한 표현으로 이름을 물을 수 있습니다.\n\n* 당신의 이름은 무엇이에요? \n* 이름이 뭔가요? \n* 어떤 이름을 쓰시나요?\n\n어떤 상황에 따라 적절한 표현을 선택하세요.\n', token_ids=(235248, 109, 235832, 239295, 235832, 235248, 245365, 238748, 237526, 235336, 235248, 109, 236770, 242251, 145887, 235832, 227991, 237526, 235336, 235248, 109, 238721, 236214, 145887, 235832, 235248, 245365, 112778, 30181, 96673, 235336, 235248, 110, 235832, 136201, 209929, 32048, 238780, 236511, 100280, 238513, 26291, 145887, 236392, 108321, 236392, 22618, 55496, 235265, 109, 235287, 132333, 236137, 145887, 236648, 60331, 242513, 235832, 236179, 237526, 235336, 235248, 108, 235287, 145887, 235832, 235248, 247291, 236361, 237526, 235336, 235248, 108, 235287, 53355, 242251, 145887, 236392, 198670, 236569, 236915, 237526, 235336, 109, 236770, 242251, 36203, 240054, 236179, 156976, 99797, 240046, 236511, 100280, 238513, 236392, 134472, 204551, 235265, 107, 108, 1), cumulative_logprob=None, logprobs=None, finish_reason=stop, stop_reason=None),
 CompletionOutput(index=4, text='\n', token_ids=(108, 1), cumulative_logprob=None, logprobs=None, finish_reason=stop, stop_reason=None),
 CompletionOutput(index=5, text=' 뭐라고 불러야 할까?\n\n', token_ids=(235248, 245365, 112778, 83133, 237822, 238305, 69225, 239303, 235336, 108, 107, 108, 1), cumulative_logprob=None, logprobs=None, finish_reason=stop, stop_reason=None)]


outputs[0].outputs[2].text
'\n\n저는 지혜입니다. 대규모 언어 모델입니다.\n'


Reference

https://fastcampus.co.kr/data_online_gpu

Categories: , ,

Updated: