https://scikit-learn.org/stable/api/sklearn.datasets.html#module-sklearn.datasets
sklearn.datasets
Utilities to load popular datasets and artificial data generators. User guide. See the Dataset loading utilities section for further details. Loaders: Sample generators:
scikit-learn.org
1. 손글씨 데이터셋
손글씨 숫자 데이터셋은 0부터 9까지의 숫자를 손글씨로 쓴 흑백 이미지로 구성되어 있으며, 각 이미지는 8x8 픽셀 크기의 64차원 벡터로 표현됩니다. 각 픽셀 값은 0(흰색)에서 16(검은색)까지의 명암값을 가집니다. 이 데이터는 총 1797개의 샘플로 이루어져 있으며, 각 샘플에는 숫자 클래스(0~9)가 레이블로 붙어 있습니다. 주로 분류 알고리즘을 학습시키거나 데이터 시각화, 차원 축소 기법 등을 실험하는 데 사용됩니다.
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
digits = load_digits()
X_data = digits['data']
y_data = digits['target']
print(X_data.shape)
print(y_data.shape)
(1797, 64)
(1797,)
X_data
array([[ 0., 0., 5., ..., 0., 0., 0.],
[ 0., 0., 0., ..., 10., 0., 0.],
[ 0., 0., 0., ..., 16., 9., 0.],
...,
[ 0., 0., 1., ..., 6., 0., 0.],
[ 0., 0., 2., ..., 12., 0., 0.],
[ 0., 0., 10., ..., 12., 1., 0.]])
y_data
array([0, 1, 2, ..., 8, 9, 8])
fig, axes = plt.subplots(nrows=2,ncols=5,figsize=(14,8))
for i, ax in enumerate(axes.flatten()):
ax.imshow(X_data[i].reshape(8,8), cmap='gray')# cmap='gray' 흑백으로 찍어주기
ax.set_title(y_data[i])
ax.axis('off')

