728x90
반응형

합성곱신경망(CNN)

📍 합성곱신경망(CNN, Convolutional Neural Network)
- 이미지 분석에 주로 사용되는 대표적 계층
- 기존의 인공신경망에서의 이미지 분석시에는 높이와 너비를 곱한 1차원을 사용하였다면 CNN은 원형 그대로의 높이와 너비 차원을 사용함
- 전체 4차원의 데이터를 사용함

- 기존 이미지 분석 시 높이와 너비를 곱하여 사용하다보면, 원형 그대로의 주변 이미지 공간 정보를 활용하지 못하는 단점이 있으며, 이러한 이유로 특징 추출을 잘 못하여, 학습이 잘 이루어지지 않는 경우가 발생함

- 이러한 기존 인공신경망 모델의 단점을 보완하여 만들어진 모델이 CNN임
       * 원형 형태의 이미지 정보를 그대로 유지한 상태로 학습 가능하도록 만들어졌음
       * 이미지의 공간정보를 이용하여 특징을 추출함
       * 인접 이미지의 특징을 포함하여 훈련됨

📍 합성곱 신경망(CNN)의 계층 구조
1. 입력 계층(Input_Layor)
- 데이터 입력 계층 (기존과 동일)
2. 합성곱 계층(Convolutional Layor, CNN 계층)
- 이미지의 특징을 추출하는 합성곱 계층이 여러층으로 구성되어 있음
3. 활성화 함수 계층 (은닉계층, Actiation 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​
  • 패션 이미지 데이터 읽어들이기
    (train_input, train_target), (test_train, test_target) = keras.datasets.fashion_mnist.load_data()
    print(train_input.shape, train_target.shape)
    print(test_train.shape, test_target.shape)
  • 차원 변경
    - CNN에서 사용하는 차원은 4차원
    - (행, 높이, 너비, 채널)
    - 채널 = 1 또는 3 (1은 흑백, 3은 컬러(RGB) 라고 보통 칭한다.)
    train_input_4d = train_input.reshape(-1, 28, 28, 1)
    train_input_4d.shape


  • 정규화
    ''' 픽셀 데이터 정규화 '''
    train_scaled = train_input_4d / 255.0
    train_scaled.shape, train_scaled[1][0]​


  • 훈련 및 검증 데이터로 분리하기 (8 : 2)
    from sklearn.model_selection import train_test_split
    
    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_train.shape, test_target.shape)​

합성곱신경망(CNN) 훈련

  • 모델 생성하기
  • CNN(입력계층으로 추가)
💡 CNN
 - 데이터와 필터(filter)가 곱해진다고 해서 합성곱이라는 단어가 붙었음
 - 이미지와 같은 2차원 데이터 분류에는 보통 2차원 합성곱(Conv2D)이 사용됨
 - 입력 계층으로 사용하는 경우에는 input_shape의 입력 차원 속성을 함께 사용

📍 kernel_size
 - 이미지를 훑으면서 특징을 추출하는 역할을 수행
 - 필터가 사용할 사이즈를 정의함
 - kernel_size=3 > 필터가 사용할 사이즈 3행 3열을 의미함(3 X 3을 줄여서 3이라고 칭함)
 - 커널 사이즈는 홀수로 정의함(3, 5가 주로 사용됨)

 📍 filters
 - 커널사이즈의 행렬의 공간 1개에 대한 필터의 갯수 정의
 - 데이터를 훑으면서 특징을 감지함
 - 필터의 값이 클수록 훈련속도가 오래 걸림
 - 보통 32, 64가 주로 사용됨
 - CNN계층을 여러개 사용하는 경우네는 처음 CNN계층에는 작은값부터 시작
     → 16, 32, 64, 128 정도가 주로 사용됨
   
📍 padding
 - 경계 처리 방식을 정의함
 - 입력 데이터의 주변에 추가되는 가상의 공간을 만들 수 있음
 - 처리방식 : same과 valid가 있음
      * same : 패딩을 사용하여 입력과 출력의 크기를 동일하게 만들어서 훈련하고자 할 때 사용
             : 주로 권장되는 방식
      * valid : 패딩을 사용하지 않음을 의미함
  
