Study/class note

딥러닝 / 언더피팅 방지(경사하강법과 활성화 함수의 조합을 적절하게 조합하기)

chanzae 2022. 4. 14. 11:08

3 경사하강법과 활성화 함수의 조합을 적절하게 조합하기

ㅇ경사하강법의 종류

1. SGD : 확률적 경사하강법으로 미니 배치 단위로 복원 추출한 데이터를 학습해서 경사하강하는 가장 일반적인 경사하강법

수식 : 가중치 = 가중치 - 러닝 레이트 * 기울기

class SGD:
    def __init__(self, lr=0.01):
        self.lr = lr
        
    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key]

 

2. Adam : 관성을 이용해서 local minimum을 빠져나가게 하는 모멘텀의 장점과 학습률을 자동 조절되게해서 경사하강하는 adagrade의 장점을 합친 경사하강법

momentum의 수식:

속도 <- 마찰계수 * 속도 - 러닝레이트 * 기울기

가중치 = 가중치 + 속도

class Momentum:
    def __init__(self, lr=0.01, momentum=0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None

    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items():                                
                self.v[key] = np.zeros_like(val)

        for key in params.keys():
            self.v[key] = self.momentum*self.v[key] - self.lr*grads[key] 
            params[key] += self.v[key]

 

 

Adagrade의 수식 :

 class AdaGrad:
    def __init__(self, lr=0.01):
        self.lr = lr
        self.h = None

    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)

        for key in params.keys():
            self.h[key] += grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

 

+) momentum + adagrade = adam

class Adam:
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.iter = 0
        self.m = None
        self.v = None

    def update(self, params, grads):
        if self.m is None:
            self.m, self.v = {}, {}
            for key, val in params.items():
                self.m[key] = np.zeros_like(val)
                self.v[key] = np.zeros_like(val)

        self.iter += 1
        lr_t  = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)         

    
        for key in params.keys():
            #self.m[key] = self.beta1*self.m[key] + (1-self.beta1)*grads[key]
            #self.v[key] = self.beta2*self.v[key] + (1-self.beta2)*(grads[key]**2)
            self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
            self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])
            params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)

            #unbias_m += (1 - self.beta1) * (grads[key] - self.m[key]) # correct bias
            #unbisa_b += (1 - self.beta2) * (grads[key]*grads[key] - self.v[key]) # correct bias
            #params[key] += self.lr * unbias_m / (np.sqrt(unbisa_b) + 1e-7)

 

 

3. RMSprop : Adagrade의 장점을 더 좋게 만든 경사하강법. 발걸음이 자동조절되는데 목표지점에 도달할 때 이전에 내려오던 그 걸음걸이를 살펴서 발걸음을 조절함.

class RMSprop:
    def __init__(self, lr=0.01, decay_rate = 0.99):
        self.lr = lr
        self.decay_rate = decay_rate
        self.h = None

    def update(self, params, grads):

        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)

        for key in params.keys():
            self.h[key] *= self.decay_rate
            self.h[key] += (1 - self.decay_rate) * grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

ex. 텐서플로우의 사용 예

model.compile(optimizer = 'SGD'.
              loss = 'categorical_crossentropy',
              metrics = ['acc'])

 

 

ㅇ 통상적으로 adma이 제일 나은 결과를 뽑아내지만, 어떤 활성함수와 결합하느냐에 따라서 결과가 달라질 수 있음

SGD + sigmoid

Adam + relu

RMSprop + relu

 

 

문제139. 아래 조합의 훈련데이터, 테스트 데이터의 정확도를 비교하시오.

SGD + sigmoid 

Adam + relu

RMSprop + relu

 

러닝레이트 주지 않았음.

# 1. 필요한 패키지 가져오는 코드 
import tensorflow as tf   # 텐써 플로우 2.0 
from tensorflow.keras.datasets.mnist import load_data  # 텐써플로우에 내장되어있는 
                                                       # mnist 데이터를 가져온다.
