인공 신경망
퍼셉트론(perceptron), 다층 퍼셉트론 (MLP)
이전 내용
심층 신경망 훈련
◆ 심층 신경망(Deep Neural Network, DNN)
[인공 신경망 실습을 통해 알게 된 두 가지]
1. 퍼셉트론은 인간의 뉴런을 모방한 '인공신경망'이다.
2. 다층 퍼셉트론은 퍼셉트론을 직렬로, 병렬로 연결하여 1개 이상의 은닉층을 가진 구조이다.
XOR문제, 기울기 소실 문제 등으로 인공신경망의 인기는 빠르게 식어갔다. 그러다 2006년 인공신경망 대신 심층 신경망(Deep Neural Network, DNN)이라는 용어가 사용되기 시작했다. 가중치 초기화 설정, ReLU 함수, 컴퓨터 성능 발전 등 다양한 방법으로 기울기 소실의 문제를 어느정도 해결하였다고 한다.
다층 퍼셉트론에서 은닉층을 많이 늘린 구조를 심층 신경망이라고 말할 수 있는데, 일반적으로 은닉층이 3개 이상인 구조를 심층 신경망이라고 하며, 이러한 심층 신경망을 이용하여 컴퓨터가 문제를 해결하는 과정을 딥러닝(Deep learning)이라고 한다. 즉 딥러닝은 컴퓨터가 데이터를 스스로 학습하여 문제를 해결하는 머신러닝(Machine learning) 방법 중 하나이다.
[심층 신경망 훈련 중 마주할 수 있는 문제들]
수백 개의 뉴런으로 구성된 10개 이상의 층을 수십만 개의 가중치로 연결해 훨씬 더 깊은 인공 신경망을 훈련한다고 생각해보면, 심층 신경망을 훈련하는 것은 쉬운 일이 아니며, 훈련 중에 아래와 같은 문제를 마주할 수 있다.
- 심층 신경망의 출력 층에서 멀어질수록 그레이디언트가 점점 더 작아지거나 커지는 문제가 나타날 수 있으며, 두 문제 모두 하위 층을 매우 훈련하기 어렵게 만든다.
- 대규모 신경망을 위한 훈현 데이터가 충분하지 않거나 레이블을 만드는 작업에 비용이 너무 많이 들어갈 수 있다.
- 훈련이 극단적으로 느려질 수 있다.
- 수백만 개의 파라미터를 가진 모델은 훈련 세트에 과대적합될 위험이 매우 크며, 특히 훈련 샘플이 충분치 않거나 잡음이 많은 경우에는 과대적합 될 확률이 더 크다.
해결책4 - 대규모 신경망을 위한 규제 기법들
1. 규제를 사용해 과대적합 피하기
1-1. L1 규제와 L2 규제
신경망의 연결 가중치를 제한하기 위해 L2 규제를 사용하거나 많은 가중치가 0인 희소 모델을 위해 L1 규제를 사용할 수 있다.
다음은 케라스 층의 연결 가중치에 규제 강도 0.01을 사용하여 L2 규제를 적용하는 방법이다.
layer = tf.keras.layers.Dense(100, activation='relu',
kernel_initializer='he_normal',
kernel_regularizer=tf.keras.regularizers.l2(0.01))
l2() 함수는 훈련하는 동안 규제 손실을 계산하기 위해 각 스텝에서 호출되는 규제 객체를 반환하며, 이 손실을 최종 손실에 합산된다.
L1 규제가 필요하면 keras.regularizers.l1()을 사용할 수 있고, 둘 다 필요하면 keras.regularizers.l1_l2() 를 사용한다.
layer = tf.keras.layers.Dense(100, activation='relu',
kernel_initializer='he_normal',
kernel_regularizer=tf.keras.regularizers.l1(0.01))
layer = tf.keras.layers.Dense(100, activation='relu',
kernel_initializer='he_normal',
kernel_regularizer=tf.keras.regularizers.l1_l2(0.01))
일반적으로 네트워크의 모든 은닉 층에 동일한 활성화 함수, 동일한 초기화 전략을 사욯아거나 모든 층에 동일한 규제를 적용하기 때문에 동일한 매개변수 값을 반복하는 경우가 많다. 그러나 이는 코드를 읽기 어렵게 하고 버그를 만들기 쉽다.
이를 피하기 위해 반복문을 사용하도록 코드를 리팩터링 할 수 있으며, 또 다른 방법은 파이썬의 functools.partial() 함수를 사용하여 기본 매개변수 값을 통해 함수 호출을 감싸는 것이다.
from functools import partial
RegularizedDense = partial(tf.keras.layers.Dense,
activation="relu",
kernel_initializer="he_normal",
kernel_regularizer=tf.keras.regularizers.l2(0.01))
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28]),
RegularizedDense(100),
RegularizedDense(100),
RegularizedDense(10, activation="softmax")
])
l2 규제는 SGD, 모멘텀 최적화, 네스테로프 모멘텀 최적화와 같이 사용해도 괜찮지만 Adam과 그 변형에 사용했을 때는 그렇지 않다. Adam에 가중치 감쇠를 적용하고 싶다면 l2 규제 대신에 AdamW를 사용해야 한다.
1-2. 드롭아웃
- 개념:
드롭아웃 규제는 신경망 모델의 과적합(overfitting)을 방지하기 위해 사용되는 기법이이다. 이 방법은 학습 과정 중 임의로 일부 뉴런을 "드롭"(혹은 비활성화)하는 방법이다.
이 방식은 매 훈련 스텝에서 각 뉴런(입력 뉴런 - 포함, 출력 뉴런 - 제외)은 임시적으로 드롭아웃될 확률 p를 가지는 데, 하이퍼파라미터 p를 드롭아웃 비율이라고 하며 보통 10~50% 사이로 지정한다.
순환 신경망에서는 20~30%에 가깝고, 합성곱 신경망에서는 40~50%에 가깝다. 훈련이 끝난 후에는 뉴런에 더는 드롭아웃을 적용하지 않는다.
한 가지 중요한 점은 드롭아웃을 적용한 훈련을 했다면 테스트하기 전 훈련이 끝난 뒤 각 가중치에 보존확률 1-p를 곱해야 하는 데, 드롭아웃을 적용하여 훈련하면 훈련을 할 때와 달리 테스트할 때 하나의 뉴런이 1-p만큼 더 많은 입력 뉴런과 연결되기 때문이다. 결국은 하나의 뉴런은 가중합(weighted sum)을 이용한 계산을 할 것이므로, 드롭아웃을 적용할 때보다 그만큼의 스케일이 커지는 데, 이를 꼭 보존해야 하는 것이다.
- 주요 특징:
- 랜덤성: 매 훈련 단계에서 각 뉴런이 드롭될 확률을 갖는다. 드롭된 뉴런은 해당 훈련 단계에서만 비활성화되며, 다음 단계에서는 다시 활성화될 수 있다.
- 과적합 방지: 다양한 하위 모델들이 학습되기 때문에 과적합을 방지하고 모델의 일반화 능력을 향상시킨다.
- 가중치 공유: 드롭아웃 규제는 서로 다른 하위 모델들이 가중치를 공유하기 때문에 효율적이다.
- 케라스에서 드롭아웃 구현
케라스에서는 tf.keras.layers.Dropout 층을 사용하여 드롭아웃을 구현한다. 이 층은 훈련하는 동안 일부 입력을 랜덤하게 버리고 (0으로 설정), 남은 입력을 보존 확률로 나눈다. 훈련이 끝난 후에는 어떤 작업도 하지 않고 입력을 다음 층으로 그냥 전달한다.
아래는 드롭아웃 비율을 0.2로 설정하고 드롭아웃 규제를 모든 Dense 층 이전에 적용하는 코드이다.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28]),
tf.keras.layers.Dropout(rate=0.2),
tf.keras.layers.Dense(100, activation='relu',
kernel_initializer='he_normal'),
tf.keras.layers.Dropout(rate=0.2),
tf.keras.layers.Dense(100, activation='relu',
kernel_initializer='he_normal'),
tf.keras.layers.Dropout(rate=0.2),
tf.keras.layers.Dense(10, activation='softmax')
])
# 모델 컴파일과 훈련
optimizer = tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.9)
model.compile(loss="sparse_categorical_crossentropy", optimizer=optimizer,
metrics=["accuracy"])
history = model.fit(X_train, y_train, epochs=10,
validation_data=(X_valid, y_valid))
드롭아웃은 훈련하는 동안에만 활성화되므로 훈련 손실과 검증 손실을 비교하면 오해를 일으키기 쉽다. 특히 비슷한 훈련 손실과 검증 손실을 얻었더라도 모델이 훈련 세트에 과대적합 될 수 있다. 따라서 드롭아웃을 빼고 훈련 손실을 평가해야 한다.
드롭아웃은 수렴을 상당히 느리게 만드는 경향이 있지만 적절하게 튜닝하면 더 좋은 모델을 만든다. 특히 대규모 모델일 경우 추가적인 시간과 노력을 기울일 가치가 있다.
만약 SELU 활성화 함수를 기반으로 자기 정규화하는 네트워크를 규제하고 싶다면 alpha 드롭아웃을 사용해야 한다. 이 방법은 입력의 평균과 표준 편차를 유지하는 드롭아웃의 한 변형이다.
[드롭아웃 비율]
- 모델이 과대적합되었다면 드롭아웃 비율을 늘릴 수 있고, 반대로 모델이 훈련 세트에 과소적합되면 드롭아웃 비율을 낮추어야 한다.
- 층이 클 때는 드롭아웃 비율을 늘리고 작을 때는 비율을 낮추어야 한다.
- 많은 최신 신경망 구조는 마지막 은닉 층 뒤에만 드롭아웃을 사용한다.
1-3. 몬테 카를로 드롭아웃
- 개념:
몬테 카를로 드롭아웃 규제는 기본 드롭아웃 기법의 변형으로, 베이지안 추론을 활용해 불확실성을 추정하는 데 사용된다. 이 기법은 훈련된 드롭아웃 모델을 재훈련하거나 전혀 수정하지 않고 성능을 크게 향상시킬 수 있는 강력한 기법으로, 모델의 불확실성을 더 잘 측정할 수 있고 단 몇 줄의 코드로 구현할 수 있다. 즉, MC 드롭아웃은 드롭아웃 모델의 성능을 높여주고 더 정확한 불확실성 추정을 제공하는 훌륭한 기술이며, 훈련하는 동안은 일반적인 드롭아웃처럼 수행하기 때문에 규제처럼 작동한다.
- 특징:
- 몬테 카를로 샘플링: 여러 번의 훈련 또는 테스트 과정에서 드롭아웃이 적용된 출력을 샘플링하여 모델의 예측 범위를 추정한다.
- 불확실성 추정: 모델의 출력뿐만 아니라 예측에 대한 불확실성도 함께 추정할 수 있어, 더 신뢰할 수 있는 예측을 제공한다.
- 정규화 효과: 기본 드롭아웃과 마찬가지로 과적합을 방지하는 정규화 효과를 가지고 있다.
다음은 앞서 훈련한 드롭아웃 모델을 재훈련하지 않고 성능을 향상시키는 몬테 카를로 드롭아웃 구현이다.
import numpy as np
y_probas = np.stack([model(X_test, training=True)
for sample in range(100)])
y_proba = y_probas.mean(axis=0)
▶ [코드 설명]
- model(X)는 넘파이 배열이 아닌 텐서를 반환하는 점을 제외하고는 model.prdiect(X)와 비슷하고 training 매개변수를 지원한다. 이 예제에서는 training=True 로 지정하여 Dropout 층이 활성화되기 때문에 예측이 달라진다.
- 테스트 세트에서 100개의 에측을 만들고 평균을 계산한다. 모델을 호출할 때 마다 샘플이 행이고 클래스마다 하나의 열을 가진 행렬이 반환된다.
- 테스트 세트에 10,000개의 샘플, 10개의 클래스가 있으므로 이 행렬의 크기는 [10000, 10]이고, 이런 행렬 100개를 쌓았기 때문에 y_probas는 [100, 10000, 10] 크기의 3D 행렬이다.
- 첫 번째 차원(axis=0)을 기준으로 평균하면 한 번의 예측을 수행했을 때와 같은 [10000, 10] 크기의 배열 y_proba를 얻게 된다.
드롭아웃으로 만든 예측을 평균하면 일반적으로 드롭아웃 없이 예측한 하나의 결과보다 더 안정적이다.
[드롭아웃 예측 비교]
드롭아웃을 끄고 패션 MNIST 테스트 세트에 있는 첫 번째 샘플의 모델 예측 확인
model.predict(X_test[:1]).round(3)
# array([[0. , 0. , 0. , 0. , 0. , 0.013, 0. , 0.049, 0. ,
0.938]], dtype=float32)
▶ 모델은 이 이미지가 클래스 9 (앵클 부츠)에 속한다고 93.8% 확신한다.
이를 MC 드롭아웃의 예측과 비교해 본다.
y_proba[0].round(3)
# array([0. , 0. , 0. , 0. , 0. , 0.043, 0.001, 0.114, 0.002,
0.84 ], dtype=float32)
▶ 모델은 여전히 이 이미지가 클래스 9에 속한다고 생각하지만 확률이 84%로 줄었고, 다른 쪽 클래스 (5-샌들, 7-스니커즈)에 대한 추정 확률이 증가했다. (5, 7 클래스 모두 신발이다)
MC 드롭아웃은 모델이 만든 확률 추정치의 신뢰성을 높인다. 또한 가장 가능성이 높은 다른 클래스를 아는 데도 유용하다.
확률 추정의 표준 분포 확인
y_std = y_probas.std(axis=0)
y_std[0].round(3)
# array([0.002, 0. , 0.001, 0.002, 0.001, 0.059, 0.005, 0.128, 0.009,
0.156], dtype=float32)
▶ 클래스 9에 대한 추정 확률이 84%인데, 표준 편차가 0.156이다. 만약 위험에 민간한 시스템을 만든다면 이런 불확실한 예측을 매우 주의 깊게 다루어야 한다.
y_pred = y_proba.argmax(axis=1)
accuracy = (y_pred == y_test).sum() / len(y_test)
accuracy
# 0.8689
▶ 모델의 정확도는 약 87%이다.
모델이 훈련하는 동안 다르게 작동하는 층을 가지고 있다면 앞에서와 같이 훈련 모드를 강제로 설정해서는 안 되며, 대신 Dropout 층을 다음과 같은 MCDropout 클래스로 바꿔준다.
class MCDropout(tf.keras.layers.Dropout):
def call(self, inputs, training=False):
return super().call(inputs, training=True)
▶ Dropout 층을 상속하고 call() 메서드를 오버라이딩하여 training 매개변수를 True로 강제 설정한다.
비슷하게 AlphaDropout 클래스를 상속하여 MCAlphaDropout 클래스를 정의할 수 있다.
처음부터 모델을 만든다면 그냥 Dropout 대신 MCDropout을 사용하면 된다.
이미 Dropout을 사용하여 모델을 훈련했다면 Dropout 층을 MCDropout 으로 바꾸고 기존 모델과 동일한 모델을 새로 만든다. 그런 다음 기존 모델의 가중치를 새로운 모델로 복사한다.
1-4. 맥스-노름 규제
- 개념:
맥스-노름(Max-Norm) 규제는 뉴런의 가중치 벡터의 크기를 일정한 최대값으로 제한하는 기법이이다. 가중치 벡터의 노름(norm)이 지정된 임계값을 초과하지 않도록 하는 것이 목표이다.
- 특징:
- 가중치 제한: 각 뉴런의 가중치 벡터의 크기를 최대값으로 제한하여 너무 큰 가중치로 인한 과적합을 방지한다.
- 모델 안정화: 가중치 값이 일정 범위를 유지함으로써 모델의 안정성을 높이고 수렴 속도를 향상시킨다.
- 간단한 구현: 구현이 간단하며, 기존의 학습 알고리즘에 추가하기 쉽다.
- 케라스에서 맥스-노름 규제 구현
케라스에서 맥스-노름 규제를 구현하려면 다음과 같이 적절한 최댓값으로 지정한 max_norm()이 반환한 객체로 은닉 층의 kernel_constraint 매개변수를 지정한다.
dense = tf.keras.layers.Dense(
100, activation='relu', kernel_initializer='he_normal',
kernel_constraint=tf.keras.constraints.max_norm(1.))
▶ 매 훈련 반복이 끝난 후 모델의 fit() 메서드가 층의 가중치와 함께 max_norm() 이 반환한 객체를 호출하고 스케일이 조정된 가중치를 반환받는다. 이 값을 사용하여 층의 가중치를 바꾼다. 필요하면 사용자 정의 규제 함수를 정의하고 kernel_constraint 매개변수에 이를 지정할 수 있고, bias_constraint 매개변수에 지정하여 편향을 규제할 수 있다.
max_norm() 함수는 기본값이 0인 axis 매개변수를 가진다. Dense 층은 일반적으로 [샘플 개수, 뉴런 개수] 크기의 가중치를 가진다.
axis=0을 사용하면 맥스-노름 규제는 각 뉴런의 가중치 벡터에 독립적으로 적용된다. 맥스-노름을 사용하려면 max_norm()의 axis 매개변수를 적절하게 지정해야 하며, 일반적으로 axis=[0, 1, 2]로 지정한다.
실용적인 가이드라인
1. 기본 DNN 설정
하이퍼파라미터 튜닝을 크게 하지 않고 대부분의 경우에 잘맞는 설정 (고정은 아님)
하이퍼파라미터 | 기본값 |
커널 초기화 | He 초기화 |
활성화 함수 | 얕은 신경망 - ELU, 깊은 신경망 - Swish |
정규화 | 얕은 신경망 - 없음. 깊은 신경망 - 배치 정규화 |
규제 | 조기 종료 필요하면 가중치 감쇠 |
옵티마이저 | 네스테로프 가속 경사 또는 AdamW |
학습률 스케줄 | 성능 기반 스케줄링 또는 1사이클 스케줄링 |
2. 자기 정규화를 위한 DNN 설정
네트워크가 완전 연결 층을 쌓은 단순한 모델일 경우 자기 정규화를 사용할 수 있으며, 아래의 설정을 사용하는 게 좋다.
하이퍼파라미터 | 기본값 |
커널 초기화 | 르쿤쿤 초기화 |
활성화 함수 | SELU |
정규화 | 없음(자기 정규화) |
규제 | 필요하다면 알파 드롭아웃 |
옵티마이저 | 네스테로프 가속 경사 |
학습률 스케줄 | 성능 기반 스케줄링 또는 1사이클 스케줄링 |
입력 특성을 정규화해야 하며, 비슷한 문제를 해결한 모델을 찾을 수 있다면 사전 훈련된 신경망의 일부를 재사용해봐야 한다. 레이블이 없는 데이터가 많다면 비지도 사전 훈련을 사용하고, 비슷한 작업을 위한 레이블된 데이터가 많다면 보조 작업에서 사전 훈련을 수행할 수 있다.
3. 예외 사항
- 희소 모델이 필요한 경우, L1 규제를 사용할 수 있다. 매우 희소한 모델이 필요하면 텐서플로 모델 최적화 툴킷(TF-MOT)을 사용할 수 있다. 이 도구는 자기 정규화를 깨뜨리므로 이 경우 기본 DNN 설정을 사용해야 한다.
- 빠른 응답을 하는 모델이 필요하면 층 개수를 줄이고 배치 정규화 층을 이전 층에 합친다. 그리고 LeakyReLU나 ReLU 같이 빠른 활성화 함수를 사용한다. 희소 모델을 만드는 것도 도움이 된다. 또한, 부동소수점 정밀도를 32비트에서 16비트 혹은 8비트로 낮출 수도 있다. (여기에서도 TF-MOT 확인)
- 위험에 민감하고 예측 속도가 매우 중요하지 않은 어플리케이션이라면 성능을 올리고 불확실성 추정과 신뢰할 수 있는 확률 추정을 얻기 위해 MC 드롭아웃 사용.
다음 내용
[출처]
핸즈 온 머신러닝
고등학생을 위한 인공신경망과 딥러닝
딥 러닝을 이용한 자연어 처리 입문
IBM
https://iambeginnerdeveloper.tistory.com/188
https://post.naver.com/my.naver?memberNo=26040503
https://jaylala.tistory.com
https://velog.io/@kyungmin1029
'[파이썬 Projects] > <파이썬 딥러닝, 신경망>' 카테고리의 다른 글
[딥러닝] 텐서플로 데이터셋 프로젝트 (0) | 2024.11.27 |
---|---|
[딥러닝] 케라스의 전처리 층 (0) | 2024.11.26 |
[딥러닝] 텐서플로를 사용한 데이터 적재와 전처리 (0) | 2024.11.25 |
[딥러닝] 텐서플로 함수와 그래프 (0) | 2024.11.25 |
[딥러닝] 심층 신경망 훈련 - 3 (1) | 2024.11.25 |