09_DL(Deep_Learning)

03_다층 인공신경망

chuuvelop 2025. 4. 18. 17:52
728x90
다층 인공신경망

 

 

from tensorflow import keras
from sklearn.model_selection import train_test_split
(x_train, y_train), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()

 

데이터 전처리

  • 픽셀값을 0 ~ 1 사이로 스케일링
  • 2차원 배열을 1차원 배열로 변환
  • 훈련, 검증 나누기
scaled_train = x_train / 255
scaled_train = scaled_train.reshape(-1, 28 * 28)

 

scaled_train.shape
(60000, 784)

 

scaled_train, scaled_val, y_train, y_val = train_test_split(scaled_train, y_train, test_size = 0.2,
                                                            stratify = y_train, random_state = 26)

 

scaled_train.shape, scaled_val.shape
((48000, 784), (12000, 784))

 

 

 

심층신경망 구성

  • 인공 신경망에 층을 추가한 구조

 

 

  • 단층 신경망과의 차이는 입력층과 출력층 사이에 밀집층이 추가된 것
    • 입력층과 출력층 사이에 있는 모든 층을 은닉층(hidden layer)라고 부름

 

 

 

  • 활성화 함수(activation function)
    • 활성화 함수를 쓰는 이유
      • 예) a * 4 + 2 = b
      • b * 3 - 5 = c
      • 위 2개의 식은 a * 12 + 1 = c 로 단순화가 가능
    • 은닉층이 선형적인 산술계산만 한다면 층이 깊어지더라도 계산식이 단순화되어 학습 효율이 떨어짐
      • 따라서 활성화함수로 선형계산을 비선형 계산으로 비틀어주는 과정이 필요
  • 출력층에 적용하는 활성화 함수와 은닉층에 적용하는 활성화 함수는 차이가 있음
    • 출력층의 활성화 함수
      • 출력층 함수라고도 부름
      • 결과물을 적절한 형식으로 출력하도록 유도해서, 데이터셋과 잘 비교할 수 있도록 하는 역할
      • 종류에 제한이 있음(이진분류: 시그모이드, 다중분류: 소프트맥스)
    • 은닉층의 활성화 함수
      • 여러 겹의 layer들 사이에서 사용됨
      • 출력층 함수에 비해 선택이 자유로움
      • 대포적인 활성화 함수: ReLU(렐루)
      • 모든 신경망의 은닉층에는 항상 활성화 함수가 있음

 

len(np.unique(y_train))
10

 

 

# 입력층 - 784개의 특징값
inputs = keras.Input(shape = (784, ))

# 은닉층 - 은닉층의 개수는 데이터의 형태에 맞추지 않아도 됨
dense1 = keras.layers.Dense(100, activation = "sigmoid") # sigmoid: 값을 0~1사이의 값으로 설정해줌

# 출력층 - 범주가 10개
dense2 = keras.layers.Dense(10, activation = "softmax")
  • dense1
    • 은닉층
    • 100개의 유닛을 가진 밀집층
      • 유닛 개수를 정하는 것은 특별한 기준이 없음
      • 다만 출력층의 유닛보다는 많게 설정하는 것을 추천
        • 은닉층의 유닛이 출력층보다 적다면 전달되는 정보량이 부족해질 수 있음
    • 활성화 함수는 시그모이드
  • dense2
    • 10개의 클래스로 분류하므로 10개의 유닛
    • 다중 분류이기 때문에 활성화 함수는 소프트맥스

 

model = keras.Sequential()
  • 가장 처음 등장하는 입력층부터 마지막 출력층까지 순서대로 추가해야함

 

model.add(inputs)
model.add(dense1)
model.add(dense2)

 

