Deep Learning/from scratch I

[밑바닥부터 시작하는 딥러닝 - 6장 학습 관련 기술들 II]

해파리냉채무침 2024. 2. 9. 01:31

가중치 초깃값 설정

가중치 초깃값을 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인 정규분포로 초기화 했을때

https://data-scientist-brian-kim.tistory.com/85

활성화값이 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배 계수를 적용함. 

 

배치 정규화

배치 정규화는 각 층의 활성화값이 적당히 분포되도록 조정한다.

배치 정규화의 장점은 다음과 같다

- 학습 속도 개선

- 초깃값에 크게 의존하지 않음

- 오버피팅 억제(드롭아웃의 필요성 감소)

https://velog.io/@dayday/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BA%A0%ED%94%84-week1-%EC%B6%94%EA%B0%80%ED%95%99%EC%8A%B5-Gradient-Vanishing-Exploding

평균0, 분산1이 되게 정규화 진행. epsilon은 0으로 나누는것을 예방한다

이 처리를 활성화 함수에 삽입함으로써 분포가 덜 치우치게함.

https://m.blog.naver.com/kkang9901/221787741517

γ : 확대
β : 이동

초기 γ=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의 거듭제곱 단위로 지정한다

출처: https://github.com/irostub/deep-learning-from-scratch/blob/master/ch06-LearningRelatedSkills/ch06.ipynb

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가 가장높은 값에 대한 학습률과 가중치계수를 최적 파라미터로 선정한다.