# GPT 배치 생성 함수 한글 예시로 완벽 이해
## 전체 코드 구조
```python
torch.manual_seed(1234)
batch_size = 4
block_size = 8
def batch_function(mode):
dataset = train_dataset if mode == "train" else test_dataset
idx = torch.randint(len(dataset) - block_size, (batch_size,))
x = torch.stack([dataset[index:index+block_size] for index in idx])
y = torch.stack([dataset[index+1:index+block_size+1] for index in idx])
return x, y
example_x, example_y = batch_function("train")
```
## 1. 함수 호출과 변수 할당 과정
### 함수 반환값 할당
```python
example_x, example_y = batch_function("train")
```
**내부 동작:**
1. `batch_function("train")` 호출 (mode="train"으로 설정)
2. 함수가 `return x, y`로 두 값 반환
3. 반환된 첫 번째 값(x) → `example_x`에 할당
4. 반환된 두 번째 값(y) → `example_y`에 할당
**다른 방법과 비교:**
```python
# 방법 1: 개별로 받기
result = batch_function("train")
example_x = result[0]
example_y = result[1]
# 방법 2: 한 번에 받기 (우리가 사용한 방법)
example_x, example_y = batch_function("train")
```
## 2. 2차원 텐서 인덱싱 구조
### 기본 형태: `tensor[행, 열]`
```python
# example_x는 (4, 8) 크기의 2차원 텐서
example_x = torch.tensor([
[1764, 2555, 0, 1236, 2248, 0, 2017, 1976], # 행 0 (배치 0)
[ 0, 1966, 2157, 0, 1951, 2062, 0, 2548], # 행 1 (배치 1)
[ 0, 1304, 1485, 1586, 0, 1907, 2450, 0], # 행 2 (배치 2)
[ 3, 2, 6, 5, 1, 0, 5, 3] # 행 3 (배치 3)
])
# 열0 열1 열2 열3 열4 열5 열6 열7
```
### 인덱싱 예시
```python
example_x[0, :4] # 행 0에서 열 0~3까지: [1764, 2555, 0, 1236]
example_y[0, 3] # 행 0에서 열 3: 2248
# 의미:
# 첫 번째 숫자 (0): 어떤 배치(행)를 선택할지
# 두 번째 부분 (:4, 3): 그 배치에서 어떤 위치(열)를 선택할지
```
## 3. 한글 예시로 전체 과정 이해
### 가상의 한글 데이터셋
```python
# 한글 텍스트를 숫자로 변환했다고 가정
train_dataset = [
# "안녕하세요 반갑습니다 좋은 하루 되세요 감사합니다"
안, 녕, 하, 세, 요, 공, 반, 갑, 습, 니, 다, 공, 좋, 은, 공, 하, 루, 공, 되, 세, 요, 공, 감, 사, 합, 니, 다, ...
]
# 숫자 매핑 (예시)
# 안=1, 녕=2, 하=3, 세=4, 요=5, 공=0(공백), 반=6, 갑=7, 습=8, 니=9, 다=10
# 좋=11, 은=12, 루=13, 되=14, 감=15, 사=16, 날=17, 씨=18, 네=19
```
### 1단계: 랜덤 인덱스 생성
```python
torch.manual_seed(1234) # 시드 고정으로 항상 같은 결과
idx = torch.randint(len(dataset) - 8, (4,))
# 예: idx = [1000, 2500, 500, 3000] (랜덤하게 4개 위치 선택)
```
### 2단계: 각 위치에서 데이터 추출
```python
# idx[0] = 1000 위치에서 8개 추출
dataset[1000:1008] = [안, 녕, 하, 세, 요, 공, 반, 갑] # x의 첫 번째 행
dataset[1001:1009] = [녕, 하, 세, 요, 공, 반, 갑, 습] # y의 첫 번째 행 (한 칸 밀림)
# idx[1] = 2500 위치에서 8개 추출
dataset[2500:2508] = [좋, 은, 공, 하, 루, 공, 되, 세] # x의 두 번째 행
dataset[2501:2509] = [은, 공, 하, 루, 공, 되, 세, 요] # y의 두 번째 행
# idx[2] = 500 위치에서 8개 추출
dataset[500:508] = [감, 사, 합, 니, 다, 공, 안, 녕] # x의 세 번째 행
dataset[501:509] = [사, 합, 니, 다, 공, 안, 녕, 하] # y의 세 번째 행
# idx[3] = 3000 위치에서 8개 추출
dataset[3000:3008] = [하, 루, 공, 좋, 은, 공, 날, 씨] # x의 네 번째 행
dataset[3001:3009] = [루, 공, 좋, 은, 공, 날, 씨, 네] # y의 네 번째 행
```
### 3단계: 배치 생성 (torch.stack으로 쌓기)
```python
example_x = torch.tensor([
[안, 녕, 하, 세, 요, 공, 반, 갑], # 배치 0
[좋, 은, 공, 하, 루, 공, 되, 세], # 배치 1
[감, 사, 합, 니, 다, 공, 안, 녕], # 배치 2
[하, 루, 공, 좋, 은, 공, 날, 씨] # 배치 3
]) # shape: (4, 8)
example_y = torch.tensor([
[녕, 하, 세, 요, 공, 반, 갑, 습], # 배치 0 (x보다 한 칸 밀림)
[은, 공, 하, 루, 공, 되, 세, 요], # 배치 1
[사, 합, 니, 다, 공, 안, 녕, 하], # 배치 2
[루, 공, 좋, 은, 공, 날, 씨, 네] # 배치 3
]) # shape: (4, 8)
```
## 4. 중첩 for 루프 실행 과정
### 실행 순서
```python
for size in range(batch_size): # size: 0, 1, 2, 3 (배치 선택)
for t in range(block_size): # t: 0, 1, 2, 3, 4, 5, 6, 7 (시간 스텝)
context = example_x[size, :t+1]
target = example_y[size, t]
```
**총 실행 횟수**: 4 × 8 = 32번
**실행 순서**:
1. size=0일 때: t=0~7까지 8번 실행
2. size=1일 때: t=0~7까지 8번 실행
3. size=2일 때: t=0~7까지 8번 실행
4. size=3일 때: t=0~7까지 8번 실행
### 배치 0 (size=0) - "안녕하세요 반갑" 상세 실행
```python
size = 0 # 첫 번째 배치
# t=0: 첫 글자로 다음 글자 예측
context = example_x[0, :1] # [안]
target = example_y[0, 0] # 녕
# 의미: "안" → "녕" 예측
# t=1: 두 글자로 다음 글자 예측
context = example_x[0, :2] # [안, 녕]
target = example_y[0, 1] # 하
# 의미: "안녕" → "하" 예측
# t=2: 세 글자로 다음 글자 예측
context = example_x[0, :3] # [안, 녕, 하]
target = example_y[0, 2] # 세
# 의미: "안녕하" → "세" 예측
# t=3: 네 글자로 다음 글자 예측
context = example_x[0, :4] # [안, 녕, 하, 세]
target = example_y[0, 3] # 요
# 의미: "안녕하세" → "요" 예측
# t=4: 다섯 글자로 다음 글자 예측
context = example_x[0, :5] # [안, 녕, 하, 세, 요]
target = example_y[0, 4] # 공(공백)
# 의미: "안녕하세요" → " " 예측
# t=5: 여섯 글자로 다음 글자 예측
context = example_x[0, :6] # [안, 녕, 하, 세, 요, 공]
target = example_y[0, 5] # 반
# 의미: "안녕하세요 " → "반" 예측
# t=6: 일곱 글자로 다음 글자 예측
context = example_x[0, :7] # [안, 녕, 하, 세, 요, 공, 반]
target = example_y[0, 6] # 갑
# 의미: "안녕하세요 반" → "갑" 예측
# t=7: 여덟 글자로 다음 글자 예측
context = example_x[0, :8] # [안, 녕, 하, 세, 요, 공, 반, 갑]
target = example_y[0, 7] # 습
# 의미: "안녕하세요 반갑" → "습" 예측
```
### 배치 1 (size=1) - "좋은 하루 되세" 상세 실행
```python
size = 1 # 두 번째 배치
# t=0
context = example_x[1, :1] # [좋]
target = example_y[1, 0] # 은
# 의미: "좋" → "은" 예측
# t=1
context = example_x[1, :2] # [좋, 은]
target = example_y[1, 1] # 공(공백)
# 의미: "좋은" → " " 예측
# t=2
context = example_x[1, :3] # [좋, 은, 공]
target = example_y[1, 2] # 하
# 의미: "좋은 " → "하" 예측
# t=3
context = example_x[1, :4] # [좋, 은, 공, 하]
target = example_y[1, 3] # 루
# 의미: "좋은 하" → "루" 예측
# t=4
context = example_x[1, :5] # [좋, 은, 공, 하, 루]
target = example_y[1, 4] # 공(공백)
# 의미: "좋은 하루" → " " 예측
# t=5
context = example_x[1, :6] # [좋, 은, 공, 하, 루, 공]
target = example_y[1, 5] # 되
# 의미: "좋은 하루 " → "되" 예측
# t=6
context = example_x[1, :7] # [좋, 은, 공, 하, 루, 공, 되]
target = example_y[1, 6] # 세
# 의미: "좋은 하루 되" → "세" 예측
# t=7
context = example_x[1, :8] # [좋, 은, 공, 하, 루, 공, 되, 세]
target = example_y[1, 7] # 요
# 의미: "좋은 하루 되세" → "요" 예측
```
## 5. 최종 출력 예시
```
inputs : torch.Size([4, 8])
example_x의 실제 값:
tensor([[안, 녕, 하, 세, 요, 공, 반, 갑],
[좋, 은, 공, 하, 루, 공, 되, 세],
[감, 사, 합, 니, 다, 공, 안, 녕],
[하, 루, 공, 좋, 은, 공, 날, 씨]])
targets : torch.Size([4, 8])
example_y의 실제 값:
tensor([[녕, 하, 세, 요, 공, 반, 갑, 습],
[은, 공, 하, 루, 공, 되, 세, 요],
[사, 합, 니, 다, 공, 안, 녕, 하],
[루, 공, 좋, 은, 공, 날, 씨, 네]])
input : tensor([안]), target : 녕
input : tensor([안, 녕]), target : 하
input : tensor([안, 녕, 하]), target : 세
input : tensor([안, 녕, 하, 세]), target : 요
input : tensor([안, 녕, 하, 세, 요]), target : 공
input : tensor([안, 녕, 하, 세, 요, 공]), target : 반
input : tensor([안, 녕, 하, 세, 요, 공, 반]), target : 갑
input : tensor([안, 녕, 하, 세, 요, 공, 반, 갑]), target : 습
-----------------------
-----------------------
input : tensor([좋]), target : 은
input : tensor([좋, 은]), target : 공
... (계속해서 총 32개의 입력-타겟 쌍 출력)
```
## 6. 핵심 정리
### 배치 생성의 목적
- **효율성**: 4개 샘플을 동시에 처리하여 GPU 활용도 극대화
- **다양성**: 서로 다른 위치의 텍스트에서 다양한 학습 패턴 확보
- **자기회귀 학습**: 각 위치에서 "문맥 → 다음 글자" 예측 관계 학습
### 핵심 개념
1. **랜덤 샘플링**: 매번 다른 위치에서 데이터 추출
2. **배치 구성**: 여러 시퀀스를 2D 텐서로 구성
3. **입력-타겟 정렬**: y는 x보다 한 칸 밀려서 다음 토큰 예측
4. **점진적 문맥 확장**: 1글자 → 2글자 → ... → 8글자로 문맥 점차 확장
### 학습 효과
- **32개의 학습 샘플**: 4개 배치 × 8개 시간 스텝
- **다양한 문맥 길이**: 1~8글자까지의 다양한 입력 길이 학습
- **실제 언어 패턴**: 짧은 문맥부터 긴 문맥까지 모든 경우 학습
## 관련 참고 자료
- [[GPT 배치 생성 함수 완벽 가이드]]
- [[PyTorch stack 메서드 완벽 가이드]]
- [[GPT 언어모델 입력-타겟 쌍 생성 원리]]
- [[PyTorch 랜덤 시드와 텐서 shape 완벽 이해]]