본문 바로가기
컴퓨터공학/AI

인공지능 6. CNN

by Jinger 2024. 4. 25.

서론

    컨볼루션 신경망(Convolutional Neural Networks, CNN)은 이미지 인식, 음성 인식, 자연어 처리 등 다양한 분야에서 뛰어난 성능을 보여주는 딥러닝의 한 방식이다. 그렇기에 이 컨볼루션 신경망(CNN)은 딥러닝 분야에서 혁신을 가져온 주요 기술 중 하나이다.


Fully-Connected DNN

     Fully-Connected DNN(Deep Neural Network)은 입력층에서부터 출력층까지 모든 뉴런이 서로 연결된 구조를 가지고 있다. 이러한 구조는 복잡한 패턴을 학습할 수 있는 능력을 가지고 있지만, 많은 파라미터와 과적합의 위험이 동반된다.

Fully-Connected DNN의 문제점

   Fully-Connected DNN은 입력받는 값들이 단순 나열되어 있기 때문에, 이미지의 구조와 같은 픽셀들 간의 관계를 즉각적으로 파악하기 어렵다. 이를 극복하기 위해 바로 옆 픽셀들도 입력층에서 연결하려고 하면 두 노드 사이에 많은 다른 픽셀들이 끼어들어 거리가 멀어진다. 즉, 인접한 두 픽셀 간의 관계를 제대로 모델링하기 어려워진다. 이를 해결하려고 weight와 bias를 과도하게 늘리면 아래와 같은 문제점이 발생할 수 있다.

  • 파라미터의 수: 모든 뉴런이 연결되어 있어 파라미터의 수가 매우 많아진다.
  • 과적합: 제한된 데이터에서 학습할 때 과적합의 위험이 크다.
  • 계산 비용: 많은 파라미터로 인해 계산 비용이 증가한다.

Convolution (합성곱)

    컨볼루션은 이미지의 픽셀 값을 필터(커널)을 통해 변환하는 과정이다. 이를 통해 이미지의 특징을 추출할 수 있으며, 파라미터의 수를 줄이고 효율적인 계산이 가능해진다.

  • 이미지 처리: 다양한 필터를 사용하여 특징을 추출
  • 합성곱: 이미지 처리에서의 필터 연산
  • 스트라이드: 필터를 적용하는 위치의 간격

패딩(Padding)

    입력 데이터에 다양한 크기의 필터를 적용할 때 출력 데이터의 크기가 불규칙하게 변화하는 문제가 발생한다. 그렇기 때문에 패딩을 사용한다. 패딩은 컨볼루션 과정에서 이미지의 크기를 유지하기 위해 주변을 특정 값(보통은 0)으로 채우는 기술이다. 패딩은 'Valid'와 'Same' 패딩으로 나눈다.


CNN

    CNN은 컨볼루션 계층, 풀링 계층, 완전 연결 계층으로 구성된다. 각 계층은 이미지에서 특징을 추출하고, 이를 바탕으로 분류나 예측을 수행한다. 대표적으로 3차원 데이터의 합성곱 연산의 예인 컬러 이미지가 있다. 컬러 이미지는 red, green, blue 채널로 구성되어 있다. 각 채널의 픽셀들은 0-255 사이의 intensitiy 값을 가진다. 이 intensitiy 값들을 숫자 화하여 3차원 데이터로 만들 수 있다.

CNN의 장점

  • 픽셀 사이의 관계를 파악하기 쉽다. 필터를 통해 동일한 가중치를 공유(weight sharing)하므로, 필요한 파라메터 수가 대폭 감소한다. 또한 파라메터 공유(stride)를 이용하여 이미지 이동에 대한 인식 능력을 향상한다.
  • 타깃의 위치에 관계없이 타깃을 인식할 수 있다.
  • 희소 연결(sparse connectivity)를 이용하여 중요한 특징만을 학습한다.
  • 피처 맵의 크기 감소로 풀링 계층을 통해 데이터 크기를 줄일 수 있다.