📍 strides
 - 커널이 이미지 데이터를 훑을 때(특징 추출 시)의 스탭을 정의함
 - 커널이 데이터 특징 추출 순서(행렬을 기준으로)
     → 왼쪽 상단에서 시작하여 오른쪽으로 이동하는 스텝 정의
     → 오른쪽 열을 다 훑고난 다음 아래로 이동하는 스텝 정의
 - strides=1 : 오른쪽으로 1씩 이동, 아래로 1씩 이동을 의미
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칸씩 이동하면서 중요 특징값을 추출하라는 의미(default = 2, 생략가능) 
- 풀링에서 가장 대표적으로 사용되는 방식임
model.add(keras.layers.MaxPool2D(pool_size=2, strides=2))

 

  • CNN계층 추가해보기
    model.add(keras.layers.Conv2D(kernel_size=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"))

  • 생성된 모델 확인
  • 훈련계층 이미지로 시각화해보기
    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)​


  • 모델 설정하기
    model.compile(optimizer="adam",
                  loss="sparse_categorical_crossentropy",
                  metrics="accuracy")

  • 콜백함수 만들기
    ''' 자동저장 '''
    save_path = "./model/best_CNN_Model.h5"
    checkpoint_cb = keras.callbacks.ModelCheckpoint(save_path)
    
    ''' 자동종료 '''
    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, batch_size=64,
              epochs=20,
              validation_data=(val_scaled, val_target),
              callbacks=[checkpoint_cb, early_stopping_cb])
  • 시각화

 

  • 훈련 및 검증데이터 모델 성능 검증결과 확인
    train_eval = model.evaluate(train_scaled, train_target)
    val_eval = model.evaluate(val_scaled, val_target)
    train_eval, val_eval


  • 훈련에 사용된 데이터를 이미지로 그려보기
    val_scaled[0].shape

      이미지 데이터는 2차원으로 줄여서 그려야 한다    
    val_scaled_0 = val_scaled[0].reshape(28, 28)
    val_scaled_0.shape

      이미지 1개 그리기   
    plt.imshow(val_scaled_0, cmap="gray_r")
    plt.show()


      검증데이터 0번째 이미지의 정답 번호는?  
    val_target[0]


  • 예측하기
    - 검증데이터 0번째 데이터를 이용해서 예측해보기
    - 예측결과 값은 모델 출력계층의 출력크기(갯수)만큼 확률값으로 반환해준다.
    - 반환된 확률값 중 가장 큰값의 '인덱스번호'가 종속변수 값이 된다.
    preds = model.predict(val_scaled[0:1])
    preds



      예측 시각화  
    plt.bar(range(10), preds[0])
    plt.xticks(range(10))
    plt.grid()
    plt.show()




  • 범주 지정하여 예측 값 맞는지 확인
    ''' 범주 명칭 '''
    classes = ["티셔츠", "바지", "스웨터", "드레스", "코트", "샌달",
              "셔츠", "스니커즈", "가방", "앵클부츠"]
    
    import numpy as np
    print(np.argmax(preds))
    print("예측값 :", classes[np.argmax(preds)])
    print("실제값 :", classes[val_target[0]])


  • (실습) 테스트 데이터로 최종 예측하기
    - 테스트 데이터를 이용해서 예측한 후, 예측결과 중 10개만 추출하여 실제이미지, 예측값, 실제값을 각각 출력
    ''' 차원 변경 '''
    test_input_4d = test_train.reshape(-1, 28, 28, 1)
    
    ''' 픽셀 데이터 정규화 '''
    test_scaled = test_input_4d / 255.0
    
    for i in range(0, 10, 1):
        test_pred = model.predict(np.expand_dims(test_scaled[i], axis=0))
    
        test_scaled_10 = test_scaled[i].reshape(28, 28)
        plt.imshow(test_scaled_10, cmap="gray_r")
        plt.show()
    
        print("예측값 :", classes[np.argmax(test_pred)])
        print("실제값 :", classes[test_target[i]])

     

    - 강사님 코드
    ''' 차원 변경 '''
    test_input_4d = test_train.reshape(-1, 28, 28, 1)
    
    ''' 픽셀 데이터 정규화 '''
    test_scaled = test_input_4d / 255.0
    
    """예측하기"""
    test_preds = model.predict(test_scaled)
    test_preds[0]
    
    """각 데이터별로 최대값의 인덱스만 추출하기"""
    test_preds_max_idx = [np.argmax(pred) for pred in test_preds]
    print(test_preds_max_idx)
    
    """예측 결과 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]]}]")
728x90
반응형

+ Recent posts