CNN 이론 요약
- Convolution Operation
- ReLU Layer
- Pooling
- Flattening
- Full Connection
- Softmax & Cross-Entropy
🔽 CNN의 대가 Yann Lecun 논문
🔽 Convolution 연산의 수학적 배경을 더 알고 싶다면,
Featuer Detector = Kernel = Filter
결과 메트릭스에 값이 적기 때문에 당연히 어떤 정보는 잃어버리게 된다.
그러나 특징을 감지하는 것이 중요하다.
가장 높은 숫자가 의미하는 것은 특징이 완벽하게 일치할 때 나온다.
특징은 우리가 사물을 보는 방식이자 인식하는 방식이다.
우리가 이미지를 보거나 실생활을 하면서 모든 픽셀을 살펴보는 것이 아니라 특징들을 찾는다.
Feature Detector는 어떻게 만들어질까?아래 실습 과정에 답이 있다.
ReLU Layer

Rectifier를 사용하는 이유는, 비선형을 높이기 위해서이다.비선형을 높이려는 이유는 이미지 자체는 굉장히 비선형적이기 때문이다.
특히 함께 놓여 있거나 배경에 있는 다른 객체를 인식하면 이미지에는 비선형 요소들이 많을 것이다.
인접한 픽셀 간의 전환들도 비선형이 될 수 있다.
그러나 Convolution 연산을 하게 되면 선형을 만들 위험이 생긴다. 그래서 선형성을 끊어야 한다.
🔽 왜 비선형적 활성화 함수가 모든 중간 레이어의 필터 출력에 꼭 필요한가?
🔽 성능에 영향을 끼치지 않으면서 더 나은 결과를 얻을 수 있는 정류화 선형 유닛
Max Pooling
신경망은
공간적 불변성이라는 특성이 있는지 확인해야 한다.특징이 이미지의 어디에 있는지는 중요하지 않다는 것이다.
특징이 약간 기울어져 있다든지, 질감이 좀 다르다든지 조금 더 가깝거나 서로 더 떨어져 있는지는 상관없다.
특징 자체가 약간 왜곡되었다면 신경망이 그 특징을 찾을 수 있을 정도의 융통성을 가지고 있어야 한다.
이것이
Pooling 이다.
위는 2x2 Matrix로 이 안에 있는 최댓값을 저장해둔 것이다.
최대 숫자가 특징과의 최대 유사성을 의미하기에 여전히 특징을 보존할 수 있다.
게다가 이 특징들을 풀링하면서 특징이 아닌 정보를 75% 제거하게 되었다.
또 다른 풀링의 장점으로는
- 크기가 줄어든다
- 매개 변수의 수가 줄어들어 과적합을 방지한다.
우리 인간들도 눈으로 들어오는 모든 잡다한 것을 받아들이기보다,
정확하게 특징을 찾아내는 것이 중요하다.
🔽 왜 맥스풀링일까? 왜 2x2 픽셀일까?
Flattening

CNN 전체 과정 요약

Full Connection

앞에서
Flatten의 과정까지 끝난 값은 이렇게 신경망에 연결된다.여기서 Hidden Layer는 Fully Connected Layer라고 불린다.
역전파 과정에서 가중치가 조정되는 것뿐만 아니라 Feature Detector도 조정된다.
Dog, Cat 뉴런도 학습을 통해 그 전 Layer에서의 뉴런에 가중치를 부여한다.
🔽 9가지 CNN의 기본적인 개요
Softmax & Cross Entropy

결과를 출력했을 때 두 개의 최종 뉴런이 서로 연결되어 있지 않은데,
어떻게 상대 뉴런의 값을 알고 총합이 1이 되게 했을까?
전형적인 버전의 인공 신경망을 알 수 없다.
유일한 방법은
Softmax라는 함수를 제공하는 것이다.또 소프트맥스 함수는
Cross-entropy 함수와 함께 제공된다.똑같지만 표현이 바뀌고 계산하기 쉬울 뿐이다.

