LLM Fine-tuning 실습 프로젝트 - Part 7
[LLM Inference]
Contents
- Inference -
transformers
- 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