728x90
반응형
필요한 라이브러리 및 패키지 임포트
from idlelib.configdialog import tracers
import numpy as np
import matplotlib.pyplot as plt
from time import time
import torch
from sympy.matrices.expressions.kronecker import rules
from torch import nn
import torchvision
import torchvision.transforms as transforms
from torchvision.datasets import CIFAR10
from torch.utils.data import DataLoader
from torchsummary import summary
numpy
,matplotlib
,torch
,torchvision
은 모두 딥러닝에서 데이터 처리, 모델 구축, 시각화에 중요한 패키지입니다.CIFAR10
데이터셋은 32x32 크기의 이미지로 구성된 10개의 클래스를 포함하는 유명한 이미지 분류 데이터셋입니다.DataLoader
는 PyTorch의 데이터 로딩 유틸리티로, 데이터를 배치(batch)로 나누고, 학습에 필요한 형식으로 불러오는 데 사용됩니다.
데이터 전처리 설정
mean = [0.5, 0.5, 0.5]
std = [0.5, 0.5, 0.5]
rules = transforms.Compose([transforms.ToTensor(), transforms.Normalize(mean=mean, std=std)])
- 전처리 방식 정의: CIFAR-10 데이터는 [32, 32, 3] 형태의 RGB 이미지이므로, 이를 PyTorch 텐서로 변환하고, 각 채널의 픽셀 값은
[0, 1]
범위로 정규화됩니다. 이후, 이를 다시 평균이 0.5, 표준편차가 0.5가 되도록 정규화(Normalization) 합니다. 즉, 값의 범위가 [-1, 1]로 변환됩니다.
데이터 로딩
train_loader = DataLoader(
CIFAR10('cifar', train=True, download=True, transform=rules),
batch_size=MY_BATCH,
shuffle=True
)
train_loader = DataLoader(
CIFAR10('cifar', train=False, download=True, transform=rules),
batch_size=MY_BATCH,
shuffle=False
)
DataLoader
: CIFAR-10 데이터셋을train_loader
와test_loader
로 나눠서 학습 및 평가를 위한 데이터를 불러옵니다.batch_size=MY_BATCH
는 한 번에 64개의 데이터를 불러오는 배치(batch) 크기를 지정합니다.shuffle=True
는 학습 시 데이터를 무작위로 섞어 로드합니다.
이미지 불러오기 및 샘플링
dataiter = iter(train_loader)
images, labels = next(iter(train_loader))
- 데이터 샘플 가져오기:
train_loader
에서 배치 데이터를 한 번 가져옵니다.images
는 CIFAR-10 데이터셋에서 64장의 이미지 배치이며,labels
는 각 이미지에 대한 정답 레이블입니다.
이미지 시각화 함수 정의
def sample(img):
img = img / 2 + 0.5 # 정규화 해제: [-1, 1] 범위에서 [0, 1]로 변환
npimg = img.numpy() # PyTorch 텐서를 NumPy 배열로 변환
print('전환 전 모양 : ', npimg.shape)
flip = np.transpose(npimg, (1, 2, 0)) # [C, H, W] 형태의 이미지를 [H, W, C]로 변환
print('전환 후 모양 : ', flip.shape)
plt.imshow(flip) # 이미지 표시
plt.axis('off') # 축을 제거하여 이미지만 표시
plt.show() # 이미지를 화면에 출력
- 정규화 해제: CIFAR-10 데이터셋은 정규화되어 [-1, 1] 범위로 변환되었으므로, 이를 다시 [0, 1] 범위로 돌려 놓습니다.
img / 2 + 0.5
는 해당 과정을 수행합니다. - 텐서를 NumPy 배열로 변환: PyTorch의
Tensor
는numpy()
메서드를 사용하여 NumPy 배열로 변환할 수 있습니다. - 배열 전치: PyTorch 텐서는
[채널, 높이, 너비]
형식으로 이미지를 저장하는데, 이를 Matplotlib에서 시각화하기 위해서는[높이, 너비, 채널]
순서로 배열을 전치(transpose)해야 합니다.np.transpose(npimg, (1, 2, 0))
는 이 작업을 수행합니다. - 이미지 출력: 변환된 이미지를
plt.imshow()
로 출력하고,plt.axis('off')
를 사용하여 축을 제거한 후 이미지를 표시합니다.
이미지 그리드 생성 및 시각화
merged = torchvision.utils.make_grid(images)
sample(merged)
- 이미지 그리드 생성:
torchvision.utils.make_grid()
함수는 여러 이미지를 하나의 그리드로 결합합니다. 여기서는images
라는 64장의 이미지를 하나의 이미지로 병합합니다. sample(merged)
호출: 병합된 이미지를sample
함수로 전달하여 시각화합니다.
해당 코드는 PyTorch에서 train_loader
라는 데이터 로더에서 데이터를 가져오는 과정입니다.
dataiter = iter(train_loader)
:train_loader
는 학습용 데이터를 제공하는 데이터 로더입니다. PyTorch에서DataLoader
객체는 학습 데이터셋을 작은 배치로 나누어 모델에 전달하는 역할을 합니다.iter()
함수는train_loader
의 반복자를 생성합니다. 이 반복자는next()
함수와 함께 사용할 수 있습니다.
images, labels = next(iter(train_loader))
:next()
함수는train_loader
로부터 한 번에 하나의 배치를 가져옵니다. 이 배치는 이미지 데이터(images
)와 해당 이미지의 레이블(labels
)로 구성됩니다.images
는 해당 배치에 포함된 이미지들의 텐서이며,labels
는 그에 대응하는 실제 레이블(정답)입니다.
즉, 이 코드는 train_loader
로부터 첫 번째 배치를 가져와, 이미지와 레이블을 변수 images
와 labels
에 저장하는 역할을 합니다. 이 코드를 통해 데이터를 모델에 입력할 준비를 할 수 있습니다.
코드 요약
- CIFAR-10 데이터셋을 다운로드하고, 배치 단위로 데이터를 로드합니다.
- 이미지는 정규화된 후, 이를 다시 [0, 1] 범위로 변환하여 시각화합니다.
- PyTorch의 이미지 텐서를 NumPy 배열로 변환하고, 시각화할 수 있는 형식으로 전치합니다.
- 이미지 그리드를 생성하여 64장의 이미지를 한 화면에 시각화합니다.
from idlelib.configdialog import tracers
import numpy as np
import matplotlib.pyplot as plt
from time import time
import torch
from sympy.matrices.expressions.kronecker import rules
from torch import nn
import torchvision
import torchvision.transforms as transforms
from torchvision.datasets import CIFAR10
from torch.utils.data import DataLoader
from torchsummary import summary
MY_EPOCH = 2
MY_BATCH = 64
torch.manual_seed(111)
# 3차원 데이터 변환 방식 지정
# 1) 파이토치 텐서로 전환
# 2) [-1,1] 정규화
mean = [0.5, 0.5, 0.5]
std = [0.5, 0.5, 0.5]
rules = transforms.Compose([transforms.ToTensor(), transforms.Normalize(mean=mean, std=std)])
# 학습용 데이터 로드
train_loader = DataLoader(
CIFAR10('cifar', train=True, download=True, transform=rules),
batch_size=MY_BATCH,
shuffle=True
)
# 평가용 데이터 로드
train_loader = DataLoader(
CIFAR10('cifar', train=False, download=True, transform=rules),
batch_size=MY_BATCH,
shuffle=False
)
#print(train_loader)
dataiter = iter(train_loader)
images, labels = next(iter(train_loader))
def sample(img):
img = img/2 +0.5
npimg = img.numpy()
print('전환 전 모양 : ', npimg.shape)
flip = np.transpose(npimg, (1,2,0))
print('전환 후 모양 : ', flip.shape)
plt.imshow(flip)
plt.axis('off')
plt.show()
# 64개 의 이미지를 하나로 통합
merged = torchvision.utils.make_grid(images)
sample(merged)
이 코드는 인공 신경망(CNN, 합성곱 신경망)을 PyTorch로 구현한 후, 모델 구조를 요약해서 출력하는 코드입니다. 각 단계가 무엇을 의미하는지 설명드리겠습니다.
CNN 모델 구현
model = nn.Sequential(
# 첫번째 합성곱 블럭
nn.Conv2d(in_channels=3, out_channels=6, kernel_size=4),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
# 두번째 합성곱 블럭
nn.Conv2d(in_channels=6, out_channels=16, kernel_size=4),
nn.ReLU(),
# DNN 블럭
nn.Flatten(),
nn.Linear(in_features=16*11*11, out_features=120),
nn.Linear(120, 84),
nn.Linear(84, 10),
nn.Softmax(dim=1)
)
nn.Sequential()
은 모델의 각 층(layer)을 차례로 쌓는 간단한 방법입니다. 아래에서 층들을 분석하겠습니다.
(1) 첫 번째 합성곱 블럭
nn.Conv2d(in_channels=3, out_channels=6, kernel_size=4)
:- 입력 채널은
3
(RGB 이미지), 출력 채널은6
개의 필터를 사용하여 특징을 추출합니다. - 커널 크기는
4x4
입니다.
- 입력 채널은
nn.ReLU()
:- 활성화 함수로 ReLU(Rectified Linear Unit)를 사용합니다. 이는 음수를 0으로 만들고, 양수는 그대로 유지하는 함수입니다. 네트워크에 비선형성을 부여합니다.
nn.MaxPool2d(kernel_size=2, stride=2)
:- 최대 풀링(Max Pooling) 층으로, 커널 크기는
2x2
, 스트라이드는 2입니다. 이는 입력 이미지의 크기를 절반으로 줄여 연산을 효율적으로 만들고, 중요한 특징만 남깁니다.
- 최대 풀링(Max Pooling) 층으로, 커널 크기는
(2) 두 번째 합성곱 블럭
nn.Conv2d(in_channels=6, out_channels=16, kernel_size=4)
:- 첫 번째 합성곱 층의 출력이 6채널이므로, 입력 채널은
6
입니다. - 출력 채널은
16
이며, 커널 크기는4x4
입니다.
- 첫 번째 합성곱 층의 출력이 6채널이므로, 입력 채널은
nn.ReLU()
:- ReLU 활성화 함수를 또 한 번 적용합니다.
(3) DNN (Deep Neural Network) 블럭
nn.Flatten()
:- 다차원 텐서(이미지 텐서)를 1차원 벡터로 펼칩니다. 여기서는 [batch_size, 16, 11, 11] 크기의 텐서를 [batch_size, 16_11_11]로 펼칩니다.
nn.Linear(in_features=16*11*11, out_features=120)
:- 입력 노드 수는
16*11*11
, 이는 두 번째 합성곱 블럭의 출력이 16채널에 11x11 크기의 특징 맵이기 때문입니다. - 출력 노드 수는
120
개로, Fully Connected Layer(완전 연결층)입니다.
- 입력 노드 수는
nn.Linear(120, 84)
:- 입력 노드 수는
120
, 출력 노드 수는84
인 또 하나의 완전 연결층입니다.
- 입력 노드 수는
nn.Linear(84, 10)
:- 최종적으로 CIFAR-10 데이터셋에는 10개의 클래스가 있으므로, 출력 노드 수는
10
입니다. 이는 이미지가 10개의 클래스 중 하나로 분류되도록 합니다.
- 최종적으로 CIFAR-10 데이터셋에는 10개의 클래스가 있으므로, 출력 노드 수는
nn.Softmax(dim=1)
:- 최종 출력에 대해 소프트맥스(Softmax) 함수가 적용됩니다. Softmax는 각 클래스에 속할 확률을 출력하며, 출력 값의 총합은 1이 됩니다.
dim=1
은 배치 단위에서 클래스별 확률을 계산하라는 의미입니다.
- 최종 출력에 대해 소프트맥스(Softmax) 함수가 적용됩니다. Softmax는 각 클래스에 속할 확률을 출력하며, 출력 값의 총합은 1이 됩니다.
모델 요약 출력
print("{0:=^20}".format('CNN 요약'))
summary(model, (3,32,32))
summary(model, (3,32,32))
는torchsummary
라이브러리를 사용하여 모델 구조와 파라미터 수를 요약해 출력합니다.- 입력 데이터는
3x32x32
크기(RGB 이미지)이며, 이 형식이summary
함수에 전달됩니다. - 각 층의 입력/출력 크기와 파라미터 수가 요약되어 출력됩니다.
- 입력 데이터는
코드 요약
- 이 코드는 두 개의 합성곱 블럭과 세 개의 완전 연결층을 가진 CNN을 구현합니다.
- 이미지에서 특징을 추출한 뒤, 이를 Flatten하여 DNN으로 학습한 후, Softmax로 각 클래스의 확률을 출력합니다.
summary()
를 통해 모델의 전체 구조를 요약해서 볼 수 있습니다.
이 CNN은 CIFAR-10 데이터셋의 10개 클래스를 분류하는 간단한 모델입니다.
print("{0:=^20}".format('인공 신경망 구현'))
# model 구현
model = nn.Sequential(
# 첫번째 합성곱 블럭
nn.Conv2d(in_channels=3, out_channels=6, kernel_size=4),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2, stride=2),
# 두번째 합성곱 블럭
nn.Conv2d(in_channels=6, out_channels=16, kernel_size=4),
nn.ReLU(),
# DNN 블럭
nn.Flatten(),
nn.Linear(in_features=16*11*11, out_features=120),
nn.Linear(120, 84),
nn.Linear(84, 10),
nn.Softmax(dim=1)
)
print("{0:=^20}".format('CNN 요약'))
summary(model, (3,32,32))
CNN 모델을 학습시키기 위한 PyTorch 기반의 기본적인 학습 루프
# 최적화 함수와 손실 함수 지정
optimizer = torch.optim.Adagrad(model.parameters(), lr=0.01)
criterion = nn.CrossEntropyLoss()
# CNN 학습
begin = time()
print("{0:=^20}".format('CNN 학습 시작'))
for epoch in range(MY_EPOCH):
batch = 0
for data in train_loader:
inputs, labels = data
outputs = model(inputs) # input 대신 inputs 사용
loss = criterion(outputs, labels) # label() 대신 labels 사용
print('배치 : ', batch, '/ 손실 : {:.3f}'.format(loss.item()))
optimizer.zero_grad()
loss.backward()
optimizer.step()
batch += 1
print('에포크: {}'.format(epoch), '/ 손실 : {:.3f}'.format(loss.item()))
end = time()
print('최종 학습 시간 : {:.3f}초'.format(end - begin), '최종 손실 : {:.3f}'.format(loss.item()))
최적화 함수와 손실 함수 설정
optimizer = torch.optim.Adagrad(model.parameters(), lr=0.01)
criterion = nn.CrossEntropyLoss()
- optimizer:
torch.optim.Adagrad
는 모델의 매개변수(model.parameters()
)를 학습률(lr=0.01
)로 업데이트하는 역할을 합니다. Adagrad는 학습 속도를 적응적으로 조절하는 최적화 알고리즘입니다. - criterion:
CrossEntropyLoss
는 다중 분류 문제에서 자주 사용되는 손실 함수입니다. 모델의 출력 값(로짓)과 실제 레이블 사이의 차이를 계산하여 손실을 도출합니다.
CNN 학습 시작
begin = time()
print("{0:=^20}".format('CNN 학습 시작'))
- begin: 학습 시작 시간을 기록합니다.
- 출력 형식:
print("{0:=^20}".format('CNN 학습 시작'))
는 텍스트를 가운데 정렬하고,=
기호로 텍스트를 감싸서CNN 학습 시작
이라는 출력이 가시적으로 구분되게 만듭니다.
Epoch 및 Batch 처리 루프
for epoch in range(MY_EPOCH):
batch = 0
for data in train_loader:
inputs, labels = data
outputs = model(inputs) # input 대신 inputs 사용
loss = criterion(outputs, labels) # label() 대신 labels 사용
print('배치 : ', batch, '/ 손실 : {:.3f}'.format(loss.item()))
optimizer.zero_grad()
loss.backward()
optimizer.step()
batch += 1
Epoch 루프
for epoch in range(MY_EPOCH)
: 전체 학습 과정을MY_EPOCH
횟수만큼 반복합니다.MY_EPOCH
은 사용자가 정의한 에포크(epochs) 수입니다.- 배치(batch) 처리: 데이터 로더(
train_loader
)를 통해 데이터를 배치 단위로 가져오며, 각 배치에서 모델의 매개변수를 업데이트합니다.
Batch 처리
inputs, labels = data
: 배치 데이터를 로더로부터 불러옵니다.inputs
는 모델에 입력될 데이터,labels
는 해당 데이터의 실제 레이블입니다.outputs = model(inputs)
: 모델에inputs
를 넣어 예측 결과(outputs
)를 얻습니다.- 이전 코드에서
input
이라고 잘못 작성된 부분을inputs
로 수정하여 오류를 해결했습니다.
- 이전 코드에서
loss = criterion(outputs, labels)
: 모델의 예측 값(outputs
)과 실제 레이블(labels
)을 비교하여 손실을 계산합니다.- 이전 코드에서 잘못된
label()
대신labels
로 수정했습니다.
- 이전 코드에서 잘못된
optimizer.zero_grad()
: 역전파 단계 이전에 이전 배치에서 계산된 그래디언트를 초기화합니다.loss.backward()
: 역전파를 통해 손실에 대한 그래디언트를 계산합니다.optimizer.step()
: Adagrad 최적화 알고리즘을 사용하여 모델의 매개변수를 업데이트합니다.batch += 1
: 배치 번호를 증가시킵니다.
출력
print('배치 : ', batch, '/ 손실 : {:.3f}'.format(loss.item()))
: 각 배치의 번호와 해당 배치에서 계산된 손실 값을 소수점 셋째 자리까지 출력합니다.
에포크 완료 후 손실 출력
print('에포크: {}'.format(epoch), '/ 손실 : {:.3f}'.format(loss.item()))
- 각 에포크가 끝날 때마다 마지막 배치에 대한 손실 값을 출력합니다.
loss.item()
을 사용하여 파이토치 텐서를 파이썬 스칼라 값으로 변환하여 출력합니다. - 여기서의 출력은 에포크가 끝날 때마다 발생합니다.
최종 학습 시간 및 손실 출력
end = time()
print('최종 학습 시간 : {:.3f}초'.format(end - begin), '최종 손실 : {:.3f}'.format(loss.item()))
- end = time(): 학습이 완료된 시점의 시간을 기록합니다.
- 학습 시간 출력:
end - begin
을 통해 총 학습 시간을 계산하여 출력합니다. 소수점 셋째 자리까지 학습 시간을 표시합니다. - 최종 손실 출력: 마지막 배치에서의 손실 값을 출력합니다.
이 코드는 CNN 모델의 학습을 위한 기본적인 학습 루프를 구현한 것으로, Adagrad
최적화를 사용하여 매개변수를 업데이트하고, 손실 함수로 CrossEntropyLoss
를 사용하여 다중 분류 문제를 해결합니다. 배치마다 손실 값을 출력하고, 각 에포크가 끝날 때 마지막 배치에 대한 손실을 기록하며, 학습이 끝난 후 총 학습 시간과 최종 손실 값을 출력합니다.
print("{0:=^20}".format("인공 신경망 평가"))
# 이미지 라벨
classes = ['Airplane', "Automobile", "Bird", 'Cat',
'Deer', 'Dog', 'Frog', 'Horse','Ship', 'Truck']
# 혼동 행렬 초기화 :: 혼동행렬이랑 (정오분류표) 오류를 찾기 위해서 분류되어 있는 표 형식의 자료
correct = 0
confusion = np.zeros([10,10], int)
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = model(images)
_, pred = torch.max(outputs, dim=1)
for i, truth in enumerate(labels):
if(truth.item() == pred[i]):
correct += 1
confusion[pred[i].item(), truth.item()] += 1
print('최종 정확도: {:.2f}%'.format(correct/10000 * 100))
print('카테고리별 정확도')
for i, row in enumerate(confusion):
print('{0:10s} : {1:.1f}%'.format(classes[i], row[i]/np.sum(row)*100))
print('혼동 행렬')
print(confusion)
print('마지막 batch 데이터 모양:', data[0].shape)
print('예상:', pred)
print('정답:', labels)
이 코드는 PyTorch를 사용하여 이미지 분류 모델의 성능을 평가하고, 혼동 행렬(Confusion Matrix)을 출력하는 코드입니다. 각 부분을 단계적으로 설명하겠습니다.
클래스 정의
classes = ['Airplane', "Automobile", "Bird", 'Cat',
'Deer', 'Dog', 'Frog', 'Horse','Ship', 'Truck']
- 분류하고자 하는 이미지들의 클래스 이름입니다. 예를 들어, 10개의 카테고리(비행기, 자동차, 새 등)가 있습니다. 이 리스트는 평가할 때 카테고리별로 정확도를 출력하는 데 사용됩니다.
혼동 행렬 초기화
correct = 0
confusion = np.zeros([10,10], int)
correct
: 모델이 정확하게 맞힌 예측의 수를 세기 위한 변수입니다.confusion
: 10x10 크기의 혼동 행렬(Confusion Matrix)을 0으로 초기화합니다. 혼동 행렬은 모델의 예측이 얼마나 정확했는지, 어떤 클래스가 다른 클래스로 잘못 분류되었는지를 나타냅니다.
모델 평가 (with torch.no_grad())
with torch.no_grad():
for data in test_loader:
images, labels = data
outputs = model(images)
_, pred = torch.max(outputs, dim=1)
for i, truth in enumerate(labels):
if(truth.item() == pred[i]):
correct += 1
confusion[pred[i].item(), truth.item()] += 1
torch.no_grad()
: 평가할 때는 역전파(가중치 업데이트)가 필요 없으므로 메모리 사용을 줄이기 위해torch.no_grad()
를 사용하여 그래디언트를 계산하지 않도록 설정합니다.test_loader
: 테스트 데이터를 배치 단위로 불러옵니다.data
는(images, labels)
로,images
는 입력 이미지,labels
는 해당 이미지의 실제 레이블입니다.outputs = model(images)
: 테스트 이미지를 모델에 입력하고, 예측 결과를outputs
에 저장합니다.torch.max(outputs, dim=1)
:outputs
에서 가장 큰 값을 가지는 인덱스(예측된 클래스)를pred
에 저장합니다.- 정확도 계산: 예측된 값(
pred[i]
)과 실제 레이블(truth.item()
)이 같으면correct
카운트를 1 증가시킵니다. - 혼동 행렬 업데이트:
confusion[pred[i].item(), truth.item()]
을 1 증가시켜, 각 예측과 실제 값 간의 관계를 기록합니다.
최종 정확도 출력
print('최종 정확도: {:.2f}%'.format(correct/10000 * 100))
- 정확도(Accuracy)는 모델이 정확하게 예측한 횟수(
correct
)를 테스트 세트 전체 데이터 수(여기서는 10,000개)로 나눈 값입니다. 이를 백분율로 표시합니다.
카테고리별 정확도 출력
print('카테고리별 정확도')
for i, row in enumerate(confusion):
print('{0:10s} : {1:.1f}%'.format(classes[i], row[i]/np.sum(row)*100))
- 각 클래스별 정확도를 출력합니다. 혼동 행렬의 각 행에서, 정답이 해당 클래스일 때 예측이 맞았던 비율을 계산합니다. 이를 통해 특정 클래스에 대해 모델이 얼마나 잘 예측했는지 알 수 있습니다.
혼동 행렬 출력
print('혼동 행렬')
print(confusion)
- 혼동 행렬은 모델의 예측 결과와 실제 레이블 간의 관계를 시각적으로 나타냅니다. 행은 모델의 예측, 열은 실제 레이블을 나타내며, 대각선 값은 모델이 정확히 맞춘 횟수를 나타냅니다.
마지막 배치 데이터 출력
print('마지막 batch 데이터 모양:', data[0].shape)
print('예상:', pred)
print('정답:', labels)
data[0].shape
: 마지막 배치에서 가져온 이미지 데이터의 모양을 출력합니다.pred
: 마지막 배치에서 예측된 레이블을 출력합니다.labels
: 마지막 배치의 실제 레이블을 출력합니다.
728x90
반응형
'PROGRAMING📚 > BigData📑' 카테고리의 다른 글
파이참(pycham) tenserflow. 에러 / 명령어로 설치 하기 (0) | 2024.12.17 |
---|---|
DNN 을 사용해서 심장병 질환 예측 분석하기 (0) | 2024.09.29 |
PyTorch를 사용하여 DNN(Deep Neural Network)을 구축하고, MNIST 데이터셋을 이용해 학습 및 평가 (1) | 2024.09.29 |
DNN 알고리즘 (0) | 2024.09.29 |
인공지능 - torch (0) | 2024.09.29 |
댓글