일반적인 합성곱 연산

   아래와 같이 일반적으로 입력 데이터와 필터의 채널 갯수는 같다.

    Fn개의 필터를 적용하면, 출력 데이터도 Fn개가 생성된다.

여러 개의 필터를 적용한 경우 | 일반적인 Convolution의 경우(가중치와 편향)

풀링(Pooling)

   풀링 계층은 피처 맵의 크기를 줄이는 역할을 한다. 주로 최대 풀링(Max Pooling)과 평균 풀링(Average Pooling)의 두 가지 방법이 사용된다. 최대 풀링은 특정 영역에서 가장 큰 값을 선택하여 특징을 강조하는 반면, 평균 풀링은 영역의 평균값을 계산하여 더 부드러운 특징을 추출한다. 이러한 풀링 과정을 통해 모델은 중요한 정보를 보존하면서도 계산량을 줄일 수 있으며, 과적합의 위험을 감소시키는 효과가 있다.

최대 풀링 (Max Pooling)| 평균 풀링 (Average Pooling)

풀링의 특징

  1. 학습해야 할 매개변수가 없음.
  2. 채널 수가 변하지 않음.
  3. 입력의 변화에 영항을 적게 받음 (국소 변화에 강함)

   신경망이 학습하는 함수가 "국소 이동"에 대해 불변인 경우에 풀링을 적용하여야 학습 효과를 얻을 수 있다.

    CNN은 층이 깊어질수록, 더욱 추상적인 내용을 이해할 수 있다.

희소 상호작용 (Sparse Interaction)

    희소 상호작용(Sparse Interaction)은 CNN(Convolutional Neural Networks)의 핵심 개념 중 하나이다. 이는 각 뉴런이 이전 층의 소수 뉴런과만 연결되어 있어, 전체적인 연결 밀도를 낮추는 것을 의미한다. 전통적인 완전 연결 신경망(Fully-Connected Neural Networks)에서는 모든 뉴런이 이전 층의 모든 뉴런과 연결되어 있어 많은 수의 매개변수와 계산량을 필요로 한다. 반면, CNN에서는 필터(또는 커널)를 통해 특정 영역의 입력 데이터만을 처리하므로, 연결의 밀도가 희박해지며, 이를 통해 효율적인 학습과 더 적은 매개변수로 높은 성능을 달성할 수 있다.


CNN의 대표 예: LeNet-5

    1998년, Yann LeCun 교수와 그의 팀은 손글씨 숫자 인식을 위한 네트워크인 LeNet-5를 발표했다. 이는 CNN의 초기 모델 중 하나로, 현대 딥러닝의 발전에 큰 영향을 미쳤다. LeNet-5는 간단하지만 효과적인 구조로 구성되어 있으며, 희소 상호작용의 원칙을 따른다.