from tensorflow.keras.models import Sequential  # 모델을 구성하기 위한 모듈
from tensorflow.keras.layers import Dense  # 완전 연결계층을 구성하기 위한 모듈
from tensorflow.keras.layers import Flatten, BatchNormalization
from tensorflow.keras.utils import to_categorical # one encoding 하는 모듈


tf.random.set_seed(777)

(x_train, y_train), (x_test, y_test) = load_data(path='mnist.npz')  # mnist 데이터 로드
    
# 2. 정규화 진행  
x_train = x_train/255
x_test = x_test/255

# 3. 정답 데이터를 준비한다. 
# 하나의 숫자를 one hot encoding 한다. (예:  4 ---> 0 0 0 0 1 0 0 0 0 0 ) 
y_train = to_categorical(y_train)  # 훈련 데이터의 라벨(정답)을 원핫 인코딩
y_test = to_categorical(y_test)    # 테스트 데이터의 라벨(정답)을 원핫 인코딩 

opt = {0:['SGD','sigmoid'],1:['Adam','relu'],2:['RMSprop','relu']}

# 4. 모델 구성 + 배치정규화
for i in opt:
    model = Sequential()
    model.add(Flatten(input_shape = (28,28)))
    model.add(Dense(50, activation = opt[i][1]))  #은닉층(1층)
    model.add(BatchNormalization())
    model.add(Dense(50, activation = opt[i][1]))  #은닉층(2층)
    model.add(BatchNormalization())
    model.add(Dense(10, activation = 'softmax'))  #출력층


    # 5. 모델을 설정합니다. ( 경사하강법, 오차함수를 정의해줍니다. )
    model.compile(optimizer= opt[i][0], 
                  loss = 'categorical_crossentropy', 
                  metrics=['acc'])  

    #6. 모델을 훈련시킵니다. 
    history = model.fit(x_train, y_train, 
                        epochs = 30,  # 30에폭
                        batch_size = 100,
                       validation_data = (x_test,y_test), verbose = 0)
    
    model.evaluate(x_test, y_test, verbose = 0)
    
    train_acc_list = history.history['acc']
    test_acc_list = history.history['val_acc']
    
    # 7.모델을 평가합니다. (오차, 정확도가 출력됩니다.)
    print(f'활성화함수 {opt[i][1]}, 경사하강법 {opt[i][0]}')
    print(f'훈련데이터 정확도 : {train_acc_list[-1]}, 테스트데이터 정확도 : {test_acc_list[-1]} ')
활성화함수 sigmoid, 경사하강법 SGD
훈련데이터 정확도 : 0.9611499905586243, 테스트데이터 정확도 : 0.9571999907493591 
활성화함수 relu, 경사하강법 Adam
훈련데이터 정확도 : 0.9955499768257141, 테스트데이터 정확도 : 0.9721999764442444 
활성화함수 relu, 경사하강법 RMSprop
훈련데이터 정확도 : 0.9955666661262512, 테스트데이터 정확도 : 0.9753999710083008 

 

+) 러닝레이트를 0.1 줬을때

from tensorflow.keras import backend as K

#코드추가
 #러닝레이트
    K.set_value(model.optimizer.learning_rate, 0.1)
    history = model.fit(x_train, y_train, 
                        epochs = 30,  # 30에폭
                        batch_size = 100,
                       validation_data = (x_test,y_test), verbose = 0)
활성화함수 sigmoid, 경사하강법 SGD
훈련데이터 정확도 : 0.9936500191688538, 테스트데이터 정확도 : 0.9739000201225281 
활성화함수 relu, 경사하강법 Adam
훈련데이터 정확도 : 0.9821000099182129, 테스트데이터 정확도 : 0.968999981880188 
활성화함수 relu, 경사하강법 RMSprop
훈련데이터 정확도 : 0.9803833365440369, 테스트데이터 정확도 : 0.9702000021934509 

 

정리하면 경사하강법은 Adam이 가장 좋았고 Adam을 사용했을 때의 활성화 함수는 relu가 좋았다. 다만 오버피팅이 발생해서 이제 오버피팅 줄이는 방법을 알아보겠습니다.

 

반응형