DL - #6, Batch Normalization
▶ Batch Normalization
신경망의 각 층의 활성화값을 고루 분포하게 하기 위해 나온 기법
- 학습 속도가 개선된다 (학습률을 높게 설정할 수 있기 때문)
- 가중치 초깃값 선택의 의존성이 적어진다 (학습을 할 때마다 출력값을 정규화하기 때문)
- 과적합(overfitting) 위험을 줄일 수 있다 (드롭아웃 같은 기법 대체 가능)
- Gradient Vanishing 문제 해결
▶ 일반화 오류
일반화(generalization)란 훈련 데이터가 아닌 새로운 데이터에 대해 모델이 예측을 얼마나 잘 하는지를 의미합니다.
모델의 성능이 좋다는 말은 일반화가 잘 되었다는 것을 의미합니다.
모델의 train 성능과 validation/test 성능의 차이를 일반화 오류(generalization error)라고 합니다.
일반화 오류가 적을 수록 일반화가 잘 된 모델입니다.
두 성능의 차이가 작아야 모델이 훈련 데이터에 과적합되지 않고 새로운 데이터에 대해 일반화를 잘하는 모델이 됩니다.
정규화는 일반화를 잘 하는 모델을 만드는 기법이라고도 합니다.
→ Underfitting / Overfitting는 과소 - 과대 적합이라고 하며, 훈련 및 테스트 Data Set이 어느 한 쪽으로 치우치거나
부족 할 경우 생기는 문제
▶ Batch Normalization 알고리즘
배치 정규화는 학습 시의 미니배치를 한 단위로 정규화를 하는 것으로 분포의 평균이 0, 분산이 1이 되도록 정규화하는 것을 말한다.
hidden layer의 활성화값/출력값에 대해서 평균이 0, 분산이 1이 되도록 정규화(Normalization)를 하며
데이터 분포가 덜 치우치게 되고 배치 정규화 단계마다 확대scale와 이동shift 변환(transform)을 수행한다.
▶ 배치 정규화 효과
파란선이 배치 정규화된 선으로 점선은 정규화가 되지 않는 부분이다.
배치 정규화가 된 부분은 학습 속도가 빠르며, 가중치 초깃값에 크게 의존 하지 않아도 학습이 잘 되고 있다.
▶ Over fitting (과소 적합, 과대 적합)
- 기계학습에서는 오버피팅 문제가 자주 발생하며, 신경망이 훈련 데이터에만 지나치게 적응 되어 그 외의 데이터에
제대로 대응하지 못하는 상태를 말한다. - 과적합은 모델 Training 과정에서 Vali Loss가 지속적으로 감소하다가 증가하는 지점부터 발생
- Training Loss와 Test Loss가 같이 감소하는 구간 (Underfitting)
- Training Loss 감소, Test Loss는 증가하는 구간 (Overfitting)
import os import sys sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정 import numpy as np import matplotlib.pyplot as plt from dataset.mnist import load_mnist from common.multi_layer_net import MultiLayerNet from common.optimizer import SGD (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) # 오버피팅을 재현하기 위해 학습 데이터 수를 줄임 # 기존 60000개 data set에서 300개만 사용하여 오버피팅을 발생 시킴 # 훈련 데이터 셋이 적으면, 오버 피팅을 발생 시킬 수 있음 x_train = x_train[:300] t_train = t_train[:300] # weight decay(가중치 감소) 설정 ======================= # weight decay를 사용하지 않을 경우 weight_decay_lambda = 0 # weight decay 0.1 적용 #weight_decay_lambda = 0.1 # ==================================================== network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10, weight_decay_lambda=weight_decay_lambda) optimizer = SGD(lr=0.01) # 학습률이 0.01인 SGD로 매개변수 갱신 max_epochs = 201 train_size = x_train.shape[0] batch_size = 100 train_loss_list = [] train_acc_list = [] test_acc_list = [] iter_per_epoch = max(train_size / batch_size, 1) epoch_cnt = 0 for i in range(1000000000): batch_mask = np.random.choice(train_size, batch_size) x_batch = x_train[batch_mask] t_batch = t_train[batch_mask] grads = network.gradient(x_batch, t_batch) optimizer.update(network.params, grads) if i % iter_per_epoch == 0: train_acc = network.accuracy(x_train, t_train) test_acc = network.accuracy(x_test, t_test) train_acc_list.append(train_acc) test_acc_list.append(test_acc) print("epoch:" + str(epoch_cnt) + ", train acc:" + str(train_acc) + ", test acc:" + str(test_acc)) epoch_cnt += 1 if epoch_cnt >= max_epochs: break # 그래프 그리기========== markers = {'train': 'o', 'test': 's'} x = np.arange(max_epochs) plt.plot(x, train_acc_list, marker='o', label='train', markevery=10) plt.plot(x, test_acc_list, marker='s', label='test', markevery=10) plt.xlabel("epochs") plt.ylabel("accuracy") plt.ylim(0, 1.0) plt.legend(loc='lower right') plt.show()
→ 우측 상단, 네모 박스를 보면, Train과 Test의 정확도가 크게 차이가 나며, 훈련 데이터에만 적응 해버린 결과
→ Train 데이터 측정한 정확도는 100 epochs를 지나는 무렵 거의 100% 도달
▶ 가중치 감소
가중치 감소는 학습 중에 가중치가 큰 것에 대해서는 일종의 패널티를 부과해 과적합의 위험을 줄이는 방법이다. 가중치의 제곱 법칙(L2 법칙; 많이 사용된다)를 손실함수에 더해 손실함수 값이 더 커지게 한다. 그만큼 가중치가 커지는 것을 억제하기 되는 것이다.
L2 법칙은 1/2곱하기 λ(람다) 곱하기 W제곱 이다.
람다는 정규화의 세기를 조절하는 하이퍼파라미터이다.
람다를 크게 설정할수록 가중치에 대한 페널티가 커진다.
import os
import sys
sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정
import numpy as np
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.multi_layer_net import MultiLayerNet
from common.optimizer import SGD
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)
# 오버피팅을 재현하기 위해 학습 데이터 수를 줄임
# 기존 60000개 data set에서 300개만 사용하여 오버피팅을 발생 시킴
# 훈련 데이터 셋이 적으면, 오버 피팅을 발생 시킬 수 있음
x_train = x_train[:300]
t_train = t_train[:300]
# weight decay(가중치 감소) 설정 =======================
# weight decay를 사용하지 않을 경우
#weight_decay_lambda = 0
# weight decay 0.1 적용
weight_decay_lambda = 0.1
# ====================================================
network = MultiLayerNet(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10,
weight_decay_lambda=weight_decay_lambda)
optimizer = SGD(lr=0.01) # 학습률이 0.01인 SGD로 매개변수 갱신
max_epochs = 201
train_size = x_train.shape[0]
batch_size = 100
train_loss_list = []
train_acc_list = []
test_acc_list = []
iter_per_epoch = max(train_size / batch_size, 1)
epoch_cnt = 0
for i in range(1000000000):
batch_mask = np.random.choice(train_size, batch_size)
x_batch = x_train[batch_mask]
t_batch = t_train[batch_mask]
grads = network.gradient(x_batch, t_batch)
optimizer.update(network.params, grads)
if i % iter_per_epoch == 0:
train_acc = network.accuracy(x_train, t_train)
test_acc = network.accuracy(x_test, t_test)
train_acc_list.append(train_acc)
test_acc_list.append(test_acc)
print("epoch:" + str(epoch_cnt) + ", train acc:" + str(train_acc) + ", test acc:" + str(test_acc))
epoch_cnt += 1
if epoch_cnt >= max_epochs:
break
# 그래프 그리기==========
markers = {'train': 'o', 'test': 's'}
x = np.arange(max_epochs)
plt.plot(x, train_acc_list, marker='o', label='train', markevery=10)
plt.plot(x, test_acc_list, marker='s', label='test', markevery=10)
plt.xlabel("epochs")
plt.ylabel("accuracy")
plt.ylim(0, 1.0)
plt.legend(loc='lower right')
plt.show()
가중치 감소 이전 (Overfitting)

