[68일차] 자연어 처리 기초와 토큰화

송정근·2026년 9월 27일

자연어 처리(Natural Language Processing, NLP)는 컴퓨터가 사람이 사용하는 언어를 분석하고 이해하며 생성할 수 있게 만드는 인공지능 분야다. 컴퓨터는 문장을 그대로 이해하지 못하므로, 텍스트를 토큰(Token)으로 나누고 숫자 ID로 바꾸는 전처리 과정을 거친다.

이번에는 자연어 처리의 기본 단위인 Corpus, Document, Token, Vocabulary를 살펴보고, 직접 만든 사전과 Hugging Face의 klue/bert-base 토크나이저를 비교한다.


1. 자연어와 자연어 처리

자연어는 사람이 일상에서 말하고 쓰는 언어다. 문법과 어휘뿐 아니라 문맥, 표현 방식, 뉘앙스처럼 규칙만으로 처리하기 어려운 요소를 포함한다.

자연어 처리는 텍스트 또는 음성 데이터를 모델이 다룰 수 있는 형태로 바꾸고, 그 안에서 의미 있는 결과를 찾거나 새로운 문장을 만드는 기술이다.

활용 분야설명
텍스트 분류문서를 뉴스, 스포츠, 경제처럼 범주로 나눈다.
감정 분석리뷰나 댓글의 긍정·부정 성향을 분석한다.
문서 요약긴 문서에서 핵심 내용을 짧게 정리한다.
기계 번역한 언어의 문장을 다른 언어로 변환한다.
질의응답질문에 맞는 답변을 찾거나 생성한다.
정보 검색사용자의 검색어와 관련된 문서를 찾는다.
챗봇·문장 생성사용자 입력에 맞춰 자연스러운 문장을 생성한다.
RAG·LLM Agent외부 문서를 검색하거나 도구를 사용해 답변을 보완한다.

최근에는 텍스트뿐 아니라 이미지, 음성, 영상과 결합하는 멀티모달 AI로도 확장되고 있다.


2. Corpus와 Document

Corpus

Corpus(말뭉치)는 자연어 처리 모델을 분석하거나 학습하기 위해 모은 전체 텍스트 데이터 집합이다.

예를 들어 영화 리뷰 10만 개를 모았다면, 리뷰 10만 개 전체가 하나의 Corpus가 된다.

Document

Document는 Corpus를 구성하는 개별 텍스트 하나다. 반드시 긴 글일 필요는 없다.

Corpus: 영화 리뷰 10만 개
 ├── Document 1: "재미있고 배우들의 연기가 좋다."
 ├── Document 2: "전개가 느려서 아쉬웠다."
 └── Document 3: "다시 보고 싶은 영화다."

뉴스 기사 하나, 리뷰 하나, 댓글 하나, 짧은 문장 하나도 모두 Document가 될 수 있다.


3. Tokenization

Tokenization(토큰화)은 텍스트를 모델이 처리할 수 있는 작은 단위인 Token으로 나누는 과정이다.

"자연어 처리를 공부합니다."
            ↓ Tokenization
["자연", "##어", "처리", "##를", "공부", "##합니다", "."]
            ↓ Token ID 변환
[3941, 2051, 4211, 2138, 4244, 11800, 18]
            ↓ Tensor 변환
tensor([3941, 2051, 4211, 2138, 4244, 11800, 18])

토큰은 항상 단어 하나와 같지 않다. 단어 전체일 수도 있고, 단어의 일부, 구두점, 공백과 관련된 단위일 수도 있다.

단순 공백 기준 토큰화

가장 간단한 방법은 공백을 기준으로 문장을 나누는 것이다.

text = "나는 자연어를 공부한다"
tokens = text.split()

print(tokens)
['나는', '자연어를', '공부한다']

이 방식은 이해하기 쉽지만, 한국어의 조사나 어미를 분리하지 못하고 구두점 처리도 세밀하지 않다. 예를 들어 자연어를은 하나의 Token으로 남고, 처음 보는 단어는 사전에 없을 가능성이 커진다.


4. Vocabulary와 Token ID

