본문 바로가기
컴퓨터공학/AI

인공지능 5. DNN

by Jinger 2024. 4. 19.

서론

   딥러닝 네트워크, 특히 DNN(Deep Neural Networks)의 기본 구조와 작동 원리에 대해 알아보자. 데이터가 네트워크를 통해 어떻게 전파되는지부터, 예측과 실제 값 사이의 차이를 어떻게 학습하는지, 그리고 기울기 손실 및 기울기 폭발 문제에 대한 현대적 해결책까지, DNN의 전반적인 메커니즘을 간략히 살펴보자.


DNN

    DNN는 인간의 뇌의 신경망에서 영감을 받은 인공지능 기술의 핵심이다. 이는 다수의 은닉층(hidden layer)을 포함하여 복잡한 데이터 패턴을 인식하고 학습할 수 있는 능력을 가지고 있다. 이러한 구조는 단순한 패턴 인식뿐만 아니라, 복잡한 추론, 의사결정, 그리고 자연어 처리 같은 고급 기능을 수행할 수 있게 한다.

Deep Network와 Shallow Network

    DNN(Deep Neural Networks, 깊은 학습)과 shallow network(얕은 학습)은 구조적 깊이에서 주요한 차이가 있다. 이러한 차이는 두 네트워크 유형의 학습 능력과 처리할 수 있는 문제의 복잡성에 큰 영향을 미친다.
   우선 구조적 깊이와 복잡성에서 차이가 보인다. DNN은 여러 개의 은닉층을 포함하며, 이 구조적 깊이로 인해 더 복잡한 특징과 패턴을 학습할 수 있습니다. 깊은 네트워크는 데이터에서 저수준 특징부터 고수준 특징까지 점차적으로 추출할 수 있으며, 이는 복잡한 문제 해결에 필수적이다. 그러나 Shallow network는 일반적으로 입력층과 출력층 사이에 하나 또는 소수의 은닉층만을 포함한다. 이로 인해 상대적으로 간단한 패턴과 관계를 학습하는 데 적합하지만, 더 복잡한 문제를 해결하는 데에는 제한적일 수 있다.
   둘째로, 학습 능력과 문제 해결 능력에서 차이가 있다. DNN은 그 구조적 깊이로 인해 복잡한 비선형 관계와 고차원 데이터에서의 추상적인 특징을 학습할 수 있는 능력이 뛰어나다. 예를 들어, 이미지 인식, 음성 인식, 자연어 처리 등 다양한 고난도 문제를 해결하는 데 기여한다. 반면에 Shallow network는 비교적 단순한 구조로 인해 빠른 학습 속도를 보일 수 있지만, 복잡한 데이터 패턴을 추출하고 학습하는 데는 한계가 있다. 따라서 간단한 분류 작업이나 회귀 분석 등 상대적으로 단순한 문제 해결에 주로 사용된다.
   마지막으로 학습 시간과 자원에서 차이가 있다. DNN은 은닉층이 많고 파라미터가 훨씬 더 많기 때문에, 학습에 더 많은 시간과 계산 자원이 필요하다. 또한, 적절한 네트워크 아키텍처 설계, 파라미터 최적화, 과적합 방지를 위한 기술이 중요하다. Shallow network는 구조가 간단하고 파라미터 수가 적어 학습 시간과 필요한 계산 자원이 상대적으로 적다. 이는 빠른 프로토타입 개발이나 간단한 문제 해결에 유리할 수 있다.
    결론적으로, DNN과 shallow network는 각각의 장단점을 가지며, 특정 문제의 복잡성과 요구 사항에 따라 적절한 모델을 선택하는 것이 중요하다. DNN은 복잡한 문제를 해결하는 데 강력한 성능을 발휘할 수 있지만, 그만큼의 자원과 시간이 필요하며, shallow network는 빠르고 효율적인 학습이 가능하지만 처리할 수 있는 문제의 범위에 한계가 있다.

