Python/인공지능

AI ( gradient descent/ momentum/ AdaGrad/ RMSProp/ Adam/과적합[overfitting]/ early stopping)

아리빠 2023. 5. 10. 20:17

● Gradient Descent (경사하강법)

-함수의 기울기(=gradient)를 이용해 x의 값을 어디로 옮겼을 때 함수가 최소값을 찾는지 알아보는 방법

 

=> 문제점

1. 극소값(local minimum)에 도달할 수 있다는 것이 증명되었으나, 전체 최소값(global minimum) 에 갈 수 있다는 보장 없음

2. 훈련이 느림

 

 


● Momentum

-GD(graient descent) 의 문제를 해결하기 위해 보편적으로 사용되는 방법

-관성(momentum)을 적용하여 변수가 가던 방향으로 계속 가도록 속도(velocity)를 추가한 것

-전체 최소값(global minimum)에 이르기전에 기울기가 0이 되는 (local minimum)에 빠지는 것을 방지

 

=>문제점

1. 여전히 지역 최소값 탈출이 어렵다

2. 수렴 속도의 불안정성

3. 메모리 요구량 증가

4. 하이퍼 파라미터 설정의 어려움

 


● AdaGrad

- 관성(momentum)은 gradient의 방향에 초점을 두었다면, AdaGrad는 step size에 초점

이미 학습이 많이 된 변수는 학습을 느리게, 학습이 아직 덜 된 드물게 등장한 변수라면 학습을 더 빨리 훈련함

 

=>문제점

학습이 오래 진행이 될 경우 step size가 너무 작아져서 거의 움직이지 않는 상태가 됨

 

 


● RMSProp

- Root Mean Square Propatation의 약자 Adagrad의 계산식에 지수 가중 이동 평균(Exponentially weighted average)를 사용하여 최신 기울기들이 더 크게 반영되도록 함

 

=>문제점

1. 여전히 하이퍼 파라미터 설정에 민감

2. 지역 지역 최소값에 빠질 수 있는 가능성 존재

 


● Adam

- Adam(Adaptive Moment Estimation) 은 RMSProp과 Momentum 방식을 융합

- Momentum과 유사하게 지금까지 계산한 기울기의 지수 평균을 저장하며, RMSProp과 유사하게 기울기의 제곱값의 지수 평균을 저장

 

=>문제점

1. 메모리 요구량이 큼

2. 학습률 조절이 자동으로 이루어지기에 학습률 감소 패턴 파악이 어려움

 

 


● 과적합(Overfitting)

- 과적합은 모델이 학습 데이터에 너무 과도하게 적합화되어, 새로운 데이터에 대한 예측 성능이 저하되는 현상

- 모델이 학습 데이터에만 맞추어져 새로운 데이터에 대해 일반화(generalization) 능력이 부족하게 되는 것

#초록색 선은 과적합된 모델을, 검은색 선은 일반 모델

 

 

 


● Early Stopping

- 과적합을 방지하기 위한 방법 중 하나

- 학습 중 모델의 성능을 모니터링하다가 학습 데이터에 대한 성능은 계속해서 향상되지만 검증 데이터에 대한 성능은 향상되지 않거나 감소하는 지점에서 학습을 조기 종료하는 것

- 일반적으로, 학습 데이터와 검증 데이터를 나누어 학습하면서 적용됨

import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
#from sklearn.datasets import load_boston # 윤리적 문제로 제공 안함
from sklearn.datasets import fetch_california_housing
import time
#1 데이터 
#daatsets = load_boston()

datasets = fetch_california_housing()
x= datasets.data #x축 변수 컬럼
y= datasets.target #집값

print(datasets.feature_names)
#MedInc, HouseAge, AveRooms, AveBedrms, Population, AveOccup, Latitude, Longitude
print(datasets.DESCR)
#- 블럭 그룹의 중위수 소득
#- 블럭 그룹의 주택 연령 중위수
#- 가구당 평균 객실 수
#- 평균 가구당 침실 수
#- 모집단 블럭 그룹 모집단
#- 평균 가구원수
#- 블록 그룹 위도
#- 경도 블록 그룹 경도

print(x.shape) #(20640, 8)
print(y.shape) #(20640,)


x_train, x_test, y_train, y_test = train_test_split(

    x,y,train_size=0.7, random_state=100, shuffle=True
)

print(x_train.shape)
print(y_train.shape)

#2 모델 구성
model= Sequential()
model.add(Dense(100, input_dim=8))
model.add(Dense(100))
model.add(Dense(100))
model.add(Dense(1))