Vocabulary는 토크나이저가 사용할 수 있는 Token의 집합이다. 모델은 문자열 자체가 아니라 Vocabulary에 등록된 정수 ID를 입력으로 받는다.

vocab = {
    "<PAD>": 0,
    "<UNK>": 1,
    "나는": 2,
    "자연어를": 3,
    "공부한다": 4,
}

text = "나는 자연어를 공부한다"
tokens = text.split()

token_ids = [vocab.get(token, vocab["<UNK>"]) for token in tokens]
input_ids = torch.tensor(token_ids, dtype=torch.long)

print("원문:", text)
print("Token:", tokens)
print("Token ID:", token_ids)
print("PyTorch Tensor:", input_ids)
print("dtype:", input_ids.dtype)

실행 결과는 다음과 같다.

원문: 나는 자연어를 공부한다
Token: ['나는', '자연어를', '공부한다']
Token ID: [2, 3, 4]
PyTorch Tensor: tensor([2, 3, 4])
dtype: torch.int64

2, 3, 4라는 숫자 자체에는 언어적 의미가 없다. 이 숫자는 Vocabulary 안에서 특정 Token을 찾기 위한 식별자다. 이후 모델은 이 ID를 Embedding 층에 전달해 학습 가능한 벡터로 바꾼다.

Special Token

Token의미용도
<PAD>Padding Token문장 길이를 맞출 때 빈자리를 채운다.
<UNK>Unknown TokenVocabulary에 없는 Token을 나타낸다.
[CLS]Classification TokenBERT 계열에서 문장 전체를 대표하는 특별한 시작 Token이다.
[SEP]Separator Token문장 또는 문장 쌍의 경계를 구분한다.

모델은 보통 한 번에 여러 문장을 Batch로 처리한다. 문장 길이가 다르면 Tensor 모양을 맞추기 어려우므로 짧은 문장 뒤에 <PAD>를 추가한다.

문장 A: [2, 3, 4]
문장 B: [2, 4]

Padding 후
문장 A: [2, 3, 4]
문장 B: [2, 4, 0]  # 0은 <PAD>

5. OOV 문제와 <UNK>

OOV(Out-Of-Vocabulary)는 입력된 Token이 Vocabulary에 존재하지 않는 상황이다.

vocab = {
    "<PAD>": 0,
    "<UNK>": 1,
    "나는": 2,
    "파이토치를": 3,
    "공부한다": 4,
}

tokens = ["나는", "트랜스포머를", "공부한다"]
token_ids = [vocab.get(token, vocab["<UNK>"]) for token in tokens]

print(token_ids)
[2, 1, 4]

트랜스포머를은 Vocabulary에 없으므로 <UNK>의 ID인 1로 바뀐다. 단어 단위 사전만 사용하면 새로운 단어, 오타, 활용형을 자주 <UNK>로 처리하게 되어 정보가 사라질 수 있다.

노트북 원본은 tokens를 중괄호 {}로 만든 set으로 작성했다. set은 순서를 보장하지 않으므로, 문장의 Token 순서를 유지해야 할 때는 위 예제처럼 대괄호 []를 사용하는 list가 알맞다.


6. Subword Tokenization

현대 NLP 모델은 OOV 문제를 줄이기 위해 Subword Tokenization을 많이 사용한다. 단어 전체를 하나로만 처리하지 않고, 자주 등장하는 부분 단위로 나눈다.

"자연어 처리를 공부합니다."
        ↓
['자연', '##어', '처리', '##를', '공부', '##합니다', '.']

##는 BERT 계열 WordPiece 토크나이저에서 앞 Token에 이어 붙는 부분이라는 표시다. 예를 들어 자연과 ##어를 합치면 자연어가 되고, 공부와 ##합니다를 합치면 공부합니다가 된다.

처음 보는 단어라도 이미 알고 있는 부분 Token의 조합으로 표현할 가능성이 높다. 이 때문에 단어 전체만 사용하는 방식보다 <UNK> 발생을 줄일 수 있다.


7. Hugging Face AutoTokenizer 사용하기

