nn embedding

PyTorch의 nn.Embedding 완벽 입문

딥러닝으로 자연어 처리(NLP)를 공부하다 보면 가장 먼저 만나게 되는 레이어 중 하나가 바로 Embedding Layer입니다.

PyTorch에서는 nn.Embedding()을 사용하여 단어, 문자, 토큰(Token) 등의 ID를 학습 가능한 벡터(Vector)로 변환할 수 있습니다.

이번 글에서는 One-Hot Encoding부터 시작하여 Embedding의 개념, 사용 방법, 그리고 사전 학습된 임베딩까지 차근차근 알아보겠습니다.


1. Embedding이 필요한 이유

컴퓨터는 문자열을 직접 처리할 수 없습니다.

예를 들어 다음과 같은 단어가 있다고 가정해 보겠습니다.

사과
바나나
포도

먼저 단어를 숫자로 변환해야 합니다.

사과   → 0
바나나 → 1
포도 → 2

이를 Token ID라고 합니다.

하지만 ID 자체에는 단어의 의미가 포함되어 있지 않습니다.

0
1
2

는 단순한 번호일 뿐이며,

2 > 1 > 0

이라는 수학적 관계가

포도 > 바나나 > 사과

라는 의미를 나타내는 것은 아닙니다.

그렇다면 단어를 어떻게 표현해야 할까요?

초기의 자연어 처리에서는 One-Hot Encoding을 사용했습니다.


2. One-Hot Encoding이란?

One-Hot Encoding은 단어를 벡터로 표현하는 가장 단순한 방법입니다.

예를 들어 단어 사전이 다음과 같다고 가정해 보겠습니다.

사과   → 0
바나나 → 1
포도 → 2

One-Hot Encoding을 적용하면

사과
[1, 0, 0]

바나나
[0, 1, 0]

포도
[0, 0, 1]

처럼 표현됩니다.

즉,

자신의 위치만 1

나머지는 모두 0

인 벡터입니다.


3. One-Hot Encoding의 문제점

문제 1 : 벡터가 너무 커진다

단어가 10,000개라면

[0,0,0,0,0, ... ,1, ... ,0]

처럼 길이가 10,000인 벡터가 필요합니다.

만약

100,000개 단어

가 존재한다면

100,000차원 벡터

가 필요합니다.

메모리 낭비가 매우 심합니다.


문제 2 : 단어 간 관계를 표현할 수 없다

예를 들어

사과
바나나

는 둘 다 과일입니다.

하지만 One-Hot Encoding에서는

사과
[1,0,0]

바나나
[0,1,0]

로 표현됩니다.

두 벡터 사이에는 아무런 의미적 관계가 없습니다.


문제 3 : 모든 단어가 동일한 거리

One-Hot 벡터에서는

사과 ↔ 바나나

사과 ↔ 자동차

가 모두 동일하게 취급됩니다.

즉,

유사도 정보를 표현할 수 없음

이라는 치명적인 문제가 있습니다.


4. Embedding의 역할

Embedding은 이러한 문제를 해결하기 위해 등장했습니다.

예를 들어

사과
[0.12, 0.88, -0.51]

바나나
[0.15, 0.91, -0.48]

자동차
[-0.82, 0.17, 0.63]

처럼 표현될 수 있습니다.

Embedding은 학습 과정에서

비슷한 단어



가까운 벡터

를 가지도록 학습됩니다.

예를 들어

사과 ↔ 바나나

는 가까워지고

사과 ↔ 자동차

는 멀어지게 됩니다.


5. One-Hot Encoding과 Embedding 비교

항목One-Hot EncodingEmbedding
벡터 크기매우 큼작음
메모리 사용량많음적음
의미 정보없음있음
단어 유사도 표현불가능가능
학습 가능불가능가능
실제 사용 여부거의 사용 안 함매우 많이 사용

현재 딥러닝에서는 One-Hot Encoding을 직접 사용하는 경우는 거의 없으며 대부분 Embedding을 사용합니다.


6. nn.Embedding 기본 문법

nn.Embedding(
num_embeddings,
embedding_dim
)

예를 들어

nn.Embedding(10000, 128)

이라면

10000개의 단어



128차원 벡터

를 의미합니다.


7. 가장 간단한 예제

import torch
from torch import nn

embedding = nn.Embedding(10,3)

x = torch.tensor([1,2,4])

out = embedding(x)

print(out)
print(out.shape)

출력

torch.Size([3,3])

입력된 3개의 ID가 각각 3차원 벡터로 변환됩니다.


8. Embedding의 내부 구조

Embedding은 사실상 하나의 Lookup Table입니다.

embedding = nn.Embedding(5,4)

print(embedding.weight.shape)

출력

torch.Size([5,4])

의미

5개의 단어



각 단어마다 4개의 값

입니다.

만약

x = torch.tensor([2])

라면

실제로는

embedding.weight[2]

를 가져오는 것과 거의 동일합니다.


9. 배치(Batch) 입력 처리

x = torch.tensor([
[1,2,3],
[4,5,6]
])

embedding = nn.Embedding(10,4)

out = embedding(x)

print(out.shape)

출력

torch.Size([2,3,4])

즉,

[배치 크기, 시퀀스 길이]



[배치 크기, 시퀀스 길이, 임베딩 차원]

으로 변환됩니다.


10. 학습 가능한 파라미터

embedding = nn.Embedding(1000,128)

print(
sum(p.numel() for p in embedding.parameters())
)

출력

128000

Embedding도 다른 신경망 가중치처럼 학습 과정에서 업데이트됩니다.


11. nn.Linear와의 차이

nn.Linear

linear = nn.Linear(3,2)

입력

[1.2,3.4,5.6]

출력

[0.8,1.5]

nn.Embedding

입력

[1,2,3]

출력

[
[0.12,0.34],
[0.56,0.78],
[0.91,0.22]
]

즉,

nn.Linear

실수 벡터 변환

nn.Embedding

정수 ID → 벡터 변환

입니다.


12. 사전 학습된(Pretrained) Embedding

모든 Embedding이 랜덤하게 시작되는 것은 아닙니다.

이미 대규모 텍스트로 학습된 벡터를 사용할 수도 있습니다.

대표적인 예는 다음과 같습니다.

  • Word2Vec
  • GloVe
  • FastText

이러한 벡터는 이미 단어 간의 의미 관계를 학습한 상태입니다.


13. Pretrained Embedding 불러오기

import torch
from torch import nn

pretrained_weights = torch.randn(5000,100)

embedding = nn.Embedding.from_pretrained(
pretrained_weights
)

shape 확인

print(embedding.weight.shape)

출력

torch.Size([5000,100])

14. Embedding 고정(Freeze)하기

추가 학습 허용

embedding = nn.Embedding.from_pretrained(
pretrained_weights,
freeze=False
)

고정

embedding = nn.Embedding.from_pretrained(
pretrained_weights,
freeze=True
)

15. Random Embedding vs Pretrained Embedding

항목RandomPretrained
초기값랜덤학습 완료
의미 정보없음있음
데이터 요구량많음적음
학습 속도느림빠름

마무리

nn.Embedding은 단순한 숫자 변환 레이어가 아닙니다.

ID 자체에는 의미 정보가 없기 때문에, 의미를 표현할 수 있는 벡터 공간으로 변환하기 위해 사용됩니다.

또한 One-Hot Encoding의 차원 폭발 문제와 의미 표현의 한계를 해결하며, 현재 자연어 처리와 추천 시스템에서 가장 널리 사용되는 범주형 데이터 표현 방법 중 하나입니다.

댓글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다