1 요약
이 문서는 통계 기반 벡터화의 한계를 넘어 텍스트 데이터로부터 풍부한 의미론적, 문맥적 정보를 추출하는 신경망 기반 벡터화 방법론을 소개한다.
- DTM 방식의 한계와 신경망 접근법의 등장:
- 전통적인 DTM(문서-단어 행렬) 방식의 문제점(차원의 저주, 희소성, 의미 관계 표현 불가)을 지적하고, 이를 극복하기 위한 신경망 기반 밀집 벡터 표현(워드 임베딩)의 필요성을 설명한다.
- 워드 임베딩 (Word Embedding) - 정적 임베딩:
- 핵심 원리: “같은 문맥에 나타나는 단어는 비슷한 의미를 가진다”는 분포 가설에 기반하여 단어를 저차원 밀집 벡터로 표현한다.
- Embedding Layer: 정수 인코딩된 단어를 밀집 벡터로 변환하는 신경망의 핵심 구성 요소로, 그 구조와 Look-up Table 방식을 설명한다.
- 실용적 응용 및 평가:
- 임베딩 모델의 성능을 평가하는 내재적 평가(단어 유사도, 관계 유추)와 외재적 평가(다운스트림 태스크 성능) 방법을 소개한다.
- 결론: 신경망 기반 벡터화 기법들의 발전 과정과 그 의의를 요약한다.
2 텍스트 인코딩 및 벡터화
텍스트 벡터화
├── 1. 전통적 방법 (통계 기반)
│ ├── BoW
│ ├── DTM
│ └── TF-IDF
│
├── 2. 신경망 기반 (문맥 독립)
│ ├── 문맥 독립적 임베딩
│ │ └── Embedding Layer (딥러닝 모델 내 구성 요소)
│ ├── Word2Vec (CBOW, Skip-gram)
│ ├── FastText
│ ├── GloVe
│ └── 기타 모델: Swivel, LexVec 등
│
└── 3. 문맥 기반 임베딩 (Contextual Embedding)
└── RNN 계열
├── LSTM
├── GRU
└── ELMo
2.0.1 신경망 사용 (2008~2018)
2.0.2 DTM 방식의 한계와 신경망 접근법의 등장
DTM 방식의 문제점: - 차원의 저주: 어휘집 크기 = 벡터 차원 (예: 50,000개 단어 → 50,000차원) - 희소성: 대부분의 값이 0인 sparse vector - 의미적 관계 부재: “왕”과 “여왕”의 관계를 벡터가 표현하지 못함 - 문제 상황:
# 기존 방식 (원-핫 인코딩)
"사과" = [1, 0, 0, 0, 0, ...] # 50,000차원 벡터
"바나나" = [0, 1, 0, 0, 0, ...]
"과일" = [0, 0, 1, 0, 0, ...]- 모든 단어가 서로 똑같이 멀어 보임 (유클리드 거리 = √2)
- “사과”와 “바나나”가 비슷한 과일이라는 정보가 없음
- 메모리 낭비 (대부분이 0)
신경망 접근법의 혁신: - 밀집 벡터(Dense Vector): 고정된 낮은 차원 (예: 300차원)에 0/1 값이 아닌 실수 값을 가짐. - 의미적 유사도: 벡터 간 거리로 단어 유사도 측정 가능 - 문맥 학습: 주변 단어들을 통해 의미 학습
# 신경망 모델: 워드 임베딩 (300차원)
"사과" = [0.2, -0.4, 0.7, 0.1, ...] # 300개 실수
"바나나" = [0.3, -0.5, 0.6, 0.2, ...] # 비슷한 값들
"과일" = [0.25, -0.45, 0.65, 0.15, ...] # 과일 카테고리- 문맥 고려 방법 (Neural / Context-dependent)
- 신경망을 통해 단어의 의미를 주변 문맥을 고려하여 학습하고, 이를 밀집 벡터(Dense Vector)로 표현.
2.0.3 워드 임베딩 (Word Embedding)
문맥 속에서 각 단어가 어떻게 사용되는지까지 신경망을 통해 벡터값을 구해 벡터에 담아내려 시도.
학습 후에는 각 단어 벡터 간의 유사도(의미반영)를 계산할 수 있다.
즉, 신경망 기반의 벡터화라는 것은 벡터의 값이 학습에 의해 결정된다는 것을 의미.
워드 임베딩 모델의 예시
- Word2Vec, GloVe, FastText, 모델 내
EmbeddingLayer 사용.
- Word2Vec, GloVe, FastText, 모델 내
어떻게 단어를 벡터화?
- 단어가 정수화 되면 차원이 정해진 임의의 가중치 테이블의 내적으로 벡터화된다.
- 이때, 이 가중치 테이블을 embedding table (= embedding layer) 이라고 하고 각 행이 단어를 의미한다.
- 따라서, embedding table의 행의 크기 = vocab_size가 되고 내적의 결과가 단어의 벡터가 되어 딥러닝 입력값으로 사용된다.
- 딥러닝의 학습을 통해 이 embedding table (가중치 행렬)의 값이 최적화되고 이 값이 단어의 벡터가 된다.
- 딥러닝 자연어 처리 시 거의 항상 하게 되는 작업
- vocab_size (고차원, 20k~30k) x embedding_dim (저차원, 128,256,512 등) 크기의 가중치 행렬이 학습되어 임베딩 벡터가 된다.
- 단어 -> 정수 인코딩 -> Embedding Layer -> 임베딩 벡터(=밀집 벡터)
- 자연어 처리에서 단어를 정수로 바꿔주는 이유가 Embedding Layer를 통해 밀집 벡터로 변환하기 위해서이다.
- Lookup table: 정수 인코딩을 밀집 벡터로 변환하는 테이블
워드 임베딩 2가지 유형
- 랜덤 초기화 임베딩
- NNLM(Neural Network Language Model)과 마찬가지로 초기에 랜덤값의 가중치를 가지고 오차를 구하는 과정에서 embedding table의 값이 학습
- NNLM은 이전 단어가 주어졌을 때, 다음 단어를 구하는 학습과정에서 오차를 줄이면서 학습되었으나 텍스트 분류, 개체명 인식등 수많은 task에서도 오차를 줄이며 학습 가능
- task에 맞도록 embedding vector값이 최적화된다.
- pytorch, keras 등 딥러닝 프레임워크에서 랜덤 초기화된 embedding layer를 제공한다.
- 모델이 역전파하는 과정에서 embedding layer의 가중치가 학습되어 최적화된다.
- 사전 훈련된 임베딩 (Pre-trained Word Embedding)
- 이미 만들어진 임베딩 테이블을 사용
- 정해진 특정 알고리즘에 방대한 데이터를 입력으로 학습시킨 후 여러 task의 입력으로 사용
- 대표적인 알고리즘으로 word2vec, glove, fasttext가 있음
- 이미 방대한 양의 텍스트 데이터로 훈련되어져 있는 임베딩 벡터값들을 갖고와서 딥러닝 모델의 입력값으로 사용
- 이때 이 임베딩 벡터들은 word2vec, glove, fasttext 등 특정 알고리즘으로 훈련되어져 있는 임베딩 벡터값들이다.
- 이미 학습된 임베딩 벡터를 사용하므로 모델 학습 시간이 줄어들고 더 좋은 성능을 보임
- 랜덤 초기화 임베딩
핵심 원리
- 분포 가설(Distributional Hypothesis):
- “같은 문맥에서 나타나는 단어들은 유사한 의미를 가진다”
- 수학적으로 표현하면: \(\text{similarity}(w_i, w_j) \propto \text{context\_overlap}(w_i, w_j)\)
- “같은 문맥에 나타나는 단어들은 비슷한 의미를 가진다”
- 예시:
문장1: "나는 사과를 먹었다" 문장2: "나는 바나나를 먹었다" 문장3: "나는 딸기를 먹었다"→ “사과”, “바나나”, “딸기”는 같은 위치(문맥)에 나타남 → 비슷한 벡터를 가져야 함
- 분포 가설(Distributional Hypothesis):
임베딩 벡터의 의미
벡터 간 유사도
- 수식: \(\text{similarity}(\mathbf{v}_1, \mathbf{v}_2) = \frac{\mathbf{v}_1 \cdot \mathbf{v}_2}{||\mathbf{v}_1|| \cdot ||\mathbf{v}_2||}\)
- 직관적 해석
- 1에 가까울수록 비슷한 의미
- 0에 가까울수록 관련 없음
- -1에 가까울수록 반대 의미
벡터 연산의 마법
- 유명한 예시:
- \(\vec{\text{king}} - \vec{\text{man}} + \vec{\text{woman}} \approx \vec{\text{queen}}\)
- \(\vec{\text{king}} - \vec{\text{man}}\): “남성성”을 제거 → “왕권” 개념만 남음
- \(+ \vec{\text{woman}}\): “여성성” 추가
- 결과: “여성 + 왕권” → “여왕”
- 수학적 설명:
- 각 벡터를 의미 성분들의 조합으로 생각:
king = [왕권: 0.9, 남성: 0.8, 권력: 0.7, ...] man = [남성: 0.9, 성인: 0.6, ...] woman = [여성: 0.9, 성인: 0.6, ...]- 연산 후:
→ “queen”과 가장 유사!king - man + woman ≈ [왕권: 0.9, 여성: 0.9, 권력: 0.7, ...]
- 유명한 예시:
실제 학습 예시
초기 상태 (랜덤)
"사과" = [0.1, -0.3, 0.7, ...] (랜덤) "바나나" = [-0.8, 0.2, -0.1, ...] (랜덤)- 서로 전혀 관련 없어 보임
학습 진행
문장들을 계속 보면서: "사과를 먹었다", "바나나를 먹었다", "딸기를 먹었다" ... * 점차 비슷한 벡터로 수렴:“사과” = [0.2, -0.4, 0.6, …] “바나나” = [0.3, -0.5, 0.7, …]
“딸기” = [0.25, -0.45, 0.65, …] ```학습 완료 후
- 의미가 비슷한 단어들 → 벡터 공간에서 가까운 위치
- 반대 의미 단어들 → 먼 위치 또는 반대 방향
- 유추 관계 → 벡터 연산으로 표현 가능
핵심: 신경망이 “문맥”이라는 단서를 통해 단어의 의미를 수치로 학습
2.0.3.1 Embedding Layer 구조 분석
- Embedding Layer란?
- 정수 인코딩 → 밀집 벡터 변환기
# 이런 변환을 해주는 것
15 → [0.2, -0.4, 0.7, 0.1, -0.3] # 300차원 벡터
23 → [0.1, 0.3, -0.2, 0.8, 0.5] # 300차원 벡터
7 → [-0.1, 0.6, 0.4, -0.2, 0.9] # 300차원 벡터- 왜 정수 인코딩이 필요한가?
- 문제: 컴퓨터는 “사과”라는 글자를 직접 처리할 수 없음
- 해결 과정:
# 1단계: 단어 → 정수 (정수 인코딩)
"사과" → 15
"바나나" → 23
"딸기" → 7
# 2단계: 정수 → 벡터 (Embedding Layer)
15 → [0.2, -0.4, 0.7, ...]
23 → [0.1, 0.3, -0.2, ...]
7 → [-0.1, 0.6, 0.4, ...]Look-up Table의 구체적 동작
- Embedding Matrix 구조: \(\mathbf{E} \in \mathbb{R}^{V \times d}\)
- 실제 예시:
행렬의 의미:
- 행(row): 각 단어의 임베딩 벡터
- 열(column): 임베딩 벡터의 각 차원
- 전체: 모든 단어의 벡터를 저장하는 “사전”
Look-up 연산 과정
- 입력:
input_ids = [2, 0, 4]
- 입력:
수학적 의미
- \(\text{embedding}(i) = \mathbf{E}[i, :]\)
- \(i\): 단어의 정수 ID
- \(\mathbf{E}[i, :]\): 행렬 E의 i번째 행 전체
- 결과: i번째 단어의 임베딩 벡터
- 구체적 예시:
- \(\text{embedding}(i) = \mathbf{E}[i, :]\)
실제 PyTorch 코드
import torch
import torch.nn as nn
# 1. Embedding Layer 생성
vocab_size = 1000 # 어휘 크기
embedding_dim = 300 # 벡터 차원
embedding = nn.Embedding(vocab_size, embedding_dim)
# 2. 내부 구조 확인
print(embedding.weight.shape) # torch.Size([1000, 300])
# → 1000×300 크기의 look-up table
# 3. 입력 데이터
input_ids = torch.tensor([15, 23, 7]) # 3개 단어의 ID
# 4. 임베딩 변환
output = embedding(input_ids)
print(output.shape) # torch.Size([3, 300])
# → 3개 단어 × 300차원 벡터- Look-up Table이 학습되는 과정
- 초기화 (랜덤)
- 학습 과정
# 예: "사과는 맛있다"라는 문장 학습
input_ids = [15, 23, 7] # [사과는, 맛있다, <END>]
# 1. 현재 임베딩으로 예측
embeddings = embedding_matrix[input_ids] # Look-up
prediction = model(embeddings)
# 2. 손실 계산
loss = criterion(prediction, target)
# 3. 역전파로 embedding_matrix 업데이트
loss.backward() # embedding_matrix의 gradient 계산
optimizer.step() # embedding_matrix 값들 업데이트핵심: 학습이 진행되면서 embedding_matrix의 각 행(단어 벡터)이 점점 더 의미 있는 값으로 변함!
왜 “Look-up Table”이라고 부르는가?
- 전통적인 사전과 비교
# 일반 사전 사전 = { "사과": "빨간 과일", "바나나": "노란 과일", "컴퓨터": "전자 기기" } 의미 = 사전["사과"] # "빨간 과일" # Embedding Table 임베딩_테이블 = { 15: [0.2, -0.4, 0.7, ...], # "사과" 23: [0.1, 0.3, -0.2, ...], # "바나나" 78: [-0.5, 0.8, 0.1, ...] # "컴퓨터" } 벡터 = 임베딩_테이블[15] # [0.2, -0.4, 0.7, ...]- 차이점:
- 일반 사전: 단어 → 설명 (텍스트)
- 임베딩 테이블: 단어 ID → 숫자 벡터
전체 과정 정리
# 전체 파이프라인
"사과는 맛있다"
→ ["사과는", "맛있다"] # 토큰화
→ [15, 23] # 정수 인코딩
→ [[0.2, -0.4, 0.7], # Embedding Layer (Look-up)
[0.1, 0.3, -0.2]]
→ 신경망 처리 # 후속 레이어들- 핵심
- Embedding Layer는 단순히 “정수 ID를 인덱스로 사용해서 미리 저장된 벡터를 가져오는” 매우 단순한 연산.
- 하지만 이 벡터들이 학습을 통해 의미 있는 값으로 변하기 때문에 강력한 도구가 되는 것
3 결론
본 문서에서는 자연어 처리(NLP) 분야에서 텍스트 데이터의 의미를 효과적으로 포착하기 위해 통계 기반 방법의 한계를 넘어, 신경망은 단어와 문맥의 복잡한 관계를 학습하여 풍부한 정보를 담은 벡터 표현을 생성한다.
- 워드 임베딩의 발전:
- 정적 임베딩 (Word2Vec, GloVe, FastText): ’분포 가설’에 기반하여 단어를 저차원 밀집 벡터로 표현함으로써 단어 간 의미적 유사성과 관계(예: 유추)를 포착했다.
Embedding Layer는 이러한 변환의 핵심이며, FastText는 하위 단어(subword) 정보를 활용하여 OOV 문제와 형태론적 특징 처리에 강점을 보였다. - 이러한 초기 신경망 기반 방법들은 단어의 의미를 고정된 벡터로 표현하여 NLP 성능을 크게 향상시켰다.
- 정적 임베딩 (Word2Vec, GloVe, FastText): ’분포 가설’에 기반하여 단어를 저차원 밀집 벡터로 표현함으로써 단어 간 의미적 유사성과 관계(예: 유추)를 포착했다.
- 벡터화 방법 선택의 중요성:
- 단순한 단어 유사도 측정부터 복잡한 문서 이해 및 생성에 이르기까지, 해결하고자 하는 문제의 특성, 데이터의 규모와 성격, 그리고 사용하려는 모델의 요구사항을 종합적으로 고려하여 적절한 벡터화 전략을 선택하는 것이 중요하다.
- 이러한 신경망 기반 벡터화 기법들은 현대 대규모 언어 모델(LLM) 발전의 핵심적인 토대가 되었으며, 자연어 이해 및 생성 능력의 비약적인 발전을 이끌고 있다.