데이터의 전파와 역전파

    데이터의 전파 과정(Forward propagation)입력층에서 시작하여 순차적으로 내부 층을 거쳐 출력층에 도달하는 과정이다. 각 층은 입력 데이터에 대해 가중치와 활성화 함수를 적용한 연산을 수행하며, 그 결과를 다음 층으로 전달한다. 반대로, 역전파(Back propagation)네트워크가 예측한 출력과 실제 목표 값 사이의 차이를 계산하여, 이 손실 함수의 값을 최소화하기 위해 네트워크의 가중치를 업데이트하는 과정이다. 이 과정은 경사 하강법을 통해 이루어지며, 네트워크의 학습 효율을 극대화한다.


 DNN 학습의 핵심 요소

    DNN 학습에서 중요한 요소 중 하나는 기울기 소실 및 폭발 문제이다. 네트워크의 깊이가 증가함에 따라, 역전파 과정에서 기울기가 점점 작아지거나 커지는 문제가 발생할 수 있다. 이를 해결하기 위해 드롭아웃과 배치 정규화 같은 기법이 개발되었으며, 이들은 네트워크의 안정성과 학습 속도를 향상한다.

기울기 손실 문제(Vanishing Gradient)

    기울기 손실 문제 (Vanishing Gradient)신경망을 거치면서 오차 기울기가 점점 작아져서 사라지는 현상을 말한다. 즉, 신경망의 맨 뒤쪽에서 시작된 오차 신호가 앞쪽으로 전파될 때, 기울기가 점점 줄어들어 앞쪽 레이어의 가중치가 거의 업데이트되지 않는 현상이다. 이 현상이 나타나는 이유는 활성화 함수(예: 시그모이드, 하이퍼볼릭 탄젠트)의 특성상 그래디언트의 절댓값이 1보다 작을 때 발생할 수 있다. 이로 인해 신경망이 깊어질수록 그래디언트가 점점 작아지게 도기에 야기된다. 그렇기에 활성화 함수를 ReLU(Rectified Linear Unit) 등 그래디언트 소실 문제에 강한 함수로 바꾸거나, 초기화 방법을 개선하고, LSTM(Long Short-Term Memory)이나 GRU(Gated Recurrent Unit) 같은 구조를 사용하여 해결할 수 있다.

   또 다른 해결 방법으로 Xavier 초기화(또는 Glorot 초기화)가 있다. Xavier 초기화는 신경망의 각 층에서 입력과 출력의 분산이 동일하게 유지되도록 하는 것이다. 이를 통해 신경망을 깊게 쌓았을 때도 각 층을 통과하는 신호가 적절한 크기를 유지할 수 있으므로 기울기 소실이나 폭발 문제를 방지할 수 있다.
   Xavier 초기화 방법

  • 가중치는 평균이 0이고 분산이 `2 / (n_in + n_out)`인 분포에서 무작위로 추출되어 초기화된다. 여기서 `n_in`은 해당 층의 입력 유닛 수, `n_out`은 출력 유닛 수를 나타낸다.
  • 이 초기화 방법은 주로 활성화 함수로 하이퍼볼릭 탄젠트(tanh)나 시그모이드(sigmoid)와 같은 S자 형태의 활성화 함수를 사용할 때 효과적이다.

    Xavier 초기화는 깊은 신경망의 학습을 안정화시키고 가속화하는 데 중요한 역할을 하며, 기울기 소실 문제를 줄이는 데 도움을 준다. 그러나 ReLU 활성화 함수와 같이 다른 유형의 활성화 함수를 사용할 때는 He 초기화(He initialization)와 같은 다른 초기화 기법이 더 적합할 수 있다. 

