4장. LLM 을 완성하는 3단계와 Hugging Face
Auto 클래스로 불러오기
처음 가는 식당에서 "오늘의 추천"이라고만 말하면 주방이 알아서 맞는 요리와 그릇을 내옵니다. transformers 의 Auto 클래스가 이렇습니다. 모델 이름만 주면 그 모델에 맞는 토크나이저와 모델 클래스를 골라 불러옵니다.
1번에서 Hub 의 모델 이름을 고르면, 2번 AutoTokenizer 와 3번 AutoModelFor… 가 같은 이름으로 짝이 맞는 토크나이저와 모델을 불러옵니다. 4번에서 generate() 로 토큰을 만들고 decode() 로 글로 바꿉니다. 여기서 "오늘의 추천"이 모델 이름, 알아서 나오는 요리와 그릇이 모델과 토크나이저입니다.
쓰임에 따른 Auto 클래스
| 클래스 | 쓰임 | 이 과정에서 |
|---|---|---|
AutoTokenizer | 그 모델의 토크나이저 | 내내 |
AutoModelForCausalLM | 앞만 보고 다음 토큰을 쓰는 모델(GPT 류) | 3장 실습 6, 4장 |
AutoModelForSeq2SeqLM | 읽고 새로 쓰는 인코더-디코더(번역) | 3장 실습 5 |
AutoModel | 머리(출력층) 없이 벡터만 내는 모델 | 7장 임베딩 |
AutoConfig | 설정 파일만 | 4장 |
토크나이저가 하는 세 가지
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B")
text = "배송비는 얼마인가요?"
ids = tok(text)["input_ids"] # 1) 글 → 번호
print(ids)
print(tok.convert_ids_to_tokens(ids)) # 2) 번호 → 토큰 조각
print(tok.decode(ids)) # 3) 번호 → 글이 문장은 Qwen 의 토크나이저로 토큰 9개가 됩니다. 조각은 ë°°, Ġìĸ¼ë§Ī 같은 낯선 글자로 보이는데, 이 토크나이저가 글을 바이트 단위로 자르기 때문입니다. decode 하면 원래 문장이 그대로 돌아옵니다.
코드에 나오는 함수
| 코드 | 쉬운 뜻 |
|---|---|
AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B") | 모델 이름에 맞는 토크나이저를 Hub 에서 받아 만든다. 처음 한 번은 인터넷이 필요하다 |
tok(text)["input_ids"] | 글을 토큰 번호 목록으로 바꾼다. 토크나이저는 사전을 돌려주는데, 그 가운데 input_ids(입력 번호) 칸만 꺼낸다 |
tok.convert_ids_to_tokens(ids) | 번호를 토크나이저 안에 적힌 토큰 조각으로 바꾼다. 조각은 사람이 읽기 어려운 바이트 꼴일 수 있다 |
tok.decode(ids) | 번호를 다시 사람이 읽는 글로 되돌린다. decode 는 "부호를 풀다"라는 뜻이다 |
이 코드가 뜻하는 것
은행 창구의 번호표를 떠올려 보세요. 손님(글)이 오면 번호표(토큰 번호)를 뽑아 주고, 창구는 번호만 보고 일을 합니다. 번호표 뒷면에는 기계가 쓰는 표시(토큰 조각)가 찍혀 있고, 마지막에 번호를 부르면 다시 손님 이름(글)이 됩니다.
| 줄 | 하는 일 | 쉽게 말하면 |
|---|---|---|
ids = tok(text)["input_ids"] | 문장을 번호 9개로 바꾼다 | 번호표를 뽑는다 |
tok.convert_ids_to_tokens(ids) | 번호마다 적힌 조각을 보여 준다 | 번호표 뒷면의 기계용 표시를 본다 |
tok.decode(ids) | 번호를 원래 글로 되돌린다 | 번호를 불러 손님 이름을 확인한다 |
모델은 1번의 번호만 보고 계산합니다. 2번의 조각은 사람이 토큰이 어떻게 잘렸는지 엿보려고 찍은 것이고, 3번은 모델이 만든 번호를 글로 바꿀 때 씁니다.
작게 줄여서 눈으로 보기
조각이 ë°° 처럼 보이는 까닭을 내려받기 없이 확인해 봅니다. 한글 한 글자는 UTF-8(Unicode Transformation Format 8-bit, 유니코드를 8비트 단위로 적는 방식)에서 바이트 3개로 저장됩니다.
word = "배"
raw = word.encode("utf-8") # 글자를 컴퓨터가 저장하는 바이트로
print(list(raw)) # 바이트 셋의 번호(0~255)
print(raw.decode("latin-1")) # 바이트 하나를 글자 하나로 억지로 보이면
print(raw.decode("utf-8")) # 바이트 셋을 한글로 다시 읽으면[235, 176, 176]
ë°°
배| 결과 | 읽는 법 |
|---|---|
[235, 176, 176] | "배" 한 글자가 바이트 3개로 저장됩니다 |
ë°° | 바이트 하나를 서양 글자 하나로 억지로 보이면 Qwen 의 토큰 조각과 같은 ë°° 가 됩니다. latin-1 은 바이트 하나를 서양 글자 하나에 짝지은 글자표입니다 |
배 | 같은 바이트 셋을 UTF-8 로 읽으면 원래 글자로 돌아옵니다. decode 가 하는 일이 이것입니다 |
바이트 단위 토크나이저는 이렇게 바이트를 글자 하나씩으로 바꿔 적어 두기 때문에 조각이 낯설게 보입니다. 앞의 Ġ 는 같은 방식으로 띄어쓰기 바이트를 나타낸 표시입니다. 글이 깨진 것이 아니므로 걱정하지 않아도 됩니다.
주의할 점
- 토크나이저와 모델은 반드시 같은 이름으로 불러옵니다. 다른 모델의 토크나이저를 쓰면 번호표가 달라 엉뚱한 글이 나옵니다.
- 기본으로 float32 로 불러오면 0.5B 모델이 메모리 2GB 쯤을 씁니다.
dtype=torch.float16을 주면 절반이 되지만, CPU 에서는 float32 가 안전합니다.