1. 간단한 CNN모델 만들기
import torch
import torch.nn as nn
import torch.optim as optim
CNN모델을 간단하게 만들기 위해서 필요한 모듈들을 임포트해주었씁니다.
# 배치크기 * 채널 (1: 그레이스킬, 3: 트루컬러) *너비 * 높이
inputs = torch.Tensor(1, 1, 28, 28)
print(inputs.shape)
#torch.Size([1, 1, 28, 28])
괄호의 의미는 순서대로(배치크기, 채널, 너비, 높이) 입니다.
# 첫번째 Conv2D
conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, padding='same')
out = conv1(inputs)
print(out.shape)
#torch.Size([1, 32, 28, 28])
지금 이미지 1개를 가지고 가중치를 32개로 늘려줍니다.
kernel_size=3 의미는 학습되는 커널이 되고 3*3 짜리 정방향이 되겠죠
padding을 same으로 하면 다음 레이어에서 이미지 크기가 동일하게 유지됩니다.
(28,28) 부분
out변수에는 위에서 만들었던 이미지를 가지고 conv1를 작동을하고 out으로 들어가게 됩니다.
# 첫번째 MaxPool2D
pool = nn.MaxPool2d(kernel_size=2)
out = pool(out)
print(out.shape)
#torch.Size([1, 32, 14, 14])
CNN은 COVD레이어가 있고 크기를 줄이는 MAXPOLL을 사용합니다.
그러면 사이즈가 반인 14로 줄어드는것을 확인 할 수 있습니다.
# 두번째 Conv2D
conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, padding='same')
out = conv2(out)
print(out.shape)
#torch.Size([1, 64, 14, 14])
# 2번째 MaxPool2D
pool = nn.MaxPool2d(kernel_size=2)
out = pool(out)
print(out.shape)
#torch.Size([1, 64, 7, 7])
flatten = nn.Flatten()
out = flatten(out)
print(out.shape)
#torch.Size([1, 3136])
fc = nn.Linear(3136,10)
out =fc(out)
print(out.shape)
#torch.Size([1, 10])
nn.Flatten을 하게되면 1줄로 쭈욱 평평하게 해줍니다.
3136이 나온 이유는 64 * 7 * 7 입니다.
그 다음 회귀문제(선을 그어서) 3136을 받아서 클래스를 10개로 내보내려고합니다.
그러면 10개의 확률로 내보내줄겁니다.
2. cnn으로 MNLIST 분류하기
import torchvision.datasets as datasets
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
#GPU사용
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)
train_data = datasets.MNIST(
root='data',
train=True,
transform=transforms.ToTensor(),
download=True)
MNLIST를 작성하면 데이터를 가져올 수 있습니다.
root는 폴더명이 data를 가져오는거입니다.(리눅스랑 비슷한)
trasform = transform.ToTenson() = ndarray로 가져오는것이 아니라 애초부터 tensor형으로 가져옵니다.
download를 하게되면 파일에 data파일이 생성되게 됩니다.
똑같이 test_data로 가져오겠습니다.
test_data = datasets.MNIST(
root='data',
train=False,
transform=transforms.ToTensor(),
download=True)
train_data
#Dataset MNIST
# Number of datapoints: 60000
# Root location: data
# Split: Train
# StandardTransform
#Transform: ToTensor()
test_data
#Dataset MNIST
# Number of datapoints: 10000
# Root location: data
# Split: Test
# StandardTransform
#Transform: ToTensor()
이렇게 데이터셋이 준비가 되었죠.
이제 데이터로더를 만들겠습니다.
loader = DataLoader(
dataset = train_data,
batch_size=64,
shuffle =True,
)
imgs, labels = next(iter(loader))
fig, axes = plt.subplots(8, 8, figsize=(16, 16))
for ax, img, label in zip(axes.flatten(), imgs, labels):
ax.imshow(img.reshape((28, 28)), cmap='gray')
ax.set_title(label.item())
ax.axis('off')
batch_size = 64 == 배치사이즈는 64개 단위로 하겠습니다.
그 이후
img, labels = next(iter(loader)) 순차적으로 나열되는데이터고 끄집어낸것을 ,imgs, labels로 넣고
서브플랏으로 보여주게 만들고
라벨은 타이틀에 찍어주는걸로 만들었습니다.
들어가있는 데이터를 출력을
한 결과입니다. 총 64개정도 나옵니다.
모델만들기
model = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding='same'),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(32, 64, kernel_size=3, padding='same'),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Flatten(),
nn.Linear(64*7*7, 10)
).to(device)
여기서 이제 히든레이어를 쌓아주는 작업입니다
model
Sequential(
(0): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=same)
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(3): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=same)
(4): ReLU()
(5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(6): Flatten(start_dim=1, end_dim=-1)
(7): Linear(in_features=3136, out_features=10, bias=True)
)
#학습하기
optimizer = optim.Adam(model.parameters(), lr=0.001)
epochs = 10
for epoch in range(epochs):
sum_losses = 0
sum_accs = 0
for x_batch, y_batch in loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
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}%')
여기까지 쓰고 돌리려면 gpu를 사용을해야 좀 더 빨라집니다.
test_loader = DataLoader(
dataset=test_data,
batch_size=64,
shuffle=False
)
imgs, labels = next(iter(test_loader))
fig, axes = plt.subplots(8, 8, figsize=(16, 16))
for ax, img, label in zip(axes.flatten(), imgs, labels):
ax.imshow(img.reshape((28, 28)), cmap='gray')
ax.set_title(label.item())
ax.axis('off')
얼마만큼 잘 맞추는지 확인합니다.
model.eval() #모델을 테스트 모드로 전환
sum_accs = 0
for x_batch, y_batch in test_loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
y_pred = model(x_batch)
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_acc = sum_accs / len(test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다!')
#테스트 정확도는 98.95% 입니다!
구글코랩 압축된 파일 풀기
1. 구글코랩 에 드라이브 연결
2. 트리를 내린 후 압축폴더를 복사해줍니다. (폴더로 이동)
%cd 경로
%체인지 디렉토리
3. 압축푸는 코드 작성하기
!unzip -qq "경로"
이렇게하면 압축이 풀립니다.
3. ○, X, △ 분류하기
○, X, △ 를 그림판에 여러가지 이미지를 저장 후 cnn 으로 학습을 시켜 해당 데이터를 분류하는 모델을 만들어보자.
#데이터경로 확인하기
1. 트레인경로
2.테스트 경로
#데이터 경로
train_path = '/content/drive/MyDrive/컴퓨터 비전 시즌2/4. 딥러닝 기초/Data/shape/train'
test_path = '/content/drive/MyDrive/컴퓨터 비전 시즌2/4. 딥러닝 기초/Data/shape/test'
todo-list
#이미지크기를 28*28 변환
#그레이스케일 적용
#텐서로 변환
#정규화 적용
-연산도 작아지고, 크기도 작아지는 효과
#색반전 (배경 흰색, 글 검정-> 배경 검정, 글 흰색)
# 이미지 28*28 변환
# 그레이스케일 적용
# 텐서전환
# 정규화 적용
# 색반전(경 흰색, 글 검정 -> 배경 검정, 글 흰색)
transformer = transforms.Compose([
transforms.Resize((28, 28)), #이미지 사이즈 변환
transforms.Grayscale(1),
transforms.ToTensor(), # 텐서형전환
transforms.Normalize((0.5), (0.5)), #평균, 표준편차
transforms.RandomInvert(1) #색 반전
])
trainset = torchvision.datasets.ImageFolder(root=train_path, transform=transformer)
testset = torchvision.datasets.ImageFolder(root=test_path, transform=transformer)
여기서 각 개수를 확인해보면 (len함수 활용)
트레인셋, 테스트 셋은 각각 (240, 60)개로 확인됩니다.
trainset.classes, testset.classes
#(['cir', 'tri', 'x'], ['cir', 'tri', 'x'])
어떻게 이미지를 알아보고 3개로 분할을 했을까 하지만
폴더이름으로 나누는것입니다.
class_map = {
0: 'cir',
1: 'tri',
2: 'x'
}
데이터로더를 만들어주고
loader = DataLoader(
dataset=trainset,
batch_size=8,
shuffle=True
)
이미지 시각화를 해줍니다.
imgs, labels = next(iter(loader))
fig, axes = plt.subplots(4,2, figsize=(8, 16))
for ax, img, label in zip(axes.flatten(), imgs, labels):
ax.imshow(img.reshape((28, 28)), cmap='gray')
ax.set_title(label.item())
ax.axis('off')
여기서 한번 오류가 났는데 이유가
subplots 를 subplot으로 적어서 그랬습니다.
이렇게 랜덤 데이터셋을 예측하는 결과가 나오게 됩니다.
#모델만들기
model = nn.Sequential(
nn.Conv2d(1, 32, kernel_size=3, padding='same'),
nn.ReLU(),
nn.Conv2d(32, 32, kernel_size=3, padding='same'),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Dropout(0.25),
nn.Conv2d(32, 64, kernel_size=3, padding='same'),
nn.ReLU(),
nn.Conv2d(64, 64, kernel_size=3, padding='same'),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Dropout(0.25),
nn.Flatten(),
nn.Linear(64*7*7, 3)
).to(device)
model
#Sequential(
# (0): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=same)
# (1): ReLU()
# (2): Conv2d(32, 32, kernel_size=(3, 3), stride=(1, 1), padding=same)
# (3): ReLU()
# (4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
# (5): Dropout(p=0.25, inplace=False)
# (6): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=same)
# (7): ReLU()
# (8): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=same)
# (9): ReLU()
# (10): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
# (11): Dropout(p=0.25, inplace=False)
# (12): Flatten(start_dim=1, end_dim=-1)
# (13): Linear(in_features=3136, out_features=3, bias=True)
#)
학습 돌려보기
optimizer = optim.Adam(model.parameters(), lr=0.001)
epochs = 20
for epoch in range(epochs):
sum_losses = 0
sum_accs = 0
for x_batch, y_batch in loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
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}%')
테스트데이터 로더
test_loader = DataLoader(
dataset=testset,
batch_size=8,
shuffle=True
)
시각화 만들기
imgs, labels = next(iter(test_loader))
fig, axes = plt.subplots(2, 4, figsize=(8, 4))
for ax, img, label in zip(axes.flatten(), imgs, labels):
ax.imshow(img.reshape(28, 28), cmap='gray')
ax.set_title(class_map[label.item()])
ax.axis('off')
평가하기
- 학습모드가 아닌 테스트 모드로 전환을 했습니다.
- 모델 소프트맥스로 다 똑같이 주도록 하겠습니다.
img_list ,y_pred_list, y_pred_list 는 변수로 비교하기 위해서 만들었습니다.
model.eval()
sum_accs = 0
img_list = torch.Tensor().to(device)
y_pred_list = torch.Tensor().to(device)
y_true_list = torch.Tensor().to(device)
for x_batch, y_batch in test_loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
y_pred = model(x_batch)
y_prob = nn.Softmax(1)(y_pred)
y_pred_index = torch.argmax(y_prob, axis=1)
y_pred_list = torch.cat((y_pred_list, y_pred_index), dim=0)
y_true_list = torch.cat((y_true_list, y_batch), dim=0)
img_list = torch.cat((img_list, x_batch), dim=0)
acc = (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
sum_accs = sum_accs + acc
avg_acc = sum_accs / len(test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다.')
결과값은 테스트 정확도는 87.50% 입니다.이 나옵니다
결과 확인하
fig, axes = plt.subplots(12, 5, figsize=(25, 25))
img_list_cpu = img_list.cpu()
y_pred_list_cpu = y_pred_list.cpu()
y_true_list_cpu = y_true_list.cpu()
for ax, img, y_pred, y_true in zip(axes.flatten(), img_list_cpu, y_pred_list_cpu, y_true_list_cpu):
ax.imshow(img.reshape(28, 28), cmap='gray')
ax.set_title(f'pred: {class_map[y_pred.item()]}, true: {class_map[y_true.item()]}')
ax.axis('off')
plt.show()
과적합이 일어난것같다면?
nn.Dropout(0.25) 를 해주면 약 25퍼센트정도 데이터에 흠집을 내줘서(값을 살짝 변형되게)
해줍니다 그러면 오버피팅이 덜 일어납니다.
'AI 컴퓨터 비전프로젝트 > [ML,DL]머신러닝,딥러닝' 카테고리의 다른 글
[ML/DL] 포켓몬 분류해보기, 나와닮은 포켓몬 찾아보기 (2) | 2024.08.01 |
---|---|
[ML/DL] 전이학습, 케글 데이터셋 활용해서 에일리언vs프레데터 예측하기 (1) | 2024.07.30 |
[DL] CNN 기초, 체험사이트 (0) | 2024.07.27 |
[DL] 비선형 활성화 함수, 역전파 (0) | 2024.07.26 |
[DL] 딥러닝_뉴런, 퍼셉트론,히든레이어... (1) | 2024.07.25 |