딥러닝 / 언더피팅 방지(경사하강법과 활성화 함수의 조합을 적절하게 조합하기)
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가 좋았다. 다만 오버피팅이 발생해서 이제 오버피팅 줄이는 방법을 알아보겠습니다.