Hugging Face는 자연어 처리뿐 아니라 이미지, 음성, 멀티모달 모델과 관련 도구를 제공하는 생태계다. AutoTokenizer를 사용하면 모델 저장소에 맞는 Tokenizer 설정과 Vocabulary를 불러올 수 있다.

from transformers import AutoTokenizer

# Hugging Face Hub의 klue/bert-base 토크나이저 불러오기
tokenizer = AutoTokenizer.from_pretrained("klue/bert-base")

text = "자연어 처리를 공부합니다."
tokens = tokenizer.tokenize(text)
token_ids = tokenizer.convert_tokens_to_ids(tokens)

print("Token:", tokens)
print("Token ID:", token_ids)

실행 결과는 다음과 같다.

Token: ['자연', '##어', '처리', '##를', '공부', '##합니다', '.']
Token ID: [3941, 2051, 4211, 2138, 4244, 11800, 18]

klue/bert-base의 Vocabulary 크기와 주요 Special Token ID는 다음과 같이 확인했다.

print("Vocabulary 크기:", tokenizer.vocab_size)
print("[PAD] ID:", tokenizer.pad_token_id)
print("[UNK] ID:", tokenizer.unk_token_id)
print("[CLS] ID:", tokenizer.cls_token_id)
print("[SEP] ID:", tokenizer.sep_token_id)
Vocabulary 크기: 32000
[PAD] ID: 0
[UNK] ID: 1
[CLS] ID: 2
[SEP] ID: 3

노트북에서는 [PAD] ID를 출력할 때 tokenizer.pad_token_type_id를 사용했다. 이 값은 이 모델에서 우연히 0으로 출력되지만, PAD Token의 Vocabulary ID를 확인하려면 의미에 맞는 tokenizer.pad_token_id를 사용해야 한다.

tokenize()와 모델 입력 만들기의 차이

tokenizer.tokenize()는 사람이 확인하기 좋은 Token 문자열 목록을 반환한다. 실제 모델 입력을 만들 때는 보통 토큰화와 ID 변환, Special Token 추가, Padding, Attention Mask 생성을 한 번에 처리한다.

encoded = tokenizer(
    "자연어 처리를 공부합니다.",
    return_tensors="pt",
)

print(encoded["input_ids"])
print(encoded["attention_mask"])

input_ids는 모델에 전달할 Token ID이고, attention_mask는 실제 Token과 Padding 위치를 구분하는 값이다. 이처럼 모델용 입력을 만들 때는 tokenizer(...) 호출이 더 편리하다.


8. macOS와 Windows 환경 차이

토큰화와 transformers API는 운영체제와 관계없이 거의 동일하다. 하지만 가상환경 활성화 명령어, 경로 표기, 사용할 수 있는 GPU 가속 방식은 macOS와 Windows에서 다르다.

8.1 한눈에 비교하기

항목macOSWindows
기본 터미널 예시Terminal, iTerm2, VS Code TerminalPowerShell, 명령 프롬프트, VS Code Terminal
가상환경 활성화source .venv/bin/activatePowerShell: .\.venv\Scripts\Activate.ps1
명령 프롬프트: .venv\Scripts\activate.bat
경로 구분자/\를 주로 사용하지만 /도 대부분의 Python 코드에서 사용할 수 있다.
대표 GPU 가속Apple Silicon의 mpsNVIDIA GPU의 cuda
GPU 확인torch.backends.mps.is_available()torch.cuda.is_available()
Hugging Face 기본 캐시~/.cache/huggingface/hubC:\Users\<사용자명>\.cache\huggingface\hub

경로를 문자열로 이어 붙이기보다 pathlib.Path를 사용하면 운영체제마다 다른 구분자를 신경 쓰지 않아도 된다.

from pathlib import Path

model_dir = Path("models") / "klue-bert"
print(model_dir)

8.2 공통 준비

transformers와 PyTorch는 프로젝트마다 독립된 가상환경에 설치하는 편이 좋다. 프로젝트마다 라이브러리 버전이 달라도 서로 영향을 주지 않는다.

프로젝트 폴더
├── .venv/          # 현재 프로젝트 전용 Python 환경
├── notebook.ipynb
└── requirements.txt

