트랜스포머·PEFT 2일 과정2장 · Transformer 입력 표현13 / 15← 이전목차다음 →MetaContents

2장. Transformer 입력 표현

프로젝트 1 — 공지문 토큰 수 계산기

회사 총무팀에서 한국어와 영어로 사내 공지를 내보낸다고 해 봅시다. 공지를 사내 챗봇(LLM)에 넣어 요약하고 번역하려는데, 팀장이 "한국어 공지와 영어 공지 중 어느 쪽이 토큰을 더 쓰나요? 숫자로 보여 주세요"라고 묻습니다. 같은 공지를 두 언어로 적은 표를 만들고, Qwen 과 BERT 토크나이저로 글자 수와 토큰 수를 세어 한눈에 보는 표로 정리합니다. 모델은 불러오지 않고 토크나이저만 쓰므로 CPU 에서 끝납니다.

요구사항

  1. 같은 공지 세 개(회의, 엘리베이터, 보안)를 한국어와 영어로 적어 pandas DataFrame 하나로 만듭니다.
  2. Qwen(Qwen/Qwen2.5-0.5B-Instruct)과 BERT(bert-base-uncased) 토크나이저를 불러와 사전 크기를 찍습니다.
  3. 공지마다, 언어마다 글자 수, Qwen 토큰 수, BERT 토큰 수, 글자당 Qwen 토큰을 한 행으로 세어 긴 표를 만듭니다(특수 토큰은 빼고 셉니다).
  4. 공지별로 한국어와 영어의 Qwen 토큰 수를 나란히 놓고 "한국어 ÷ 영어" 비를 구합니다.
  5. 첫 공지의 한국어 문장이 두 토크나이저에서 어떤 조각으로 잘리는지 찍어 보고, 표를 out_ch02_notice_tokens.csv 로 저장합니다.

힌트

  1. 토큰 수는 len(tokenizer(text, add_special_tokens=False)["input_ids"]) 입니다. 함수 하나로 묶어 두면 두 토크나이저에 똑같이 씁니다.
  2. 긴 표는 행 사전을 리스트에 모아 pd.DataFrame(rows) 로 만듭니다.
  3. 나란히 놓기는 table.pivot(index="공지", columns="언어", values="Qwen 토큰") 입니다.
  4. 언어별 합계는 table.groupby("언어")[["글자 수", "Qwen 토큰"]].sum() 입니다.
  5. 엑셀에서 한글이 깨지지 않게 to_csv(..., encoding="utf-8-sig") 로 저장합니다.

채점 기준

항목기준점수
공지 표같은 뜻의 한국어·영어 공지 세 쌍을 DataFrame 으로 만든다15
토크나이저 준비두 토크나이저를 불러오고 사전 크기를 찍는다15
토큰 세기특수 토큰을 빼고 글자 수, 두 토크나이저의 토큰 수, 글자당 토큰을 표로 만든다30
언어 비교공지별 한국어 ÷ 영어 비와 언어별 합계를 구한다20
조각 확인과 저장한국어 문장의 조각을 찍어 해석하고 csv 로 저장한다20

코드의 흐름

프로젝트 코드의 실행 흐름도. 공지 3개를 한국어와 영어로 적은 notices 표를 만들고, Qwen 과 BERT 토크나이저를 불러 사전 크기를 찍는다. count_tokens 함수를 정의한 뒤, 공지마다 도는 반복 안에서 언어마다 도는 반복으로 글자 수와 두 토크나이저의 토큰 수를 rows 에 쌓는다. 반복을 마치면 table 을 만들어 pivot 으로 한국어÷영어 비를, groupby 로 언어별 합계를 구하고, 첫 공지의 조각을 본 뒤 csv 로 저장한다
단계하는 일반복과 조건핵심 한 줄
1같은 공지 세 개를 한국어·영어로 적은 표 만들기없음notices = pd.DataFrame({...})
2Qwen 과 BERT 토크나이저 불러오기없음AutoTokenizer.from_pretrained(...)
3공지마다, 언어마다 글자 수와 토큰 수 세기이중 반복: 공지 3개(for _, row in notices.iterrows()) × 언어 2개(for lang in)rows.append({...})
4한국어와 영어를 나란히 놓고 비와 합계 구하기없음table.pivot(index="공지", columns="언어", values="Qwen 토큰")
5첫 공지의 조각을 보고 csv 로 저장하기없음table.to_csv("out_ch02_notice_tokens.csv", ...)
  • 겹친 반복: 3단계는 바깥 마름모(공지 남았나?) 안에 안쪽 마름모(언어 남았나?)가 들어 있습니다. 공지 하나마다 언어 두 개를 돌므로 rows 에 3 × 2 = 6 행이 쌓입니다. 엑셀에서 공지마다 한국어 줄과 영어 줄을 한 줄씩 적어 내려가는 일과 같습니다.
  • 정의와 실행: def count_tokens 는 3단계 맨 앞에서 정의만 하고, 실제로는 안쪽 반복에서 Qwen 과 BERT 에 한 번씩 부릅니다.
  • 반복 뒤의 표 돌리기: 4단계는 반복 없이 pandas 의 pivot 과 groupby 로 표를 돌립니다. 데이터 분석 때 쓰던 방법 그대로입니다.
