가중치 초깃값 설정
가중치 초깃값을 0으로 설정하면 갱신을 해도 여전히 같은 값이 유지가된다
그러므로 초깃값을 무작위로 설정해야한다
은닉층의 활성화값 분포
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
return 1/(1+np.exp(-x))
x = np.random.randn(1000,100) #1000개의 데이터
node_num = 100 #각 은닉층의 노드 수
hidden_layer_size = 5 #총 5개의 은닉층
activations = {} #활성화 결과(활성화 값)을 저장
for i in range(hidden_layer_size):
if i != 0:
x = activations[i-1]
#표준편차가 1일때
w = np.random.randn(node_num, node_num) * 1
#표준편차를 0.01 일때
#w = np.random.randn(node_num, node_num) * 0.01
#Xavier 초기값을 사용하였을 때
#w = np.random.randn(node_num, node_num) / np.sqrt(node_num)
a = np.dot(x,w)
z = sigmoid(a)
activations[i] = z
가중치를 표준편차가 1인 정규분포로 초기화 했을때
활성화값이 0과 1에 치우쳐져 있음. 미분값이 0에 가까워짐 -> 기울기 소실 문제
가중치를 표준편차가 0.01인 정규분포로 초기화 했을때
활성화 값들이 치우쳐져있음 ->뉴런을 여러개 둔것이 의미가 없음 (표현력 제한)
Xavier 초깃값
앞 계층의 노드가 n개면 표준편차가 1/√n 인 분포를 사용함
node_num = 100 # 앞 층의 노드 수
w = np.random.randn(node_num, node_num) / np.sqrt(node_num)
확실히 넓게 분포되는 결과를 가져온다.
활성화 함수가 선형인 것을 전제로 이끈 결과이다. sigmoid나 tanh 함수처럼 좌우대칭인 함수에 쓴다.
He 초깃값
ReLU에 특화된 초깃값이다.
앞 계층의 노드가 n개 일때, 표준편차가 sqrt(2/n) 인 정규분포를 사용한다.
ReLU는 0 미만은 모두 0이여서 더 넓게 분포시키기 위해 2배 계수를 적용함.
배치 정규화
배치 정규화는 각 층의 활성화값이 적당히 분포되도록 조정한다.
배치 정규화의 장점은 다음과 같다
- 학습 속도 개선
- 초깃값에 크게 의존하지 않음
- 오버피팅 억제(드롭아웃의 필요성 감소)
평균0, 분산1이 되게 정규화 진행. epsilon은 0으로 나누는것을 예방한다
이 처리를 활성화 함수에 삽입함으로써 분포가 덜 치우치게함.
γ : 확대
β : 이동
초기 γ=1, β=0부터 시작
오버피팅
오버피팅이 일어나는 조건은 다음과 같다
- 매개변수가 많고 표현력이 높은 모델
- 훈련 데이터가 적음
그래프로 나타내었을때, train data의 정확도가 100%과 가깝거나 100%이다. 하지만 test data는 다른 accuracy를 보인다
오버피팅을 억제하기 위해서는?
오버피팅을 억제하기 위해서는 가중치 감소를 한다
학습과정 중 큰 가중치에 대해서는 penalty를 부여하여 오버피팅을 억제하는 방법이다.
가중치 W = (w1, w2, ..., wn)
L2 노름: √(w1² + ... + wn²)
L1 노름 : 절댓값의 합. |w1| + ... + |wn|
L∞ 노름 : Max 노름. 각 원소의 절댓값 중 가장 큰 것
L2 norm을 예를 들면 L2 규제에 따른 가중치 감소는 1/2 λW^2가 되고, 이값을 손실함수에 더한다.
여기서 람다는 정규화의 세기를 조절한다. 람다가 커질수록 페널티가 커진다. 1/2는 1/2 λW^2의 미분결과인 λW를 조정하는 역할의 상수이다.
드롭아웃
드롭아웃은 뉴런을 임의로 삭제하면서 학습하는 방법이다.
train 때 은닉층의 뉴런을 무작위로 골라 삭제한다. 단 test 때는 각 뉴련의 출력에 삭제 하지 않은 비율을 곱해야 한다.
class Dropout:
def __init__(self, dropout_ratio=0.5):
self.dropout_ratio = dropout_ratio
self.mask = None
def forward(self, x, train_flg = True):#x와 형상이 같은 배열 무작위 생성, 그 값이 dropout 비율보다 큰 것만 True
if train_flg:
self.mask = np.random.rand(*x.shape)>self.dropout_ration
return x * self.mask
else:
return x * (1.0 - self.dropout_ratio)
def backward(self, dout): #relu때와 동작 같음
return dout * self.mask
순전파 때 신호를 통과시키면 역전파 때도 그대로 통과
순전파 때 통과시키지 않은 신호는 역전파 때는 신호를 차단
validation data
하이퍼파라미터를 조정할때는 validation data(검증 데이터)를 사용한다(약 20%)
train: aoroqustn gkrtmq
valid: 하이퍼파라미터 성능평가
test: 신경망 성능 평가
import sys, os
sys.path.append(os.pardir)
from common.util import shuffle_dataset
(x_train, t_train), (x_test, t_test) = load_mnist()
#훈련 데이터를 셔플
x_train, t_train = shuffle_dataset(x_train, t_train)
#20%를 검증 데이터로 분할
validation_rate = 0.2
validation_num = int(x_train.shape[0] * validation_rate)
x_val = x_train[:validation_num]
t_val = t_train[:validation_num]
x_train = x_train[validation_num:]
t_train = t_train[validation_num:]
하이퍼 파라미터 최적화하기
하이퍼 파라미터의 범위는 대략적으로 지정한다.
log scale: 0.001~1 사이로 10의 거듭제곱 단위로 지정한다
from common.trainer import Trainer
def __train(lr, weight_decay, epocs=50):
network = MultiLayerNet(input_size=784,
hidden_size_list=[100, 100, 100, 100, 100, 100],
output_size=10, weight_decay_lambda=weight_decay)
trainer = Trainer(network, x_train, t_train, x_val, t_val,
epochs=epocs, mini_batch_size=100,
optimizer='sgd',#SGD 최적화
optimizer_param={'lr': lr}, verbose=False)
trainer.train()
return trainer.test_acc_list, trainer.train_acc_list
optimization_trial = 100 #최적화 시행
results_val = {} #딕셔너리 초기화
results_train = {}
for _ in range(optimization_trial):
weight_decay = 10 ** np.random.uniform(-8,-4)#가중치 감소계수
lr = 10 ** np.random.uniform(-6,-2) #학습률
val_acc_list, train_acc_list = __train(lr, weight_decay)
print("val acc:" + str(val_acc_list[-1]) + " | lr:" + str(lr) + ", weight decay:" + str(weight_decay))
key = "lr:" + str(lr) + ", weight decay:" + str(weight_decay)
results_val[key] = val_acc_list
results_train[key] = train_acc_list
print("=========== Hyper-Parameter Optimization Result ===========")
graph_draw_num = 20
col_num = 5
row_num = int(np.ceil(graph_draw_num / col_num))
i = 0
for key, val_acc_list in sorted(results_val.items(), key=lambda x: x[1][-1], reverse=True):
print("Best-" + str(i+1) + "(val acc:" + str(val_acc_list[-1]) + ") | " + key)
=========== Hyper-Parameter Optimization Result ===========
Best-1(val acc:0.96975) | lr:0.009670679277174084, weight decay:8.141969904396711e-05
Best-2(val acc:0.968) | lr:0.005645893550979283, weight decay:4.187901269145063e-05
Best-3(val acc:0.9670833333333333) | lr:0.008201293185096941, weight decay:5.310830620412764e-05
Best-4(val acc:0.9653333333333334) | lr:0.0059708428940421065, weight decay:4.1304948916864125e-07
Best-5(val acc:0.9645) | lr:0.003817887651834717, weight decay:1.597148973392731e-08
Best-6(val acc:0.9635) | lr:0.0033466570410879875, weight decay:4.538298081326221e-08
Best-7(val acc:0.96175) | lr:0.0019354422304412651, weight decay:6.262348129159304e-06
Best-8(val acc:0.96075) | lr:0.0027213190650062272, weight decay:3.776206334278005e-08
Best-9(val acc:0.9585833333333333) | lr:0.0017557676932367667, weight decay:3.591588279639057e-05
Best-10(val acc:0.9585) | lr:0.0018411932755400093, weight decay:4.994072781499758e-07
acc가 가장높은 값에 대한 학습률과 가중치계수를 최적 파라미터로 선정한다.
'Deep Learning > from scratch I' 카테고리의 다른 글
[밑바닥부터 시작하는 딥러닝 - 7장 합성곱 신경망(CNN) II] (1) | 2024.02.10 |
---|---|
[밑바닥부터 시작하는 딥러닝 - 7장 합성곱 신경망(CNN) I] (1) | 2024.02.10 |
[밑바닥부터 시작하는 딥러닝 - 6장 학습 관련 기술들 I] (0) | 2024.02.08 |
[밑바닥부터 시작하는 딥러닝 - 5장 오차역전파법 II] (1) | 2024.02.08 |
[밑바닥부터 시작하는 딥러닝 - 5장 오차역전파법 I] (0) | 2024.02.08 |