CNN에서는 손실함수로 MSE보다 소프트맥스 함수를 적용하고 크로스 엔트로피 함수가 더 나은 선택지이다.
- 출력값이 아주 작아서 경사 하강법의 경사도 낮을거라 올바른 방향으로 나아가기 어려울 것이다.
- 반면에 크로스 엔트로피를 사용하면 안에 로그가 있어서 이런 작은 오류도 평가해서 조치할 수 있다.
그래서 MSE를 사용하면 아주 작은 값일 때, 제곱 오차를 사용하면 별로 바뀌지 않았다고 느끼지만,
크로스 엔트로피를 사용하면 아주 사소한 변화들이라도 상대적인 측면에서 아주 큰 발전으로 보인다.
크로스 엔트로피는 분류할 때만 선호하는 방법이다.
회귀 같은 것은 MSE 평균 제곱 오차가 낫다.
🔽 크로스 엔트로피에 대한 가벼운 소개 논문
CNN 실습
- Data Processing
- Building the CNN
- Initialize the CNN
- Convolution
- Pooling
- Add second covolutional layer
- Flattening
- Full Connection
- Output Layer
- Training the CNN
- Compile the CNN
- Traning and Evaluating
- Making a single prediction
0. Importing the libraries
import tensorflow as tf from tensorflow.keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing.image import ImageDataGenerator
이렇게 import를 하니 오류가 생겼다는데, 앞에 tensorflow를 붙이니 해결되었다.
1. Data processing
Preprocessing the Training set
train_datagen = ImageDataGenerator( rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True ) training_set = train_datagen.flow_from_directory( 'dataset/training_set', target_size=(64,64), batch_size=32, class_mode='binary' )
rescale은 숫자 255를 보면 대충 유추할 수 있다.RGB의 값이 0~255의 값을 가지므로,
rescale을 통해 0~1까지의 값을 갖도록 변환하는 것이다.그리고 shear_range, zoom_range, horizontal_flip은 이미지를 변환하는 것으로,
이미지를 변환하는 과정을 통해 과적합을 피할 수 있다고 한다.
근데 위에서 CNN은 공간적 불변성이라는 특징을 가진다고 했는데 이렇게 이미지를 변환하는 이유는 무엇일까?
CNN은 약한 수준의 위치 불변성만을 자동으로 학습해낼 수 있다고 한다. 하지만 크고 복잡한 변형에는 불변하지 않는다고 한다. 그래서 학습 데이터의 다양화를 위해서 데이터를 변형하고 이것을 데이터 증강이라고 부른다.
target_size는 이미지의 크기를 조절하는 것이고, batch_size는 ANN 때와 마찬가지로 학습할 이미지의 수다.마지막으로
class_mode는 binary 로 되어있는데 이 예제가 개와 고양이를 나누는 학습이기 때문이다.클래스가 여러 가지일 경우에는
categorical을 사용하면 된다.근데 2개일때도
categorical를 사용하면 binary보다 성능이 떨어질까?class_mode | 출력층 설정 | 출력 형태 | 손실 함수 |
binary | activation=sigmoid | 0~1 사이 실수 | binary_crossentopy |
categorical | activation=softmax | [1, 0] 또는 [0, 1] | categorical_crossentropy |
binary_crossentropy는 이진 분류 문제에 최적화되어 있다.
categorical_crossentropy는 원-핫 인코딩된 출력에 대해 작동하므로, 2개의 클래스인데도 불필요하게 더 많은 연산을 하게 된다.
즉,
categorical은 가능은 하지만 비효율적 이다.Preprocessing the Test set
test_datagen = ImageDataGenerator(rescale=1./255) test_set = test_datagen.flow_from_directory( 'dataset/test_set', target_size=(64,64), batch_size=32, class_mode='binary' )
test_set에는 ANN에서
scaling 과정에서 fit을 하지 않고 transform만 사용했듯이,CNN에서도 이미지 변환을 하지 않는다.
2. Building the CNN
Initialize the CNN
cnn = tf.keras.models.Sequential()
이건 ANN 때와 같다.
Convolution
cnn.add(tf.keras.layers.Conv2D(filters=32, kernel_size=3, activation='relu', input_shape=[64, 64, 3]))
filters는 말 그대로 filter의 개수
kernel_size는 filter의 크기 (여기서는 3 x 3 matrix이다.)
activation는 이제는 알아야 한다.
input_shape은 위에서 targert_size(64) + RGB(3) 만약 흑백이라면 3이 아니라 1을 넣어야 한다.
근데
filters 개수를 정하면, 그 filters의 모양은 어떻게 정해지는걸까?CNN 필터는 처음엔 랜덤한 값으로 초기화 된다. 그러나 학습을 반복하면서 유용한 형태로 변형된다.
Pooling
cnn.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2, padding='valid'))
pool_size는 pool의 크기
strides는 pool마다 이동할 단위 (여기서는 2칸씩 이동)
padding은 범위를 넘었을 때 대응 방법이다. valid가 기본값으로 index가 넘어가도 처리 가능하다.
Adding a second convolutional layer
cnn.add(tf.keras.layers.Conv2D(filters=32, kernel_size=3, activation='relu')) cnn.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2, padding='valid'))
위에서 convoltional layer추가하는 과정과 똑같다.
그러나
input_shape은 이미 위에서 선언했기 때문에 여기서는 필요 없다. Flattening
cnn.add(tf.keras.layers.Flatten())
Full connection
cnn.add(tf.keras.layers.Dense(units=128, activation='relu'))
여기서
units은 뉴런의 개수인데,ANN 글에서 말했듯이 units 수를 잘 정하는 것은 굉장히 실험적이고 철학적이다.
그냥 직관적으로 정해야 한다는 뜻이다.
Output Layer
cnn.add(tf.keras.layers.Dense(units=1, activation='sigmoid'))
여기서는 Binary를 이용했기 때문에 0과 1을 출력하는 뉴런 하나만 있으면 된다.
그러나 강아지와 고양이를 비교하는 예제에서 둘 다 아닌 경우도 있을 수 있기 때문에 Binary는 좋지 않은 선택지인 것 같다. Ouput 뉴런이 2개는 있어야 한다고 생각한다.
3. Training the CNN
Compiling the CNN
cnn.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
Training the CNN on the Training set and evaluating it on the Test set
cnn.fit(x = training_set, validation_data= test_set, epochs = 25)
ANN 때와는 다르게
test_set을 validation_data 에 할당했다.training_set과 test_set은 ImageDataGenerator가 만든 generator 객체고,
이 generator는 이미 내부적으로 (x, y) 쌍을 자동으로 제공한다.
따라서 test_set을 validation 용으로 추가하는 것이다.
4. Making a single prediction
import numpy as np from keras.preprocessing import image test_image = image.load_img('dataset/single_prediction/cat_or_dog_1.jpg', target_size = (64, 64)) test_image = image.img_to_array(test_image) test_image = np.expand_dims(test_image, axis = 0) result = cnn.predict(test_image) training_set.class_indices if result[0][0] == 1: prediction = 'dog' else: prediction = 'cat'
image.img_to_array는 load_img에서 반환된 PIL 이미지를 numpy 배열로 변환시켜준다.- keras 모델이 numpy 배열만 입력받을 수 있기 때문이다.
np.expand_dims는 배치 차원을 추가해주는 함수이다.- 딥러닝 모델은 항상 배치 단위로 처리하도록 설계돼 있기 때문이다.
- 근데 ANN 시간에는 배치 단위로 처리하지 않지 않았나? → 2차원 배열 형태로 만들어준게 배치 단위다.
axis의 역할은, 맨 앞에 차원 하나를 추가한다는 뜻이다.- 원래 이미지 하나를 부르면 test_image.shape → (64, 64, 3) 이다.
- CNN은 (batch_size, height, width, channels) 인자를 받아야 한다.
- 따라서 np.expand_dims 를 통해 (1, 64, 64, 3)가 된다.
result[0][0]을 하는 이유는result가 아래와 같은 형태로 나오기 때문이다.
result # 예: [[0.934]] result[0] # [0.934] result[0][0] # 0.934

