CNN_test_Model / README.md
OneclickAI's picture
Fixed
0aba846 verified
---
license: apache-2.0
---
안녕하세요 Oneclick AI 입니다!!
오늘은, CNN 모델에 대해서 깊게 알아보는 시간을 가져볼까 합니다.
딥러닝에 이미지 데이터를 사용할 수 있게 된 이유가 바로 CNN의 합성곱 신경망 (Convolutional Neural Network, CNN) 덕분인데요, 오늘은 이 신경망이 어떻게 작동하는지, CNN은 어떻게 사진 속의 숫자를 구분할 수 있는지 알아봅시다.
---
## 목차
1. CNN 핵심 원리 파악하기
- 왜 이미지에 CNN을 사용할까?
- CNN의 핵심 : 지역 수용 영역과 파라미터 공유
- CNN의 주요 구성 요소
2. 아키텍처를 통한 내부 코드 들여다 보기
- keras로 구현한 CNN 모델 아키텍쳐
- model.summary()로 구조 확인하기
3. 직접 CNN 구현해 보기
- 1단계 : 데이터 로드 및 전처리
- 2단계 : 모델 컴파일
- 3단계 : 모델 학습 및 평가
- 4단계 : 학습된 모델 저장하기
- 5단계 : 모델 사용하기
4. 나만의 CNN 모델 만들어보기
- 하이퍼파라미터 튜닝
- 모델 구조 변경하기
- 전이학습으로 성능 극대화 하기
5. 결론
---
## 1. CNN 핵심원리 파악하기
들어가기 앞서, CNN 이 어떤 원리로 이미지를 이해하는지 먼저 살펴보겠습니다.
**왜 이미지에 CNN을 사용할까??**
단순한 신경망(Fully Connected Layer)에 이미지를 입력하려면, 2차원인 이미지를 1차원의 긴 데이터로 펼치는 데이터 전처리 과정이 꼭 필요합니다.
이 과정에서 픽셀 간의 공간적인 정보가 전부 파괴됩니다.
이는 어떤 픽셀이 서로 이웃해 있는지 알 수 없어져서 눈이 코 옆에 있다는 위치정보 같은 내용이 가라저 버린다는 의미 입니다.
CNN은 이런 문제를 해결하기 위해 인간의 시신경 구조를 모방하여 설계되었습니다.
**CNN의 핵심 아이디어**
이것이 바로 지역적 수용영역과 파라미터 공유 입니다.
- 지역적 수용 영역(Local Receptive Fields)
신경망의 각 뉴런이 이미지 전체가 아닌, 작은 일부에만 연결됩니다.
이는 전체 픽셀에 대해서가 아닌 예시를 들면 3 * 3 픽셀에만 적용되는 방식인데요, 이를 통해 모델은 이미지의 전체 맥락보다 선, 모서리, 질감과 같은 지역적인 패턴을 먼저 학습하게 됩니다.
- 파라미터 공유(Parameter Sharing)
CNN은 이미지 전체를 필터를 통해서 스캔하는 느낌으로 학습합니다.
따라서, 한번 이미지의 특징을 학습하면, 이미지의 모든 위치에서 해당 특징을 감지할 수 있습니다.
이를 통해서 학습할 파라미터 수를 많이 줄일 수 있습니다.
**CNN의 주요 구성 요소**
앞선 아이디어를 바탕으로, CNN은 다음 3가지의 계층을 조합해서 만듭니다.
- 합성곱 계층 (Convolutional Layer)
학습 가능한 필터를 사용해서 이미지의 특징을 추출해 냅니다.
edge, corner 등을 추출하여 얻는 결과물을 특징 맵(Feature Map) 이라고 합니다.
- 풀링 계층 (Pooling Layer)
앞서 만든 맵의 크기를 줄이는 요약단계 입니다.
최대 풀링(Max Pooling)은 특정 영역헤서 가장 중요한 특징(가장 큰 값)만 남겨 계산량을 줄이고, 모델이 특징의 미세한 위치 변화에 덜 민감해 하도록 만듭니다.
- 완전 연결 계층 (Dense Layer)
추출된 특징들을 종합하여 최종적으로 이미지가 어떤 클래스에 속하는지 분류하는 역할을 합니다.
---
## 2. 아키텍처를 통한 내부 코드 들여다 보기
이제, 앞서 설명한 내용을 바탕으로, 실제 TensorFlow Keras 코드를 통해서 어떻게 작동하는지 실감해 봅시다.
다음은, Keras로 구현한 CNN 모델 아키텍쳐 입니다.
```python
import tensorflow as tf
from tensorflow import keras
# 모델 아키텍처 정의
model = keras.Sequential([
# Input: (28, 28, 1) 이미지
# 첫 번째 Conv-Pool 블록
keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=(28, 28, 1)),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
# 두 번째 Conv-Pool 블록
keras.layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
# 분류기(Classifier)
keras.layers.Flatten(),
keras.layers.Dropout(0.5),
keras.layers.Dense(10, activation="softmax"),
])
```
이제, 앞서 설명했던 이론이 이 코드에 어떻게 녹아있는지 알아봅시다.
- **합성곱 계층(Conv2D)**
```python
keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=(28, 28, 1))
```
이 코드를 통해서, 합성곱 계층을 형성, 다음 아이디어를 구현합니다.
1. 지역 수용영역
```kernel_size(3, 3)```을 통해서 이미지 전체가 아닌 3 * 3 크기의 작은 영역만 보도록 만듭니다.
이렇게, 지역적 수용영역을 만듭니다
2. 파라미터 공유
```Conv2D``` 계층은 32개의 필터를 생성합니다.
3 * 3필터는 고유한 파라미터(가중치)세트를 가지며, 이 필터 하나가 이미지 전체를 스캔합니다.
만약, 파라미터 공유가 없다면, 각 3 * 3 위치마다 별도의 파라미터를 사용해야 하므로 크기가 엄청 커집니다.
하지만, 파라미터 공유 덕분에, 이 경우에서 ```(3 * 3 * 1 +1) * 32 = 320``` 개의 파라미터 만으로 이미지 전체의 특징을 추출할 수 있습니다.
- **풀링 계층(MaxPooling2D)**
```python
keras.layers.MaxPooling2D(pool_size=(2, 2))
```
앞선 합성곱 계층이 생성한 특징맵을 2* 2 크기의 영역으로 나누고, 각 영역에서 가장 큰 값만 남기라는 의미입니다.
이를 통해 맵 크기가 절반으로 줄어드는 **다운 샘플링**이 일어나고, 계산 효율성이 높아져 모델 학습이 더 가벼워 집니다.
- **완전 연결 계층(Dense Layer)**
```python
keras.layers.Flatten()
keras.layers.Dense(10, activation="softmax")
```
최종 분류기 이며, 완전연결계층 입니다.
1. ```keras.layers.Flatten()```
완전연결계층은 1차원 백터를 입력으로 받기 때문에, Flastten 계층이 먼저 들어와 2차원 형태의 특징 맵을 한 줄로 펼쳐줍니다.
2. ```keras.layers.Dense(10, activation="softmax")```
이 코드가 완전연결계층이며, 보통 Dense Layer 라고 부릅니다.
특징백터를 입력받아 10개의 클래스 중 어느 클래스에 할당할지 최종적으로 결정합니다.
```activation="softmax"```는 각 클래스에 대한 예측값을 0 과 1 사이의 확률값으로 하게 하여 모든 확률의 합이 1이 되도록 만들어 줍니다.
---
## 3. 직접 CNN 구현해 보기
이제, 직접 CNN 학습 코드를 단계별로 구현해 봅시다.
**1단계. 데이터 로드 및 전처리**
모델이 학습할 데이터를 가져와 줍니다.
이번엔, 쉽게 불러올 수 있는 MNIST 손글씨 숫자 데이터셋을 가져와 적절한 형태로 전처리 하겠습니다.
```python
import numpy as np
import tensorflow as tf
from tensorflow import keras
from keras import layers
# Keras 라이브러리를 통해 MNIST 데이터셋을 손쉽게 불러옵니다.
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# 정규화: 픽셀 값의 범위를 0~255에서 0~1 사이로 조정하여 학습 안정성 및 속도를 높입니다.
x_train = x_train.astype("float32") / 255.0
x_test = x_test.astype("float32") / 255.0
# 채널 차원 추가: 흑백 이미지(채널 1)의 차원을 명시적으로 추가합니다.
x_train = np.expand_dims(x_train, -1)
x_test = np.expand_dims(x_test, -1)
# 레이블 원-핫 인코딩: 숫자 '5'를 [0,0,0,0,0,1,0,0,0,0] 형태의 벡터로 변환합니다.
num_classes = 10
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
```
**2단계. 모델 컴파일**
모델 아키텍쳐를 정의하고 모델을 어떻게 학습시킬지에 대해 정합니다.
```python
model = keras.Sequential([
keras.Input(shape=(28, 28, 1)), # 입력 레이어
layers.Conv2D(32, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
layers.MaxPooling2D(pool_size=(2, 2)),
layers.Flatten(),
layers.Dropout(0.5),
layers.Dense(num_classes, activation="softmax")
])
model.compile(
# 손실 함수(Loss Function): 모델의 예측이 정답과 얼마나 다른지 측정합니다.
loss="categorical_crossentropy",
# 옵티마이저(Optimizer): 손실을 최소화하기 위해 모델의 가중치를 업데이트하는 방법입니다.
optimizer="adam",
# 평가지표(Metrics): 훈련 과정을 모니터링할 지표로, 정확도를 사용합니다.
metrics=["accuracy"]
)
```
**3단계. 모델 학습 및 평가**
```model.fit()```함수를 통해서 학습을 시작하고, 학습이 끝난 후 ```model.evaluate()```로 최종 성능을 확인합니다.
```python
batch_size = 128
epochs = 15
# 모델 학습 실행
history = model.fit(
x_train, y_train,
batch_size=batch_size,
epochs=epochs,
validation_data=(x_test, y_test)
)
# 학습 완료 후 최종 성능 평가
score = model.evaluate(x_test, y_test, verbose=0)
print(f"\nTest loss: {score[0]:.4f}")
print(f"Test accuracy: {score[1]:.4f}")
```
**4단계. 학습된 모델 저장하기**
모델을 저장하고, 불러올 수 있도록 합니다.
```python
# 모델의 구조, 가중치, 학습 설정을 모두 '.keras' 파일 하나에 저장합니다.
model.save("my_keras_model.keras")
print("\nModel saved to my_keras_model.keras")
```
위 단계를 전부 수행한 모델이 지금 이 허깅페이스 라이브러리에 들어있는 모델입니다. 이어서, 모델을 사용해 볼 떄, 위 코드를은 직접 실행하지 말고, 다음 코드를 실행시켜 주세요!
만일, 위 코드를 통해 직접 딥러닝을 시켭고 싶으시다면, Files의
train.py를 실행시켜 주세요!
**5단계. 모델 사용해 보기**
앞선 단계들을 거쳐 완성한 모델이 이 허깅페이스 페이지에 올라가 있습니다.
이제, 이 허깅페이스 페이지의 모델을 불러와서, 직접 사용해 보겠습니다.
Files의 test.py를 실행시켜 보세요!!
직접 준비한 숫자 손글씨를 모델에 입력으로 넣으면, 그 숫자가 어떤 숫자인지 맞춰줄 겁니다!!
코드 실행을 위해서, 이 종속성을 설치해야 합니다.
cmd 창을 열고, 이 코드를 넣고 실행하여 먼저 종속성을 받아주세요
```bash
pip install tensorflow huggingface_hub Pillow numpy
```
## 4. 나만의 CNN 모델 만들기
이제, 성능을 더 끌어올리기 위해, 또 원하는 목적에 맞게 모델을 수정할 차례입니다.
- **하이퍼파라미터 튜닝**
모델의 성능에 큰 영향을 미치는 batch_size, epochs, 옵티나이저의 leaarning_rate등을 조합하여 최적화 합니다.
다음 코드를 건드려서 수정합니다.
```python
# 예: Adam 옵티마이저의 학습률(learning_rate)을 직접 설정
optimizer = keras.optimizers.Adam(learning_rate=0.001)
model.compile(loss="categorical_crossentropy", optimizer=optimizer, metrics=["accuracy"])
```
- **모델 구조 변경**
모델의 성능을 위해서, ```Conv2D-MaxPooling2D``` 블록을 더 깊게, ```Conv2D``` 계층의 필터 수를 늘려 더 풍부하게 할 수 있습니다.
```python
model = keras.Sequential([
keras.layers.Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=(28, 28, 1)),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
# 블록 추가!
keras.layers.Conv2D(64, kernel_size=(3, 3), activation="relu"),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
# 필터 수를 늘린 블록 추가!
keras.layers.Conv2D(128, kernel_size=(3, 3), activation="relu"),
keras.layers.MaxPooling2D(pool_size=(2, 2)),
keras.layers.Flatten(),
keras.layers.Dense(128, activation='relu'), # Dense 층 추가
keras.layers.Dropout(0.5),
keras.layers.Dense(10, activation="softmax"),
])
```
- **전이학습**
아주 큰 데이터셋으로 학습된 이미 강력한 모델을 가져와, 그 모델이 학습한 이미지 특징추출능력만 가져와 사용하는 방법 입니다.
적은 데이터로도 높은 성능을 낼 수 있습니다.
```python
# Keras에서 제공하는 사전 학습된 VGG16 모델 불러오기 (분류기는 제외)
base_model = keras.applications.VGG16(
weights='imagenet', # ImageNet으로 사전 학습된 가중치 사용
include_top=False, # 분류기(Dense 층)는 제외
input_shape=(32, 32, 3) # VGG16은 최소 32x32 컬러 이미지를 입력으로 받음
)
# 불러온 모델의 가중치는 고정(freeze)
base_model.trainable = False
# 새로운 분류기 추가
model = keras.Sequential([
base_model,
keras.layers.Flatten(),
keras.layers.Dense(256, activation='relu'),
keras.layers.Dropout(0.5),
keras.layers.Dense(10, activation='softmax') # 나의 문제에 맞는 출력층
])
# 새로 추가한 분류기 부분만 학습
model.compile(...)
model.fit(...)
```
## 5. 결론
오늘은, 이렇게 CNN 모델에 대해 간단하게 알아봤습니다.
이미지 처리에 특화된 CNN은 나중에 트랜스포머 모델이 나오면서 Vit라는 모델이 만들어지는데 큰 기여를 하게 됩니다.
이렇듯 근본 넘치는 CNN 많이 사랑해 주세요!!
다음에는 RNN모델로 돌아오겠습니다
오늘도 좋은하루 보내세용!!