1. 커스텀 데이터셋(Custom Dataset)
앞서 사용했던 torch.utils.data.Dataset과 torch.utils.data.DataLoader 외에 torch.utils.data.Dataset을 상속받아 직접 커스텀 데이터셋(Custom Dataset)을 만드는 경우도 있습니다. torch.utils.data.Dataset은 파이토치에서 데이터셋을 제공하는 추상 클래스입니다. Dataset을 상속받아 다음 메소드들을 오버라이드 하여 커스텀 데이터셋을 만들어보겠습니다.
커스텀 데이터셋을 만들 때, 일단 가장 기본적인 뼈대는 아래와 같습니다. 여기서 필요한 기본적인 define은 3개입니다.
class CustomDataset(torch.utils.data.Dataset):
def __init__(self):
데이터셋의 전처리를 해주는 부분
def __len__(self):
데이터셋의 길이. 즉, 총 샘플의 수를 적어주는 부분
def __getitem__(self, idx):
데이터셋에서 특정 1개의 샘플을 가져오는 함수
- len(dataset)을 했을 때 데이터셋의 크기를 리턴할 len
- dataset[i]을 했을 때 i번째 샘플을 가져오도록 하는 인덱싱을 위한 get_item
- 샘플(sample) : 데이터셋에서 하나의 데이터 포인트
2. 커스텀 데이터셋(Custom Dataset)으로 선형 회귀 구현하기
import torch
import torch.nn.functional as F
from torch.utils.data import Dataset
from torch.utils.data import DataLoader
# Dataset 상속
class CustomDataset(Dataset):
# 데이터 전처리
def __init__(self):
self.x_data = [[73, 80, 75],
[93, 88, 93],
[89, 91, 90],
[96, 98, 100],
[73, 66, 70]]
self.y_data = [[152], [185], [180], [196], [142]]
# 총 데이터의 개수를 리턴
def __len__(self):
return len(self.x_data)
# 인덱스를 입력받아 그에 맵핑되는 입출력 데이터를 파이토치의 Tensor 형태로 리턴
def __getitem__(self, idx):
x = torch.FloatTensor(self.x_data[idx])
y = torch.FloatTensor(self.y_data[idx])
return x, y
dataset = CustomDataset()
dataloader = DataLoader(dataset, batch_size=2, shuffle=True)
Q. 데이터셋이 5행 3열이었잖아. 근데 미니 배치의 크기를 2로 설정한다는게뭐야? 2행,2행,1행으로 나눠서 본다는거야?
A. 네, 맞습니다! batch_size=2라는 설정은 데이터 로딩 과정에서 미니 배치(mini-batch)의 크기를 2로 설정한다는 의미입니다. 즉, 데이터셋에서 한 번에 처리할 데이터 샘플의 수를 2로 지정한 것입니다. 데이터셋이 5행 3열이라고 하면, 여기서 5행은 데이터 샘플이 5개 있다는 것을 의미하고, 3열은 각 샘플이 3개의 특성(feature)을 가지고 있다는 것을 의미합니다.
따라서, 전체 데이터셋을 미니 배치로 나누면 다음과 같이 됩니다:
- 첫 번째 미니 배치: 첫 번째와 두 번째 샘플
- 두 번째 미니 배치: 세 번째와 네 번째 샘플
- 세 번째 미니 배치: 다섯 번째 샘플만 포함
학습 과정에서 모델은 이렇게 나눠진 미니 배치를 순서대로 처리하게 됩니다. 각 미니 배치에 대해 모델의 가중치를 업데이트하며, 모든 미니 배치를 처리하면 한 에포크(epoch)의 학습이 완료된 것으로 간주합니다. 이 과정은 설정된 에포크 수만큼 반복됩니다.
Q. 그럼 batch_size=4이면 4개 행을 한번에 보는거야?
A. 맞아요, batch_size=4라고 설정하면, 학습 과정에서 데이터셋의 샘플(행) 4개를 한 번에 묶어서 처리하게 됩니다. 즉, 한 번의 이터레이션(또는 스텝)에서 모델은 4개의 데이터 샘플을 동시에 받아서 학습합니다.
예를 들어, 데이터셋이 총 5행 3열이라고 할 때:
- 첫 번째 미니 배치는 첫 번째부터 네 번째 샘플까지의 4개 행을 포함합니다.
- 그 다음 이터레이션에서는 남은 다섯 번째 샘플 1개만 처리하게 됩니다.
model = torch.nn.Linear(3,1)
optimizer = torch.optim.SGD(model.parameters(), lr=1e-5)
nb_epochs = 20
for epoch in range(nb_epochs + 1):
for batch_idx, samples in enumerate(dataloader):
# print(batch_idx)
# print(samples)
x_train, y_train = samples
# H(x) 계산
prediction = model(x_train)
# cost 계산
cost = F.mse_loss(prediction, y_train)
# cost로 H(x) 계산
optimizer.zero_grad()
cost.backward()
optimizer.step()
print('Epoch {:4d}/{} Batch {}/{} Cost: {:.6f}'.format(
epoch, nb_epochs, batch_idx+1, len(dataloader),
cost.item()
))
batch_idx : 0
samples : [tensor([[ 96., 98., 100.],
[ 89., 91., 90.]]), tensor([[196.],
[180.]])]
Epoch 0/20 Batch 1/3 Cost: 45593.117188
batch_idx : 1
samples : [tensor([[73., 80., 75.],
[93., 88., 93.]]), tensor([[152.],
[185.]])]
Epoch 0/20 Batch 2/3 Cost: 8223.790039
batch_idx : 2
samples : [tensor([[73., 66., 70.]]), tensor([[142.]])]
Q. samples가 뜻하는건 뭐야?
A. 여기서 `samples`는 학습을 위해 데이터 로더(data loader)에서 추출한 한 미니 배치(mini-batch)의 예시입니다. 이 미니 배치는 두 개의 텐서(tensor)로 구성되어 있으며, 첫 번째 텐서는 특성(features)을 포함하고, 두 번째 텐서는 해당 샘플의 레이블(labels) 또는 목표(targets)를 포함합니다.
- 첫 번째 텐서는 크기가 `[2, 3]`인 2D 텐서입니다. 여기서 2는 미니 배치의 크기를 나타내며, 즉 이 미니 배치에는 두 개의 샘플이 포함되어 있습니다. 3은 각 샘플의 특성 개수를 의미합니다. (실제 데이터 값이 무작위로 미니 배치로 들어간 것)
- 두 번째 텐서는 크기가 `[2, 1]`인 2D 텐서로, 이는 두 개의 샘플 각각에 대한 레이블 또는 목표 값을 포함하고 있습니다. 여기서 각 샘플의 레이블은 1개의 값으로 표현됩니다. (실제 데이터 값이 x에 들어간 것에 대응하는 y값이 들어간 것)
이 예시에서, `samples`는 머신러닝 모델 학습을 위한 입력 데이터와 해당 데이터의 정답(레이블)을 포함하고 있습니다. 모델은 이 입력 데이터를 사용하여 예측을 수행하고, 예측 결과와 실제 레이블을 비교하여 모델의 성능을 평가하고 개선합니다. 이 과정에서 손실 함수(loss function)를 계산하고, 그디언트를 역전파하여 모델의 가중치를 업데이트합니다.
Epoch 0/20 Batch 1/3 Cost: 29410.156250
Epoch 0/20 Batch 2/3 Cost: 7150.685059
Epoch 0/20 Batch 3/3 Cost: 3482.803467
... 중략 ...
Epoch 20/20 Batch 1/3 Cost: 0.350531
Epoch 20/20 Batch 2/3 Cost: 0.653316
Epoch 20/20 Batch 3/3 Cost: 0.010318
# 임의의 입력 [73, 80, 75]를 선언
new_var = torch.FloatTensor([[73, 80, 75]])
# 입력한 값 [73, 80, 75]에 대해서 예측값 y를 리턴받아서 pred_y에 저장
pred_y = model(new_var)
print("훈련 후 입력이 73, 80, 75일 때의 예측값 :", pred_y)
Copy훈련 후 입력이 73, 80, 75일 때의 예측값 : tensor([[151.2319]], grad_fn=<AddmmBackward>)
'AI > ML' 카테고리의 다른 글
[ML] 원-핫 인코딩(One-Hot Encoding) (0) | 2024.04.05 |
---|---|
[ML] 로지스틱 회귀(Logistic Regression) (1) | 2024.03.29 |
[ML] 미니 배치와 데이터 로드(Mini Batch and Data Load) (0) | 2024.03.28 |
[ML] nn.Module로 구현하는 선형 회귀 (0) | 2024.03.26 |
[pytorch] 파이토치 입문 (0) | 2024.03.23 |