가중치 감소 이후

▶ DropOut
- 드롭 아웃은 뉴런을 무작위로 선택해 삭제하여 신호 전달을 차단하는 오버피팅 억제 기법 중 한 가지이다.
- 입력값의 일부를 0으로 두기에, 역전파 시, 파라미터 업데이트가 되지 않고, 이는 모형의 불확실성을 증가시켜
과적합 해결에 기여한다. - 훈련 때는 데이터를 흘릴 때마다 삭제할 뉴런을 무작위로 선택하고, 시험 때는 모든 뉴런에 신호를 전달
→ 시험 때는 각 뉴런의 출력에 훈련 때 삭제한 비율을 곱하여 출력
import os import sys sys.path.append(os.pardir) # 부모 디렉터리의 파일을 가져올 수 있도록 설정 import numpy as np import matplotlib.pyplot as plt from dataset.mnist import load_mnist from common.multi_layer_net_extend import MultiLayerNetExtend from common.trainer import Trainer from common.util import shuffle_dataset (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True) x_train, t_train = shuffle_dataset(x_train, t_train) val_rate = 0.2 val_num = int(x_train.shape[0] * val_rate) print(val_num) # 검증 Data Set x_train shape 60000 중 20% 추출하여 12,000개 검증 Data Set 선정 # x_val = x_train[:vali_num] # 오버피팅을 재현하기 위해 학습 데이터 수를 줄임 x_train = x_train[:300] t_train = t_train[:300] # 드롭아웃 사용 유무와 비울 설정 ======================== use_dropout = True # 드롭아웃을 쓰지 않을 때는 False dropout_ratio = 0.2 # ==================================================== network = MultiLayerNetExtend(input_size=784, hidden_size_list=[100, 100, 100, 100, 100, 100], output_size=10, use_dropout=use_dropout, dropout_ration=dropout_ratio) trainer = Trainer(network, x_train, t_train, x_test, t_test, epochs=301, mini_batch_size=100, optimizer='sgd', optimizer_param={'lr': 0.01}, verbose=True) trainer.train() train_acc_list, test_acc_list = trainer.train_acc_list, trainer.test_acc_list # 그래프 그리기========== markers = {'train': 'o', 'test': 's'} x = np.arange(len(train_acc_list)) plt.plot(x, train_acc_list, marker='o', label='train', markevery=10) plt.plot(x, test_acc_list, marker='s', label='test', markevery=10) plt.xlabel("epochs") plt.ylabel("accuracy") plt.ylim(0, 1.0) plt.legend(loc='lower right') plt.show()
- 순전파 때 신호를 통과 시키는 뉴런은 역전파 때도 신호를 그대로 통과 시키고, 순전파 때 통과시키지 않은 뉴런은
역전파 때도 신호를 차단 - 위 코드에서 self.mask는 x와 형상이 같은 배열을 무작위로 생성하고, 그 값이 드롭아웃 비율보다 큰 원소만 true로 설정
→ 7층 네트워크로 진행 (각 층의 뉴런 수는 100개, 활성화 함수는 ReLU 사용)
# 앙상블 학습 (ensemble learning)
1. 개별적으로 학습싴니 여러 모델의 출력을 평균 내어 추론하는 방식.
2. 추론 때는 뉴런의 출력에 삭제한 비율을 곱함으로써 앙상블 학습에서 여러 모델의 평균을 내는 것과 동일
▶ 결론
1. 다수의 신경망이 구축이 되었을 경우, 하이퍼파라미터를 조절해 가면서 모니터링 후, 최적화
2. Dropout과 Regularization를 골고루 사용 하여, 해당 모델의 최적화 성능 찾기