본문 바로가기
[파이썬]/딥러닝

[딥러닝] 인공신경망(ANN) 개념 및 모델 구축+성능 개선(계층 추가)

by sung min_Kim 2024. 1. 4.


 이번 글에서는 딥러닝의 핵심 요소 중 하나인 "인공신경망(ANN) 개념 및 모델 생성과 더불어 성능 개선(계층 추가)"에 대한 방법들을 살펴보려 한다.
차례와 사용 툴 및 라이브러리는 아래와 같다.

 [차례]
첫 번째, 인공신경망이란
두 번째, 인공신경망 모델 구축

세 번째, 인공신경망 모델 성능 개선

 [사용 툴]

- Jupyter notebook(웹 기반 대화형 코딩 환경)
 
 [사용 라이브러리 및 모듈]

  • 연산 라이브러리: numpy

  • 시각화 라이브러리 및 모듈: matplotlib의 pyplot 모듈

  • 머신러닝 라이브러리 및 모델: scikit-learn
    - sklearn.model_selection.train_test_split: 훈련 및 테스트 데이터 세트 분리

  • 딥러닝 라이브러리 및 모델: TensorFlow
    - tensorflow.keras: 사용자 친화적 인터페이스를 제공하는 TensorFlow의 고수준 API

 


인공신경망(Artificial Neural Network, ANN)


 인공신경망은 복잡한 연산을 수행하는 컴퓨터 알고리즘이다. 이 알고리즘은 다양한 층(layer)으로 구성되며, 각 층은 데이터에서 복잡한 패턴과 관계를 학습하는 뉴런(특성)으로 이루어져 있다.

인공신경망 (출처: 위키백과)


 인공신경망은 입력층(Input Layer), 은닉층(Hidden Layer), 그리고 출력층(Output Layer)이라는 세 가지 주요 층으로 구성된다. '입력층'은 데이터를 모델로 입력하는 첫 번째 단계로, 여기서부터 데이터의 처리가 시작된다. '은닉층'은 모델의 내부층으로, 여러 개가 존재할 수 있으며 입력 데이터에서 복잡한 특징을 추출하는 데 핵심적인 역할을 한다. 각 은닉층은 데이터를 더 높은 수준의 추상적 정보로 변환한다. 마지막으로, '출력층'은 모델이 최종적으로 예측하거나 분류하는 결과를 출력하는 단계이다.

 이런 계층적 구조를 통해 인공신경망은 간단한 패턴부터 복잡한 패턴까지 다양한 수준의 데이터를 학습할 수 있다. 학습 과정에서는 손실 함수(loss)를 사용하여 예측이 얼마나 잘못됐는지를 측정하고, 이를 최소화하기 위해 잘못된 부분을 되돌아보며 수정해나가는 방법을 사용하여 각 단계의 가중치를 조정한다. 이 과정은 모델이 데이터를 더 잘 이해하고 예측할 수 있도록 만들어 준다.

 데이터는 모델을 훈련시키는 동안 각 층을 통과하며, 각 뉴런(특성)은 입력 데이터에 포함된 중요한 특성을 추출한다. 이 때, 뉴런(특성)들은 가중치를 조정하며 학습하고, 이 가중치는 각 입력 신호가 결과에 미치는 영향을 조절한다. 또한, 활성화 함수(activation function)를 통해 뉴런(특성)의 출력 신호를 결정하며, 이는 다음 층으로 전달된다.

 인공신경망의 각 층에서는 활성화 함수를 통해 뉴런(특성)의 출력이 다음 층으로 전달되기 전에 비선형 변환을 거친다. 이 비선형 변환은 모델이 복잡한 문제를 해결하는 능력을 부여한다.

 인공신경망은 이런 구조와 메커니즘을 통해 데이터 내의 복잡한 구조와 패턴을 모델링하며, 이를 통해 다양한 실세계 문제에 대한 강력한 예측 도구를 제공한다. 그러므로, 인공신경망은 그 유연성강력한 학습 능력으로 인해 복잡한 데이터 구조를 학습하고, 새로운 데이터에 대해 잘 작동할 수 있는 일반화 능력을 가지고 있어, 다양한 분야에서 실용적인 솔루션을 제공하는 중요한 도구이다. 


