Data_Analysis_Track_33/Python

Python_Deeplearning_pytorch_07(CNN_Model 정의)

lsc99 2023. 10. 30. 18:32

1. Convolutional Neural Network 모델 정의

 

import 및 device 설정

import torch
import torch.nn as nn

device = "cuda" if torch.cuda.is_available() else "cpu"
print(device)

 

 

layer = nn.Conv2d(in_channels=4,  #입력 데이터의 channel 수
                  out_channels=2, #filter(kernel) 수
                  kernel_size=3,  #filter 크기(3:h, 3:w)
#                   stride=1, # 이동크기 => 좌우, 상하 1칸씩 이동하면서 계산.
#                   padding=0 # 패딩 크기
#                   padding="same"
                 )
print(layer)

 

input_data = torch.ones(1, 4, 3, 3)  # (데이터개수, channel, height, width)
feature_map = layer(input_data)
print(feature_map.shape)
# [1:데이터개수 , 2:out_channels, 1:height, 1:width]
feature_map

 

# 파라미터 weight
weight = layer.weight # conv2d의 weight 조회 => filter 조회
weight.shape
# [2:필터개수, 4:필터채널개수, 3:필터height, 3:필터width]

 

# 파라미터 bias
bias = layer.bias
bias.shape #[2:필터개수]
bias

 

첫번째 필터 계산

# 첫번째 필터 계산.
input_data[0].shape, weight[0].shape

 

ch1 = torch.sum(input_data[0, 0] * weight[0, 0])  #[0: 첫번째 필터, 0: 첫번째 채널]
ch2 = torch.sum(input_data[0, 1] * weight[0, 1])  #[0: 첫번째 필터, 1: 두번째 채널]
ch3 = torch.sum(input_data[0, 2] * weight[0, 2])
ch4 = torch.sum(input_data[0, 3] * weight[0, 3])
result = ch1 + ch2 + ch3 + ch4 + bias[0]
result

 

ch1 = torch.sum(input_data[0, 0] * weight[1, 0])  #[0: 첫번째 필터, 0: 첫번째 채널]
ch2 = torch.sum(input_data[0, 1] * weight[1, 1])  #[0: 첫번째 필터, 1: 두번째 채널]
ch3 = torch.sum(input_data[0, 2] * weight[1, 2])
ch4 = torch.sum(input_data[0, 3] * weight[1, 3])
result = ch1 + ch2 + ch3 + ch4 + bias[1]
result

 

p_layer = nn.MaxPool2d(kernel_size=2, # 최대값을 추출할 영역 크기
                       stride=2       # 이동 size => kernel_size와 stride는 같은 값은 값을 지정해서 영역이 겹치지 않도록 한다.
                      )
input_data2 = torch.rand(1, 4, 4)
input_data2

 

result2 = p_layer(input_data2)
print(result2.shape)
result2

 

p_layer = nn.MaxPool2d(kernel_size=2, stride=2       
                      , padding=1) 
# kernel_size보다 작은 영역에서는 최대값을 추출하지 않는다. =>
#   padding을 지정해서 zero_padding을 추가해서 작은영역에서도 추출 될 수 있도록 한다.
input_data3 = torch.rand(1, 5, 5)
input_data3

result3 = p_layer(input_data3)

 

print(input_data3)
result3

 

2. MNIST

 

import

import os

import torch
from torch import nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision import models, datasets, transforms
from torchinfo import summary

import matplotlib.pyplot as plt
import numpy as np

from module.data import load_mnist_dataset, load_fashion_mnist_dataset
from module.train import fit

device = "cuda" if torch.cuda.is_available() else "cpu"

 

하이퍼파라미터

# 하이퍼파라미터
N_EPOCH = 1
BATCH_SIZE = 256
LR = 0.001

 

2.1 Data 준비

 

MNIST

# MNIST
train_loader = load_mnist_dataset("datasets", BATCH_SIZE, True) #저장경로, batch크기, Tainset여부
test_loader = load_mnist_dataset("datasets", BATCH_SIZE, False)

 

Fashion MNIST

# Fashion MNIST
train_loader = load_fashion_mnist_dataset("datasets", BATCH_SIZE, True) #저장경로, batch크기, Tainset여부
test_loader = load_fashion_mnist_dataset("datasets", BATCH_SIZE, False)

 

train_loader.dataset

test_loader.dataset

 

2.2 CNN 모델 정의

 

# CNN -> Convolution Layer: fitlter 개수(out_channels로 설정) 뒤로 갈수록 크게 잡는다.
#        Max Pooling Layer를 이용해서 출력 결과(Feature map)의 
#            size(height, width) 는 줄여나간다. (보통 절반씩 줄인다.)

# conv block
## 1. Conv + ReLU + MaxPooling
## 2. Conv + BatchNorm + ReLU + MaxPooling
## 3. Conv + BatchNorm + ReLU + Dropout + MaxPooling


class MNISTCNNModel(nn.Module):
    
    def __init__(self):
        super().__init__()
        self.b1 = nn.Sequential(
            # Conv2d(): 3 X 3 필터, stide=1, padding=1 => same padding(입력 size와 출력 size가 동일)
            nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(32), # channel을 기준을 정규화 -> 입력 channel수 지정.
            nn.ReLU(), 
            nn.Dropout2d(p=0.3), 
            nn.MaxPool2d(kernel_size=2, stride=2)
            # kernel_size와 stride가 같은 경우에는 stride를 생략가능
            # MaxPool2d() 에서도 padding 지정.
        )
        self.b2 = nn.Sequential(
            nn.Conv2d(32, 64, kernel_size=3, padding="same"),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.Dropout2d(p=0.3),
            nn.MaxPool2d(kernel_size=2)
        )
        self.b3 = nn.Sequential(
            nn.Conv2d(64, 128, kernel_size=3, padding="same"), 
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.Dropout2d(p=0.3),
            nn.MaxPool2d(kernel_size=2, padding=1)  # 입력: 7 x 7 => 1/2 줄이면 -> 3.5 -> 0.5를 살리기 위해 padding 지정
        )
        
        # 결과출력레이어 => Linear() 사용. 
        self.output_block = nn.Sequential(
            # MaxPool2d() 출력결과 입력으로 받는다. => 4차원 (batch, ch, h, w)
            # 3차원 -> 1차원
            nn.Flatten(), 
            nn.Linear(in_features=128*4*4, out_features=512),
            nn.ReLU(),
            nn.Dropout(p=0.3),
            nn.Linear(512, 10) # out=>클래스 개수
        )
        
    def forward(self, X):
        out = self.b1(X)
        out = self.b2(out)
        out = self.b3(out)
        out = self.output_block(out)
        
        return out

 

모델 생성 및 summary

model = MNISTCNNModel()
summary(model, (1, 1, 28, 28))

 

2.3 Train

 

MNIST

# MNIST
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=LR)

result = fit(train_loader, test_loader, model, loss_fn, optimizer, N_EPOCH, 
             save_best_model=False, early_stopping=True, device=device, 
             mode="multi")

 

Fashion MNIST

# Fashion MNIST
loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=LR)

result = fit(train_loader, test_loader, model, loss_fn, optimizer, N_EPOCH, 
             save_best_model=False, early_stopping=True, device=device, 
             mode="multi")