본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
공부 시작

강의 종료

강의장

학습 인증샷

학습후기
임베딩이란
데이터를 벡터 공간으로 변환하는 것
복잡한 표현을 컴퓨터가 학습 가능한 수치 벡터로 변환 하는것.
["king", "queen", "man", "woman"] 이런 데이터를
단어임베딩 벡터 (예: 3차원)
| king | [0.52, -1.23, 0.77] |
| queen | [0.48, -1.10, 0.81] |
| man | [0.20, -0.97, 0.44] |
| woman | [0.19, -0.88, 0.53] |
이렇게 변환
장점은 10만개의 단어를 10만 차원이 아닌 100~300차원 벡터로 공간을 절약할 수 있음
유사한 의미를 가진 단어를 가까운 벡터로 표현
실수 벡터이기 때문에 딥러닝 모델 학습에 사용 가능
추천시스템에서 유저 임베딩으로 유사한 유저 찾기 가능
word2vec 의 핵심 아이디어는 "같은 문맥에서 자주 나오는 단어는 비슷한 의미를 가진다"라는 아이디어에서 나옴
1. CBOW
주변 단어를 보고 중심 단어를 예측
- 예:
- 문장: "The cat sits on the mat"
- context: ["The", "cat", "on", "the", "mat"]
- center: "sits"
- 특징:
- 자주 나오는 단어를 더 잘 학습
- 전체 문맥을 평균해서 예측 → 빠름
- 희귀 단어엔 약함
2. Skip-gram (주로 사용됨)
- 중심 단어(center)를 보고 주변 단어(context)를 예측
- 예:
- 중심: "sits" → 예측 대상: ["The", "cat", "on", "the", "mat"]
- 특징:
- 느리지만 희귀 단어도 잘 표현 가능
- 추천 시스템에서 sequence를 학습할 때 주로 이 방식 사용
학습방식
[one-hot 단어 입력] → [임베딩 레이어] → [출력층: context 단어 예측]
- 임베딩 레이어의 weight가 우리가 얻고 싶은 단어 임베딩
- 훈련이 끝나면 이 weight 행렬을 그대로 임베딩 테이블로 씀
기본적으로 (입력 단어, 출력 단어) 쌍을 예측하는 방식
예를 들어 Skip-gram에서 "sits"라는 중심 단어로부터 context를 예측하면 다음처럼 학습함
각 단어는 실수 벡터(예: 100차원)로 표현됨
비슷한 단어는 벡터 공간에서 가까운 위치에 위치함
단어 사이의 관계도 벡터 연산으로 표현 가능
word2vec 한계
문맥 순서 정보는 반영 안 됨 (Bag-of-Words 기반)
단어 다의어(예: "bank" = 강변 or 은행) 구분 어려움
문장 수준 이해는 불가
코드예제
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from collections import Counter
import random
# 1. Sample corpus
corpus = """
we are what we repeatedly do excellence then is not an act but a habit
""".lower().split()
# 2. Vocabulary and word-to-index mapping
vocab = list(set(corpus))
vocab_size = len(vocab)
word2idx = {w: i for i, w in enumerate(vocab)}
idx2word = {i: w for w, i in word2idx.items()}
# 3. Generate Skip-gram training pairs
def generate_pairs(corpus, window_size=2):
pairs = []
for i, center in enumerate(corpus):
for j in range(-window_size, window_size + 1):
context_idx = i + j
if j != 0 and 0 <= context_idx < len(corpus):
context = corpus[context_idx]
pairs.append((center, context))
return pairs
pairs = generate_pairs(corpus)
# 4. Dataset class
class Word2VecDataset(torch.utils.data.Dataset):
def __init__(self, pairs):
self.pairs = [(word2idx[c], word2idx[t]) for c, t in pairs]
def __len__(self):
return len(self.pairs)
def __getitem__(self, idx):
return torch.tensor(self.pairs[idx][0]), torch.tensor(self.pairs[idx][1])
# 5. Model definition
class SkipGramModel(nn.Module):
def __init__(self, vocab_size, embedding_dim):
super().__init__()
self.in_embed = nn.Embedding(vocab_size, embedding_dim)
self.out_embed = nn.Embedding(vocab_size, embedding_dim)
def forward(self, center, target):
center_emb = self.in_embed(center) # (batch, embed_dim)
target_emb = self.out_embed(target) # (batch, embed_dim)
score = torch.mul(center_emb, target_emb).sum(dim=1) # (batch)
return score
# 6. Training
embedding_dim = 50
epochs = 100
batch_size = 16
learning_rate = 0.01
dataset = Word2VecDataset(pairs)
dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size, shuffle=True)
model = SkipGramModel(vocab_size, embedding_dim)
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
for epoch in range(epochs):
total_loss = 0
for center, context in dataloader:
score = model(center, context)
loss = F.binary_cross_entropy_with_logits(score, torch.ones_like(score)) # positive sampling only
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
if (epoch + 1) % 10 == 0:
print(f"Epoch {epoch+1}, Loss: {total_loss:.4f}")
# 7. Get word embeddings
embeddings = model.in_embed.weight.data
print("\n'we' vector:", embeddings[word2idx['we']][:5]) # 예시 출력
'패스트캠퍼스' 카테고리의 다른 글
| 패스트캠퍼스 환급챌린지 12일차 : 30개 프로젝트로 끝내는 추천시스템 구현 초격차 패키지 강의 후기 (0) | 2025.04.12 |
|---|---|
| 패스트캠퍼스 환급챌린지 11일차 : 30개 프로젝트로 끝내는 추천시스템 구현 초격차 패키지 강의 후기 (0) | 2025.04.11 |
| 패스트캠퍼스 환급챌린지 9일차 : 30개 프로젝트로 끝내는 추천시스템 구현 초격차 패키지 강의 후기 (0) | 2025.04.09 |
| 패스트캠퍼스 환급챌린지 8일차 : 30개 프로젝트로 끝내는 추천시스템 구현 초격차 패키지 강의 후기 (0) | 2025.04.08 |
| 패스트캠퍼스 환급챌린지 7일차 : 30개 프로젝트로 끝내는 추천시스템 구현 초격차 패키지 강의 후기 (0) | 2025.04.07 |