본문 바로가기
인공지능/Deep Learning

[DeepLearning] Dive into Deep Learning 필사 7. Convolutional Neural Networks (CNN) (7.6. Convolutional Neural Networks (LeNet))

by 이준언 2024. 10. 9.

7.6. Convolutional Neural Networks (LeNet)

* LeNet

LeNet은 Convolution과 pooling 층을 교대로 사용하여 입력 이미지에서 특징을 추출하고, 마지막에 fully connected layr를 사용하여 최종적으로 클래스를 분류하는 딥러닝 모델

 

import torch
from torch import nn
from d2l import torch as d2l

 

7.6.1. LeNet

def init_cnn(module):  #@save
    """Initialize weights for CNNs."""
    if type(module) == nn.Linear or type(module) == nn.Conv2d:
        nn.init.xavier_uniform_(module.weight)

class LeNet(d2l.Classifier):  #@save
    """The LeNet-5 model."""
    def __init__(self, lr=0.1, num_classes=10):
        super().__init__()
        self.save_hyperparameters()
        self.net = nn.Sequential(
            nn.LazyConv2d(6, kernel_size=5, padding=2), nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),
            nn.LazyConv2d(16, kernel_size=5), nn.Sigmoid(),
            nn.AvgPool2d(kernel_size=2, stride=2),
            nn.Flatten(),
            nn.LazyLinear(120), nn.Sigmoid(),
            nn.LazyLinear(84), nn.Sigmoid(),
            nn.LazyLinear(num_classes))
@d2l.add_to_class(d2l.Classifier)  #@save
def layer_summary(self, X_shape):
    X = torch.randn(*X_shape)
    for layer in self.net:
        X = layer(X)
        print(layer.__class__.__name__, 'output shape:\t', X.shape)

model = LeNet()
model.layer_summary((1, 1, 28, 28))

 

7.6.2. Training

trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
data = d2l.FashionMNIST(batch_size=128)
model = LeNet(lr=0.1)
model.apply_init([next(iter(data.get_dataloader(True)))[0]], init_cnn)
trainer.fit(model, data)

 

1. average pooling 대신 max pooling을, softmax 대신 ReLU 적용

class LeNet(d2l.Classifier):
  def __init__(self, lr=0.1, num_classes=10):
    super().__init__()
    self.save_hyperparameters()
    self.net = nn.Sequential(
        nn.LazyConv2d(6, kernel_size=5, padding=2),
        nn.ReLU(),
        nn.MaxPool2d(kernel_size=2, stride=2),  # Max Pooling으로 변경
        nn.LazyConv2d(16, kernel_size=5),
        nn.ReLU(),
        nn.MaxPool2d(kernel_size=2, stride=2),  # Max Pooling으로 변경
        nn.Flatten(),
        nn.LazyLinear(120),
        nn.ReLU(),  # Softmax 대신 ReLU 사용
        nn.LazyLinear(83),
        nn.ReLU(),  # Softmax 대신 ReLU 사용
        nn.LazyLinear(num_classes)
    )

 

2. 

1) Convolution window size 변경

kernel_size

 

2) the number of output channel 변경

Convolution 레이어의 out_channels 파라미터를 통해 변경

 

3) the number of convolution layers 변경

모델 정의 부분에서 합성곱 레이어를 수정하여 변경

 

4) the number of fully connected layers

 nn.LazyLinear()레이어를 추가하거나 제거하여 변경

 

5) learning rate 등 training detail 변경

ex: trainer = d2l.Trainer(lr=0.01, max_epochs=20, num_gpus=1

파라미터를 통해 변경

 

3. 

MNIST 데이터셋: 손글씨 숫자 (0~9) 데이터셋으로, 28x28 크기의 흑백 이미지로 구성되어 있음. 딥러닝 모델을 테스트하고 학습하는 데 자주 사용되는 기본적인 이미지 데이터셋

# MNIST 데이터셋 로드
data = d2l.MNIST(batch_size=128)

# 모델 정의 및 초기화
model = LeNet(lr=0.1)  # 개선된 LeNet 모델
model.apply_init([next(iter(data.get_dataloader(True)))[0]], init_cnn)

# Trainer 설정 및 훈련 시작
trainer = d2l.Trainer(max_epochs=10, num_gpus=1)
trainer.fit(model, data)  # 훈련 실행

 

4. Displaying activations of the first and second layer

첫번째 두번째 활성화 값을 시각화하는 방법

# 입력 데이터를 LeNet 모델에 통과시키고 각 레이어의 활성화 값 추출
def get_activations(model, layer_num, input_tensor):
    layers = list(model.net.children())  # Sequential 네트워크의 각 레이어 가져오기
    activation = input_tensor
    for i in range(layer_num + 1):  # 지정된 레이어까지 통과
        activation = layers[i](activation)
    return activation

# 가상의 스웨터와 코트 이미지 예시
sweater_image = torch.randn(1, 1, 28, 28)  # 가상 스웨터 이미지
coat_image = torch.randn(1, 1, 28, 28)     # 가상 코트 이미지

# 첫 번째 레이어 활성화
activation_layer1_sweater = get_activations(model, 0, sweater_image)
activation_layer1_coat = get_activations(model, 0, coat_image)

# 두 번째 레이어 활성화
activation_layer2_sweater = get_activations(model, 2, sweater_image)
activation_layer2_coat = get_activations(model, 2, coat_image)

# 활성화 결과 출력
print("첫 번째 레이어 스웨터 이미지 활성화:", activation_layer1_sweater)
print("첫 번째 레이어 코트 이미지 활성화:", activation_layer1_coat)
print("두 번째 레이어 스웨터 이미지 활성화:", activation_layer2_sweater)
print("두 번째 레이어 코트 이미지 활성화:", activation_layer2_coat)

 

5. 확실하게 다른 이미지를 모델에 입력했을 때 활성화 변화

현재 손글씨 숫자에 대해 훈련되었으므로 다른 데이터를 입력하면 모델이 예상치 못한 특징을 추출하거나 활성화 값이 달라질 수 있음

# 가상의 고양이, 자동차, 잡음 이미지 생성
cat_image = torch.randn(1, 1, 28, 28)   # 고양이 이미지
car_image = torch.randn(1, 1, 28, 28)   # 자동차 이미지
noise_image = torch.randn(1, 1, 28, 28) # 무작위 잡음 이미지

# 첫 번째 레이어에 대한 활성화 값
activation_cat = get_activations(model, 0, cat_image)
activation_car = get_activations(model, 0, car_image)
activation_noise = get_activations(model, 0, noise_image)

# 활성화 결과 출력
print("고양이 이미지 첫 번째 레이어 활성화:", activation_cat)
print("자동차 이미지 첫 번째 레이어 활성화:", activation_car)
print("잡음 이미지 첫 번째 레이어 활성화:", activation_noise)