#3 컴파일

model.compile(loss='mse', optimizer='adam')

##ealry stopping
from keras.callbacks import EarlyStopping

earlyStopping = EarlyStopping(monitor='val_loss', patience=100, mode='min',
                              verbose=1, restore_best_weights=True) # restore_best_weights 는 디폴트(기본값)이 False이므로 True로 변경필수


start_time = time.time()
hist= model.fit(x_train, y_train, epochs=500, batch_size=200,
          validation_split=0.2, callbacks=[earlyStopping], verbose=1) #validation_data =>0.2 (train:0.6 / test:0.2)


end_time = time.time() - start_time

#4 평가 예측
loss = model.evaluate(x_test, y_test)

print('loss: ', loss)
y_predict = model.predict(x_test)

r2= r2_score(y_test,y_predict)
print('r2 스코어: ' ,r2)

print('end time:' ,end_time)

#시각화

import matplotlib.pyplot as plt
plt.figure(figsize=(9,6))
plt.plot(hist.history['loss'], marker = '.' , c='orange', label='loss')
plt.plot(hist.history['val_loss'], marker= '.', c='blue' ,label='val_loss')

plt.title('loss & val_loss')
plt.ylabel('loss')
plt.xlabel('epochs')
plt.legend()
plt.show()

 

 

 


● 라이브러리 충돌 오류 해결 코드

# 자주뜨는 라이브러리 충돌 오류 고치는 코드
import os  
os.environ['KMP_DUPLICATE_LIB_OK'] ='True'

 


● 실습 코딩

# validation01
import numpy as np
from keras.models import Sequential
from keras.layers import Dense

#1 데이터
x = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])
y = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])


#x= np.array(range(1,21))
#y= np.array(range(1,21))
'''
#데이터 쉐입보기
print (x.shape)
print (y.shape)
'''

x_train = np.array([1,2,3,4,5,6,7,8,9,10,11,12])
y_train = np.array([1,2,3,4,5,6,7,8,9,10,11,12])

x_test = np.array([17,18,19,20])
y_test = np.array([17,18,19,20])

x_val = np.array([13,14,15,16])
y_val = np.array([13,14,15,16])


#2 모델 구성
model= Sequential()
model.add(Dense(14, input_dim=1))
model.add(Dense(50))
model.add(Dense(1))

#3 컴파일 훈련
model.compile(loss='mse', optimizer='adam')
model.fit(x_train, y_train, epochs=100, batch_size=1,
          validation_data=[x_val, y_val])

#4 평가,예측
loss = model.evaluate(x_test, y_test)
print('loss: ', loss)

result = model.predict([21])
print('21의 예측값: ', result)

 

# validation02
import numpy as np
from keras.models import Sequential
from keras.layers import Dense

#1 데이터
x = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])
y = np.array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])


#x= np.array(range(1,21))
#y= np.array(range(1,21))
'''
#데이터 쉐입보기
print (x.shape)
print (y.shape)
'''

x_train = np.array([1,2,3,4,5,6,7,8,9,10,11,12])
y_train = np.array([1,2,3,4,5,6,7,8,9,10,11,12])

x_test = np.array([17,18,19,20])
y_test = np.array([17,18,19,20])

x_val = np.array([13,14,15,16])
y_val = np.array([13,14,15,16])


#2 모델 구성
model= Sequential()
model.add(Dense(14, input_dim=1))
model.add(Dense(50))
model.add(Dense(1))

#3 컴파일 훈련
model.compile(loss='mse', optimizer='adam')
hist = model.fit(x_train, y_train, epochs=100, batch_size=1,
          validation_data=[x_val, y_val])

#4 평가,예측
loss = model.evaluate(x_test, y_test)
print('loss: ', loss)

result = model.predict([21])
print('21의 예측값: ', result)

##history_val_loss 출력  출력하는 이유: 나중에 ealrystop 시 val loss 최소화 지점에서 멈춰야하므로
print('==================================================================================')
print(hist)
#print(hist.history)
print(hist.history['val_loss'])


## loss 와 val_loss 시각화 
import matplotlib.pyplot as plt


import os   # 자주뜨는 라이브러리 충돌 오류 고치는 코드
os.environ['KMP_DUPLICATE_LIB_OK'] ='True'