model.summary()

 

 

  • 모델 요약 정보
    • 모델에 포함된 층들이 순서대로 나열됨
      • 첫 은닉층부터 출력층까지
    • 층마다 이름, 클래스, 출력 크기, 파라미터 개수가 나옴
      • 이름
        • 층을 만들 때 name 매개변수로 지정 가능(다른 층과 구분하기 위해 이름을 지정)
        • 지정하지 않으면 기본값 "dense"
    • Output Shape
      • 출력 크기
      • (None, 100)
        • 첫 번째 차원은 샘플의 개수를 의미
        • 샘플의 개수가 None인 이유는 한 번에 몇 개의 이미지씩 사용할 지 알 수 없기 때문에 어떤 배치 크기에도 유연하게 대응할 수 있도록 None으로 설정
          • 케라스는 기본적으로 미니배치 경사하강법을 사용
          • batch_size를 설정하지 않으면 기본값 32(48000/1500)
        • 두 번째 차원은 출력 개수
          • 100개의 유닛에서 결과가 나오기 때문에 출력개수가 100
          • 즉, 각 이미지마다 784개의 픽셀값이 은닉층을 통과하면서 100개의 특성으로 압축됨
      • Param
        • 모델 파라미터 개수
        • dense층
          • 784픽셀의 입력값과 100개의 유닛의 모든 조합에 대한 가중치 + 각 유닛의 절편 1개씩
            • 784 * 100 + 100 = 78500
        • dense_1층
          • 앞 은닉층의 100개의 유닛과 10개의 출력층 유닛의 모든 조합에 대한 가중치 + 각 유닛의 절편 1개씩
            • 100 * 10 + 10 = 1010
      • Non-trainable params
        • 훈련되지 않은 파라미터
        • 경사하강법으로 훈련되지 않는 파라미터를 가진 층이 있다면 여기에 표시됨

 

 

층을 추가하는 다른 방법

model = keras.Sequential([
    keras.Input(shape = (784,)),
    keras.layers.Dense(100, activation = "sigmoid", name = "hidden"),
    keras.layers.Dense(10, activation = "softmax", name = "output")
], name = "Fashion_MNIST_model")

 

model.summary()

 

  • 여러 모델과 많은 층을 사용할 때 구분을 위해서 name 매개변수를 사용

 

 

모델 훈련

y_train[:5]
array([5, 3, 5, 7, 8], dtype=uint8)

 

 

model.compile(loss = "sparse_categorical_crossentropy", metrics = ["accuracy"])
model.fit(scaled_train, y_train, epochs = 5, batch_size = 32)

 

  • 은닉층의 추가로 훈련 세트에 대한 성능이 향상됨

 

 

 

시그모이드

 

  • 초창기 인공신경망의 은닉층에서 많이 사용된 활성화 함수는 시그모이드
  • 입력값이 아무리 크더라도 0 ~ 1 사이의 값으로 출력되어 출력값의 범위가 너무 좁음
    • 경사하강법 수행 시에 기울기가 0에 수렴하는 기울기 소실(Gradient Vanishing)이 발생할 수 있음
    • 층이 많아지고 모델이 복잡해질수록 그 효과가 누적되어 더욱 학습을 어렵게 만듦

 

 

렐루 함수(ReLU)

  • 입력이 양수일 경우 마치 활성화 함수가 없는 것처럼 그냥 입력을 통과시키고, 음수일 경우에는 0이 됨
  • 표현식 : max(0, z)

 

 

Flatten

  • 지금까지는 패션 MNIST 데이터가 28 * 28 크기이기 때문에 인공신경망에 주입하기 전에 reshape를 이용하여 1차원으로 펼쳤음
  • 같은 기능을 위해서 케라스에서는 Flatten 층을 제공함
    • 샘플의 개수 차원을 제외하고 나머지 모든 입력 차원을 일렬로 펼쳐주는 역할
    • 가중치나 절편이 없음
    • 하지만 입력층과 은닉층 사이에 추가하기 때문에 편의상 층이라고 부르지만 신경망의 깊이가 깊어진 것으로 보지 않음

 

model = keras.Sequential()
model.add(keras.Input(shape = (28, 28)))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(100, activation = "relu"))
model.add(keras.layers.Dense(10, activation = "softmax"))

 

model.summary()

 

  • Flatten 층의 파라미터는 0
  • Flatten 층을 추가하면 입력값의 차원을 짐작할 수 있다는 것이 장점
    • 784개의 입력이 첫 번째 은닉층에 전달된다는 것이 명확하게 드러남
  • 입력 데이터에 대한 전처리 과정을 가능한 한 모델에 포함시키는 것이 케라스 API의 철학 중 하나

 

 

새 모델을 위한 데이터를 다시 준비