- plt.subplots(nrows=2, ncols=5)
- 2개의 행과 5개의 열을 가진 서브플롯(총 10개의 서브플롯)을 생성.
- 이 결과로 fig(전체 그림)과 axes(각 서브플롯의 배열)가 반환됨.
- figsize=(14,8)
- 전체 플롯의 크기를 (14,8) 인치 단위로 설정.
- 그래프가 너무 작으면 해상도가 낮아지고, 너무 크면 보기 어려울 수 있으므로 적절한 크기 조정.
- axes는 (2, 5) 크기의 NumPy 배열 형태로 반환됨.
- 즉, axes는 2행 × 5열의 서브플롯 객체 배열이다.
- axes.flatten()을 사용하여 (2,5) 모양의 2D 배열을 1D 배열
- enumerate(axes.flatten()):
- i: 현재 인덱스 (0부터 시작).
- ax: 현재 순회 중인 개별 서브플롯 객체.
- 이 루프는 총 10번 실행됨. (2 × 5 = 10개의 서브플롯)
- X_data[i]: i번째 샘플의 입력 데이터.
- .reshape(8,8): 원본 데이터가 (64,) (1차원 벡터)라면 (8,8) 형태로 변환하여 2D 이미지로 표시.
- cmap='gray': **그레이스케일(흑백)**로 출력.
- y_data[i]: i번째 샘플의 정답(클래스 레이블).
- ax.set_title()을 사용하여 각 서브플롯에 해당 이미지의 정답(클래스) 표시.
- 기본적으로 imshow()를 사용하면 x축, y축 눈금이 표시된다.
- axis('off')를 사용하면 축을 숨겨서 더 깔끔한 시각화 가능.
X_data = torch.FloatTensor(X_data)
y_data = torch.LongTensor(y_data)
print(X_data.shape)
print(y_data.shape)
torch.Size([1797, 64])
torch.Size([1797])
X_train,X_test,y_train,y_test = train_test_split(X_data,y_data,test_size=0.3,random_state=2025)
X_train.shape,X_test.shape
(torch.Size([1257, 64]), torch.Size([540, 64]))
y_train.shape,y_test.shape
(torch.Size([1257]), torch.Size([540]))
2. 데이터 로더
데이터로더(Data Loader)는 데이터셋을 효율적으로 관리하고, 모델 학습 과정에서 데이터를 쉽게 가져올 수 있도록 도와주는 도구입니다. 일반적으로 데이터셋을 배치(batch) 단위로 나누어 모델에 제공하며, 데이터의 크기가 클 경우에도 메모리 효율적으로 처리할 수 있도록 설계되었습니다. 데이터 증강, 셔플링, 병렬 처리와 같은 기능을 지원하여 학습 성능을 향상시키고, 모델 학습과 평가 시 일관된 데이터 제공 방식을 유지합니다. 딥러닝 프레임워크에서는 PyTorch의 DataLoader나 TensorFlow의 tf.data 같은 도구를 통해 쉽게 사용할 수 있습니다.
데이터로더의 주요 역할
- 배치 처리: 데이터를 지정된 크기의 배치로 나누어 모델에 제공.
- 셔플링: 데이터 순서를 무작위로 섞어 과적합 방지.
- 병렬 처리: num_workers 옵션을 통해 데이터를 병렬로 로드하여 속도 향상.
- 반복 처리: 학습 epoch 동안 데이터를 자동으로 반복해서 제공.
loader = DataLoader(
dataset=list(zip(X_train,y_train)),
batch_size=64,
shuffle=True,
drop_last=False
)
imgs,labels = next(iter(loader))
fig, axes = plt.subplots(nrows=8,ncols=8,figsize=(14,14))
for ax, img, label in zip(axes.flatten(),imgs,labels):
ax.imshow(img.reshape(8,8), cmap='gray')# cmap='gray' 흑백으로 찍어주기
ax.set_title(str(label))
ax.axis('off')
axes.flatten()
axes.flatten()은 다차원 배열 형태로 구성된 Matplotlib의 서브플롯 배열을 1차원 배열로 변환하는 메서드입니다. Matplotlib에서 다수의 서브플롯을 생성할 때, plt.subplots()는 2차원 배열 형태로 서브플롯 객체를 반환합니다. 이 배열은 각 서브플롯을 접근하기 위해 행과 열의 인덱스를 사용해야 하지만, flatten() 메서드를 사용하면 이 배열을 1차원으로 펼쳐서 각 서브플롯을 단일 인덱스로 순회할 수 있게 됩니다.

위 시각 자료를 보면 plt.subplots(2, 2)를 사용하여 생성된 서브플롯이 2x2 형태의 배열로 구성되어 있습니다. 이 상태에서는 axes[0, 0], axes[0, 1], axes[1, 0], axes[1, 1]과 같이 2차원 인덱스를 사용해야 합니다.

