728x90
학습 곡선을 통해 과대 적합과 과소 적합을 본다
- 과대 적합
- 모델이 훈련 세트에서는 좋은 성능을 내나 검증 세트에서는 낮은 성능을 내는 경우
- 훈련 세트의 정확도가 99%일때 검증 세트의 정확도가 80%라면 의심할 수 있다.
- 과소 적합
- 훈련 세트와 검증 세트의 성능 차이가 크지 않으나 모두 낮은 성능을 내는 경우
- 훈련 세트의 크기와 과대적합, 과소 적합 분석
- 첫 번째 학습 곡선
- 과대 적합의 전형적인 모습
- 훈련 세트와 검증 세트의 성능의 간격이 크다
- 분산이 크다(high variance)
- 원인으로는 훈련 세트에 충분히 다양한 패턴의 샘플이 포함되지 않은 경우
- 해결 방안
- 더 많은 훈련 샘플로 검증 세트의 성능 향상
- 훈련 샘플을 모을 수 없는 경우 가중치 제한으로 조정
- 가중치 제한을 하는 방법 == 모델의 복잡도를 낮추는 것
- 두 번째 학습 곡선
- 과소적합의 전형적인 모습
- 훈련 세트와 검증 세트의 간격은 점점 가까워지나 성능이 낮음
- 편향이 크다(high bias)
- 원인으로는 모델이 충분히 복잡하지 않아 훈련 데이터에 있는 패턴을 모두 잡아내지 못함
- 해결방안
- 복잡도가 더 높은 모델을 사용
- 가중치의 규제를 완화
- 세번째 학습 곡선
- 과대 적합과 과소 적합의 절충선을 찾음
- 에포크와 손실 함수의 그래프로 과대 적합과 과소 적합 분석
- 왼쪽 그래프
- 검증 세트, 훈련 세트의 손실을 나타낸 것
- 훈련 세트의 손실을 에포크가 진행될 수록 감소, 검증 세트의 손실은 증가
- 이유는 최적점 이후에 계속 훈련 세트로 모델을 학습할 경우 모델이 훈련 세트의 샘플에 더 밀착하기 때문
- 과대 적합의 방향으로 이동
- 그러나 최적점 이전에 손실이 비슷할 경우 학습 중단시 과소 적합 모델의 완성
- 오른쪽 그래프
- 왼쪽은 손실, 오른쪽은 정확도에 비교
- 그래프의 모습만 뒤집힐 뿐 해석은 동일
- 모델의 복잡도와 손실 함수의 그래프로 과대적합과 과소 적합 분석
- 모델의 복잡도 : 모델이 가진 학습 가능한 가중치의 개수
- 층의 개수나 유닛의 개수가 많을 경우 복잡도가 높아진다
- 복잡도가 높다 - 과대 적합 위험
- 복잡도가 낮다 - 과소 적합 위험
적절한 편향-분산 트레이드오프 선택
- 과소적합 모델(편향), 과대 적합 모델(분산) 사이의 관계를 편향 - 분산 트레이드 오프(bias-variance tradeoff)
- 트레이드오프의 의미
- 편향을 줄이면 (훈련 세트의 성능을 높이면)
- 분산이 커지고 (검증 세트와 차이가 커짐)
- 분산을 줄이면 (검증 세트와 성능 차이를 줄이면)
- 편향이 커짐 (훈련 세트의 성능이 낮아짐)
- 목표 : 분산이나 편향이 너무 심해지지 않는 적절한 중간지점 선택
- 검증 손실을 기록하기 위한 변수 추가
def __init__(self, learning_rate=0.1) :
self.w = None
self.b = None
self.losses = []
self.val_losses = []
self.w_history = []
self.lr = learning_rate
- 이전에 사용한 Singlelayer 클래스에 __init__() 메서드에 self.val_losses를 추가
- fit() 메서드에 검증 세트 전달을 위한 매개변수 추가 (x_val, y_val)
def fit(self, x, y, epochs=100, x_val=None, y_val = None) :
self.w = np.ones(x.shape[1]) # 가중치 초기화
self.b = 0 # 절편 포기화
self.w_history.append(self.w.copy()) # 가중치 기록
np.random.seed(42) # 무작위 시드 지정
for i in range(epochs) : # epochs 만큼 반복
loss = 0
# 인덱스 섞기
indexes = np.random.permutation(np.arange(len(x)))
for i in indexes : # 모든 샘플에 대해 반복
z = self.forpass(x[i]) # 정방향 계산
a = self.activation(z) # 활성화 함수 적용
err = -(y[i] - a) # 오차 계산
w_grad, b_grad = self.backprop(x[i], err) # 역방향 계산
self.w -= self.lr * w_grad # 가중치 업데이트(학습률 적용)
self.b -= b_grad # 절편 업데이트
# 가중치를 기록
self.w_history.append(self.w.copy())
# 안전한 로그 계산을 위해 클리핑한 후 손실을 누적
a = np.clip(a, 1e-10, 1-1e-10)
loss += -(y[i]*np.log(a)+(1-y[i])*np.log(1-a))
# 에포크마다 평균 손실 저장
self.losses.append(loss/len(y))
# 검증 세트에 대한 손실 계산
self.update_val_loss(x_val, y_val)
- 검증 손실 계산
def update_val_loss(self, x_val, y_val) :
if x_val is None :
return
val_loss = 0
for i in range(;en(x_val)) :
z = self.forpass(x_val[i]) # 정방향 계산
a = self.activation(z) # 활성화 함수 적용
a = np.clip(a, 1e-10, 1-1e-10)
val_loss += -(y_val[i]*np.log(a)+(1-y_val[i])*np.log(1-a))
self.val_losses.append(val_loss/len(y_val))
- 검증 세트 샘플 정방향 계산
- 활성화 함수 통과
- 그 결과를 이용한 로지스틱 손실 함수 값 계산을 위한 fit()에서 1 에포크마다 update_val_loss() 호출
- 모델 훈련(단일 신경망)
layer3 = SingleLayer()
layer3.fit(x_train_scaled, y_train, x_val = x_val_scaled, y_val=y_val)
- 손실 값으로 그래프그래 에포크 횟수 지정
plt.ylim(0, 0.3)
plt.plot(layer3.losses)
plt.plot(layer3.val_losses)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train_loss', 'val_loss'])
plt.show()
- 약 20번째 이후로 검증 손실이 훈련 세트보다 높아진다
- 훈련 조기 종료
- 훈련 조기 종료방식은 조기종료(early stoppping)이라 한다
- 20번째 에포크 까지만 진후 성능 확인
layer4 = SingleLayer()
layer4.fit(x_train_scaled, y_train, epochs=20)
layer4.score(x_val_scaled, y_val)
- 약 97%의 정확도를 가진다
728x90
'AI' 카테고리의 다른 글
5-1 검증 세트를 나누고 전처리 과정 배우기 (0) | 2020.11.25 |
---|---|
4-7 사이킷 런으로 로지스틱 회귀 수행 (0) | 2020.11.18 |
4-6 로지스틱 회귀 뉴런으로 단일층 신경망 제작 (0) | 2020.11.18 |
4-5 로지스틱 회귀를 위한 뉴런 만들기 (0) | 2020.11.18 |
4-4 분류용 데이터 세트 (0) | 2020.11.18 |