LeNet-5의 특징

  1. 컨볼루션 레이어와 풀링 레이어의 조합: LeNet-5는 여러 개의 컨볼루션 레이어와 풀링(서브샘플링) 레이어를 교차하여 배치함으로써, 이미지에서 점진적으로 고수준의 특징을 추출합니다. 컨볼루션 레이어는 이미지의 로컬 패턴을 인식하고, 풀링 레이어는 공간적인 변화에 강인한 특징을 생성한다.
  2. 희소 연결: LeNet-5의 각 뉴런은 입력 이미지의 소규모 영역에만 연결되어 있다. 이는 전체 이미지를 한 번에 처리하는 대신, 로컬 패턴을 효율적으로 학습할 수 있게 해 준다. 이러한 희소 연결 구조는 매개변수의 수를 크게 줄이며, 과적합(overfitting)의 위험을 감소시킨다.
  3. 공유 가중치와 편향: 컨볼루션 레이어 내의 뉴런들은 같은 가중치와 편향을 공유한다. 이는 네트워크가 이미지의 어느 부분에서든 동일한 패턴을 인식할 수 있도록 하며, 매개변수의 수를 더욱 줄인다.
  4. 다중 채널 입력 처리: LeNet-5는 단일 채널(흑백 이미지) 입력을 처리하도록 설계되었지만, 이 원칙은 컬러 이미지와 같은 다중 채널 입력 처리에도 적용될 수 있다. 각 채널은 독립적인 특징을 추출하며, 이후 레이어에서 이러한 특징들이 결합되어 더욱 복잡하고 고차원적인 패턴을 인식할 수 있게 한다. 이러한 접근 방식은 다양한 종류의 이미지 데이터에 대한 네트워크의 유연성과 적용성을 높여준다.

    희소 상호작용CNN이 대규모 이미지 데이터를 효과적으로 처리하면서도, 계산 비용과 메모리 사용량을 크게 줄일 수 있게 하는 중요한 원리이다. 이는 특히, 모바일 기기나 임베디드 시스템과 같이 제한된 계산 자원을 가진 환경에서 딥러닝 모델을 배치할 때 큰 이점을 제공한다. 또한, 이러한 희소성은 네트워크가 필요 이상으로 복잡해지는 것을 방지하며, 더욱 일반화된 학습 결과를 도출하는 데 도움을 준다.
    LeNet-5의 성공 이후, 다양한 연구와 개발을 통해 CNN의 구조와 기능은 크게 발전하였다. 오늘날에는 LeNet-5보다 훨씬 더 깊고 복잡한 모델들이 등장하였으며, 이들은 이미지 인식뿐만 아니라, 자연어 처리, 음성 인식, 비디오 분석 등 다양한 분야에서 폭넓게 활용되고 있다. 이러한 모든 발전의 기반이 되는 것은 여전히 희소 상호작용과 같은 기본적인 원칙들이다. 


참고

더보기

CNN

# http://yann.lecun.com/exdb/mnist/ 에서 손글씨 데이터 추출하기
from tensorflow.keras.datasets import mnist

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

print(train_images.shape,train_labels.shape)
print(test_images.shape,test_labels.shape)
# 데이터를 학습에 맞도록 크기를 변환
from tensorflow.keras.utils import to_categorical
 
train_images=train_images.astype('float32')/255
test_images=test_images.astype('float32')/255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
# 학습
from tensorflow.keras import models
from tensorflow.keras import layers

train_images=train_images.reshape((60000,28,28,1)) # 마지막 열은 Channel의 갯수, 흑백이므로 channel = 1
test_images=test_images.reshape((10000,28,28,1)) # 마지막 열은 Channel의 갯수, 흑백이므로 channel = 1


model=models.Sequential()

model.add(layers.Conv2D(filters = 6, kernel_size=(5, 5),  padding = "same", activation='relu', input_shape=(28, 28, 1)))
model.add(layers.AveragePooling2D(pool_size=(2, 2)))

model.add(layers.Conv2D(16, kernel_size=(5, 5), activation='relu'))
model.add(layers.AveragePooling2D(pool_size=(2, 2)))

