합성곱신경망(CNN) 🐸
합성곱신경망(CNN, Convolutional Neural Network)
- 이미지 분석에 주로 사용되는 대표적 계층
- 기존의 인공신경망에서의 이미지 분석시에는 높이와 너비를 곱한 1차원을 사용하였다면,
- CNN은 원형 그대로의 높이와 너비 차원을 사용함
- 전체 4차원(행, 높이, 너비, 채널)의 데이터를 사용함
- 기존 이미지 분석 시 높이와 너비를 곱하여 사용하다보면,
* 원형 그대로의 주변 이미지 공간 정보를 활용하지 못하는 단점이 있으며,
* 이러한 이유로 특징 추출을 잘 못하여, 학습이 잘 이루어지지 않는 경우가 발생함
- 이러한 기존 인공신경망 모델의 단점을 보완하여 만들어진 모델이 CNN임
* 원형 형태의 이미지 정보를 그대로 유지한 상태로 학습 가능하도록 만들어졌음
* 이미지의 공간정보를 이용하여 특징을 추출함
* 인접 이미지의 특징을 포함하여 훈련됨
합성곱신경망(CNN) 계층 구조 🐸
합성곱신경망(CNN) 계층 구조
1. 입력 계층(Input Layer)
- 데이터 입력 계층 (기존과 동일)
2. 합성곱 계층(Convolutional Layer, CNN 계층)
- 이미지의 특징을 추출하는 합성곱 계층이 여러층으로 구성되어 있음
3. 활성화 함수 계층(은닉계층, Activation Layer)
- 합성곱 계층의 출력에 대한 비선형성 추가한 활성화 함수 ReLU와 같은 함수 적용
4. 풀링 계층(Pooling Layer)
- 공간 크기를 줄이고 계산량을 감소시키기 위한 계층(중요 특징만 추출하는 계층)
- 풀링 방법으로 최대풀링(Max Pooling), 평균풀링(Average Pooling)이 있음
- 주로 Max Pooling 사용됨
5. 완전연결 계층(은닉계층, Dense Layer)
- 추출된 특징을 이용하여 최종 예측을 수행하는 계층
- 이때는 기존의 방법과 동일하게 1차원(높이 x 높이)의 전처리 계층(Plattern)을 사용하는 경우도 있음
(인공신경망 모델과 동일한 계층 구조로 진행)
6. 출력 계층(Output Layer)
- 최종 예측이 이루어지는 계층
*** CNN에서 2~5번의 계층구조가 일반적으로 사용됨,
- 나머지 계층은 기존과 동일한 계층
- 2~5번의 CNN 계층은 여러개 추가 가능
라이브러리 🐸
import tensorflow as tf
from tensorflow import keras
from sklearn.model_selection import train_test_split
"""훈련계층 시각화"""
from tensorflow.keras.utils import plot_model
패션 이미지 데이터 읽어들이기 🐸
"""패션 데이터셋 load"""
(train_input, train_target),(test_input, test_target) = keras.datasets.fashion_mnist.load_data()
print(train_input.shape, train_target.shape)
print(test_input.shape, test_target.shape)
(60000, 28, 28) (60000,)
(10000, 28, 28) (10000,)
"""3차원"""
train_input
4차원 만들기 🐸
CNN에서 사용하는 차원은 4차원
- (행, 높이, 너비, 채널)
- 채널 = 1 또는 3 (1은 흑백, 3은 컬러(RGB)라고 보통 칭합니다.)
train_input_4d = train_input.reshape(-1, 28, 28, 1)
train_input_4d.shape
(60000, 28, 28, 1)
정규화 🐸
"""픽셀 데이터 정규화"""
train_scaled = train_input_4d / 255.0
train_scaled.shape, train_scaled[1][0]
((60000, 28, 28, 1),
array([[0. ],
[0. ],
[0. ],
[0. ],
[0. ],
[0.00392157],
[0. ],
[0. ],
[0. ],
[0. ],
[0.16078431],
[0.7372549 ],
[0.40392157],
[0.21176471],
[0.18823529],
[0.16862745],
[0.34117647],
[0.65882353],
[0.52156863],
[0.0627451 ],
[0. ],
[0. ],
[0. ],
[0. ],
[0. ],
[0. ],
[0. ],
[0. ]]))
훈련 및 검증 데이터로 분리하기 → 8 : 2 🐸
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)
print(train_scaled.shape, train_target.shape)
print(val_scaled.shape, val_target.shape)
print(test_input.shape, test_target.shape)
(48000, 28, 28, 1) (48000,)
(12000, 28, 28, 1) (12000,)
(10000, 28, 28) (10000,)
합성곱신경망(CNN) 모델 + 계층 생성하기 🐸
CNN(입력 계층으로 추가)
- 데이터와 필터(filter)가 곱해진다고 해서 합성곱이라는 단어가 붙었음
- 이미지와 같은 2차원 데이터 분류에는 보통 2차원 합성곱(Conv2D)이 사용됨
- 입력 계층으로 사용하는 경우에는 input_shape의 입력 차원 속성을 함께 사용
<kernel_size>
- 이미지를 훑으면서 특징을 추출하는 역할을 수행
- 필터가 사용할 사이즈를 정의함
- kernel_size=3 → 필터가 사용할 사이즈 3행 3열을 의미함(3x3을 줄여서 3이라고 칭함)
- 커널 사이즈는 홀수로 정의함(3, 5가 주로 사용됨)
- kernel_size=(3, 3) 또는 kernel_size=3
<filters>
- 커널사이즈의 행렬의 공간 1개에 대한 필터의 갯수 정의
- 데이터를 훑으면서 특징을 감지함
- 필터의 값이 클수록 훈련속도가 오래 걸림
- 보통 32, 64가 주로 사용됨
- CNN계층을 여러개 사용하는 경우에는 처음 CNN계층에는 작은 값부터 시작...
→ 16, 32, 64, 128 정도가 주로 사용됨
<padding>
- 경계 처리 방식을 정의함
- 입력 데이터의 주변에 추가되는 가상의 공간을 만들수 있음
- 처리 방식 : same과 valid가 있음
* same : 패딩을 사용하여 입력과 출력의 크기를 동일하게 만들어서 훈련하고자 할 때 사용
: 주로 권장되는 방식
* valid : 패딩을 사용하지 않음을 의미함
<strides>
- 커널이 이미지 데이터를 훑을 때(특징 추출 시)의 스탭을 정의함
- 커널이 데이터 특징 추출 순서(행렬을 기준으로)
→ 왼쪽 상단에서 시작하여 오른쪽으로 이동하는 스탭 정의
→ 오른쪽 열을 다 훑고난 다음 아래로 이동하는 스탭 정의
- strides=1 : 오른쪽으로 1씩 이동, 아래로 1씩 이동을 의미
"""모델 생성하기"""
model = keras.Sequential()
model
"""CNN 계층 생성하기"""
model.add(keras.layers.Conv2D(kernel_size=3,
filters=32,
activation="relu",
padding="same",
strides=1,
input_shape=(28, 28, 1)))
풀링레이어(Pooling Layer) 계층 추가하기
<풀링레이어(Pooling Layer)>
- CNN 계층 추가 이후에 일반적으로 사용되는 계층
- CNN 계층에서 추출된 특징들 중에 중요한 정보만을 추출하는 계층
- 머신러닝에서 주성분 분석(PCA)과 유사한 개념
- 이미지를 구성하는 픽셀들이, 주변 픽셀들끼리는 유사한 정보를 가진다는 개념에서
중복된 값들이나 유사한 값들을 대표하는 값들, 즉 중요한 특징들만 추출하게 됩니다.
- 과적합 방지에 효율적으로 사용되며 훈련 성능에 영향을 미치지 않는 전처리 계층임
* MaxPool2D
- 사소한 값들은 무시하고 최대값의 특징들만 추출하는 방식
- pool_size=2 : 2행 2열의 공간에 중요 특징들만 저장하라는 의미
- strides=2 : CNN에서 추출한 특징값들의 행렬을 오른쪽 2칸씩,
아래로 2칸씩 이동하면서 중요 특징값 추출하라는 의미
: 기본 디폴트값은 2 (생략가능)
- 풀링에서 가장 대표적으로 사용되는 방식임
"""풀링 계층 추가하기"""
model.add(keras.layers.MaxPool2D(pool_size=2, strides=2))
"""CNN 계층 추가하기"""
model.add(keras.layers.Conv2D(kernel_size=(3, 3),
filters=64,
activation="relu",
padding="same",
strides=1))
"""풀링 계층 추가하기"""
model.add(keras.layers.MaxPool2D(pool_size=2, strides=2))
인공신경망 계층 추가(전처리 또는 은닉계층 + 출력계층)
"""(전처리 계층)예측을 위해 중요 특징 데이터를 1차원(높이 x 너비)로 변환하기"""
model.add(keras.layers.Flatten())
"""은닉계층 추가 - 활성화함수 추가됨 """
model.add(keras.layers.Dense(100, activation="relu"))
"""(전처리 계층)드롭아웃도 적용"""
model.add(keras.layers.Dropout(0.2))
"""출력계층 추가"""
model.add(keras.layers.Dense(10, activation="softmax"))
model.summary()
훈련계층을 이미지로 시각화 - plot_model()🐸
from tensorflow.keras.utils import plot_model
plot_model(model)
계층모델 속성 정의하여 시각화 및 저장시키기
- show_shapes : 층의 형태를 세부적으로 표현(기본값은 False)
- dpi : 이미지 해상도
- to_file : 저장위치(기본값은 현재 실행파일이 있는 위치와 동일한 곳에 저장됨)
plot_model( model, show_shapes=True, to_file="./model_img/CNN_Layer.png", dpi=300 )
모델 설정하기 🐸
"""옵티마이저 Adam"""
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
콜백함수 만들기(자동저장, 자동종료) 🐸
"""자동저장"""
checkpoint_cb = keras.callbacks.ModelCheckpoint("./model/best_CNN_Model.h5")
"""자동종료"""
early_stopping_cb = keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True)
checkpoint_cb, early_stopping_cb
훈련 시키기 🐸
훈련 20회만 수행한 후 손실곡선과 정확도 곡선 시각화하기
""" 모델 훈련 시키기 """
history=model.fit(train_scaled, train_target, epochs=20, verbose=1,
validation_data=(val_scaled, val_target), callbacks=[checkpoint_cb, early_stopping_cb])
"""시각화하기"""
import matplotlib.pyplot as plt
import seaborn as sns
"""한글처리"""
plt.rc("font", family = "Malgun Gothic")
"""마이너스 기호 처리"""
plt.rcParams["axes.unicode_minus"] = True
plt.figure(figsize=(12, 5))
plt.suptitle("합성곱신경망(CNN)을 이용한 이미지 분류", y=1.02, fontsize=16)
# 손실 시각화 - Loss
plt.subplot(1, 2, 1) # 1행 2열 중 첫 번째 subplot
plt.title("CNN Train & Val - Loss")
plt.plot(history.epoch, history.history["loss"])
plt.plot(history.epoch, history.history["val_loss"])
plt.xlabel("epoch")
plt.ylabel("loss")
plt.legend(["Train", "Val"])
plt.grid()
# 정확도 시각화 - Accuracy
plt.subplot(1, 2, 2) # 1행 2열 중 두 번째 subplot
plt.title("CNN Train & Val - Accuracy")
plt.plot(history.epoch, history.history["accuracy"])
plt.plot(history.epoch, history.history["val_accuracy"])
plt.xlabel("epoch")
plt.ylabel("accuracy")
plt.legend(["Train", "Val"])
plt.grid()
plt.tight_layout() # subplot 간 간격 조절
plt.show()
훈련 및 검증데이터 모델 성능 검증결과 확인 🐸
train_eval = model.evaluate(train_scaled, train_target)
val_eval = model.evaluate(val_scaled, val_target)
train_eval, val_eval
1500/1500 [==============================] - 5s 3ms/step - loss: 0.1362 - accuracy: 0.9497
375/375 [==============================] - 1s 3ms/step - loss: 0.2170 - accuracy: 0.9202
([0.13621293008327484, 0.9497083425521851],
[0.2169836014509201, 0.9201666712760925])
훈련에 사용된 데이터를 이미지로 그려보기 🐸
훈련에 사용된 데이터를 이미지로 그려보기
- (행, 높이, 너비, 채널)
- 이미지 데이터는 2차원으로 줄여서 그려야 합니다. reshape
val_scaled[0].shape
(28, 28, 1)
""" 이미지 데이터는 2차원으로 줄여서 그려야 합니다."""
val_scaled_0 = val_scaled[0].reshape(28, 28)
val_scaled_0.shape
(28, 28)
"""이미지 한개 그려보기"""
plt.imshow(val_scaled_0, cmap="gray_r")
plt.show()
"""실제 값"""
val_target[0]
8
예측하기 🐸
검증데이터 0번째 데이터를 이용해서 예측해보기
- 예측결과값은 모델 출력계층의 출력크기(갯수)만큼 확률값으로 반환해줍니다.
- 반환된 확률값 중 가장 큰 값의 "인덱스 번호"가 종속변수 값이 됩니다.
[내코드]
import numpy as np
preds = model.predict(val_scaled)
preds_max = np.argmax(preds[0])
preds[0], preds_max
(array([4.1726835e-13, 3.1553179e-16, 4.2426482e-13, 3.4465784e-13,
1.9473605e-12, 1.8247194e-13, 4.3801055e-13, 3.0728848e-13,
1.0000000e+00, 1.0426476e-15], dtype=float32),
8)
[강사님 코드]
preds = model.predict(val_scaled[0:1])
preds
array([4.1726835e-13, 3.1553179e-16, 4.2426482e-13, 3.4465784e-13,
1.9473605e-12, 1.8247194e-13, 4.3801055e-13, 3.0728848e-13,
1.0000000e+00, 1.0426476e-15], dtype=float32)
plt.bar(range(10), preds[0])
plt.xticks(range(10))
plt.grid()
plt.show()
"""범주 명칭"""
classes = ["티셔츠", "바지", "스웨터", "드레스", "코트",
"샌들", "셔츠", "스니커즈", "가방", "앵클부츠"]
print(np.argmax(preds))
print(f"예측값 : {classes[np.argmax(preds)]}")
print(f"실제값 : {classes[val_target[0]]}")
8
예측값 : 가방
실제값 : 가방
테스트 데이터로 최종 예측하기 🐸
테스트 데이터로 최종 예측하기
테스트 데이터를 이용해서 예측한 후,
- 예측 결과 중 10개만 추출하여,
→ 실제이미지 출력, 예측값, 실제값을 각각 출력해 주세요
"""테스트 데이터 정규화하기"""
test_scaled = test_input / 255.0
"""테스트 데이터 예측하기"""
test_pred = model.predict(test_scaled)
"""예측 결과 10개만 추출"""
test_pred_10 = test_pred[0:10]
len(test_pred_10), test_pred_10
(10,
array([[1.45199849e-07, 7.93101140e-11, 6.97332525e-10, 6.03566477e-08,
2.40284268e-11, 9.09285404e-07, 2.43776638e-10, 3.26200316e-05,
1.92863880e-09, 9.99966264e-01],
[1.41747307e-06, 9.56859808e-13, 9.99956012e-01, 3.77283982e-10,
4.20387114e-05, 3.99349743e-13, 4.66400337e-07, 7.16907228e-11,
1.20789309e-10, 7.70235525e-12],
[1.03377494e-10, 1.00000000e+00, 3.66464498e-10, 7.59104424e-09,
1.28722144e-10, 8.21483554e-15, 1.40686464e-12, 1.26187137e-18,
6.59135507e-12, 2.36610928e-17],
[1.18863701e-08, 9.99999881e-01, 1.22996835e-09, 4.74561936e-08,
5.74258330e-08, 1.11506312e-12, 2.09339504e-10, 2.38901887e-17,
6.73742702e-12, 1.69071673e-14],
[6.11671694e-02, 1.94290877e-07, 2.51566619e-03, 4.19271877e-04,
1.53910602e-03, 9.31109412e-07, 9.34357226e-01, 4.62401104e-08,
2.24246762e-07, 1.30901743e-08],
[2.45150122e-10, 1.00000000e+00, 8.31993863e-10, 6.22483315e-11,
4.20519002e-11, 1.17871167e-13, 2.83125764e-13, 2.35233752e-19,
2.70576409e-11, 3.99504165e-18],
[1.54505869e-05, 2.95058888e-09, 7.71999508e-02, 6.81573287e-09,
9.22689617e-01, 1.39609557e-09, 9.50211906e-05, 6.20762400e-11,
4.74907003e-10, 2.33394665e-10],
[8.38937740e-06, 2.22202026e-08, 1.25062594e-04, 5.82211305e-06,
1.28208101e-02, 1.70984862e-07, 9.87039387e-01, 3.63273500e-09,
3.28636588e-07, 2.77321384e-08],
[3.24827511e-06, 2.93293478e-08, 1.14028808e-07, 1.47327093e-08,
4.34307310e-07, 9.99812901e-01, 2.21275656e-07, 1.54532128e-04,
2.84388461e-05, 9.22231322e-08],
[7.14366948e-08, 5.17943577e-10, 5.18394572e-09, 4.09034158e-08,
1.67608361e-09, 5.75658952e-08, 2.03331629e-10, 9.99998331e-01,
6.58265720e-10, 1.52245400e-06]], dtype=float32))
"""각 데이터별로 최대값의 인덱스만 추출하기"""
test_preds_max_idx = [np.argmax(pred) for pred in test_pred_10]
print(test_preds_max_idx)
[9, 2, 1, 1, 6, 1, 4, 6, 5, 7]
"""예측 결과 10개만 출력하기"""
for i in range(0, 10, 1):
plt.figure(figsize=(2, 2))
"""이미지로 표현하기 위해 2차원으로 변환"""
plt.imshow(test_scaled[i].reshape(28, 28), cmap="gray_r")
plt.show()
"""실제값과 예측결과값 비교를 위해 출력하기"""
print(f"실제값[{test_target[i]} / {classes[test_target[i]]}]")
print(f"예측값[{test_preds_max_idx[i]} / {classes[test_preds_max_idx[i]]}]")
'인공지능 > 딥러닝' 카테고리의 다른 글
[YOLO] YOLO 설치 및 객체탐지 Image사용 (1) | 2024.01.10 |
---|---|
[머신러닝 + 딥러닝] 에너지 사용 패턴 확인을 통한 부하 타입 분류 실습해보기 (0) | 2024.01.10 |
[딥러닝DL] RNN응용 규칙기반 챗봇 (0) | 2024.01.08 |
[딥러닝DL] 순환신경망(RNN) - 장기기억 순환신경망(LSTM), 게이트웨이 반복 순환신경망(GRU) (3) | 2024.01.08 |
[딥러닝DL] DNN 분류데이터사용 (1) | 2024.01.05 |