인공신경망 모델 구축

 

1. 라이브러리 정의 및 데이터 수집
1.1 라이브러리 정의


 딥러닝의 인공신경망을 모델링하기 위해 'tensorflow', 'keras' 라이브러리를 호출한다. 또한, 결과의 일관성을 보장하기 위해 난수 시드를 설정하고, 연산 고정 옵션을 활성화한다. 이를 통해, 모델의 훈련 과정이나 결과를 다른 실무자들이 재현할 수 있도록 도와준다. 이는 실제 서비스 환경에서도 중요한 요소이다.

import tensorflow as tf
from tensorflow import keras

# 실행 결과의 일관성을 위한 난수 시드 설정
tf.keras.utils.set_random_seed(42)

# 연산의 결정성을 확보하기 위한 연산 고정 처리
tf.config.experimental.enable_op_determinism()

import matplotlib.pyplot as plt
import numpy as np

from sklearn.model_selection import train_test_split

 

1.2 데이터 수집


 keras 라이브러리에서 제공하는 'fashion_mnist' 패션 데이터셋을 로드하면, 훈련 데이터셋(train_input, train_target)과 테스트 데이터셋(test_input, test_target)이 튜플 형태로 반환된다.

 이 데이터셋은 픽셀 값으로 구성된 3차원 이미지 배열을 포함하고 있으며, 여기서 3차원 배열은 색상, 이미지의 높이, 너비를 의미한다. 픽셀값은 0부터 255 사이의 정수로, 총 256개의 다른 색상 값을 나타내며, 이는 이미지의 밝기 또는 그레이스케일 값을 나타낸다.

 따라서, 훈련 및 테스트 데이터셋의 독립변수는 3차원 배열의 픽셀 데이터를, 종속변수는 1차원 배열의 이미지 데이터의 레이블(옷의 종류를 나타내는 정수)을 담게 된다.

(train_input, train_target), (test_inpurt, test_target) = keras.datasets.fashion_mnist.load_data()

print(train_input.shape, train_target.shape)
print(test_inpurt.shape, test_target.shape)

훈련 및 테스트 독립변수

 

2. 데이터 전처리
2.1 데이터 시각화


 서브플롯을 활용해 훈련 데이터셋에 포함된 첫 10개의 이미지를 시각화함으로써, 데이터셋이 어떠한 정보를 담고 있는지를 확인한다. 각 서브플롯은 imshow 함수를 사용하여 픽셀 데이터를 그레이스케일 이미지로 변환하고, 축을 숨겨 이미지만 강조하여 표시한다.

# 서브플롯 - 이미지 10개를 하나로 시각화
fig, axs = plt.subplots(1, 10, figsize=(10, 10))

# 훈련데이터 10개에 대한 처리
for i in range(10) :
    
    # - 픽셀 데이터를 이미지로 시각화
    axs[i].imshow(train_input[i], cmap="gray_r")
    
    # - x, y 좌표계 숨기기
    axs[i].axis("off")

픽셀데이터를 이미지로 시각화

 

2.2 범주별 이미지 데이터 분포 확인


 'np.unique' 함수를 활용하여 훈련 데이터셋의 각 종속변수(또는 범주)에 속하는 패션 아이템의 유형과 그 개수를 확인할 수 있다. 'return_counts=True' 옵션을 설정함으로써, 함수는 데이터셋 내 각 범주별로, 예를 들어 티셔츠나 바지 등, 동일하게 6천 개씩의 이미지가 포함되어 있는지의 빈도수를 반환해 준다. 이를 통해 데이터셋이 각 패션 아이템에 대해 균일한 분포를 가지고 있음을 확인할 수 있다.