(x_train, y_train), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()
scaled_train = x_train / 255
# Flatten을 했으므로 reshape가 필요 없음 -> reshape없이도 학습이 잘 진행됨
scaled_train, scaled_val, y_train, y_val = train_test_split(scaled_train, y_train, test_size = 0.2,
                                                            stratify = y_train, random_state = 26)

 

scaled_train.shape
(48000, 28, 28)

 

 

model.compile(loss = "sparse_categorical_crossentropy", metrics = ["accuracy"])

 

model.fit(scaled_train, y_train, epochs = 5, batch_size = 32)

 

 

# 모델 검증
model.evaluate(scaled_val, y_val)

[0.3593044579029083, 0.8735833168029785]

 

 

 

딥러닝의 하이퍼파라미터

  • 하이퍼파라미터 : 모델이 학습하지 않아 사람이 지정해줘야하는 파라미터
  • 인공신경망에서 하이퍼파라미터의 종류
    • 은닉층의 개수
    • 은닉층의 유닛 개수
    • 활성화 함수
    • 층의 종류
      • 밀집층, CNN, RNN
    • 미니배치 크기(batch_size)
    • 반복 횟수(epochs)
    • 옵티마이저(optimizer)
    • 옵티마이저의 학습률

 

 

옵티마이저

  • 케라스에서는 기본적으로 경사하강법 알고리즘(RMSprop)을 사용
  • 이 외에도 다양한 경사하강법 알고리즘을 제공하고, 이를 옵티마이저라고 부름

 

 

# sgd 옵티마이저를 사용하려면
sgd = keras.optimizers.SGD()
model.compile(optimizer = sgd, loss = "sparse_categorical_crossentropy", metrics = ["accuracy"])

 

# 위와 동일한 코드
# ("sgd"로 설정해주면 기본값으로 객체를 자동 생성해줌)
# 원래는 위의 코드처럼 각각의 클래스 객체를 만들어서 사용하는 것이 정석
# 번거로움을 피하기 위해 "sgd"라고 입력하면 자동으로 SGD클래스 객체를 생성해줌
model.compile(optimizer = "sgd", loss = "sparse_categorical_crossentropy", metrics = ["accuracy"])

 

# 옵티마이저의 학습률을 조절하고 싶다면
sgd = keras.optimizers.SGD(learning_rate = 0.1)

 

 

옵티마이저의 종류

  • Momentum
    • SGD 클래스에서 momentum 기본값은 0
    • momentum을 0보다 큰 값으로 지정하면 모멘텀 최적화(momentum optimization)을 사용
    • 일반적으로 momentum 매개변수는 0.9 이상을 지정
  • NAG(Nesterov Accelerated Gradient)
    • SGD 클래스의 nesterov 매개변수를 기본값 False에서 True로 바꾸면 네스테로프 모멘텀 최적화를 사용할 수 있음
    • 대부분의 경우 네스테로프 모멘텀 최적화가 기본 경사하강법 보다는 더 나은 성능을 제공

 

 

# 네스테로프 모멘텀 최적화
nag = keras.optimizers.SGD(momentum = 0.9, nesterov = True)

 

  • 적응적 학습률(adaptive learning rate)
    • 모델이 최적점에 가까이 갈수록 학습률을 낮춤
      • 안정적으로 최적점에 수렴할 가능성이 높음
    • 적응적 학습률을 사용하는 대표적인 옵티마이저
      • Adagrad, RMSProp
# Adagrad
adagrad = keras.optimizers.Adagrad()

# RMSprop
rmsprop = keras.optimizers.RMSprop()

 

model.compile(optimizer = rmsprop, loss = "sparse_categorical_crossentropy", metrics = ["accuracy"])

 

  • 위의 모멘텀 최적화와 적응적 학습률을 접목한 것이 Adam
    • 기본적으로 가장 많이 쓰이는 옵티마이저

 

model = keras.Sequential()
model.add(keras.Input(shape = (28, 28)))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(100, activation = "relu"))
model.add(keras.layers.Dense(10, activation = "softmax"))

 

model.summary()

 

 

model.compile(optimizer = "adam", loss = "sparse_categorical_crossentropy", metrics = ["accuracy"])

 

model.fit(scaled_train, y_train, epochs = 5, batch_size = 32)

 

 

model.evaluate(scaled_val, y_val)

[0.3450092077255249, 0.8745833039283752]
728x90