Hugging Face의 from_pretrained()는 처음 실행할 때 모델 또는 토크나이저 파일을 Hub에서 내려받아 로컬 캐시에 저장한다. 이후에는 같은 버전이 캐시에 있으면 로컬 파일을 사용한다.

8.3 macOS: Apple Silicon과 MPS

Apple Silicon Mac에서는 PyTorch의 MPS(Metal Performance Shaders) 백엔드를 사용할 수 있다. 노트북의 실행 결과도 mps였다.

python3 -m venv .venv
source .venv/bin/activate

python -m pip install --upgrade pip
python -m pip install torch torchvision transformers

설치 후에는 MPS 사용 가능 여부를 확인한다.

import torch

print("MPS 사용 가능:", torch.backends.mps.is_available())
print("MPS 빌드 여부:", torch.backends.mps.is_built())
  • is_built()가 False이면 현재 PyTorch 빌드에 MPS 지원이 포함되지 않은 상태다.
  • is_built()는 True인데 is_available()이 False이면 현재 장치나 macOS 환경에서 MPS를 사용할 수 없는 상태다.
  • MPS를 사용할 수 없으면 cpu로 실행하면 된다. 기능이 틀린 것이 아니라 가속 장치만 달라지는 것이다.

macOS에서 cuda는 NVIDIA CUDA를 뜻하므로 일반적인 Apple Silicon Mac에서는 선택되지 않는다. 따라서 torch.cuda.is_available()이 False여도 오류가 아니다.

8.4 Windows: NVIDIA GPU와 CUDA

Windows에서는 NVIDIA GPU가 있고 CUDA용 PyTorch를 설치했다면 보통 cuda를 사용한다. GPU가 없거나 CPU 전용 PyTorch를 설치했다면 cpu로 실행된다.

py -m venv .venv
.\.venv\Scripts\Activate.ps1

py -m pip install --upgrade pip
py -m pip install transformers

PyTorch는 Windows 환경에서 GPU와 CUDA 버전에 맞는 설치 명령을 선택해야 한다. PyTorch의 설치 선택 화면에서 Windows, Pip, 사용 중인 CUDA 또는 CPU를 고른 뒤 제시된 명령을 사용한다.

# CPU 환경 예시
py -m pip install torch torchvision transformers

# NVIDIA GPU 환경은 PyTorch 공식 선택 화면에서
# 현재 CUDA 조합에 맞는 명령을 확인해 설치한다.

설치가 끝나면 Python에서 GPU를 확인한다.

import torch

print("CUDA 사용 가능:", torch.cuda.is_available())
if torch.cuda.is_available():
    print("GPU 이름:", torch.cuda.get_device_name(0))

torch.cuda.is_available()이 False라면 NVIDIA GPU가 없거나, GPU 드라이버·CUDA 조합과 PyTorch 패키지가 맞지 않거나, CPU 전용 빌드를 설치했을 가능성이 있다. 이 경우 PyTorch 공식 설치 선택 화면에서 환경에 맞는 명령을 다시 확인한다.

8.5 운영체제와 관계없이 동작하는 장치 선택 코드

노트북의 흐름을 조금 보완하면 macOS, Windows, CPU 환경에서 모두 안전하게 사용할 수 있다.

import torch

if torch.cuda.is_available():
    DEVICE = torch.device("cuda")       # 주로 Windows 또는 Linux의 NVIDIA GPU
elif torch.backends.mps.is_available():
    DEVICE = torch.device("mps")        # Apple Silicon Mac
elif hasattr(torch, "xpu") and torch.xpu.is_available():
    DEVICE = torch.device("xpu")        # 지원되는 Intel GPU 환경
else:
    DEVICE = torch.device("cpu")

print("사용 장치:", DEVICE)

hasattr(torch, "xpu") 검사는 PyTorch 버전에 따라 torch.xpu 속성이 없는 환경에서도 오류 없이 다음 조건으로 넘어가게 한다.


9. PyTorch Tensor와 실행 장치

Token ID는 정수 인덱스이므로 torch.long, 즉 일반적으로 torch.int64 자료형 Tensor로 만든다.

input_ids = torch.tensor(token_ids, dtype=torch.long)

