# GPT 배치 생성 함수 완벽 가이드
## 배치(Batch) 생성이란?
### 배치의 개념
- **배치**: 여러 개의 데이터를 묶어서 한 번에 처리하는 단위
- 한 개씩 처리하는 것보다 **효율적**이고 **빠름**
- GPU의 병렬 처리 능력을 최대한 활용
### 왜 배치 처리를 하는가?
1. **계산 효율성**: GPU는 행렬 연산에 최적화되어 있음
2. **학습 안정성**: 여러 샘플의 평균 그래디언트로 업데이트
3. **메모리 효율성**: 적절한 크기로 데이터를 나누어 처리
## 코드 상세 분석
### 1. 초기 설정
```python
torch.manual_seed(1234) # 재현 가능한 랜덤 결과를 위한 시드 설정
batch_size = 4 # 한 번에 처리할 샘플 수
block_size = 8 # 각 샘플의 시퀀스 길이
```
### 2. batch_function 함수 분석
```python
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
```
#### 2.1 데이터셋 선택
```python
dataset = train_dataset if mode == "train" else test_dataset
```
- `mode`가 "train"이면 훈련 데이터, 아니면 테스트 데이터 사용
#### 2.2 랜덤 인덱스 생성
```python
idx = torch.randint(len(dataset) - block_size, (batch_size,))
```
- `torch.randint()`: 랜덤 정수 생성
- 범위: 0 ~ (데이터셋 길이 - block_size - 1)
- 개수: batch_size개 (여기서는 4개)
**예시:**
```python
# dataset 길이가 1000, block_size가 8일 때
idx = torch.randint(992, (4,)) # 0~991 사이에서 4개 랜덤 선택
# 결과: tensor([234, 567, 123, 890])
```
#### 2.3 입력 데이터(x) 생성
```python
x = torch.stack([dataset[index:index+block_size] for index in idx])
```
- 각 랜덤 위치에서 block_size만큼 슬라이싱
- `torch.stack()`: 여러 텐서를 새로운 차원으로 쌓기
**예시:**
```python
# idx = [234, 567, 123, 890]일 때
x = torch.stack([
dataset[234:242], # 8개 요소
dataset[567:575], # 8개 요소
dataset[123:131], # 8개 요소
dataset[890:898] # 8개 요소
])
# 결과: (4, 8) 크기의 2차원 텐서
```
#### 2.4 타겟 데이터(y) 생성
```python
y = torch.stack([dataset[index+1:index+block_size+1] for index in idx])
```
- x보다 한 칸씩 밀린 데이터
- 각 위치의 다음 토큰이 정답
**예시:**
```python
# 같은 idx에서
y = torch.stack([
dataset[235:243], # x보다 1칸 밀림
dataset[568:576],
dataset[124:132],
dataset[891:899]
])
```
### 3. 출력 결과 분석
```python
inputs : torch.Size([4, 8]) # 4개 배치, 각 8개 토큰
targets : torch.Size([4, 8]) # 동일한 크기
example_x의 실제 값:
tensor([[1764, 2555, 0, 1236, 2248, 0, 2017, 1976],
[ 0, 1966, 2157, 0, 1951, 2062, 0, 2548],
[ 0, 1304, 1485, 1586, 0, 1907, 2450, 0],
[ 3, 2, 6, 5, 1, 0, 5, 3]])
example_y의 실제 값:
tensor([[2555, 0, 1236, 2248, 0, 2017, 1976, 2546],
[1966, 2157, 0, 1951, 2062, 0, 2548, 2289],
[1304, 1485, 1586, 0, 1907, 2450, 0, 2480],
[ 2, 6, 5, 1, 0, 5, 3, 5]])
```
### 4. 배치 내 모든 입력-타겟 쌍 확인
```python
for size in range(batch_size): # 각 배치 샘플에 대해
for t in range(block_size): # 각 시간 스텝에 대해
context = example_x[size, :t+1]
target = example_y[size, t]
print(f"input : {context}, target : {target}")
```
#### 첫 번째 배치 샘플 (size=0) 예시:
```
t=0: input=[1764], target=2555
t=1: input=[1764,2555], target=0
t=2: input=[1764,2555,0], target=1236
...
```
## torch.stack vs torch.cat 비교
### torch.stack
- **새로운 차원 추가**
- 입력: 여러 개의 (8,) 텐서
- 출력: (4, 8) 텐서
```python
a = torch.tensor([1, 2, 3])
b = torch.tensor([4, 5, 6])
torch.stack([a, b]) # [[1,2,3], [4,5,6]] - (2,3) 크기
```
### torch.cat
- **기존 차원에서 연결**
- 입력: 여러 개의 (8,) 텐서
- 출력: (32,) 텐서
```python
torch.cat([a, b]) # [1,2,3,4,5,6] - (6,) 크기
```
## 배치 처리의 장점
1. **병렬 처리**: GPU가 4개 샘플을 동시에 처리
2. **안정적 학습**: 4개 샘플의 평균 그래디언트 사용
3. **효율적 메모리 사용**: 전체 데이터를 한 번에 로드하지 않음
## 실제 학습에서의 활용
```python
# 학습 루프에서
for step in range(training_steps):
x_batch, y_batch = batch_function("train")
# 모델에 배치 입력
logits, loss = model(x_batch, y_batch)
# 역전파 및 가중치 업데이트
optimizer.zero_grad()
loss.backward()
optimizer.step()
```
## 핵심 포인트
1. **랜덤 샘플링**: 매번 다른 위치에서 데이터 추출
2. **배치 구성**: 여러 시퀀스를 2D 텐서로 구성
3. **입력-타겟 정렬**: y는 x보다 한 칸 밀려서 다음 토큰 예측
4. **효율성**: 한 번에 여러 샘플 처리로 학습 속도 향상
## 관련 참고 자료
- [[02일차_2장 to 2.4_GPT 기초]]
- [[GPT 언어모델 입력-타겟 쌍 생성 원리]]
- [[PyTorch 텐서와 torch.tensor() 완전 가이드]]