# 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() 완전 가이드]]