결과 보기 (예시 풀이)

1단계. 공지 표 만들기

같은 공지를 한국어와 영어로 한 행에 적습니다.

Python
import pandas as pd

# 공지 세 개를 한국어와 영어로 적은 표. 한 행이 같은 뜻의 공지 한 쌍이다
notices = pd.DataFrame({
    "공지": ["회의", "엘리베이터", "보안"],
    "한국어": [
        "다음 주 월요일 오전 10시에 3층 대회의실에서 전체 회의가 있습니다.",
        "건물 점검으로 금요일 오후 6시부터 엘리베이터 운행을 멈춥니다.",
        "개인정보 보호를 위해 퇴근 전에 모니터 화면을 잠가 주십시오.",
    ],
    "영어": [
        "There is an all-hands meeting in the main conference room on the 3rd floor next Monday at 10 a.m.",
        "Elevator service will stop from 6 p.m. on Friday for a building inspection.",
        "To protect personal information, please lock your monitor screen before you leave work.",
    ],
})
# 결과: (3, 3)  공지 3개 × 열 3개
print(notices.shape)
출력
(3, 3)

2단계. 토크나이저 두 개 불러오기

두 회사의 설명서(토크나이저)를 준비하고, 각 사전에 블록이 몇 종류인지 봅니다.

Python
from transformers import AutoTokenizer

# Qwen(Byte-level BPE)과 BERT(WordPiece) 토크나이저. 모델 무게는 내려받지 않는다
qwen = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
bert = AutoTokenizer.from_pretrained("bert-base-uncased")

# 사전 크기. 결과: Qwen 151,665 / BERT 30,522
print(f"Qwen {len(qwen):,} / BERT {len(bert):,}")
출력
Qwen 151,665 / BERT 30,522

3단계. 글자 수와 토큰 수 세기

공지마다, 언어마다 미터기를 눌러 한 행씩 기록합니다.

Python
def count_tokens(tokenizer, text):
    # 특수 토큰을 빼고 센 토큰 수. 두 토크나이저에 똑같이 쓴다
    return len(tokenizer(text, add_special_tokens=False)["input_ids"])

rows = []
# iterrows = 표를 한 행씩 꺼내기. _ 는 행 번호(쓰지 않음), row 는 그 행
for _, row in notices.iterrows():
    for lang in ["한국어", "영어"]:
        text = row[lang]
        rows.append({
            "공지": row["공지"],
            "언어": lang,
            "글자 수": len(text),
            "Qwen 토큰": count_tokens(qwen, text),
            "BERT 토큰": count_tokens(bert, text),
        })

# 행 사전 6개로 긴 표를 만든다(공지 3 × 언어 2)
table = pd.DataFrame(rows)
# 글자당 Qwen 토큰 = 토큰 수 ÷ 글자 수. 소수 둘째 자리까지
table["글자당 Qwen 토큰"] = (table["Qwen 토큰"] / table["글자 수"]).round(2)
# 결과: 한국어 행은 글자당 0.69~0.86, 영어 행은 0.17~0.28
print(table.to_string(index=False))
출력
   공지  언어  글자 수  Qwen 토큰  BERT 토큰  글자당 Qwen 토큰
   회의 한국어    39       27       38         0.69
   회의  영어    97       27       24         0.28