기울기 폭발 문제(Exploding Gradient)

    기울기 폭발(Exploding Gradient) 오차 기울기가 신경망을 거치면서 점점 커져서, 수치적으로 매우 큰 값이 되어버리는 현상이다. 이는 가중치의 값이 너무 커져서 네트워크가 불안정해지는 상황으로 이어질 수 있다. 해당 션상이 발생하는 원인은 깊은 신경망에서 가중치 값이 크거나 활성화 함수의 그래디언트가 1보다 크게 설정되어 있을 때 발생할 수 있다. 그렇기에 그래디언트 클리핑(Gradient Clipping)을 통해 그래디언트의 크기가 특정 임계값을 넘지 않도록 조정하거나, 적절한 가중치 초기화 방법을 사용해야 한다. 이를 통해 오버 피팅(Overfitting)을 방지할 수 있다.


성능 최적화 전략

    DNN의 성능을 최적화하는 전략은 모델의 일반화 능력을 향상하고, 학습 시간을 단축시키며, 더 나은 결과를 얻기 위해 필수적이다. 드롭아웃과 배치 정규화 외에도, 조기 정지(Early Stopping)는 과적합을 방지하기 위해 학습을 조기에 중단시키는 방법이다. 이러한 기법들은 모델의 복잡성을 관리하고, 학습 과정을 더 효율적으로 만들며, 최종적으로는 더 높은 성능의 모델을 구축하는데 기여한다.

드롭아웃(Dropout)

    드롭아웃(Dropout)은 과적합을 방지하기 위해 학습 과정 중 무작위로 일부 뉴런을 비활성화시키는 기법이다. 이로써 모델의 일반화 능력이 향상된다.

  • 임의로 노드를 삭제하면서 학습하는 방법. 훈련 시 Hidden layer (은닉층)의 노드를 무작위로 삭제.
  • 삭제하는 비율: Hyper-parameter (조절하는 변수) 임.
  • 앙상블 학습 (Ensemble learning): 개별적으로 학습시킨 여러 모델의 출력을 평균 내어 추론

배치 정규화(Batch - Normalization)

    배치 정규화(Batch Normalization)는 각 층의 입력을 정규화하여 학습 과정을 안정화하고 속도를 가속화하는 기법은 학습 과정에서의 효율성을 크게 높인다. 이 방법은 네트워크의 각 층에서 입력의 평균을 0으로, 분산을 1로 조정함으로써 내부 공변량 변화를 줄이는 역할을 한다. 이는 네트워크의 학습이 더욱 안정적으로 이루어지게 하며, 기울기 소실이나 폭발 문제가 발생할 확률을 감소시킨다. 따라서, 모델의 학습 속도가 가속화되고, 학습 과정 중 발생할 수 있는 여러 어려움들을 완화시키는 중요한 역할을 한다.

계산 그래프

     계산 그래프는 복잡한 연산을 시각적으로 표현한 것으로, 노드(node)와 에지(edge)로 구성된다. 여기서 노드는 연산 혹은 변수를, 에지는 연산의 입력 또는 출력을 의미한다. 이러한 구성을 통해 데이터와 그래디언트의 흐름을 명확하게 파악할 수 있으며, 복잡한 미분 과정을 단순화시켜 준다.
    계산 그래프 내에서, 학습 변수인 Affine 변환의 가중치(ω)와 편향(b), 그리고 배치 정규화에서 사용되는 γ와 β의 그래디언트를 계산한다. 예를 들어, Affine 변환 노드에서는 입력 데이터에 대한 가중치의 곱과 편향의 합을 계산한다. 역전파 시, 이 노드를 통과하며 그래디언트를 계산하고, 이를 통해 가중치와 편향의 업데이트가 이루어진다.
    배치 정규화 노드에서도 비슷한 과정을 거치는데, 여기서는 데이터의 분포를 정규화하여 학습 과정을 안정화시키는 역할을 한다. 역전파를 통해 γ와 β의 그래디언트를 계산하고, 이를 업데이트함으로써 학습 과정의 효율성을 높인다.
    계산 그래프는 딥러닝 모델의 학습 과정을 시각적으로 이해하는 데 큰 도움을 준다. 역전파와 체인룰을 이용한 그래디언트의 계산과 학습 변수의 업데이트는 모델의 성능을 개선하는 데 필수적인 과정이다. 이러한 이해를 바탕으로, 우리는 보다 효율적으로 딥러닝 모델을 훈련시킬 수 있다.