'''
from matplotlib import font_manager, rc
font_path = 'C:\Windows\Fonts/Calibri.ttf'
font = font_manager.FontProperties(fname=font_path).get_name()
rc('font', family=font)
'''
#plot:선 scatter:점
plt.figure(figsize=(9,6))
plt.plot(hist.history['loss'],marker='.', c='red', label='loss')
plt.plot(hist.history['val_loss'],marker='.', c='blue', label='val_loss')
plt.title('0')
plt.ylabel('loss')
plt.xlabel('epochs')
plt.legend()
plt.show()

 

#iris_validation
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris
import time

# 데이터
datasets = load_iris()
print(datasets.DESCR)
print(datasets.feature_names)

x=datasets['data'] # =x=datasets.data
y= datasets.target
print(x.shape, y.shape) #(150, 4) (150,)


### one hot encoding 
from keras.utils import to_categorical
y = to_categorical(y)
print(y)
print(y.shape)



x_train, x_test, y_train, y_test = train_test_split(

    x,y,train_size=0.7, random_state=100, shuffle= True
)
print(x_train.shape, y_train.shape) #(105, 4) (105,)
print(x_test.shape, y_test.shape)   #(45, 4) (45,)
print(y_test)



#2 모델 구성

model = Sequential()
model.add(Dense(100, input_dim=4))
model.add(Dense(100))
model.add(Dense(100))
model.add(Dense(100))
model.add(Dense(100))
model.add(Dense(100))
model.add(Dense(3,activation='softmax'))

#3 컴파일 + 훈련

model.compile(loss='categorical_crossentropy', 
              optimizer= 'adam', 
              metrics=['accuracy'])


start_time = time.time()

hist = model.fit(x_train, y_train, epochs=500, batch_size=100,
                 validation_split= 0.3)

end_time = time.time() - start_time

print('걸린시간: ', end_time)

#4 평가예측

loss,acc = model.evaluate(x_test, y_test)
print('loss: ', loss)
print('acc: ',acc)
import matplotlib.pyplot as plt
plt.figure(figsize=(9,6))
plt.plot(hist.history['loss'], marker = '.' , c='orange', label='loss')
plt.plot(hist.history['val_loss'], marker= '.', c='blue' ,label='val_loss')
plt.title('iris loss & val_loss')
plt.ylabel('loss')
plt.xlabel('epochs')
plt.legend()
plt.show()

400~500 에서 튄 그래프가 과적함임을 보여줌


●Save model

-model.save() 함수는 모델의 구조와 가중치를 함께 저장
따라서 해당 함수를 호출하는 위치에 따라 저장되는 내용이 달라진다

 

-만약 model.save()를 model.compile() 이후, model.fit() 이전, 즉 모델 구성이 완료된 후에 호출한다면,그 시점의 모델 구조와 초기화된 가중치(훈련 전이므로 무작위로 초기화된 값)가 저장된다

 

model.save
load model

위 코드에서 ('''    '''') 로 주석 처리 된 부분이 model.save 함수가 저장하는 가중치 영역이다

 

만약 model.save()를 model.fit() 이후에 호출한다면, 그 시점의 모델 구조와 훈련된 가중치가 함께 저장된다

save model
load model


●Save weight

 

모델의 가중치를 저장하기 위해서는 model.save_weights(filepath) 함수를 사용

 

여기서 filepath는 가중치를 저장할 경로를 나타낸다

저장된 가중치는 model.load_weights(filepath) 함수를 사용하여 다시 로드할 수 있다

위 코드에서 주석처리한 부분이 model.save_weights 함수가 저장하는 가중치 영역


●Model Check Point

-Keras에서 제공하는 콜백(callback) 중 하나, 훈련 중간에 모델의 가중치 또는 전체 모델을 저장할 수 있다 
-이를 통해 훈련 과정에서 얻은 최적의 가중치 또는 모델을 자동으로 저장, 훈련이 중단되거나 완료된 후에도 최적의 결과를 사용
-일반적으로 ModelCheckpoint는 model.fit()의 callbacks 매개변수를 통해 사용, 이렇게 사용하면 에폭(epoch)이 끝날 때마다 모델이 저장된다
+저장할 모델의 조건을 설정할 수 있다(ex) 검증 성능이 개선될 때만 저장)

from tensorflow.keras.callbacks import ModelCheckpoint

# ModelCheckpoint 콜백 생성
checkpoint = ModelCheckpoint(filepath='best_model.h5', monitor='val_loss', save_best_only=True, mode='min')

# 훈련 중 최적의 모델을 저장하기 위해 ModelCheckpoint 콜백 사용
model.fit(X_train, y_train, epochs=10, batch_size=32, validation_data=(X_val, y_val), callbacks=[checkpoint])