노트북에서는 실행 장치를 다음 순서로 선택했고, 현재 환경에서는 mps가 선택됐다.

if torch.cuda.is_available():
    DEVICE = torch.device("cuda")
elif torch.backends.mps.is_available():
    DEVICE = torch.device("mps")
elif hasattr(torch, "xpu") and torch.xpu.is_available():
    DEVICE = torch.device("xpu")
else:
    DEVICE = torch.device("cpu")

print(DEVICE)
mps

mps는 Apple Silicon Mac의 GPU 가속을 위한 PyTorch 장치다. 학습이나 추론 시 모델과 입력 Tensor를 같은 장치에 올려야 한다.

model = model.to(DEVICE)
encoded = {key: value.to(DEVICE) for key, value in encoded.items()}

모델은 mps에 있는데 입력은 CPU Tensor인 상태처럼 장치가 다르면 오류가 발생한다. model과 input_ids, attention_mask 등 입력 Tensor를 모두 같은 DEVICE로 옮긴다.


10. 자주 만나는 환경 오류

상황원인해결 방법
ModuleNotFoundError: No module named 'transformers'현재 실행 중인 Python 환경에 transformers가 설치되지 않았다.가상환경을 활성화한 뒤 python -m pip install transformers를 실행한다.
Jupyter에서는 import 오류, 터미널에서는 정상Notebook Kernel이 다른 가상환경을 사용한다.Notebook의 Kernel을 .venv 환경으로 바꾸고, import sys; print(sys.executable)로 경로를 확인한다.
MPS is not availableApple Silicon, macOS, PyTorch 빌드 중 하나가 MPS 조건을 만족하지 않는다.torch.backends.mps.is_built()와 is_available()을 확인하고, 사용 불가하면 CPU로 실행한다.
torch.cuda.is_available()이 FalseWindows에서 CPU 전용 PyTorch를 설치했거나 NVIDIA GPU·드라이버·CUDA 조합이 맞지 않는다.PyTorch 공식 설치 선택 화면에서 Windows와 CUDA 조합에 맞는 명령을 다시 확인한다.
IProgress not found 경고Jupyter의 진행 표시 위젯이 설치되지 않았다.현재 가상환경에 python -m pip install ipywidgets를 설치하고 Kernel을 다시 시작한다.
Hugging Face 비인증 요청 경고공개 모델은 불러올 수 있지만 인증되지 않은 요청이라 제한 관련 안내가 표시된다.학습용 공개 모델 실습에서는 경고만으로 중단되지는 않는다. 반복 사용 시 Hugging Face 계정 인증과 캐시 사용을 검토한다.

가상환경에서 pip가 다른 Python을 가리키는 문제를 줄이려면 pip install ...보다 python -m pip install ... 형식을 사용하는 편이 안전하다. python이 바로 현재 활성화된 가상환경의 Python을 가리키기 때문이다.


11. 전체 흐름 정리

Corpus
  ↓
Document 선택
  ↓
Tokenization
  ↓
Vocabulary에서 Token ID 조회
  ↓
Padding·Attention Mask 생성
  ↓
PyTorch Tensor로 변환
  ↓
NLP 모델 입력
  • Corpus는 학습·분석에 사용하는 전체 텍스트 집합이고, Document는 그 안의 개별 텍스트다.
  • Token은 모델이 다루는 입력 단위이며, 단어 하나와 항상 같지 않다.
  • Vocabulary는 Token과 정수 ID의 대응표다.
  • <UNK>는 사전에 없는 Token을 처리하지만, Subword Tokenization은 OOV 문제를 줄이는 데 도움이 된다.
  • AutoTokenizer는 모델에 맞는 Vocabulary와 Tokenization 규칙을 불러온다.
  • 세밀한 NLP 모델 입력에는 Token ID뿐 아니라 Special Token, Padding, Attention Mask도 함께 필요하다.
  • macOS에서는 MPS, Windows의 NVIDIA GPU 환경에서는 CUDA를 우선 확인하고, GPU가 없거나 사용할 수 없으면 CPU로 실행한다.

profile
기록하며 성장하는 개발자

0개의 댓글