배치 학습

데이터 배치 학습하기

    데이터 배치 학습학습 데이터 전체를 하나의 큰 배치로 처리하여 모델을 학습시키는 방식이다. 이 방법은 그래디언트 업데이트를 계산할 때 전체 데이터를 사용하기 때문에, 매우 안정적인 업데이트가 가능하고, 수렴 방향이 명확하다. 하지만, 큰 데이터 세트를 한 번에 메모리에 로드해야 하므로, 메모리 용량에 제한이 있을 경우 처리가 불가능할 수 있다. 또한, 전체 데이터를 사용하여 업데이트를 계산하기 때문에 속도가 느릴 수 있으며, 특히 대용량 데이터셋에서는 이러한 문제가 더욱 심각해질 수 있다.

미니 배치 학습하기

   미니 배치 학습전체 데이터를 작은 배치로 나누어 각 미니 배치에 대해 학습을 수행하는 방식이다. 이 방법은 메모리 요구 사항을 줄이고 학습 속도를 높이는 데 도움이 된다. 각 미니 배치에 대해 그래디언트 업데이트를 수행하기 때문에, 데이터 배치 학습보다 더 빈번한 업데이트가 가능하며, 이는 일반적으로 더 빠른 수렴으로 이어진다. 그러나, 미니 배치의 크기가 너무 작을 경우 그래디언트의 추정이 불안정해질 수 있으며, 이는 학습 과정을 불안정하게 만들 수 있다.

    미니 배치 학습은 메모리 제약과 학습 속도 개선을 위한 효과적인 방법이다. 데이터 배치 학습에 비해 더 유연하며, 대규모 데이터셋에 대한 학습이 가능하다. 미니 배치의 크기는 모델의 성능과 학습 속도에 중요한 요소이므로, 적절한 크기를 선택하는 것이 중요하다. 일반적으로, 미니 배치의 크기는 메모리 용량, 모델의 복잡성 및 훈련 데이터의 크기를 고려하여 결정된다.
   따라서, 데이터 배치 학습과 미니 배치 학습은 각각의 장단점이 있으며, 학습 목표와 환경에 따라 적절한 방법을 선택하는 것이 중요하다.

비교


주섬주섬

  • 에폭 (epoch): 1 에폭 = 훈련 데이터를 모두 소진하였을 때의 횟수. 예) 100,000 개의 데이터가 있을 때, 미니배치 크기가 100인 경우. 1000회 반복 = 1 에폭

참고

더보기

DNN Classification

# mnist 에서 손글씨 데이터 추출하기
from tensorflow.keras.datasets import mnist
import os
os.environ['KMP_DUPLICATE_LIB_OK']='True'

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

print(train_images.shape,train_labels.shape)
print(test_images.shape,test_labels.shape)

# 데이터를 학습에 맞도록 크기를 변환
from tensorflow.keras.utils import to_categorical

train_images=train_images.astype('float32')/255
test_images=test_images.astype('float32')/255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

i=1

print(train_labels[i])
print(train_labels[j])
print(train_images.shape)
print(train_labels.shape)

# 학습하기
from tensorflow.keras import models
from tensorflow.keras import layers


model=models.Sequential()