np.unique(train_target, return_counts=True)

범주별 이미지 데이터 분포

 

2.3 데이터 스케일링


 픽셀 데이터는 0에서 255까지의 큰 범위폭을 갖는 값을 가지고 있기 때문에, 모델이 이를 효과적으로 처리할 수 있도록 최소값과 최대값 사이를 0과 1 사이로 압축하는 데이터 스케일링(일반화) 과정이 필요하다. 이 작업은 전용 라이브러리 함수를 사용하거나, 단순히 모든 픽셀 값을 '255'로 나누는 산술 연산을 통해 수행할 수 있으며, 여기서는 후자의 방법을 사용하여 데이터를 스케일링할 예정이다.

train_input[0]

값의 범위: 0~255

 

# - 훈련 데이터 스케일링
train_scaled_255 = train_input / 255.0
train_scaled_255[0]

# - 테스트 데이터 스케일링
test_sclaed_255 = test_inpurt / 255.0
test_sclaed_255[0]

np.unique(train_scaled_255)

데이터 스케일링(일반화)


 모든 픽셀 값을 최대 픽셀 값인 '255'로 나눔으로써, 훈련 및 테스트 데이터의 독립변수(픽셀 데이터)를 0과 1 사이의 범위로 스케일링하였다.

2.4 데이터의 차원 변환


 모델 훈련을 위해 3차원으로 정규화된 픽셀 데이터를 2차원으로 변환한다. 이 과정에서 이미지의 너비(28)와 높이(28)를 곱하여 각 이미지를 '784' 개의 픽셀 값을 갖는 1차원 배열로 재구성하고, 이를 전체 데이터에 적용하여 3차원 배열을 2차원 배열로 변환한다.

train_input.reshape(-1, 28*28)

2차원 배열로 변환

 

2.5 데이터 분리


 앞서 'fashion_mnist' 패션 데이터셋을 훈련 데이터와 테스트 데이터로 분리하였고, 이후에는 훈련 데이터를 다시 8:2 비율로 나누어 추가적으로 검증 데이터셋을 생성한다. 이렇게 분할함으로써, 모델을 평가하고 조정하는 과정에서 검증 데이터셋을 사용할 수 있게 된다.

train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled_2d, train_target,
                                                                      test_size=0.2,
                                                                      random_state=42)
print(train_scaled.shape, train_target.shape)
print(val_scaled.shape, val_target.shape)

훈련 및 검증 데이터

3. 인공신경망 계층 생성


 인공신경망은 여러 층(layer)으로 구성된 계층 구조 모델이다. 기본적인 층인 'Dense'는 모델에 추가되어 데이터를 학습하는 데 사용된다.

1) 딥러닝 용어 설명

  • 특성: '뉴런'이라고도 하며, 데이터의 개별 요소를 의미한다.

  • 크기: 층에 있는 뉴런의 수를 나타낸다.

 

2) 딥러닝에서 사용되는 숫자 범위

  • 숫자 범위는 주로 '16'에서 '512' 사이이며, 이미지의 높이와 너비를 나타내는 경우 '3x3' 또는 '5x5'를 사용한다.

 

3) 모델 설정

  • units: 층의 출력 크기를 결정하며, 출력 계층에서는 종속변수의 범주 수를 설정한다.

  • kernel_initializer: 모델 가중치의 초기값 설정 방법으로, 'unifrom(균일 분포)' 또는 'normal(정규 분포)'이 있다. 여기서 '가중치'란 모델이 훈련을 반복하는 과정에서 손실을 최소화하기 위해 스스로 조정하는 값을 의미한다.

  • activation: 활성화 함수는 신경망 층의 뉴런(특성)이 받은 입력을 적절한 출력으로 변환하는 규칙이다. 회귀 문제에서는 주로 'linear' 함수를 사용해 출력을 직선적으로 모델링하며, 분류 문제에서는 'sigmoid', 'softmax', 'relu', 'leaky relu', 'tanh'과 같은 함수들을 사용하여 입력을 범주의 확률로 변환한다. 이진 분류에서는 'sigmoid'가 일반적이지만, 'relu', 'leaky relu', 'tanh'도 사용될 수 있으며, 다중 분류 문제에서는 'softmax'가 적합하다. 입력 계층과 은닉 계층에서는 회귀와 분류 문제에 사용되는 활성화 함수들을 모두 사용할 수 있다.

 

