학습률, 학습률 감소 / 계획법, 가중치 초기화, 과적합 방지 기법(가중치 감소, 드롭아웃, 조기종료)
오늘 배운 것은 신경망 학습이 더 잘되도록 하는 방법에 대한 것이다. 이 점을 기억하며 다음 내용을 읽어보면 된다.
(오전 QnA 세션 때 설명들은 내용인데 좋았어서 적어둔다.)
우리는 a,b를 바꿀 수 있다.
학습률
이다.Learning rate
이란 매 가중치에 대해 구해진 기울기 값을 얼마나 경사 하강법에 적용할지를 결정하는 하이퍼 파라미터이다. 근데 오늘 이 내용 공부하면서 경사하강법
에서 학습률에 따라 그래프상으로 어떻게 작용하며 내려간다는거지? 그 부분이 문득 헷갈려서 다시 찾아서 공부했다. (참고영상)
함수의 기울기(gradient)
를 이용해 x의 값을 어디로 옮길 때 최솟값을 갖는지 알아보는 방법이다.기울기 반대 방향으로 이동
이라고 하는거다. 그래서 기울기 앞에 -
가 붙어있는 거고. step size
라고 생각하면 된다. 학습률의 감소 주기는 100 step이다.
라는 말이 있었는데, 만약 초기 학습률이 0.001이었다면 그 다음 학습률은 0.001*100
으로 생각하면 됨.아무튼 정리!
최적의 학습률을 설정하는 것이 매우 중요하다.
학습률 감소(Learning rate decay)
, 학습률 계획법(Learning rate scheduling)
이다.학습률 감소(Learning rate decay)
model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001, beta_1 = 0.89)
, loss='sparse_categorical_crossentropy'
, metrics=['accuracy'])
beta_1
이 뭔지는 나중에 쓸 때 찾아보면 된다고 함!?학습률 계획법(Learning rate scheduling)
처음 warm-up step에서 학습률 보폭 크게 해서 정확도 빠르게 올리고, 어느 지점에서 다시 학습률 낮춰서 보폭 낮추고 조금씩 가면서 정확도를 점점 올려나가며 최적화된 상태를 찾는 것. (보폭이 계속 크면 뱅글뱅글 돌면서 글로벌 미니멈 찾기가 어려우니까)
이었는데 맞는지는 찾아봐도 헷갈린다. 좀 더 찾아봐야할 듯. .experimental
내부 함수를 통해 설계 가능.first_decay_steps = 1000
initial_learning_rate = 0.01
lr_decayed_fn = (
tf.keras.experimental.CosineDecayRestarts(
initial_learning_rate,
first_decay_steps))
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=lr_decayed_fn)
, loss='sparse_categorical_crossentropy'
, metrics=['accuracy'])
1. 표준편차를 1인 정규분포로 가중치를 초기화 할 때 각 층의 활성화 값 분포
2. Xavier 초기화를 해주었을 때의 활성화 값의 분포
glort_normal
라고 한다. 만든사람이 glort xavier라서 그렇다. 3. He 초기화를 해주었을 때의 활성화 값의 분포
He initailization
이다. He 초기화는 이전 층의 노드가 n개일 때, 현재 층의 가중치를 표준편차가 √n인 정규분포로 초기화합니다. 요약!! Activation function에 따른 초기값 추천
1. 가중치 감소 (Weight Decay)
Dense(64,
kernel_regularizer=regularizers.l2(0.01),
activity_regularizer=regularizers.l1(0.01))
# `kernel_regularizer` ⇒ 가중치 제한해주는 것. 위 코드에서는 l1,l2 둘다 적용한 거임. 0.01은 람다값임.
# `activity_regularizer` ⇒ 출력값을 규제해준다.
# `bias_regularizer` ⇒ 편향을 규제해준다.
2. 드롭아웃 (Dropout)
Dense(64,
kernel_regularizer=regularizers.l2(0.01),
activity_regularizer=regularizers.l1(0.01))
Dropout(0.5) # 50% 의 노드를 드롭하겠다는 뜻. 즉 32개만 쓰겠다.
3. 조기 종료 (early stopping)
각 방법별로 필요한 코드 비워진 곳을 채우고 돌려보는 거였다. 나중에 써먹을 때 참고하기 위해 그대로 옮겨온다.
[Base model]
import keras
import tensorflow as tf
import numpy as np
from tensorflow.keras.datasets import cifar100
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Flatten, Dropout
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import regularizers
import os, random
# seed를 고정합니다.
random.seed(1)
np.random.seed(1)
os.environ["PYTHONHASHSEED"] = str(1)
os.environ['TF_DETERMINISTIC_OPS'] = str(1)
tf.random.set_seed(1)
# 데이터 불러오기
(X_train, y_train), (X_test, y_test) = cifar100.load_data()
# 정규화(전처리)
X_train = X_train / 255.0
X_test = X_test / 255.0 ## => 각 픽셀은 0~255 사이의 정숫값을 가진다. X_train.max()/min()으로 직접 알 수도 있으나 나는 그냥 검색해서 알았다.
## X_train.shape => (50000, 32, 32, 3)
## np.unique(y_train) => 레이블 확인용
# 변수 설정을 따로 하는 방법을 적용하기 위한 코드입니다.
batch_size = 100
epochs_max = 20
# model
model = Sequential()
model.add(Flatten(input_shape=(32, 32, 3)))
## CIFAR-100 이미지 데이터는 32x32 픽셀의 이미지로, RGB 3채널의 컬러 이미지이다. 이 글을 참고하자. https://keepdev.tistory.com/52 흑백인 경우 이 3을 빼면 될 거다.
model.add(Dense(128, activation='relu'))
model.add(Dense(128, activation='relu'))
model.add(Dense(100, activation='softmax'))
# 컴파일 단계, 옵티마이저와 손실함수, 측정지표를 연결해서 계산 그래프를 구성함
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
results = model.fit(X_train, y_train, epochs=epochs_max, batch_size=batch_size, verbose=1, validation_data=(X_test,y_test))
#결과 확인
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=1) # loss: 3.3778 - accuracy: 0.2018
[+ Weight Decay]
# seed를 고정합니다.
random.seed(1)
np.random.seed(1)
os.environ["PYTHONHASHSEED"] = str(1)
os.environ['TF_DETERMINISTIC_OPS'] = str(1)
tf.random.set_seed(1)
# 데이터 불러오기
(X_train, y_train), (X_test, y_test) = cifar100.load_data()
# 정규화(전처리)
X_train, X_test = X_train / 255.0, X_test / 255.0
# 변수 설정을 따로 하는 방법을 적용하기 위한 코드입니다.
batch_size = 100
epochs_max = 20
# model
model = Sequential()
model.add(Flatten(input_shape=(32,32,3)))
model.add(Dense(128, activation='relu',
kernel_regularizer=regularizers.l2(0.00001), ###L2 regularization / param = 0.00001### => 가중치 초기화
activity_regularizer=regularizers.l1(0.00001))) ###L1 regularization / param = 0.00001### => 출력값 규제
model.add(Dense(128, activation='relu'))
model.add(Dense(100, activation='softmax'))
# 컴파일 단계, 옵티마이저와 손실함수, 측정지표를 연결해서 계산 그래프를 구성함
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
results = model.fit(X_train, y_train, epochs=epochs_max, batch_size=batch_size, verbose=1, validation_data=(X_test,y_test))
#결과 확인
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=1) #loss: 3.3056 - accuracy: 0.2169 // baseline model보다 좋아짐.
[+ Dropout]
# seed를 고정합니다.
random.seed(1)
np.random.seed(1)
os.environ["PYTHONHASHSEED"] = str(1)
os.environ['TF_DETERMINISTIC_OPS'] = str(1)
tf.random.set_seed(1)
# 데이터 불러오기
(X_train, y_train), (X_test, y_test) = cifar100.load_data()
# 정규화(전처리)
X_train, X_test = X_train / 255.0, X_test / 255.0
# 변수 설정을 따로 하는 방법을 적용하기 위한 코드입니다.
batch_size = 100
epochs_max = 20
# model
model = Sequential()
model.add(Flatten(input_shape=(32,32,3)))
model.add(Dense(128*1.1, activation='relu')) # 128*1.1 이거 왜 한거지? 140.8. Dropout 할 때 대강 숫자 맞추기 용도가 있는 것 같은데 아닌가..
model.add(Dropout(0.1)) # => 10% out, only use 90%
model.add(Dense(128, activation='relu'))
model.add(Dense(100, activation='softmax'))
# 컴파일 단계, 옵티마이저와 손실함수, 측정지표를 연결해서 계산 그래프를 구성함
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
results = model.fit(X_train, y_train, epochs=epochs_max, batch_size=batch_size, verbose=1, validation_data=(X_test,y_test))
128*1.1
로 한건 뒤에 드롭하는게 10%니까 다른 모델들과 노드 수를 대략 맞춰서 성능 비교하기 좋게 해주려는 의도로 넣어둔거라고 한다.128*1.1
을 하면 140.8이 나오는데, 원래 노드 수에는 정수형태로 입력되어야 한다고 공식문서에 나와있다. 따라서 이렇게 소수점 자리가 있는 경우 대체적으로 제거가 된 형태로 출력된다고 한다. 반올림 아니고 그냥 140으로 출력! 재밌다. 동기님이 알려주셨다. 감사합니다..!#결과 확인
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=1) #loss: 3.3898 - accuracy: 0.1951
[+ Early Stopping]
- 멈추는 기준을
val_loss
(검증 데이터셋의 loss 값)로 하고 loss가 Best 값보다 5번 높아질 때 Stop 하도록 설정합니다.- Best 모델을 저장해봅시다. Best 모델 역시 멈추는 기준을
val_loss
(검증 데이터셋의 loss 값)로 하고save_best_only=True
,save_weights_only=True
로 설정합니다.
# seed를 고정합니다.
random.seed(1)
np.random.seed(1)
os.environ["PYTHONHASHSEED"] = str(1)
os.environ['TF_DETERMINISTIC_OPS'] = str(1)
tf.random.set_seed(1)
# 데이터 불러오기
(X_train, y_train), (X_test, y_test) = cifar100.load_data()
# 정규화(전처리)
X_train, X_test = X_train / 255.0, X_test / 255.0
# 학습시킨 데이터를 저장시키기 위한 코드입니다.
checkpoint_filepath = "FMbest.hdf5"
# 변수 설정을 따로 하는 방법을 적용하기 위한 코드입니다.
batch_size = 100
epochs_max = 50 # => quiz에서 주어진 조건임.
model = Sequential()
model.add(Flatten(input_shape=(32,32,3)))
model.add(Dense(128, activation='relu'))
model.add(Dense(128, activation='relu'))
model.add(Dense(100, activation='softmax'))
# 컴파일 단계, 옵티마이저와 손실함수, 측정지표를 연결해서 계산 그래프를 구성함
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# early stopping
# 파라미터 저장 경로를 설정하는 코드
checkpoint_filepath = "IMbest.hdf5"
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=5, verbose=1)
# Validation Set을 기준으로 가장 최적의 모델을 찾기
save_best = keras.callbacks.ModelCheckpoint(
filepath=checkpoint_filepath, monitor='val_loss', verbose=1, save_best_only=True,
save_weights_only=True, mode='auto', save_freq='epoch', options=None) # => 파라미터 레퍼런스 https://deep-deep-deep.tistory.com/53
results = model.fit(X_train, y_train, batch_size=batch_size, epochs=epochs_max, verbose=1,
validation_data=(X_test,y_test),
callbacks=[early_stop, save_best])
# 학습된 모델을 이용하여 테스트하는 코드
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=1)
#loss: 3.3223 - accuracy: 0.2159 => acurracy를 보면 알겠지만 early stopping 지점의 모델 성능임.
model.load_weights(checkpoint_filepath)
# best model을 이용한 테스트 데이터 예측 정확도 재확인 코드
test_loss, test_acc = model.evaluate(X_test, y_test, verbose=1) # loss: 3.3183 - accuracy: 0.2133
Normalization
vs standardization
vs regularization
정규화
라고 번역되니 헷갈릴 수 밖에.. (참고한 글)Normalization
: 값의 범위를 0~1사이의 값으로 바꾸는 것.standardization
: 값의 범위를 평균0, 분산 1이 되도록 변환.regularization
: weight를 조정하는데 규제(제약)을 거는 방법. 과적합 방지를 위해 사용되며, L1(Lasso), L2(Lidge) 등의 종류가 있음. .hdf5
(혹은 .h5
) 파일 형식은 데이터를 계층 구조로 저장하는 하나의 파일 확장자이다. 계층 구조로 저장한다는 의미는 학습별로 가중치를 계층 순서에 따라 저장을 한다고 받아들이면 될 것 같다. hdf5 파일에 대해서는 이 글 참고.