model.add(layers.Conv2D(120, kernel_size=(5, 5), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(84, activation='relu'))

model.add(layers.Dense(10, activation='softmax'))

model.summary()
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

history= model.fit(train_images,train_labels,epochs=20, batch_size=100, verbose=2,validation_data=(test_images, test_labels))
test_loss, test_acc = model.evaluate(test_images, test_labels)

print('test accuracy=',test_acc)
import matplotlib.pyplot as plt


history_dict= history.history

loss = history_dict['loss']
val_loss = history_dict['val_loss']

accuracy = history_dict['accuracy']
val_accuracy = history_dict['val_accuracy']

epochs = range(1, len(loss)+1)

plt.figure(figsize=(10, 4))

plt.subplot(121)


plt.plot(epochs, loss, 'bo',label='training loss')
plt.plot(epochs, val_loss, 'b', label='test loss')
plt.xlabel('Epochs')
plt.ylabel('Loss') 
plt.legend()

plt.subplot(122)


plt.plot(epochs, accuracy, 'bo',label='training accuracy')
plt.plot(epochs, val_accuracy, 'b', label='test accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.ylim((0.9,1.02)) 
plt.legend()

plt.tight_layout()
plt.show()
# 생성된 네트워크 모델을 저장하기
from tensorflow.keras.models import load_model

model.save('mnist_CNN.h5')

pred_out = model_CNN.predict(test_images)

pred_out.shape

from numpy import argmax

for i in range(10):
    print('True : ' + str(argmax(test_labels[i])) + ', Predict : ' + str(argmax(pred_out[i])))

 

LeNet

# http://yann.lecun.com/exdb/mnist/ 에서 손글씨 데이터 추출하기
from tensorflow.keras.datasets import mnist

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

print(train_images.shape,train_labels.shape)
print(test_images.shape,test_labels.shape)

i=2

import matplotlib.pyplot as plt
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.show()
print(train_labels[i])
# 데이터를 학습에 맞도록 크기를 변환
from tensorflow.keras.utils import to_categorical
 
train_images=train_images.astype('float32')/255
test_images=test_images.astype('float32')/255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
from tensorflow.keras import models
from tensorflow.keras import layers

train_images=train_images.reshape((60000,28,28,1)) # 마지막 열은 Channel의 갯수, 흑백이므로 channel = 1
test_images=test_images.reshape((10000,28,28,1)) # 마지막 열은 Channel의 갯수, 흑백이므로 channel = 1


model=models.Sequential()

model.add(layers.Conv2D(filters =     , kernel_size=   ,  padding = "same", activation='relu', input_shape=(28, 28, 1)))
model.add(layers.AveragePooling2D(pool_size=(3,3)))

model.add(layers.Conv2D(filters =    , kernel_size=    , activation='relu'))
model.add(layers.AveragePooling2D(pool_size=(2, 2)))

model.add(layers.Conv2D(filters =  , kernel_size=     , activation='relu'))
model.add(layers.AveragePooling2D(pool_size=(2, 2)))

model.add(layers.Flatten())
model.add(layers.Dense(20, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

model.summary()
# 모델을 학습
model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

history= model.fit(train_images,train_labels,epochs=20, batch_size=100, verbose=2,validation_data=(test_images, test_labels))
import matplotlib.pyplot as plt


history_dict= history.history

loss = history_dict['loss']
val_loss = history_dict['val_loss']

accuracy = history_dict['accuracy']
val_accuracy = history_dict['val_accuracy']

epochs = range(1, len(loss)+1)

plt.figure(figsize=(10, 4))

plt.subplot(121)


plt.plot(epochs, loss, 'bo',label='training loss')
plt.plot(epochs, val_loss, 'b', label='test loss')
plt.xlabel('Epochs')
plt.ylabel('Loss') 
plt.legend()

plt.subplot(122)


plt.plot(epochs, accuracy, 'bo',label='training accuracy')
plt.plot(epochs, val_accuracy, 'b', label='test accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.ylim((0.5,1.02)) 
plt.legend()

plt.tight_layout()
plt.show()
 

기계 학습 3. 분류(Classification)

서론 기계 학습에서 Classification(분류)은 데이터를 미리 정의된 클래스 또는 카테고리로 분류하는 작업을 의미한다. Classification은 데이터 분석, 패턴 인식, 예측 및 의사 결정 등 다양한 분야에서

jinger.tistory.com

 

MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges

 

yann.lecun.com

반응형

'컴퓨터공학 > AI' 카테고리의 다른 글

인공지능 8. RNN  (1) 2024.07.07
인공지능 7. 자연어 처리(NLP)  (0) 2024.05.07
인공지능 5. DNN  (1) 2024.04.19
인공지능 4. 다층 신경망  (0) 2024.04.11
인공지능 3. 단층 신경망  (1) 2024.04.07

댓글