dense = keras.layers.Dense(
    units=10, 
    kernel_initializer="uniform",
    activation="softmax",
    input_shape=(784, )
)
dense

계층(layer) 생성

 

4. 인공신경망 모델 구축


 keras 라이브러리의 'Sequential' 함수를 사용하여, 위에서 정의한 Dense 계층(dense)을 모델에 추가함으로써 인공신경망 모델(model)을 구축한다.

model = keras.Sequential(dense)
model

신경망 구축

 

5. 인공신경망 모델 설정


  모델을 설정(compile)하는 단계에서는 손실 함수(loss)를 설정해야 한다. 손실 함수는 모델이 얼마나 잘 예측하고 있는지를 측정하는 지표로, 훈련 동안 이 값을 최소화하는 것이 모델의 목표이다.

  • categorical_crossentropy: 원-핫 인코딩 된 레이블이 있는 다중 분류 문제에 사용된다. 예를 들어, 레이블이 [0, 1, 0]과 같이 주어질 때 적합하다.

  • sparse_categorical_crossentropy: 레이블이 정수 형태로 주어진 다중 분류 문제에 사용된다. 예를 들어, 레이블이 0, 1, 2와 같이 주어질 때 적합하다.

  • binary_crossentropy: 두 개의 클래스를 가진 이진 분류 문제에 사용된다. 예를 들어, 레이블이 0 또는 1로 주어질 때 적합하다.

 또한, 모델의 성능을 평가하는 지표로 'metrics'를 설정한다. 여기서 'accuracy'는 '정확도'로, 모델이 얼마나 많은 비율로 정확한 예측을 하는지를 나타낸다.

model.compile(
    # - 손실율을 측정하는 함수
    loss="sparse_categorical_crossentropy",
    # - 훈련 과정에서 정확도 추적
    metrics="accuracy"
)

 

6. 인공신경망 모델 학습


 모델을 학습(훈련)시키기 위해 fit 함수를 사용하며, 여기서 'epochs'는 모델이 전체 훈련 데이터셋을 사용하여 학습을 반복하는 횟수를 의미한다. 예를 들어 'epochs=10'은 훈련 데이터셋을 10번 반복 및 사용하여 모델을 훈련시키겠다는 의미로, 각 반복마다 손실 함수가 계산하는 손실률을 점차 줄여나가며 모델의 성능을 개선한다.

model.fit(train_scaled, train_target, epochs=10)

모델 학습 - 손실율(loss) 감소 목적

 

7. 인공신경망 모델 성능 평가


 모델의 성능을 평가(검증) 하기 위해, evaluate 함수를 사용하여 검증 데이터셋(val_scaled, val_target)으로 모델을 평가(검증)한다. 만약 모델이 훈련 과정에서 발생한 손실률(loss)이 '0.4200'이고, 정확도(accuracy)가 '0.8632'이라고 가정해 보면, 이 수치들을 검증 데이터셋의 결과와 비교해 볼 때 유사하거나 더 좋으면, 모델이 새로운 데이터에 대해서도 잘 작동할 것으로 보고 과적합 없이 잘 학습되었다고 볼 수 있다.

score = model.evaluate(val_scaled, val_target)
score

모델 성능 검증

 

