('혼자 공부하는 머신러닝+딥러닝' 199~217p 내용을 정리한 것입니다.)
만약 훈련 데이터가 한 번에 준비되는 것이 아니라 조금씩 만들어진다면, 앞서 훈련한 모델을 버리지 않고, 새로운 데이터에 대해서만 조금씩 더 훈련하는 방법이 좋다.(훈련에 사용한 데이터를 모두 유지할 필요도 없고 앞서 학습한 데이터를 잊어버릴 걱정도 없다.)
이런 훈련 방식을 점진적 학습이라고 하는데, 대표적으로 확률적 경사 하강법(Stochastic Gradient Descent)이 있다.
즉, 확률적 경사 하강법은 훈련 세트에서 랜덤하게 하나의 샘플을 선택하여 가파른 경사를 조금 내려간다. 그 다음 훈련 세트에서 랜덤하게 또 다른 샘플을 하나 선택해 경사를 조금 내려간다. 이런식으로 샘플을 전부 사용할 때까지 계속하는 것.
만약 샘플을 다 사용했는데 가장 낮은 곳에 도달하지 못했다면, 다시 처음부터 시작한다. 모든 샘플을 훈련 세트에 다시 채워넣고 랜덤하게 하나의 샘플을 선택해 내려가는 것을 반복한다.
확률적 경사 하강법에서 훈련 세트를 한 번 모두 사용하는 과정을 에포크(epoch) 라고 한다.
경사하강법의 종류
조금씩 경사를 내려가는 방식 덕분에 훈련 데이터가 모두 준비되어 있지 않고 매일 업데이트 되어도 학습을 계속 이어나갈 수 있다. 즉, 다시 처음부터 시작할 필요가 없다.
신경망 알고리즘은 일반적으로 많은 데이터를 학습하는데, 한 번에 모든 데이터를 사용하기 어렵다. 그리고 모델이 복잡해서 수학적인 방법으로 해답을 얻기가 어렵기 때문에 확률적 경사 하강법을 꼭 사용한다
(데이터 양이 많기 때문에 확률적 경사하강법이나 미니배치 경사 하강법을 사용함)
비용함수(cost function)은 훈련 세트에 있는 모든 샘플에 대한 손실 함수의 합을 말한다. 샘플 하나에 대한 손실을 정의하는 손실 함수와는 다른 뜻이지만 엄격하게 구분하지 않고 섞어서 사용한다.
분류의 경우 손실의 의미는 정답을 못맞히는 것이다.
중요한 건 정확도는 손실함수로 사용할 수 없다는 점인데, 예를 들어 4개의 샘플에 대한 정확도를 따지면,
샘플 4개의 예측 확률을 각각 0.9, 0.3, 0.2, 0.8로 가정하고 어떻게 손실 함수를 만들 수 있는지를 보면,
첫 번째 샘플의 예측은 0.9로 양성 클래스의 타깃인 1과 곱한 다음 음수로 바꿀 수 있다.(1과 가까울 수록 좋은 모델임)
예측이 1에 가까울 수록 예측과 타깃의 곱의 음수는 점점 작아진다. 이 값을 손실 함수로 사용한다.
두번째 샘플의 예측은 0.3이니까 -0.3이 되는데, 첫 번째 샘플보다 높은 손실이 됨.
단, 세 번째 샘플인 0.2는 음성 클래스인데, 이 값을 타깃과 곱하면 무조건 0이 되니까 양성 클래스에 대한 예측, 즉 0.8로 바꿔주고 타깃과 곱한 다음 음수로 바꾼다. -> 0.2를 0.8로 바꾸고 타깃 1과 곱한 다음 음수 = -0.8
네 번째 샘플 0.8도 음성 클래스이기 때문에 0.2로 바꾼다. 따라서 손실은 -0.2
지금까지의 손실을 정리하면 -0.9, -0.3, -0.8, -0.2이다.
예측 확률을 사용해 앞선 방식대로 계산하면 연속적인 손실 함수를 얻을 수 있고, 로그 함수를 적용하면 더 좋다.
- 예측 확률의 범위는 0~1 사이인데, 로그 함수는 이 사이에서 음수가 된다. 그래서 최종 손실 값은 양수가 된다.
- 손실이 양수면 이해하기 더 좋음.
- 로그 함수는 0에 가까울 수록 아주 큰 음수가 되기 때문에 손실을 아주 크게 만들어 모델에 영향을 미칠 수 있다.
(자세한 그래프와 설명은 책 206p 참고)
이 손실함수를 로지스틱 손실 함수 또는, 이진 크로스 엔트로피 손실 함수 라고 부른다.
사이킷런에서 확률적 경사 하강법을 제공하는 대표적인 분류용 클래스이다.
from sklearn.linear_model import SGDClassifier
sc = SGDClassifier(loss='log', max_iter=10, random_state=42)
sc.fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
결과
0.773109243697479
0.775
다중 분류일 경우 SGDClassifier에 loss='log'로 지정하면 클래스마다 이진 분류 모델을 만든다고 한다. 생선 클래스를 예로들면 도미를 양성 클래스로 두고 나머지를 모두 음성 클래스로 두고 모델을 만드는 식임. 이런 방식을 OvR(One versus Rest)라고 부른다.
SGDClassifier는 확률적 경사 하강법을 제공한다. 즉 점진적 학습이 가능함. 객체를 다시 만들지 않고 훈련할 모델 sc를 추가로 더 훈련해보면,
# 모델을 이어서 훈련할 땐 partial_fit() 메서드를 사용한다.
sc.partial_fit(train_scaled, train_target)
print(sc.score(train_scaled, train_target))
print(sc.score(test_scaled, test_target))
결과
0.8151260504201681
0.85