# torch.nn 선형 레이어와 임베딩 레이어 대학생 수준 완벽 가이드
## torch.nn 기본 개념
`torch.nn`은 PyTorch의 **신경망 구축 도구모음**입니다. 딥러닝 모델의 모든 구성 요소를 제공하는 도구상자라고 생각하면 됩니다.
## 1. 레이어(Layer)란 무엇인가?
### 일상 비유로 이해하기
레이어는 **공장의 작업대**와 같습니다.
```
원료 → [작업대 1] → 중간재 → [작업대 2] → 완성품
입력 → [레이어 1] → 중간결과 → [레이어 2] → 최종출력
```
### 구체적 예시: 학생 성적 예측 시스템
```python
# 학생 성적 예측 시스템
입력: [수학점수, 과학점수, 영어점수] = [80, 90, 75]
↓
[레이어 1]: 각 과목의 가중치 적용하여 종합점수 계산
↓
출력: [대학합격확률] = [0.85] (85% 확률)
```
## 2. 선형 레이어(Linear Layer) 완벽 이해
### 수학적 정의 (간단하게)
**선형 레이어 = 가중치 곱셈 + 편향 더하기**
```python
# 공식: y = x × W + b
# y: 출력
# x: 입력
# W: 가중치 행렬
# b: 편향(bias)
```
### 실생활 예시: 성적 계산기
```python
# 3과목 점수로 종합점수 계산
입력 = [수학, 과학, 영어] = [80, 90, 75]
# 각 과목의 중요도 (가중치)
가중치 = [0.4, 0.3, 0.3] # 수학이 더 중요
# 계산 과정
종합점수 = 80×0.4 + 90×0.3 + 75×0.3 + 5(보너스점수)
= 32 + 27 + 22.5 + 5 = 86.5점
```
### PyTorch로 구현
```python
import torch
import torch.nn as nn
# nn.Linear(입력크기, 출력크기)
grade_calculator = nn.Linear(3, 1) # 3과목 → 1개 종합점수
# 사용법
scores = torch.tensor([80.0, 90.0, 75.0]) # 3과목 점수
final_score = grade_calculator(scores) # 종합점수 계산
print(final_score) # tensor([86.5], grad_fn=<AddBackward0>)
```
### nn.Linear 매개변수 상세 해석
#### 기본 구조
```python
linear_layer = nn.Linear(120, 230)
# ↑ ↑
# 입력차원 출력차원
```
#### 실제 의미
- **120**: 들어오는 데이터의 특성 개수
- **230**: 나가는 데이터의 특성 개수
#### 구체적 예시들
```python
# 예시 1: 이미지 분류
linear1 = nn.Linear(784, 10)
# ↑ ↑
# 28×28=784 10개 클래스
# 픽셀 개수 (고양이,개,새...)
# 예시 2: 자연어 처리
linear2 = nn.Linear(512, 256)
# ↑ ↑
# 문장벡터 압축된벡터
# 512차원 256차원
# 예시 3: 감정 분석
linear3 = nn.Linear(256, 2)
# ↑ ↑
# 특성벡터 감정클래스
# 256차원 (긍정/부정)
```
### 내부 구조 들여다보기
```python
linear = nn.Linear(120, 230)
# 내부적으로 생성되는 것들:
# 1. 가중치 행렬: W (230 × 120 크기)
# 2. 편향 벡터: b (230 크기)
print("가중치 크기:", linear.weight.shape) # torch.Size([230, 120])
print("편향 크기:", linear.bias.shape) # torch.Size([230])
print("전체 파라미터 수:", linear.weight.numel() + linear.bias.numel()) # 27,830개
```
### 동작 과정 시각화
```python
# 입력 데이터: (batch_size, 120)
input_data = torch.randn(32, 120) # 32개 샘플, 각각 120차원
# 선형 변환 적용
linear = nn.Linear(120, 230)
output = linear(input_data)
print(f"입력 크기: {input_data.shape}") # torch.Size([32, 120])
print(f"출력 크기: {output.shape}") # torch.Size([32, 230])
# 내부 계산: output = input @ weight.T + bias
# @ 는 행렬 곱셈, .T는 전치(transpose)
```
## 3. 임베딩 레이어(Embedding Layer) 완전 이해
### 기본 개념
**임베딩 = 단어를 숫자 벡터로 바꾸는 사전**
### 일상 비유
한영사전과 같은 개념:
- 입력: 한국어 단어 "사과"
- 출력: 영어 설명 "apple, red fruit, sweet"
임베딩 레이어:
- 입력: 단어 ID (정수)
- 출력: 의미 벡터 (실수들의 나열)
### 단어에서 벡터로 변환 과정
```python
# 1단계: 단어 → 숫자 ID 변환
단어사전 = {
"안녕": 0,
"하세요": 1,
"반갑": 2,
"습니다": 3
}
# 2단계: 임베딩 레이어로 ID → 벡터 변환
embedding = nn.Embedding(4, 3) # 4개 단어, 3차원 벡터
# ↑ ↑
# 어휘개수 벡터크기
# 3단계: 사용법
word_id = torch.tensor([0]) # "안녕"의 ID
vector = embedding(word_id) # 예: tensor([[ 0.1, -0.3, 0.8]])
print(f"'안녕'의 벡터: {vector}")
```
### nn.Embedding 매개변수 상세 해석
```python
embedding = nn.Embedding(1000, 128)
# ↑ ↑
# 어휘크기 벡터차원
# 의미:
# - 1000개의 서로 다른 단어를 알고 있음
# - 각 단어를 128차원 벡터로 표현
# - 마치 1000개 항목이 있는 사전과 같음
```
### 임베딩 테이블 구조
```python
# 내부적으로는 큰 표(테이블) 형태
embedding = nn.Embedding(4, 3)
# 임베딩 테이블 내용 확인
print("임베딩 테이블:")
print(embedding.weight)
# 출력 예시:
# tensor([[ 0.1, -0.3, 0.8], # 단어 0 "안녕"의 벡터
# [-0.2, 0.5, 0.1], # 단어 1 "하세요"의 벡터
# [ 0.9, -0.1, 0.4], # 단어 2 "반갑"의 벡터
# [ 0.3, 0.7, -0.5]]) # 단어 3 "습니다"의 벡터
# 단어 ID로 해당 벡터 찾아서 반환하는 방식
word_ids = torch.tensor([0, 2, 1]) # "안녕", "반갑", "하세요"
vectors = embedding(word_ids)
print(f"문장 벡터들: {vectors}")
```
### 임베딩의 학습 과정
```python
# 학습 전: 랜덤한 벡터
"고양이" → [0.1, -0.5, 0.3] # 의미 없는 숫자들
"개" → [0.8, 0.2, -0.1]
# 학습 후: 의미있는 벡터 (비슷한 동물은 비슷한 벡터)
"고양이" → [0.7, 0.8, 0.1] # 애완동물 특성
"개" → [0.8, 0.7, 0.2] # 애완동물 특성 (고양이와 유사)
"사자" → [0.9, 0.2, 0.8] # 야생동물 특성 (고양이/개와 다름)
```
## 4. 왜 이런 레이어들이 필요한가?
### 선형 레이어의 필요성
#### 1. 차원 변환
```python
# 예: 이미지를 문장으로 변환
image_features = torch.randn(512) # 이미지 특성 512차원
text_converter = nn.Linear(512, 256) # 텍스트 공간으로 변환
text_features = text_converter(image_features) # 256차원 텍스트 특성
```
#### 2. 특성 결합
```python
# 예: 여러 정보를 종합하여 최종 판단
user_age = 25
user_income = 50000
user_location = 3 # 지역코드
# 여러 특성을 하나로 결합
features = torch.tensor([25.0, 50000.0, 3.0])
decision_maker = nn.Linear(3, 1) # 3개 특성 → 1개 결정값
approval_score = decision_maker(features) # 승인 점수
```
#### 3. 패턴 학습
```python
# 예: 감정 분석
문장벡터 = torch.randn(512) # 문장을 512차원으로 표현
감정분석기 = nn.Linear(512, 2) # 2가지 감정 (긍정/부정)
감정점수 = 감정분석기(문장벡터) # [긍정확률, 부정확률]
print(f"감정 분석 결과: {감정점수}")
# 예: tensor([0.8, 0.2]) → 80% 긍정, 20% 부정
```
### 임베딩 레이어의 필요성
#### 1. 단어를 숫자로 변환
```python
# 컴퓨터는 숫자만 이해할 수 있음
sentence = "안녕하세요" # 문자열 (컴퓨터가 직접 처리 불가)
token_ids = [0, 1, 2] # 숫자 ID (컴퓨터가 처리 가능)
embedding = nn.Embedding(1000, 128)
vectors = embedding(torch.tensor(token_ids)) # 숫자 벡터로 변환
```
#### 2. 의미 포함
```python
# 비슷한 의미의 단어는 비슷한 벡터를 가짐
embedding = nn.Embedding(1000, 128)
# 학습된 임베딩에서 유사도 계산 (코사인 유사도)
def similarity(word1_id, word2_id):
vec1 = embedding(torch.tensor([word1_id]))
vec2 = embedding(torch.tensor([word2_id]))
return torch.cosine_similarity(vec1, vec2, dim=1)
# 예상 결과 (학습 후)
# similarity("고양이", "개") = 0.8 (높은 유사도)
# similarity("고양이", "컴퓨터") = 0.1 (낮은 유사도)
```
#### 3. 효율적 저장
```python
# One-hot encoding vs Embedding 비교
# One-hot (비효율적): 어휘가 10,000개라면
one_hot_cat = [0, 0, 0, ..., 1, ..., 0] # 10,000차원, 대부분 0
# Embedding (효율적): 128차원으로 압축
embedding_cat = [0.1, 0.5, -0.3, ...] # 128차원, 모든 값 의미있음
```
## 5. GPT에서의 실제 사용
### GPT 기본 구조
```python
import torch.nn as nn
import torch.nn.functional as F
class SimpleGPT(nn.Module):
def __init__(self, vocab_size):
super().__init__()
# 1. 임베딩: 단어 ID → 벡터
self.token_embedding = nn.Embedding(vocab_size, vocab_size)
def forward(self, tokens):
# 단계 1: 토큰을 벡터로 변환
embedded = self.token_embedding(tokens)
return embedded
```
### 구체적 동작 예시
```python
# 예: vocab_size = 1000 (1000개 단어)
model = SimpleGPT(1000)
# 입력: "안녕하" (토큰 ID: [5, 10, 23])
tokens = torch.tensor([5, 10, 23])
# 1단계: 임베딩
embedded = model(tokens)
print(f"입력 토큰: {tokens}")
print(f"임베딩 결과 크기: {embedded.shape}") # torch.Size([3, 1000])
# 각 토큰이 1000차원 벡터로 변환됨
# embedded[0] = 토큰 5의 벡터 (1000차원)
# embedded[1] = 토큰 10의 벡터 (1000차원)
# embedded[2] = 토큰 23의 벡터 (1000차원)
```
### 완전한 GPT 예시 (다음 토큰 예측)
```python
class SimpleGPT(nn.Module):
def __init__(self, vocab_size):
super().__init__()
# 임베딩: 토큰 → 벡터
self.token_embedding = nn.Embedding(vocab_size, vocab_size)
# 선형 레이어: 벡터 → 다음 토큰 확률
self.output_layer = nn.Linear(vocab_size, vocab_size)
def forward(self, tokens):
# 1. 토큰을 벡터로 변환
embedded = self.token_embedding(tokens) # (seq_len, vocab_size)
# 2. 다음 토큰 확률 계산
logits = self.output_layer(embedded) # (seq_len, vocab_size)
return logits
def predict_next_token(self, tokens):
logits = self.forward(tokens)
# 마지막 토큰의 예측만 사용
last_logits = logits[-1] # (vocab_size,)
# 확률로 변환
probs = F.softmax(last_logits, dim=-1)
# 가장 높은 확률의 토큰 선택
next_token = torch.argmax(probs)
return next_token
# 사용 예시
model = SimpleGPT(1000)
input_tokens = torch.tensor([5, 10, 23]) # "안녕하"
next_token = model.predict_next_token(input_tokens)
print(f"다음 토큰 예측: {next_token}") # 예: tensor(156) → "세요"
```
## 6. 실전 팁과 주의사항
### 차원 맞추기
```python
# 자주 하는 실수: 차원이 안 맞는 경우
embedding = nn.Embedding(1000, 128) # 출력: 128차원
linear = nn.Linear(256, 64) # 입력: 256차원 필요
# 해결책: 중간에 차원 조정 레이어 추가
adapter = nn.Linear(128, 256)
```
### 파라미터 수 계산
```python
def count_parameters(model):
return sum(p.numel() for p in model.parameters() if p.requires_grad)
model = SimpleGPT(1000)
total_params = count_parameters(model)
print(f"전체 파라미터 수: {total_params:,}")
# 출력: 전체 파라미터 수: 2,001,000 (약 200만개)
```
### 메모리 사용량 추정
```python
# 대략적인 메모리 사용량 (단정도 부동소수점 기준)
vocab_size = 50000
embed_dim = 512
embedding_params = vocab_size * embed_dim # 25,600,000
memory_mb = embedding_params * 4 / (1024**2) # 약 98MB
print(f"임베딩 레이어 메모리 사용량: {memory_mb:.1f}MB")
```
## 핵심 정리
### 개념 요약
- **레이어**: 데이터를 변환하는 작업대, 신경망의 기본 구성 요소
- **선형 레이어**: 가중치 곱셈으로 정보를 결합하고 차원을 변환
- **임베딩 레이어**: 단어 ID를 의미있는 벡터로 변환하는 사전
### 매개변수 해석
- **nn.Linear(120, 230)**: 120차원 입력을 230차원 출력으로 변환
- **nn.Embedding(1000, 128)**: 1000개 단어를 각각 128차원 벡터로 표현
### 실용적 가치
- **효율성**: GPU에서 병렬 처리 가능한 행렬 연산
- **학습성**: 훈련을 통해 최적의 가중치와 임베딩 학습
- **확장성**: 다양한 크기의 입력/출력에 유연하게 대응
### 다음 학습 방향
이제 실제 GPT 모델 구현에서 이들이 어떻게 조합되어 언어를 이해하고 생성하는지 살펴볼 준비가 완료되었습니다!
## 관련 참고 자료
- [[02일차_2장 to 2.4_GPT 기초]]
- [[GPT 배치 생성 함수 한글 예시로 완벽 이해]]
- [[PyTorch 텐서와 torch.tensor() 완전 가이드]]