8. 인공신경망 모델의 구조 확인


 summary 함수를 사용하여, 학습된 모델에 포함된 계층들과 각 계층의 세부 사항을 확인할 수 있다. 이는 모델의 구조를 이해하고 각 계층에서 파라미터들이 어떻게 구성되어 있는지를 파악하는 데 도움 된다.

 아래 표의 'output shape'는 출력 크기 또는 개수(10개)를 나타내며, 'Param'은 각 Dense 계층의 파라미터, 즉 모델이 학습하는 동안 조정해야 하는 가중치와 편향의 총 수를 나타낸다. 이는 입력 데이터의 각 특성에 할당된 가중치와 각 뉴런의 편향 값을 포함한다. 즉, 모델의 각 계층에서 파라미터의 수는 그 계층의 입력 특성 수에 따라 결정되며, 계산식은 '(입력 특성의 크기 + 1) x 출력 특성의 크기'로 파악할 수 있다. 여기서 '+1'은 각 출력 특성에 대한 편향(bias)을 위한 파라미터를 포함하는 것을 의미한다.


 예를 들어, 입력 특성이 784개이고 출력 특성이 10개인 계층에서, 총 파라미터 수는 7850개가 된다. 

model.summary()

모델에 사용된 계층 확인

 


인공신경망 모델 성능 개선


 모델의 성능을 개선하기 위한 방법으로는 데이터양 증가, 하이퍼파라메터 튜닝, 계층 추가 등이 있으며, 이 중에서 계층을 추가하여 모델을 개선하는 방법을 사용하려 한다.

1. 은닉계층(Hidden Layer) 추가하기


 Dense라는 새로운 계층을 모델에 추가하면서, 이 계층에 10개의 뉴런(특성)을 할당하고, 'relu'라는 활성화 함수를 적용하여 비선형적 특성을 모델에 적용한다. 또한, 'kernel_initializer="uniform"'을 사용하여 계층의 가중치를 균일하게 초기화한다. 'input_shape(784,)'는 이 계층이 받아들일 입력 데이터의 형태를 정의하는데, 여기서는 784개의 픽셀 값을 가진 1차원 배열을 입력으로 받는다.

model.add(
    keras.layers.Dense(
        # - units 파라메터명은 생략 가능
        10, kernel_initializer="uniform",
        activation="relu",
        input_shape=(784, )
    )
)

 

2. (계층 추가 후) 모델 재훈련


 추가된 은닉 계층을 포함하여 모델을 다시 훈련시킨 결과, 새로운 구조의 모델은 이전보다 낮은 손실률(loss)을 기록했으며, 정확도 또한 약간 향상되었다. 이는 추가된 계층이 모델 성능 개선에 긍정적인 영향을 미쳤음을 나타낸다.

model.fit(train_scaled, train_target, epochs=10)

# 계층 추가 전, loss: 0.4200 - accuracy: 0.8632

모델 재훈련

 

3. (계층 추가 후)모델 성능 재평가


 계층을 추가한 후 모델을 검증 데이터셋에 대해 다시 평가한 결과, 손실률(loss)은 약간 증가했지만(0.008 정도), 정확도(accuracy)는 소폭 상승(0.002) 했다. 이는 모델이 전반적으로 안정적인 성능을 유지하면서도 약간의 정확도 개선을 이루었음을 의미한다.

model.evaluate(val_scaled, val_target)

# 계층 추가 전, [0.44187089800834656, 0.8520833253860474]

모델 재평가

 

4.  (계층 추가 후) 모델 구조 재확인


 계층을 추가한 후 모델의 구조를 summary 함수를 통해 다시 살펴보면, 입력 계층에서 정의된 출력 특성의 크기(10개)가 은닉 계층의 입력으로 전달되어 모델이 이에 맞추어 재훈련된다. 이 과정을 통해 각 계층의 연결성과 모델이 학습해야 할 파라미터의 총 수(110개)를 파악할 수 있다.

model.summary()