model.add(layers.Flatten(input_shape=(28,28))) # Neural Network에 입력하기 위해 2차원 배열을 1차원 배열로 flatten 시킴
model.add(layers.Dense(100,activation='relu'))
model.add(layers.Dense(50, activation='relu'))
model.add(layers.Dense(20, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()

model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

history= model.fit(train_images,train_labels,epochs=20, batch_size=100, verbose=2,validation_data=(test_images, test_labels))
# !pip install matplotlib
import matplotlib.pyplot as plt

history_dict= history.history

loss = history_dict['loss']
val_loss = history_dict['val_loss']

accuracy = history_dict['accuracy']
val_accuracy = history_dict['val_accuracy']

epochs = range(1, len(loss)+1)

plt.figure(figsize=(10, 4))

plt.subplot(121)

plt.plot(epochs, loss, 'bo',label='training loss')
plt.plot(epochs, val_loss, 'b', label='test loss')
plt.xlabel('Epochs')
plt.ylabel('Loss') 
plt.legend()

plt.subplot(122)

plt.plot(epochs, accuracy, 'bo',label='training accuracy')
plt.plot(epochs, val_accuracy, 'b', label='test accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.ylim((0.9,1.02)) 
plt.legend()

plt.tight_layout()
plt.show()

test_loss, test_acc = model.evaluate(test_images, test_labels)

print('test accuracy=',test_acc)

# 정보의 병목현상: 중간층의 노드개수를 최종 출력보다 노드개수보다 적게 만드는 경우
model=models.Sequential()

model.add(layers.Flatten(input_shape=(28,28))) # Neural Network에 입력하기 위해 2차원 배열을 1차원 배열로 flatten 시킴
model.add(layers.Dense(100,activation='relu'))
model.add(layers.Dense(50, activation='relu'))
model.add(layers.Dense(3, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()

model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

test= model.fit(train_images,train_labels,epochs=20, batch_size=100, verbose=2, validation_data=(test_images, test_labels))

test_dict= test.history

loss2 = test_dict['loss']
val_loss2 = test_dict['val_loss']
accuracy2 = test_dict['accuracy']
val_accuracy2 = test_dict['val_accuracy']

epochs = range(1, len(loss2)+1)

plt.figure(figsize=(10, 4))

plt.subplot(121)

plt.plot(epochs, loss, 'bo',label='training loss')
plt.plot(epochs, val_loss, 'b', label='test loss')
plt.plot(epochs, loss2, 'rx',label='training loss with bottle net')
plt.plot(epochs, val_loss2, 'r', label='test loss with bottle net')
plt.xlabel('Epochs')
plt.ylabel('Loss') 
plt.legend()

plt.subplot(122)

plt.plot(epochs, accuracy, 'bo',label='training accuracy')
plt.plot(epochs, val_accuracy, 'b', label='test accuracy')
plt.plot(epochs, accuracy2, 'rx',label='training accuracy with bottle net')
plt.plot(epochs, val_accuracy2, 'r', label='test accuracy with bottle net')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.ylim((0.9,1.02)) 
plt.legend()

plt.tight_layout()
plt.show()
# Weight Regularization : Over fitting 을 피하는 방법
from tensorflow.keras import regularizers

model=models.Sequential()

model.add(layers.Flatten(input_shape=(28,28))) # Neural Network에 입력하기 위해 2차원 배열을 1차원 배열로 flatten 시킴
model.add(layers.Dense(100,kernel_regularizer=regularizers.l2(0.001), activation='relu'))
model.add(layers.Dense(50,kernel_regularizer=regularizers.l2(0.001), activation='relu'))
model.add(layers.Dense(20,kernel_regularizer=regularizers.l2(0.001), activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()

model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

test= model.fit(train_images,train_labels,epochs=20, batch_size=100, verbose=2, validation_data=(test_images, test_labels))

test_dict= test.history

test_dict= test.history

loss2 = test_dict['loss']
val_loss2 = test_dict['val_loss']
accuracy2 = test_dict['accuracy']
val_accuracy2 = test_dict['val_accuracy']


plt.figure(figsize=(10, 4))

plt.subplot(121)
 
plt.plot(epochs, loss, 'bo',label='training loss')
plt.plot(epochs, val_loss, 'b', label='test loss')
plt.plot(epochs, loss2, 'rx',label='training loss with L2 regularizer')
plt.plot(epochs, val_loss2, 'r', label='test loss with L2 regularizer')

plt.xlabel('Epochs')
plt.ylabel('Loss') 
plt.legend()

plt.subplot(122)
 
plt.plot(epochs, accuracy, 'bo',label='training accuracy')
plt.plot(epochs, val_accuracy, 'b', label='test accuracy')
plt.plot(epochs, accuracy2, 'rx',label='training accuracy with L2 regularizer')
plt.plot(epochs, val_accuracy2, 'r', label='test accuracy with L2 regularizer')

plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.ylim((0.9,1.02)) 
plt.legend()

plt.tight_layout()
plt.show()
# Dropout : Over fitting 을 피하는 방법
model=models.Sequential()

model.add(layers.Flatten(input_shape=(28,28))) # Neural Network에 입력하기 위해 2차원 배열을 1차원 배열로 flatten 시킴
model.add(layers.Dense(100,activation='relu'))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(50, activation='relu'))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(20, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
model.summary()

model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['accuracy'])

test2= model.fit(train_images,train_labels,epochs=20, batch_size=100, verbose=2,validation_data=(test_images, test_labels))

test2_dict= test2.history

loss3 = test2_dict['loss']
val_loss3 = test2_dict['val_loss']

accuracy3 = test2_dict['accuracy']
val_accuracy3 = test2_dict['val_accuracy']

epochs = range(1, len(loss3)+1)

plt.figure(figsize=(10, 4))

plt.subplot(121)

plt.plot(epochs, loss, 'bo',label='training loss')
plt.plot(epochs, val_loss, 'b', label='test loss')
plt.plot(epochs, loss2, 'rx',label='training loss with L2 regularizer')
plt.plot(epochs, val_loss2, 'r', label='test loss with L2 regularizer')
plt.plot(epochs, loss3, 'gx',label='training loss with dropout')
plt.plot(epochs, val_loss3, 'g', label='test loss with dropout')

plt.xlabel('Epochs')
plt.ylabel('Loss') 
plt.legend()

plt.subplot(122)

plt.plot(epochs, accuracy, 'bo',label='training accuracy')
plt.plot(epochs, val_accuracy, 'b', label='test accuracy')
plt.plot(epochs, accuracy2, 'rx',label='training accuracy with L2 regularizer')
plt.plot(epochs, val_accuracy2, 'r', label='test accuracy with L2 regularizer')
plt.plot(epochs, accuracy3, 'gx',label='training accuracy with dropout')
plt.plot(epochs, val_accuracy3, 'g', label='test accuracy with dropout')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.ylim((0.9,1.02)) 
plt.legend()

plt.tight_layout()
plt.show()
 

인공지능 4. 다층 신경망

서론 다층신경망(Multi-layer Neural Networks)은 인공지능(AI)과 머신러닝에서 사용되는 핵심적인 알고리즘 중 하나로, 복잡한 데이터 문제를 해결할 수 있는 강력한 도구이다. 다층신경망은 그 구조상

jinger.tistory.com

 

기계 학습 3. 분류(Classification)

서론 기계 학습에서 Classification(분류)은 데이터를 미리 정의된 클래스 또는 카테고리로 분류하는 작업을 의미한다. Classification은 데이터 분석, 패턴 인식, 예측 및 의사 결정 등 다양한 분야에서

jinger.tistory.com

 

반응형

'컴퓨터공학 > AI' 카테고리의 다른 글

인공지능 7. 자연어 처리(NLP)  (0) 2024.05.07
인공지능 6. CNN  (0) 2024.04.25
인공지능 4. 다층 신경망  (0) 2024.04.11
인공지능 3. 단층 신경망  (1) 2024.04.07
인공지능 2. 기초 최적화 이론  (0) 2024.04.05

댓글