-
Notifications
You must be signed in to change notification settings - Fork 285
띄어쓰기 오류에 강건한 모델을 위한 실험
사용자는 (특히 모바일 환경에서) 띄어 써야할 곳에서 붙여 쓰는 경우가 많습니다. 이러한 띄어쓰기 오류가 없는 세종 코퍼스를 통해 학습한 khaiii는 띄어쓰기 오류에 취약합니다. CNN 모델 문서를 보면 음절 기반으로 분석하기 위해 윈도우 크기만큼 문맥을 생성할 때, 현재 어절의 좌/우 경계를 나타내는 "<w>"와 "</w>"라는 가상의 음절을 추가해 줍니다. 이로 인해 띄어쓰기에 상당히 의존적인 모델이 되어버렸기 때문입니다.
신경망 알고리즘들 중 Dropout 기법에서 착안하여 좌/우 공백을 나타내는 가상의 음절 "<w>"와 "</w>"를 추가해 줄 때 일정 확률로 무작위로 추가하지 않도록 하여 학습을 하고, 디코더에서는 사용자의 입력에 따라 공백 음절을 항상 사용하도록 실험을 해 봤습니다.
실험 결과
- 파란색: 기존 방법 (dropout 0.0)
- 빨간색: dropout 1.0 (공백을 아예 사용하지 않음)
- 주황색: dropout 0.5
세종 코퍼스는 띄어쓰기가 정확히 되어 있으므로 이 정보를 적극적으로 사용하는 기존 모델이 가장 성능이 좋을 것이라는 것은 자명합니다. 그러나 공백을 아예 사용하지 않는 모델에 비해 dropout을 적용한 모델이 오히려 성능이 낮게 나옵니다.
이러한 결과가 나온 이유는 아마도 공백을 나타내는 가상의 음절이 중간에서 들어가기도 하고, 빠지기도 하면서 그 바깥쪽 음절이 포지션 인코딩 정보도 달라지고, convolution filter에 들어가는 입력도 들쑥날쑥해져 버려 오히려 학습을 방해하는 것이 아닐까 추측이 됩니다. 그래서 아예 공백을 사용하지 않는 모델에 비해 오히려 낮은 성능을 나타낸 것이 아닐까 생각합니다.
현재 모델은 공백 음절도 다른 음절과 동일하게 문맥에서 하나의 음절로 위치를 차지하고 있는데, 이렇게 하지 않고 어절의 좌/우 경계에 해당하는 음절에 각각 "<w>"와 "</w>" 가상 음절의 임베딩을 elementwise로 더하는 것으로 실험을 해보려 합니다. 이 모델의 성능이 기존 모델과 비슷한 성능을 나타낸다면, 이때 공백 음절을 더할 때 dropout을 적용해 보려고 합니다. 그러면 기존에 dropout에 따라 공백이 들어가거나 빠지면서 위치도 들쑥날쑥해지는 문제도 해결할 수 있지 않을까 생각합니다.
아래와 같이 코드를 변경하여 실험을 진행했습니다. #49
-
기존에 좌/우 패딩에 해당하는 <s> 및 </s> 가상 음절에 대해서도 임베딩 학습이 되도록 했었는데, 이번에 리팩토링 하면서 일반적인 패딩처럼 zero 임베딩을 부여하고 학습도 되지 않도록 변경했습니다. 다만, positional encoding 과정에서 이 패딩에도 positional encoding이 적용이 되는데, 이 부분은 정확히 마스킹 처리하지는 않았습니다.
-
공백의 경우 <w> 및 </w> 좌/우 모두 하나씩 사용하여 해당 위치의 음절에 elementwise로 더하여 사용하도록 했습니다.
실험 결과
- 파란색: 공백 음절을 더하는 모델에서 dropout을 적용하지 않은 모델. 즉, dropout=0
- 분홍색 > 갈색 > 초록색: dropout 비율을 각각 0.25, 0.5, 0.75
- 하늘색: 공백 음절을 전혀 사용하지 않는 모델. 즉, dropout=1.0
기존에 공백 음절을 더하지 않고 다른 음절처럼 자리를 차지하도록 하여 실험했던 경우, 공백을 사용하지 않는 모델보다 오히려 성능이 떨어졌었는데, 더하는 모델의 경우 공백을 사용하지 않는 모델에 비해 높은 성능을 보입니다.
dropout 비율의 경우 많이 적용하면 적용할 수록 정확도도 점점 떨어지는 결과를 보입니다.
dropout 비율 0.5를 적용한 모델(갈색)이 적용하지 않은 모델에 비해 미세하게 차이가 난다면 도입이 가능할 듯 한데, f-score에서 1%p 이상의 성능 차이를 보이고 있어서 애매합니다. 도입하려면 dropout 비율 0.25를 적용한 모델이 0.5%p 정도로 비교적 성능 차이가 크지 않아 고려해볼 만 합니다.
역시 아래 multi-task 실험까지 해보고 도입 여부를 결정해야 할 듯 합니다.
세종 코퍼스는 형태소 정보도 있지만, 띄어쓰기나 문장 분리가 정확하게 되어 있어서 그러한 모델도 학습이 가능할 것입니다. 음절 기반으로 embedding과 convolution 부분을 공유하고 마지막 fully connected layer만 다르게 하여 띄어쓰기(공백)를 분류하는 모델과, 형태소 태그를 분류하는 모델을 multi-task learning을 적용하여 한꺼번에 학습하도록 개선해 봤습니다.
아래와 같이 loss를 적용했습니다. #58
- 음절 별 품사를 판단하는 기존 cross entropy loss (품사 loss)
- 음절 다음에 공백 여부를 판단하는 cross entropy loss (공백 loss)
- total loss = (품사 loss) + (공백 loss)
forward와 backward 스텝은 다음과 같이 했습니다.
- 공백 음절의 임베딩을 사용하지 않고 공백 판단 forward 진행 후 loss 계산
- 공백 음절을 사용하여 (dropout도 적용) 품사 판단 forward 진행 후 loss 계산
- total loss를 구하여 한번에 backward
- 갈색: 기존의 single task learning 방식
- 하늘색: multi-task learing 방식
- 분홍색: MTL 방식에 dropout 0.25 적용
- 초록색: MTL 방식에 dropout 0.5 적용
- 회색: MTL 방식에 dropout 0.75 적용
single task 방식(갈색)과 multi-task 방식(하늘색)을 비교해 보면 약간의 성능 감소가 보입니다. multi-task 방식 내에서 dropout 비율을 비교해 보면 위의 실험 결과들도 일관되게 dropout 비율을 증가함에 따라 성능도 조금식 떨어집니다.
그렇다면 지금까지 개발한 모델의 성능은 최초의 모델보다 못한 걸까요? 우선 전통에 빛나는(?) 입력 아버지가방에들어가신다.
에 대한 정성적인 분석 결과를 한번 보시죠. (base 모델)
모델 | 결과 |
---|---|
v0.3 | 아버지가방/NNG + 에/JKB + 들/VV + 어/EC + 가/VX + 시/EP + ㄴ다/EF + ./SF |
MTL | 아버지/NNG + 가/JKS + 방/NNG + 에/JKB + 들어가/VV + 시/EP + ㄴ다/EF + ./SF |
base 모델을 선정하기 위해 dropout을 0.1로 정하고 f-score가 95%에 근접한 모델을 찾은 결과 window 4, embedding 35인 모델(아래 갈색)이 적당해 보입니다.
MTL 모델과 v0.3 모델을 보다 정량적으로 비교하기 위해 학습을 위해 나눴던 train, dev, test 중 test 셋에 대해 무작위로 공백을 제거하여 어절을 합친 후 실험을 했습니다.
v0.3 모델은 공백을 많이 제거하면 할 수록 성능이 급격하게 떨어지는 데 반해, MTL 모델은 보다 완만히 떨어져서 최종적으로 공백을 모두 제거했을 때 45.51%과 80.76%라는 성능 차이를 보였습니다.
multi-task 학습 모델의 경우 세종 코퍼스에서 비록 기존 v0.3 모델에 비해 약간의 성능 하락이 있지만 띄어쓰기 오류에는 보다 강건한 모델이라 생각합니다. 오히려 기존 v0.3 모델이 공백 오류가 전혀 없는 코퍼스에 오버피팅 되었다는 느낌이 듭니다. 이 논문에서 말하는 것처럼 multi-task 학습이 모델의 generalization에 도움을 주었다고 보아도 될 것 같습니다.
이 모델을 기반으로 C++ 디코더를 수정하여 조만간 v0.4 버전으로 찾아뵙도록 하겠습니다.