엘리베이터 한국어    35       30       66         0.86
엘리베이터  영어    75       18       17         0.24
   보안 한국어    34       26       53         0.76
   보안  영어    87       15       15         0.17

4단계. 한국어와 영어 견주기

같은 공지를 두 언어로 나란히 놓고 비를 구합니다. 데이터 분석에서 자주 쓰던 pivot 과 groupby 그대로입니다.

Python
# pivot = 긴 표를 넓은 표로. 행은 공지, 열은 언어, 값은 Qwen 토큰 수
pivot = table.pivot(index="공지", columns="언어", values="Qwen 토큰")
pivot["한국어÷영어"] = (pivot["한국어"] / pivot["영어"]).round(2)
# 결과: 보안 1.73, 엘리베이터 1.67, 회의 1.00
print(pivot)

# 언어별 합계. 결과: 한국어 108글자 83토큰, 영어 259글자 60토큰
print(table.groupby("언어")[["글자 수", "Qwen 토큰"]].sum())
출력
언어     영어  한국어  한국어÷영어
공지
보안     15   26    1.73
엘리베이터  18   30    1.67
회의     27   27    1.00
     글자 수  Qwen 토큰
언어
영어    259       60
한국어   108       83

5단계. 조각 확인과 저장

첫 공지의 한국어 문장이 어떤 조각으로 잘렸는지 보고, 표를 파일로 남깁니다.

Python
first_ko = notices.loc[0, "한국어"]

# Qwen 조각: 번호를 하나씩 decode 해서 본다
q_ids = qwen(first_ko, add_special_tokens=False)["input_ids"]
print([qwen.decode([i]) for i in q_ids])
# BERT 조각: 한글을 자모로 쪼개고, 사전에 없는 것은 [UNK](unknown, 모름)으로 둔다
print(bert.tokenize(first_ko))

# utf-8-sig = 엑셀에서 열어도 한글이 깨지지 않는 저장 방식
table.to_csv("out_ch02_notice_tokens.csv", index=False, encoding="utf-8-sig")
print("저장: out_ch02_notice_tokens.csv", table.shape)  # 결과: 저장: out_ch02_notice_tokens.csv (6, 6)
출력
['다', '음', ' 주', ' �', '�', '요', '일', ' 오', '전', ' ', '1', '0', '시', '에', ' ', '3', '층', ' 대', '회의', '실', '에서', ' 전체', ' 회', '의', '가', ' 있습니다', '.']
['ᄃ', '##ᅡ', '##ᄋ', '##ᅳ', '##ᆷ', 'ᄌ', '##ᅮ', 'ᄋ', '##ᅯ', '##ᆯ', '##ᄋ', '##ᅭ', '##ᄋ', '##ᅵ', '##ᆯ', 'ᄋ', '##ᅩ', '##ᄌ', '##ᅥ', '##ᆫ', '10', '##ᄉ', '##ᅵ', '##ᄋ', '##ᅦ', '3', '##ᄎ', '##ᅳ', '##ᆼ', '[UNK]', 'ᄌ', '##ᅥ', '##ᆫ', '##ᄎ', '##ᅦ', '[UNK]', '[UNK]', '.']
저장: out_ch02_notice_tokens.csv (6, 6)

세 공지를 합치면 한국어는 108글자에 83토큰, 영어는 259글자에 60토큰입니다. 같은 내용을 Qwen 으로 보내면 한국어가 약 1.4배(83 ÷ 60) 토큰을 씁니다. 다만 "회의" 공지는 두 언어가 27토큰으로 같았습니다. 영어 문장이 97글자로 길게 쓰였고, 한국어 쪽에 "회의", " 있습니다" 처럼 사전에 통째로 든 조각이 있어 차이가 줄었습니다. 비는 문장마다 달라지므로 실제 공지로 세어 봐야 합니다. BERT(bert-base-uncased)는 영어 위주 사전이라 한글을 자모로 잘게 쪼개고 [UNK] 까지 내므로, 한국어 문장을 다루는 모델에는 맞지 않습니다. 팀장에게는 "같은 공지라도 언어와 토크나이저에 따라 토큰 수가 다르니, 실제로 쓸 모델의 토크나이저로 세어 예산을 잡자"고 답하면 됩니다.

← 이전 절2장 · 실습 2 — 한국어와 영어 토큰 수 견주기다음 절 →2장 · 정리