카테고리 없음

허깅페이스 LLM fine-tuning하기 (1)

leejeong6 2025. 5. 9. 15:28

hugging face 로그인 후 원하는 LLM 찾아서 불러오는 과정은 생략

 

저는 SKT에서 만든 KoGPT2를 가져다가 safety에 대한 데이터로 fine-tuning 하였습니다

 

먼저 https://huggingface.co/skt/kogpt2-base-v2에서 코드를 불러옵니다.

 

# Load model directly
from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained("skt/kogpt2-base-v2")
model = AutoModelForCausalLM.from_pretrained("skt/kogpt2-base-v2")

그러면 이제 kogpt2 tokenizer와 model을 쓸 수 있습니다.

참고로 이 코드를 실행 전에 pip install transformers, datasets는 필수입니다

 

AutoTokenizer, AutoModelForCausalLM과 같이 앞에 Auto가 붙은 라이브러리는 자동으로 불러온 모델에 맞는 구성으로 로드해 주는 역할입니다.

참고로 GPT2 LMHeadModel이라는 클래스도 있는데, 이는 AutoModelForCausalLM과 달리 GPT2모델에 딱 맞는 정해진 클래스로 kogpt의 경우 GPT2를 기반으로 만들어졌기 때문에 이 클래스도 사용가능합니다

 

print(tokenizer)

tokenizer는 어떻게 구성되어 있나 확인해 봤습니다.

이 토크나이저는 사람이 학습한 게 아니라 kogpt에 맞게 불러와진 tokenizer입니다.

결과는 아래와 같이 나왔습니다

GPT2TokenizerFast(name_or_path='skt/kogpt2-base-v2', vocab_size=51200, model_max_length=1000000000000000019884624838656, is_fast=True, padding_side='right', truncation_side='right', special_tokens={'bos_token': '<|endoftext|>', 'eos_token': '<|endoftext|>', 'unk_token': '<|endoftext|>'}, clean_up_tokenization_spaces=False, added_tokens_decoder={
	0: AddedToken("<s>", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
	1: AddedToken("</s>", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
	2: AddedToken("<usr>", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
	3: AddedToken("<pad>", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
	4: AddedToken("<sys>", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
	5: AddedToken("<unk>", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),

name_or_path:모델 경로

vocab_size:토크나이저가 인식할 수 있는 전체 토큰 수

model_max_length:허용가능한 토큰 길이

padding_side='right' : 시퀀스가 짧으면 오른쪽에 padding을 추가

truncation_side='right' : 시퀀스가 길면 오른쪽을 자름

specail_tokens : bos, eos, unk모두 <|endoftext|>를 사용     

    -GPT는 기본적으로 |endoftext| (end-of-sequence, EOS)만을 사용합니다

    -GPT decoder 기반인 BERT는 아래와 같은 여러 토큰을 추가해서 더 좋은 성능을 나타낼 수 있다고 합니다.

  • <PAD>: 시퀀스의 길이를 맞추기 위한 패딩 토큰. 시퀀스들의 길이를 동일하게 맞춰주기 위해 추가되는 토큰이다.
  • <UNK>: 모르는 단어를 나타내는 토큰. 어휘에 없는 단어나 희귀한 단어 등을 대체하는 용도로 사용된다.
  • <SOS>: 문장의 시작을 나타내는 토큰. 번역이나 생성 모델에서 사용되어 문장 생성의 시작을 표시한다.
  • <EOS>: 문장의 끝을 나타내는 토큰. 번역이나 생성 모델에서 사용되어 문장 생성의 종료를 표시한다

clean_up_tokenization_spaces:토크나이징 후 불필요한 공백을 자동제거 

added_tokens_decoder={  }: 사용자가 추가로 정의한 토큰 ex) 이모티콘

 

다음은 padding token입니다

아무것도 모르고 할 때 여기서 오류가 가장 많이 발생했는데 GPT2계열의 모델은 원래 pad_token이 없습니다.

그 이유는 이전 문장을 기반으로 다음 문장을 예측하기 때문입니다. 근데 batch를 처리할 때 입력 길이가 서로 다르면, 짧은 문장은 반드시 padding으로 맞춰야 하며 CrossEntropyLoss에서 ignore_index를 처리하려면 pad_token_idx가 있어야 합니다.

그리고 generation시 padding은 무시해야 하니까 아래와 같은 코드를 넣습니다.

tokenizer.pad_token = tokenizer.eos_token
model.config.pad_token_id = tokenizer.eos_token_id

또는 아래와 같이 pad_token을 직접 설정할 수도 있습니다.

tokenizer = PreTrainedTokenizerFast.from_pretrained("skt/kogpt2-base-v2",
  bos_token='</s>', eos_token='</s>', unk_token='<unk>',
  pad_token='<pad>', mask_token='<mask>')

 

최종적으로 text를 생성해서 아래와 같이 비교 실험해 봤습니다

"""1번"""

tokenizer = AutoTokenizer.from_pretrained("skt/kogpt2-base-v2")
model = AutoModelForCausalLM.from_pretrained("skt/kogpt2-base-v2")
tokenizer.pad_token = tokenizer.eos_token
model.config.pad_token_id = tokenizer.eos_token_id
text = '근육이 커지기 위해서는'
input_ids = tokenizer.encode(text, return_tensors='pt')
gen_ids = model.generate(input_ids,
                           max_length=128,
                           repetition_penalty=2.0,
                           pad_token_id=tokenizer.pad_token_id,
                           eos_token_id=tokenizer.eos_token_id,
                           bos_token_id=tokenizer.bos_token_id,
                           use_cache=True)
generated = tokenizer.decode(gen_ids[0])
print(generated)


"""2번"""

tokenizer = PreTrainedTokenizerFast.from_pretrained("skt/kogpt2-base-v2",
  bos_token='</s>', eos_token='</s>', unk_token='<unk>',
  pad_token='<pad>', mask_token='<mask>')
model = GPT2LMHeadModel.from_pretrained('skt/kogpt2-base-v2')
text = '근육이 커지기 위해서는'
input_ids = tokenizer.encode(text, return_tensors='pt')
gen_ids = model.generate(input_ids,
                           max_length=128,
                           repetition_penalty=2.0,
                           pad_token_id=tokenizer.pad_token_id,
                           eos_token_id=tokenizer.eos_token_id,
                           bos_token_id=tokenizer.bos_token_id,
                           use_cache=True)
generated = tokenizer.decode(gen_ids[0])
print(generated)

결과는 당연히 근육이 커지기 위해서는 무엇보다 규칙적인 생활습관이 중요하다. 특히, 아침식사는 단백질과 비타민이 풍부한 과일과 채소를 많이 섭취하는 것이 좋다. 또한 하루 30분 이상 충분한 수면을 취하는 것도 도움이 된다. 아침 식사를 거르지 않고 규칙적으로 운동을 하면 혈액순환에 도움을 줄 뿐만 아니라 신진대사를 촉진해 체내 노폐물을 배출하고 혈압을 낮춰준다. 운동은 하루에 10분 정도만 하는 게 좋으며 운동 후에는 반드시 스트레칭을 통해 근육량을 늘리고 유연성을 높여야 한다. 운동 후 바로 잠자리에 드는 것은 피해야 하며 특히 아침에 일어나면 몸이 피곤해지기 때문에 무리하게 움직이면 오히려 역효과가 날 수도 있다. 운동을

둘 다 똑같이 나왔습니다. 그저 tokenizer를 어떻게 하냐 차이니까 하나의 text만 이렇게 비교하면 당연한 결과입니다.