아래 내용은 ‘케라스 창시자에게 배우는 딥러닝 (프랑소와 슐레 저, 박해선 옮김, 길벗 출판사)’ 을 공부한 뒤, 배운 내용을 제 언어로 정리.기록한 것 입니다.
머신러닝 네 가지 분류
지도 학습
정의
사람이 정답 주고, 모델이 주어진 정답 잘 맞추도록 학습시키는 기법
종류
- 분류
- 회귀
- 시퀀스 생성
- 구문 트리 예측
- 물체 감지
- 이미지 분할
비지도 학습
정의
데이터 자체의 특성 파악. 추출하도록 학습시키는 기법
종류
- 차원 축소
- 군집(Clustering)
자기 지도 학습
정의
사람이 개입하지 않는 지도학습
- 모형이 경험적 알고리듬(heuristic algorithm) 사용해 입력 데이터로부터 레이블 생성한다.
종류
- 오토인코더(autoencoder)
- 시간에 따른 지도 학습
강화학습
정의
모형이 주어진 상황에서 보상 강화하는 출력을 선택하도록 학습시키는 기법
- 아직 현장에서는 잘 사용되지 않고, 연구 영역에 있다.
- 하지만 발전 가능성, 비전 있는 머신러닝 분야다.
예
게임에서 강화학습
- 게임 속 전장 상황이 주어지면, 모형이 게임 점수 최대화 할 수 있는 게임 내 행동을 출력
머신러닝 모델 평가
‘일반화 할 수 있는 모델 평가’
$\Rightarrow$ 새 데이터셋에서 모델 성능 평가
- 모델 성능 평가 위해 ‘신뢰할 수 있는 모델 성능 측정 방법’이 필요하다.
데이터셋을 훈련용, 검증용, 테스트용 셋으로 나누기
모델 훈련시키고 성능 평가하는 과정
- 훈련용 셋에서 모델을 훈련시킨다.
- 검증용 셋으로 새 데이터셋에서 모델 성능 평가한다.
- 검증용 셋 결과 가지고. 신경망 각 층의 히든유닛 수, 층 수 등 하이퍼파라미터 ‘튜닝’한다. 모델 성능 올리기 위한 작업이다.
- 튜닝된 모델을 다시 훈련용 셋으로 훈련시키고, 성능 검증하고, 튜닝한다.
- 튜닝 모두 끝나면 테스트용 셋으로 딱 한 번 모델 성능 평가한다.
테스트용 셋 따로 두는 이유
과정 중 하이퍼파라미터 튜닝 반복하면서 모델이 검증용 셋에 과적합 되는 경향 나타난다.
따라서 튜닝 반복하다 보면 검증용 셋에서 성능이 갈수록 올라갈 수 밖에 없다.
모델 일반화 성능 제대로 평가하기 위해 완전히 새로운 데이터가 필요하고, 그 역할 하는 게 테스트 셋이다.
데이터셋 나누는 기법
단순 홀드아웃 검증
Hold out: 남겨두다
정의
전체 셋에서 검증용 셋 따로 떼어두는 방법
- 테스트용 셋은 검증용 셋 분리 전에 따로 떼 두었다고 가정
- 훈련용 셋으로 모델 훈련시킨다
- 검증 셋으로 모델 성능 검증하고, 하이퍼파라미터 튜닝한다
장점
단순하다. 복잡한 작업 필요 없다.
단점
데이터 적으면 훈련용 셋과 검증용 셋의 전체 데이터에 대한 통계적 대표성 떨어진다.
$\Rightarrow$ 데이터 수 적을 때는 적용할 수 없다.
K-겹 교차검증
데이터 수 작을 때 특히 유용한 방법이다.
정의
전체 데이터셋 k개 분할로 나눠 그 중 하나는 검증용 셋, 나머지는 훈련용 셋으로 삼는 방법
- 모델 훈련 - 검증 과정 k번 반복한다.
- k개 성능 점수 평균을 최종 성능 점수로 삼는다.
셔플링 사용한 반복 K-겹 교차검증
데이터 수 작을 때 특히 유용한 방법이다.
정의
P번 반복해서 K-겹 교차검증 수행
- K-겹 교차검증 수행 하기 전 매번 데이터셋 무작위로 섞는다(셔플)
- P번의 K-겹 교차검증 점수 평균이 최종 점수 된다.
단점
시간 많이 걸린다.
이외 기억해야 할 점
- 데이터셋을 훈련용 셋, 검증용 셋, 테스트 셋으로 나누기 전에 되도록 데이터셋 한번 섞자(셔플).
1
2
3
# 셔플
np.random.shuffle(data)
데이터에 시간 순서가 나타나면 절대 섞으면 안 된다. 훈련용 셋은 상대적으로 과거 데이터, 테스트 셋은 상대적으로 미래 데이터로 구성되도록 분리하자.
데이터셋에 중복된 데이터(레코드)가 있으면 제거하는 것이 좋다.
데이터 전처리
데이터 전처리 기법들은 입력 데이터 종류별로 특화되어 있다. 예컨대 이미지, 텍스트 데이터 전처리 방법이 다르다.
신경망 위한 데이터 전처리 일반론
벡터화(데이터 벡터화)
정의
입력 데이터를 부동 소수점 실수 또는 정수로 구성된 텐서로 변환하는 작업.
- 신경망 모든 입력은 텐서여야 하므로, 데이터 전처리 할 때 반드시 거치는 과정이다.
정규화
정의
각 데이터를 0과 1 사이(또는 작은 값) 로 변환하고, 특성값들 간 스케일 맞춰주는 작업이다.
- 신경망의 원활한 학습 위해 반드시 거쳐야 할 과정이다.
보다 엄격한 정규화(수학적 정규화)
정의
각 특성 별 데이터를 평균이 0, 표준편차가 1로 만드는 작업.
누락된 값(Null/NA) 값 다루기
전체 평균에 영향 미치지 않는 값으로 누락된 값 채운다.
Null 자리에 뭘 넣는가
- 일반적으로 0 넣는다.
- 평균값을 넣기도 한다.
- 중앙값을 넣기도 한다.
만약 훈련용 셋 누락 값을 그 평균. 중앙값으로 대체하기로 했다면,
테스트 셋 누락 값도 훈련용 셋 평균. 중앙값으로 대체해야 한다.
교차검증 할 때도 검증용 셋 누락 값은 훈련용 셋 평균. 중앙값으로 채워야 한다.
만약 훈련용 셋에 누락 값 없는데 테스트셋에 있다면?
모델이 훈련 받을 때 누락 값 처리 방법을 학습하지 못했으므로, 문제 발생한다.
따라서
- 전체 데이터셋에서 누락 값 있는 샘플(레코드 or 행벡터) 수가 적다면, 테스트셋 떼어놓기 전 이 레코드들 제외한다.
- 누락된 값 있는 특성이 별로 안 중요하면, 이 특성을 통째로 제외하고 테스트셋 떼어 놓는다.
특성 공학
정의
원본 데이터에서 특성만 추출해서 데이터 변환하는 작업.
- 문제에 대한 명료한 정의를 내릴 수 있어야 한다.
예시
시계 사진(이미지) 에 나타난 시간 정보 출력하는 모형 만들고 싶다.
- 시계 사진 그대로 써서 정보 추출하기에는 보다 복잡한 모형, 높은 컴퓨팅 파워 필요하다.
한편 시계 사진 데이터에 특성 공학 적용하면 아래와 같아진다.
내가 추출하고 싶은 정보는 ‘시간 정보’다.
그러면 굳이 원본 데이터 전체가 필요 없다. 시간 정보만 있으면 된다.
$\Rightarrow$ 원본 데이터에서 시간 정보 나타내는 특성만 추출한다.
여기서 ‘시간’에 대한 정의가 필요하다.
시간 정의: 초침과 분침이 가리키는 지점.
$\Rightarrow$ 원본 데이터에서 초침과 분침이 가리키는 지점 정보만 추출한다.
또는
시간 정의: 초침과 분침이 이루는 각도.
$\Rightarrow$ 원본 데이터에서 초침과 분침이 이루는 각도 정보만 추출한다.
결과로
2차원 벡터공간 상의 특정 지점(point)
또는
원점과 2차원 직교좌표계를 중심으로 한 어떤 각도 값들로
구성된 1차원 텐서(벡터)가 나올 것이다.
이 벡터가 원본 이미지 데이터가 ‘변환된’ 데이터 이고, 이렇게 원본 데이터 변환하는 작업을 ‘특성 공학’ 이라 한다.
쓰임
- 특성 공학은 전통적 머신러닝 기법들 사용할 때 아주 중요하게 쓰인다.
- 딥러닝 기법 사용할 때는 특성 공학 필요 없다.
그럼에도
- 특성 공학 사용하면. 딥러닝 모델 썼을 때 보다. 특정 문제를 더 적은 자원 & 훨씬 효율적으로 해결할 수 있다. 위 시계 문제가 예다.
- 데이터 수 적어서 딥러닝 모델 적용할 수 없을 때. 특성 공학 사용하면 적은 데이터로 문제 효과적으로 해결할 수 있다.
과대적합과 과소적합
머신러닝 근본 이슈는 ‘일반화’와 ‘최적화’ 사이 줄다리기
최적화는 ‘훈련 데이터’에서 모델 성능 최대화 하기 위해 최적 파라미터 찾는 작업 말한다.
일반화는 ‘새 데이터’에서 모델 성능이 잘 나오도록 하는 걸 말한다.
최적화가 과도하면 과대적합 나타난다. 모델 일반화 성능은 떨어진다.
반면 최적화 부족하면 과소적합 나타난다. 모델 일반화 성능 더 끌어올릴 여지 남아있다.
과대적합(Overfitting)
모든 머신러닝 문제에서 과대적합은 종종.자주. 마주치는 문제다.
따라서 머신러닝에서는 과대적합 잘 제어하는 것이 중요하다.
정의
모델이 학습 데이터에 특화된 패턴을 학습하기 시작한 상태.
$\Rightarrow$ 모델이 학습 데이터와 레이블을 ‘외워버리기 시작한’ 상태.
과대적합 있을 때 모델 성능
과대적합이 나타나면 검증용 셋에서 모델 성능은 떨어지기 시작한다.
테스트 셋에서도 모델 성능이 낮게 나온다. 곧, 과대적합 나타나면 모델 일반화 성능 떨어진다.
과소적합(Underfitting)
모델 훈련 초기에 나타난다.
정의
모델이 훈련 데이터에 나타난 특징들을 아직 충분히(모두) 학습하지 못한 상태.
과소적합 있을 때 모델 성능
과소적합 있을 때, 모델 성능은 훈련용 셋과 검증용 셋 모두에서 함께 증가한다.
과소적합 있을 때는 모델 성능이 아직 더 향상될 여지가 남아있다.
- 과소적합 상태 끝나고나면 곧이어 과대적합 나타나기 시작한다.
규제(Regularization)
정의
모델에 과대적합 발생 억제하는 과정
- 모델에 과대적합 발생하면 모델 일반화 성능(모델 개발 목표)이 떨어진다. 그래서 규제 통해 과대적합 발생 억제한다.
종류
더 많은 훈련 데이터 모으기
과대적합 억제하는 가장 좋은 방법이다. 훈련 데이터가 많으면 많을 수록. 과대적합 발생 억제되고, 모델 일반화 성능도 올라간다.
네트워크 크기 축소(모델 학습 파라미터 수 줄이기)
*학습 파라미터 수 = 모델 크기 = 모델 용량
모델 학습 파라미터 수를 줄인다는 건. 모델이 제한적 정보만 저장할 수 있도록 한다는 거다.
모델이 제한적 정보만 저장하게 되면. 보다 중요한 패턴에 집중하게 된다.
이렇게 해서 모델 일반화 성능을 끌어올릴 수 있다.
(딥러닝 모델은 항상 과대적합 쪽으로 흘려가려는 경향이 있다. 즉, 놔두면 과도한 최적화 쪽으로 알아서 흘러간다는 거다. 따라서 우리의 관심사는 ‘일반화’다)
다만 유념해야 할 것은. 모델 학습 파라미터 수 너무 줄이면 과소적합 발생한다는 거다.
따라서 과대적합 피하기 위해 학습 파라미터 수를 줄이되, 적정한 정도로 줄이는 것이 좋다.
학습 파라미터 수는 층 수 또는 각 층 히든유닛 수 줄이면 감소된다.
가중치 규제 추가
가중치 ‘크기’ 규제.
정의: 가중치가 작은 값만 갖도록 규제하는 작업이다.
방법: 손실함수에 가중치 크기만큼 손실(비용) 추가한다.
가중치 규제 종류:
L1규제: 가중치 벡터 요소들의 절댓값에 비례하는 비용을 손실함수에 추가한다(가중치 L1 놈(norm))
$\Rightarrow$ 손실함수 + 비용(상숫값)
L2규제: 가중치 벡터 놈 제곱을 손실함수에 추가한다(가중치 L2 놈(norm)). 가중치 감쇠(weight decay) 라고도 한다.
$\Rightarrow$ 손실함수 + 가중치 크기(상숫값)
- 케라스에서 모형에 가중치 규제 적용하려면 각 층 kernel_regularizer 매개변수에 가중치 규제 객체 전달하면 된다.
1
2
3
4
5
6
7
8
9
10
11
# 모델에 가중치 규제 적용 예
from keras import regularizers
model = models.Sequential()
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001), activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001), activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
- l2(0.001)은 가중치 행렬 요소 제곱 합 값에 0.001 곱한 결과값을 손실함수에 더한다는 뜻이다. 이 결과값 항을 ‘패널티 항’ 이라고도 한다. 패널티 항은 훈련할 때만 손실함수에 추가된다.
- 훈련할 때 손실함수에 패널티 항이 추가되면서. 훈련 손실은 추가 전보다 높아질 것이다.
- 한편 손실함수 최적화 하면서 가중치 크기도 자연스레 함께 줄어들 것이다. 가중치 크기 작아지면 과대적합 완화할 수 있다. 훈련 완료된 모델은 과대적합에 잘 견딜 것이다. 따라서 모델을 검증용 데이터로 성능 테스트하면. 검증 손실 그래프 기울기가 훨씬 완만하게 증가할 것이다. 곧, 모델 일반화 성능도 보다 높일 수 있다.
l2 규제 이외 l1규제 또는 l1, l2규제 동시 적용 위해 아래 코드를 적용할 수 있다.
1
2
3
4
5
6
7
# l1규제, l1,l2규제 동시 적용
from keras import regularizers
regularizers.l1(0.001) # l1규제
regularizers.l1_l2(l1=0.001, l2=0.001) # l1, l2규제 동시 적용
드롭아웃 추가
드롭아웃 정의
훈련 동안. 층의 출력 특성 중 일부를. 무작위로. 0 만드는 규제기법.
특징
- 각 층에 적용한다.
- 가장 효과적이고 널리 사용되는 규제기법이다.
- 훈련 동안만 적용한다.
드롭아웃 비율
층 출력의 요소 중 몇% 를 0으로 만들지 나타내는 비율이다.
예컨대 드롭아웃 비율이 0.5 면 층 출력 요소 중 절반을 랜덤하게 0 만든다.
층 출력이 $[0.5, 0.2, 0.4, 0.6]^{T}$ 이라고 하면. 0.5 비율로 드롭아웃 적용했을 때 $[0, 0.2, 0.4, 0]^{T}$ 으로 바뀌는 식이다.
- 테스트 단계에서는 드롭아웃 적용하지 않는다. 대신, 각 층 출력의 요소들을 드롭아웃 비율만큼 스케일 다운 해야 한다. 예컨대 드롭아웃 비율이 0.5 였으면, 테스트 단계 각 층 출력 요소들에 0.5씩 곱해서 스케일을 절반으로 줄인다. 테스트 단계 층 출력이 $[1,2,3,4]^{T}$ 면, 각 요소에 0.5 씩 곱해서 $[0.5, 1, 1.5, 2]^{T}$ 로 스케일 낮추는 식이다.
테스트 단계 출력 스케일 유지하는 다른 방법
훈련 단계 층 출력에 드롭아웃 적용하고, 출력 각 요소들을 드롭아웃 비율만큼 역으로 스케일 업 시킨다.
예컨대 드롭아웃 비율이 $0.5$ 였으면. 층 출력 각 요소들 스케일 $2$ 배로 키운다.
$[1,2,3,4]^{T} \Rightarrow [2,4,6,8]^{T}$
이러면 테스트 단계 층 출력은 스케일 변화시킬 필요 없다.
드롭아웃 규제기법이 과대적합 감소시키는 원리
층 출력에 노이즈 추가($0$) 해서. 훈련 데이터에 특화된 지엽적 패턴을 깨뜨린다.
결과로 훈련 동안 모델이 지엽적 패턴을 학습하지 못하게 되고, 훈련 데이터의 주요 패턴(특성)만 집중적으로 학습하게 될 것이다. 이는 과대적합 회피로 이어진다.
케라스에서 드롭아웃 적용
각 층 바로 다음에 드롭아웃 층을 배치하는 방식으로 각 층에 드롭아웃 적용할 수 있다.
1
2
3
4
5
6
7
8
# 모델 각 층에 드롭아웃 적용
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dropout(0.5)) # 드롭아웃 비율 = 0.5
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dropout(0.5)) # 드롭아웃 비율 = 0.5
model.add(layers.Dense(1, activation='sigmoid'))
보편적 머신러닝 작업 흐름
1. 문제 정의 & 모델 학습시킬 데이터 수집
내가 지금 해결하려는 문제가 이진 분류인지, 다중 분류인지, 회귀인지 파악해야 한다.
동시에 지금 문제 해결을 위해 필요한 데이터는 무엇인지, 그 데이터를 구할 수 있는지 등도 따져봐야 한다.
2. 모델 성능 측정 지표 설정하기 & 손실함수 선택하기
모델 성능 측정 지표가 손실함수 선택 기준이 된다.
3. 모델 성능 검증 방법 설정하기(데이터셋 나누기)
단순 홀드아웃 검증, K-겹 교차검증, 반복 K-겹 교차검증 중 한 방법을 선택해 전체 데이터셋을 훈련용 셋과 검증용 셋으로 분리한다.
단순 홀드아웃 검증 - 전체 데이터셋을 훈련용 셋과 검증용 셋으로 나눈 뒤 검증용 셋으로 일반화 성능 검증한다.
K-겹 교차검증 - 전체 셋을 K개로 나눈 뒤 그 중 하나는 검증용 셋, 나머지는 훈련용 셋으로 사용한다. K번 과정 반복한다.
반복 K-겹 교차검증 - K-겹 교차검증을 P번 반복한다. 단, K-겹 교차검증 매번 시행하기 전에. 셔플(Shuffle) 통해 데이터셋을 함 섞는다.
대부분 경우 단순 홀드아웃 검증이면 충분하다. 데이터가 충분할 것이기 때문이다.
하지만 데이터가 부족한 경우엔 K-겹 교차검증 또는 반복 K-겹 교차검증이 유용한 대안이다.
4. 데이터 전처리
신경망의 입력은 텐서다. 텐서는 넘파이 다차원 배열을 일컫는다. 따라서 신경망에 데이터 주입 전, 모든 데이터를 부동 소수점 실수 또는 정수 텐서로 바꿔줘야 한다.
각 특성값들은 모두 스케일이 비슷해지도록 조정해야 한다. 대표적 방법으로 정규화가 있다.
데이터 수가 적어서 신경망 적용이 어렵거나, 굳이 신경망 안 써도 될 문제라면 특성 공학 써서 보다 효율적으로 해결할 수도 있다.
5. 크기 작은 모델로 시작하기
과소적합이 있는 모델. 또는 과도한 일반화 쪽에 가까운 모델.
층 수 또는 히든유닛 수 작은 모델로 적합한 모델 찾는 과정 시작한다.
이런 모델을 통계적 검정력이 확보된 모델이라고도 한다.
모델 만들 때 세 가지 요소를 선택한다.
마지막 층 활성화 함수: 신경망 출력 값에 필요한 제한을 가한다. 이진분류 예로 들면, 마지막 출력 층 활성화 함수로 시그모이드 함수가 들어가 출력 값을 0과 1 사이로 제한해준다.
손실함수: 풀려는 문제에 적합한 손실함수를 선택한다. 예컨대 회귀문제라면 손실함수로 $mse$ 를 선택할 것이고, 이진분류 문제라면 binary crossentropy (로그손실) 를 사용할 것이다.
최적화 알고리듬 설정: 옵티마이저와 학습률 선택한다. 일반적으로 확률적 경사 하강법(rmsprop)과 기본 학습률 사용한다.
6. 모델 몸집 키우기: 과대적합 모델 구축
통계적 검정력이 확보된 모델은 크기가 작아서 과소적합 여지가 있다.
곧, 성능이 더 향상될 여지가 남아있다.
머신러닝을 한줄로 정의히자면 ‘일반화와 최적화 사이 줄다리기’ 로 정의할 수 있다.
현재 모델 상태는 ‘과도한 일반화’ 쪽에 가깝다. 최적화 쪽으로 옮겨서 둘 사이의 균형점에 도달해야 한다.
하지만 실제로 과소적합과 과대적합 사이 적절한 균형점이 어디인지는 알 수 없다.
따라서 균형점에 도달하기 위해 일단 균형점을 지나 과도한 최적화(과대적합) 쪽으로 움직인다.
이를 위해 기존 모델 크기를 키운다. 곧, 과대적합 모델을 구축한다.
모델에 층 추가한다.
층 크기를 키운다(히든유닛 수 증가).
더 많은 에포크 동안 훈련한다.
크기 많이 키울 수록 매우 빠르게 과대적합 도달할 것이다.
모델 검증 손실이 증가하기 시작하는 지점부터 과대적합에 도달한 것이다.
이제 모델 규제와 하이퍼파라미터 튜닝 통해 과대적합을 억제하면서. 과소적합과 과대적합 사이 균형점을 찾을 것이다.
7. 모델 규제와 하이퍼파라미터 튜닝
반복적으로 모델을 ‘수정’ 하고 ‘훈련’하고 검증데이터에서 ‘평가’한다. 좋은 모델을 얻을 때 까지 반복한다.
위에서 모델 규제 방법들을 열거했다.
- 훈련 데이터 수 증가시키기
- 네트워크 크기 축소(학습 파라미터 수 줄이기)
- 가중치 크기 규제(가중치 크기가 작도록)
- 드롭아웃 추가
한편 층 수, 히든유닛 수, 옵티마이저 학습률 등을 조정하는 걸 하이퍼파라미터 튜닝 이라고 정의했다.
과대적합된 모델의 검증 결과를 바탕으로 위 규제와 튜닝을 적용한다. 그리고 모델을 훈련데이터로 다시 훈련시킨다.
훈련된 모델을 검증 데이터로 다시 검증하고, 그 결과를 통해 다시 규제하고 튜닝한다.
- 주의점: 모델 수정을 반복할 때 마다 모델이 서서히 검증 데이터에 익숙해진다. 검증 데이터로 모델을 학습시키지도 않았지만 모델이 검증 데이터에 ‘과대적합’ 될 수 있다. 따라서 모델 튜닝을 너무 많이 반복하는 건 검증 데이터 신뢰성을 떨어뜨린다.
과정을 반복하면서 만족할 만 한 모델을 얻었다면, 훈련용 데이터와 검증용 데이터를 합친 전체 데이터셋으로 모델을 훈련시킨다. 그 후 테스트 데이터셋으로 모델 일반화 성능을 검증한다.
만약 테스트 데이터셋에 나타난 모델 일반화 성능이 검증에서 나타난 일반화 성능보다 많이 나쁘다면. 이는 검증 데이터셋 자체가 애초에 신뢰성이 없었거나(편향 등) 모델이 수정 반복하면서 검증용 셋에 과대적합 된 결과일 수 있다.
어찌됬건 둘 다 검증용 셋이 신뢰성을 잃어버린 경우다. 따라서 기존 모델 파기하고, 새 모델에 대해 반복 K-겹 교차검증 등을 써서 검증함으로써 검증 과정 신뢰성을 확보해야 한다.