하지만 axes.flatten()을 적용하면 이 서브플롯 배열이 1차원 리스트처럼 변환되어 flattened_axes[0], flattened_axes[1], flattened_axes[2], flattened_axes[3]처럼 단일 인덱스로 순회할 수 있게 됩니다.
이러한 변환을 사용하면 루프를 돌면서 서브플롯을 설정할 때 인덱싱이 훨씬 단순해져 편리합니다.
model = nn.Sequential(
nn.Linear(64,10)
)
optimizer = optim.Adam(model.parameters(),lr=0.01)
epochs = 50
for epoch in range(epochs+1):
sum_losses = 0
sum_accs = 0
for X_batch, y_batch in loader:
y_pred = model(X_batch)
loss = nn.CrossEntropyLoss()(y_pred,y_batch)
optimizer.zero_grad() #경사하강법을 사용하는 아담에 대한 기울기를 초기화
loss.backward()# 역전파를 이용해 미분한 값으로 웨이트와 바이오값 뽑아서
optimizer.step()# 웨이트와 바이오스 갱신 적용
sum_losses = sum_losses + loss
y_prob = nn.Softmax(1)(y_pred)#실제 구하고자하는 확률값을 뽑아냄
y_pred_index = torch.argmax(y_prob,axis=1) #가장 높은 확률의 인덱스값을 뽑아옴
acc = (y_batch==y_pred_index).float().sum() / len(y_batch) * 100 #이거 한줄 설명도 적기
sum_accs = sum_accs + acc
#여기까지 배치 단위 계산
#에폭 설정
avg_loss = sum_losses / len(loader) #전체 데이터 평균 로스값
avg_acc = sum_accs / len(loader) # 전체 데이터 평균 정확도
print(f'Epoch {epoch:4d}/{epochs} Loss: {avg_loss:.6f} Accuracy: {avg_acc:.2f}%')
Epoch 0/50 Loss: 2.059032 Accuracy: 53.75%
Epoch 1/50 Loss: 0.306242 Accuracy: 90.07%
Epoch 2/50 Loss: 0.186663 Accuracy: 93.58%
Epoch 3/50 Loss: 0.129892 Accuracy: 96.36%
Epoch 4/50 Loss: 0.112430 Accuracy: 97.03%
Epoch 5/50 Loss: 0.090612 Accuracy: 97.49%
Epoch 6/50 Loss: 0.085378 Accuracy: 97.50%
Epoch 7/50 Loss: 0.075866 Accuracy: 98.20%
Epoch 8/50 Loss: 0.060378 Accuracy: 98.59%
Epoch 9/50 Loss: 0.065021 Accuracy: 98.05%
Epoch 10/50 Loss: 0.057262 Accuracy: 98.67%
Epoch 11/50 Loss: 0.049868 Accuracy: 98.91%
Epoch 12/50 Loss: 0.046253 Accuracy: 98.91%
Epoch 13/50 Loss: 0.044165 Accuracy: 99.06%
Epoch 14/50 Loss: 0.039842 Accuracy: 99.61%
Epoch 15/50 Loss: 0.036627 Accuracy: 99.38%
Epoch 16/50 Loss: 0.041312 Accuracy: 99.14%
Epoch 17/50 Loss: 0.038287 Accuracy: 99.30%
Epoch 18/50 Loss: 0.031735 Accuracy: 99.61%
Epoch 19/50 Loss: 0.026393 Accuracy: 99.84%
Epoch 20/50 Loss: 0.029508 Accuracy: 99.77%
Epoch 21/50 Loss: 0.025417 Accuracy: 99.69%
Epoch 22/50 Loss: 0.026414 Accuracy: 99.77%
Epoch 23/50 Loss: 0.026406 Accuracy: 99.38%
Epoch 24/50 Loss: 0.025807 Accuracy: 99.45%
Epoch 25/50 Loss: 0.019285 Accuracy: 99.77%
Epoch 26/50 Loss: 0.017832 Accuracy: 100.00%
Epoch 27/50 Loss: 0.021703 Accuracy: 99.84%
Epoch 28/50 Loss: 0.015931 Accuracy: 99.84%
Epoch 29/50 Loss: 0.015503 Accuracy: 99.92%
Epoch 30/50 Loss: 0.018646 Accuracy: 99.69%
Epoch 31/50 Loss: 0.014456 Accuracy: 99.92%
Epoch 32/50 Loss: 0.016027 Accuracy: 99.84%
Epoch 33/50 Loss: 0.013954 Accuracy: 99.84%
Epoch 34/50 Loss: 0.012925 Accuracy: 99.92%
Epoch 35/50 Loss: 0.013075 Accuracy: 99.84%
Epoch 36/50 Loss: 0.012973 Accuracy: 99.77%
Epoch 37/50 Loss: 0.010807 Accuracy: 100.00%
Epoch 38/50 Loss: 0.011722 Accuracy: 99.92%
Epoch 39/50 Loss: 0.015281 Accuracy: 99.92%
Epoch 40/50 Loss: 0.014243 Accuracy: 99.69%
Epoch 41/50 Loss: 0.014695 Accuracy: 99.69%
Epoch 42/50 Loss: 0.010457 Accuracy: 99.92%
Epoch 43/50 Loss: 0.013000 Accuracy: 99.77%
Epoch 44/50 Loss: 0.012177 Accuracy: 99.92%
Epoch 45/50 Loss: 0.008631 Accuracy: 99.92%
Epoch 46/50 Loss: 0.009301 Accuracy: 100.00%
Epoch 47/50 Loss: 0.008152 Accuracy: 100.00%
Epoch 48/50 Loss: 0.008642 Accuracy: 99.92%
Epoch 49/50 Loss: 0.007367 Accuracy: 100.00%
Epoch 50/50 Loss: 0.008092 Accuracy: 99.92%
plt.imshow(X_test[10].reshape((8, 8)), cmap='gray')
print(y_test[10])
y_pred = model(X_test)
y_pred[10]
- model(X_test): X_test(테스트 데이터)를 신경망 모델에 입력하여 예측값(y_pred)을 얻습니다.
- y_pred[10]: 예측값 중에서 10번째 샘플의 출력값을 확인합니다.
- y_pred는 모델의 마지막 층에서 나온 로짓(logit) 값으로, 아직 확률이 아닌 가공되지 않은 점수(raw score) 입니다.
tensor([ -3.2551, -8.3913, -3.3586, -2.7096, -3.8491, 13.2806, -10.4161,
2.7601, 2.1381, -9.1885], grad_fn=<SelectBackward0>)
y_prob = nn.Softmax(1)(y_pred)
y_prob[10]
- nn.Softmax(1): Softmax 함수는 모델의 출력값을 확률 분포로 변환하는 역할을 합니다.
- Softmax(dim=1): dim=1은 배치 차원을 유지하면서, 각 샘플의 예측값을 클래스별 확률로 변환합니다.
- y_prob[10]: 10번째 샘플의 확률 분포를 확인합니다.
- 예를 들어, y_prob[10]의 결과가 [0.1, 0.05, 0.05, 0.2, ...]처럼 나올 수 있습니다.
- 이는 각 클래스(0~9)에 대해 모델이 예측한 확률 값입니다.
tensor([6.5862e-08, 3.8726e-10, 5.9385e-08, 1.1365e-07, 3.6362e-08, 9.9996e-01,
5.1129e-11, 2.6977e-05, 1.4483e-05, 1.7450e-10],
grad_fn=<SelectBackward0>)
for i in range(10):
print(f'숫자 {i}일 확률 : {y_prob[10][i]:.2f}')
숫자 0일 확률 : 0.00
숫자 1일 확률 : 0.00
숫자 2일 확률 : 0.00
숫자 3일 확률 : 0.00
숫자 4일 확률 : 0.00
숫자 5일 확률 : 1.00
숫자 6일 확률 : 0.00
숫자 7일 확률 : 0.00
숫자 8일 확률 : 0.00
숫자 9일 확률 : 0.00
y_pred_index = torch.argmax(y_prob,axis=1)
accuracy = (y_test==y_pred_index).float().sum() / len(y_test) * 100
print(f'테스트 데이터 정확도 : {accuracy:.2f}% 입니다.')
- y_prob는 Softmax를 적용한 확률 값입니다.
- torch.argmax(y_prob, axis=1): 가장 높은 확률을 가진 클래스의 인덱스를 선택합니다.
- axis=1: y_prob의 각 행(즉, 각 샘플)에서 가장 높은 확률을 가진 클래스(0~9 중 하나)를 찾습니다.
- 결과적으로, y_pred_index는 모델이 예측한 최종 숫자 레이블(0~9)로 이루어진 1차원 텐서가 됩니다.
- y_test == y_pred_index: 정답(y_test)과 모델 예측값(y_pred_index)을 비교합니다.
- y_test는 실제 정답 레이블이 들어 있는 텐서입니다.
- y_pred_index는 모델이 예측한 최종 클래스 인덱스입니다.
- 같은 값이면 True, 다르면 False가 됩니다.
- .float(): True(정답이면) → 1.0, False(오답이면) → 0.0으로 변환합니다.
- .sum(): 맞춘 개수를 합산합니다.
- / len(y_test): 전체 샘플 수로 나눠서 비율을 구합니다.
- * 100: 백분율(%) 형태의 정확도로 변환합니다.
테스트 데이터 정확도 : 96.48% 입니다.
3. 데이터 증강
데이터 증강(Data Augmentation)은 학습 데이터를 인위적으로 변환하여 데이터셋의 다양성을 높이고 모델의 일반화 성능을 향상시키는 기법입니다. 회전, 크기 조정, 반전, 블러링, 밝기 조정 등 다양한 변환을 적용하여 원본 데이터로부터 새로운 데이터를 생성합니다. 이를 통해 데이터 부족 문제를 완화하고 모델이 특정 패턴에 과적합되지 않도록 도와줍니다. 특히, 이미지나 음성 데이터와 같이 특징이 직관적인 데이터에서 효과적으로 활용되며, 증강된 데이터는 모델이 예측 대상의 다양한 변형에 대해 강하게 학습할 수 있도록 돕습니다.
from torchvision import transforms
from torch.utils.data import TensorDataset
from torch.utils.data import Dataset
X_train,X_test,y_train,y_test = train_test_split(X_data,y_data,test_size=0.3,random_state=2025)
print(X_train.shape,X_test.shape)
print(y_train.shape,y_test.shape)
torch.Size([1257, 64]) torch.Size([540, 64])
torch.Size([1257]) torch.Size([540])
train_dataset = TensorDataset(X_train,y_train)
test_dataset = TensorDataset(X_test,y_test)
transfrom = transforms.Compose([
transforms.RandomRotation(10),
transforms.RandomAffine(0, shear=5, scale=(0.9, 1.1))
])
transforms.Compose
여러 데이터 변환(transform) 작업을 순차적으로 적용할 수 있도록 해줍니다. 이미지 데이터 전처리와 증강 과정에서 자주 사용되며, 각 변환을 하나의 리스트로 묶어 실행합니다.
1. transforms.RandomRotation(10)
- 기능: 이미지를 -10도에서 +10도 사이로 무작위 회전시킵니다.
- 10은 회전 범위를 나타냅니다.
- 각 호출 시, -10도 ~ +10도 범위에서 무작위로 각도를 선택하여 이미지를 회전합니다.
2. transforms.RandomAffine(0, shear=5, scale=(0.9, 1.1))
- 기능: 이미지를 비틀기(shear), 크기 조정(scale) 등의 변환을 수행합니다.
- 0: 회전(각도) 변환을 수행하지 않음을 의미합니다.
- shear=5: 이미지를 최대 5도만큼 비스듬하게 비틀기(shear) 변환을 수행합니다.
- 예: 정사각형이 평행사변형처럼 기울어질 수 있습니다.
- scale=(0.9, 1.1):
- 이미지를 0.9배(축소)에서 1.1배(확대) 범위 내에서 무작위 크기 조정을 수행합니다.
- 각 호출 시, 무작위로 크기가 변경됩니다.
class AugmentedDataset(Dataset):
def __init__(self, dataset, transform):
self.dataset = dataset
self.transform = transform
#오버라이딩
def __len__(self):
return len(self.dataset)
#스폐셜 메서드 기억 안나면 다시 내용 뜻 쓰자
#인덱싱했을때 기능
def __getitem__(self, idx):
x, y = self.dataset[idx]
x = x.view(8,8).unsqueeze(0) # x: 피쳐(64,) -> x,y축 네모 (8,8) -> 이미지(1,8,8)
x = self.transform(x) #증강 적용
return x.flatten(),y # 다시 Flatten
augmented_train_dataset = AugmentedDataset(train_dataset, transfrom)
- train_dataset: 원본 학습 데이터셋
- transfrom: 데이터 변환(transform) 적용
- AugmentedDataset 클래스를 사용하여 train_dataset의 데이터를 변환 후 새로운 데이터셋으로 만든다.
- augmented_train_dataset의 __getitem__()을 호출할 때 데이터 증강이 적용된다.
train_loader = DataLoader(augmented_train_dataset,batch_size=64,shuffle=True)
test_loader = DataLoader(test_dataset,batch_size=64,shuffle=False)
- DataLoader는 PyTorch의 데이터셋을 batch 단위로 제공하는 역할을 한다.
- augmented_train_dataset: 변환된 학습 데이터셋 사용.
- batch_size=64: 한 번에 64개의 샘플을 가져옴.
- shuffle=True:
- 매 epoch마다 데이터 순서를 랜덤하게 섞음.
- 학습 데이터는 shuffle=True로 설정하는 것이 일반적이다.
- 이유: 모델이 특정 데이터 패턴을 학습하는 것을 방지하여 일반화 성능을 높일 수 있음.
- test_dataset을 배치 단위로 로드하는 DataLoader.
- batch_size=64: 한 번에 64개의 샘플을 가져옴.
- shuffle=False:
- 테스트 데이터는 순서를 유지한 채 사용.
- 평가할 때 데이터 순서를 섞을 필요가 없기 때문.
imgs, labels = next(iter(train_loader))
fig, axes = plt.subplots(nrows=8, ncols=8, figsize=(14, 14))
for ax, img, label in zip(axes.flatten(), imgs, labels):
ax.imshow(img.reshape((8, 8)), cmap='gray')
ax.set_title(str(label))
ax.axis('off')
for images, labels in train_loader:
print(f"Image batch shape: {images.shape}")
print(f"Label batch shape: {labels.shape}")
break
# Image batch shape: torch.Size([64, 64]) 64개 배치 64개 이미지
# Label batch shape: torch.Size([64]) 64개 정답
Image batch shape: torch.Size([64, 64])
Label batch shape: torch.Size([64])
model = nn.Sequential(
nn.Linear(64, 10)
)
optimizer = optim.Adam(model.parameters(), lr=0.01)
epochs = 50
for epoch in range(epochs + 1):
sum_losses = 0
sum_accs = 0
for x_batch, y_batch in train_loader:
y_pred = model(x_batch)
loss = nn.CrossEntropyLoss()(y_pred, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
sum_losses = sum_losses + loss
y_prob = nn.Softmax(1)(y_pred)
y_pred_index = torch.argmax(y_prob, axis=1)
acc = (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
sum_accs = sum_accs + acc
if epoch % 10 == 0:
avg_loss = sum_losses / len(loader)
avg_acc = sum_accs / len(loader)
print(f'Epoch {epoch:4d}/{epochs} Loss: {avg_loss:.6f} Accuracy: {avg_acc:.2f}%')
Epoch 0/50 Loss: 2.120254 Accuracy: 55.27%
Epoch 10/50 Loss: 0.083456 Accuracy: 97.77%
Epoch 20/50 Loss: 0.044431 Accuracy: 98.63%
Epoch 30/50 Loss: 0.032165 Accuracy: 99.30%
Epoch 40/50 Loss: 0.047757 Accuracy: 98.44%
Epoch 50/50 Loss: 0.023758 Accuracy: 99.33%
plt.imshow(X_test[11].reshape((8, 8)), cmap='gray')
print(y_test[11])
y_pred = model(X_test)
y_pred[11]
tensor([ -9.5922, -7.5206, -0.4817, 6.3523, -0.7500, -2.6544, -18.8556,
18.1157, -5.7229, 3.4873], grad_fn=<SelectBackward0>)
y_prob = nn.Softmax(1)(y_pred)
y_prob[11]
tensor([9.2597e-13, 7.3500e-12, 8.3799e-09, 7.7840e-06, 6.4079e-09, 9.5417e-10,
8.7811e-17, 9.9999e-01, 4.4362e-11, 4.4356e-07],
grad_fn=<SelectBackward0>)
for i in range(10):
print(f'숫자 {i}일 확률: {y_prob[11][i]:.2f}')
숫자 0일 확률: 0.00
숫자 1일 확률: 0.00
숫자 2일 확률: 0.00
숫자 3일 확률: 0.00
숫자 4일 확률: 0.00
숫자 5일 확률: 0.00
숫자 6일 확률: 0.00
숫자 7일 확률: 1.00
숫자 8일 확률: 0.00
숫자 9일 확률: 0.00
'AI ML LLM > 딥러닝' 카테고리의 다른 글
Multi-class Weather Dataset (0) | 2025.03.03 |
---|---|
딥러닝: 퍼셉트론과 다층 퍼셉트론 (0) | 2025.03.03 |
파이토치로 구현한 논리 회귀 (0) | 2025.02.01 |
파이토치로 구현한 선형 회귀 (1) | 2025.01.29 |
인공지능과 머신러닝, 딥러닝 (2) | 2025.01.29 |