Colab으로 하루에 하나씩 딥러닝

합성곱 신경망_5.이미지 분류를 위한 신경망_2)AlexNet 본문

딥러닝_개념

합성곱 신경망_5.이미지 분류를 위한 신경망_2)AlexNet

Elleik 2023. 1. 9. 23:03
728x90

AlexNet(알렉스넷)

  •  2개의 GPU에서 실행되는 병렬처리 구조로 설계됨
    • GPU-1: 주로 컬러와 상관없는 정보를 추출하기 위한 커널이 학습
    • GPU-2: 주로 컬러와 관련된 정보를 추출하기 위한 커널이 학습
  • 모델 구조
    • 8 계층: 콘벌루션 5 계층 + 완전 연결 3 계층과 연결된 구조
    • 파라미터가 완전연결층에 집중되어 있음
    • 맨 마지막 완전연결층은 카테고리 1000개로 분류하기 위해 소프트맥스 활성화 함수 사용

AlexNet(알렉스넷) 실습

### 라이브러리 호출

%load_ext tensorboard

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

from tensorflow.keras import Model
from tensorflow.keras.models import Sequential
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.losses import categorical_crossentropy
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers import Dense, Flatten, Conv2D, MaxPooling2D, Dropout

### 모델 생성

num_classes = 2
class AlexNet(Sequential):
  def __init__(self, input_shape, num_classes):
    super().__init__()
    self.add(Conv2D(96, kernel_size=(11,11), strides=4,
                    padding='valid', activation='relu',
                    input_shape=input_shape,
                    kernel_initializer='he_normal'))  # 설명 1
    self.add(MaxPooling2D(pool_size=(3,3), strides=(2,2),
                          padding='valid', data_format='channels_last'))  # 설명 2

    self.add(Conv2D(256, kernel_size=(5,5), strides=1,
                    padding='same', activation='relu',
                    kernel_initializer='he_normal'))
    self.add(MaxPooling2D(pool_size=(3,3), strides=(2,2),
                          padding='valid', data_format='channels_last'))
    
    self.add(Conv2D(384, kernel_size=(3,3), strides=1,
                    padding='same', activation='relu',
                    kernel_initializer='he_normal'))
    
    self.add(Conv2D(384, kernel_size=(3,3), strides=1,
                    padding='same', activation='relu',
                    kernel_initializer='he_normal'))
    
    self.add(Conv2D(256, kernel_size=(3,3), strides=1,
                    padding='same', activation='relu',
                    kernel_initializer='he_normal'))
    
    self.add(MaxPooling2D(pool_size=(3,3), strides=(2,2),
                          padding='valid', data_format='channels_last'))
    
    self.add(Flatten())
    self.add(Dense(4096, activation='relu'))
    self.add(Dense(4096, activation='relu'))
    self.add(Dense(1000, activation='relu'))
    self.add(Dense(num_classes, activation='softmax'))

    self.compile(optimizer=tf.keras.optimizers.Adam(0.001),
                 loss='categorical_crossentropy',
                 metrics=['accuracy'])

상세 설명

  • 설명 1: 
    • 가중치 초기화 방법으로 kernel_initializer 파라미터 사용
    • 가중치 초기화 방법
      • 확률 분포 기반의 가중치 초기화 → 특정한 확률분포에 기반하여 랜덤한 값을 추출하여 가중치 초기화
        • 균일 분포(uniform distribution)
          • 최솟값과 최댓값 사이의 값들이 동일한 확률로 추출되는 분포
        • 정규 분포(normal distribution)
          • 종 모양의 분포를 가지는 분포
      • 분산 조정 기반의 가중치 초기화 → 확률 분포의 분산을 가중치별로 동적으로 조절
        • Lecun: 입력 값의 크기가 커질수록 초기화 값의 분산을 작게 만듦
        • Xavier: fan in과 fan out을 사용, 렐루를 활성화 함수로 사용하면 잘 작동되지 않음
        • He: Xavier의 단점을 극복하기 위해 fan in에 집중한 가중치를 가져 CNN의 깊은 신경망을 잘 학습시킴
        • fan in:  해당 계층에 들어오는 입력 텐서에 대한 차원의 크기(input tensor)
        • fan out: 해당 계층이 출력하는 텐서(output tensor)
  • 설명 2:
    • data_format: 입력에 대한 형식을 지정
      • channels_last: 기본값, 입력 데이터 텐서의 형식이 (배치크기, 높이, 너비, 채널 개수)
      • channels_first: 입력 데이터 텐서의 형식이(배치크기, 채널 개수, 높이, 너비)

### 모델 생성

model = AlexNet((100, 100, 3), num_classes)
model.summary()

모델 생성 결과


### Git에서 데이터 가져오기

!git clone https://github.com/gilbutITbook/080263.git

폴더명 '080263'으로 클론 완료


### 데이터 호출 및 데이터셋 전처리

EPOCHS = 100
BATCH_SIZE = 32
image_height = 100
image_width = 100
train_dir = "/content/080263/chap6/data/catanddog/train"
valid_dir = "/content/080263/chap6/data/catanddog/validation"

train = ImageDataGenerator(
    rescale=1./255,
    rotation_range=10,
    width_shift_range=0.1,
    height_shift_range=0.1,
    shear_range=0.1,
    zoom_range=0.1)

train_generator = train.flow_from_directory(train_dir, 
                                            target_size=(image_height, image_width),
                                            color_mode="rgb",
                                            batch_size=BATCH_SIZE,
                                            seed=1,
                                            shuffle=True,
                                            class_mode="categorical")

valid = ImageDataGenerator(rescale=1.0/255.0)
valid_generator = valid.flow_from_directory(valid_dir, 
                                            target_size=(image_height, image_width),
                                            color_mode="rgb",
                                            batch_size=BATCH_SIZE,
                                            seed=7,
                                            shuffle=True,
                                            class_mode="categorical")

train_num = train_generator.samples
valid_num = valid_generator.samples

데이터셋 전처리 실행 완료


### 텐서보드 설정 및 모델 훈련

log_dir = "/content"
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, 
                                                      histogram_freq=1, profile_batch=0)

model.fit(train_generator,
          epochs=EPOCHS,
          steps_per_epoch=train_num // BATCH_SIZE,
          validation_data=valid_generator,
          validation_steps=valid_num // BATCH_SIZE,
          callbacks=[tensorboard_callback],
          verbose=1)

텐서보드 결과 저장 전
텐서보드 결과 저장 후
모델 훈련 결과, 해당 모델에서는 LeNet-5보다 성능이 좋지 않음


### 분류에 대한 예측

class_names = ['cat', 'dog']  # 이미지를 개와 고양이 클래스 두개로 분류
validation, label_batch = next(iter(valid_generator))
prediction_values = model.predict(validation)
prediction_values = np.argmax(prediction_values, axis=1)

fig = plt.figure(figsize=(12,8))
fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)

for i in range(8):
  ax = fig.add_subplot(2, 4, i+1, xticks=[], yticks=[])
  ax.imshow(validation[i,:], cmap=plt.cm.gray_r, interpolation='nearest')

  if prediction_values[i] == np.argmax(label_batch[i]):
    ax.text(3, 17, class_names[prediction_values[i]], color='yellow', fontsize=14)
  else:
    ax.text(3, 17, class_names[prediction_values[i]], color='red', fontsize=14)

모델 분류 예측 결과, 성능에 비해 랜덤 이미지의 결과는 좋게 나옴

참고: 서지영, 『딥러닝 텐서플로 교과서』, 길벗(2022)