상세 컨텐츠

본문 제목

[Kiwi] 문장 같은 고유명사 잘 추출해내기

프로그래밍/NLP

by ∫2tdt=t²+c 2022. 3. 20. 21:58

본문

고유명사 처리의 어려움

형태소 분석을 진행할 때 어려운 부분 중 하나는 고유명사(NNP) 처리입니다. 나머지 품사의 경우는 말뭉치를 잘 구축해두면 그 안에서 어지간한 패턴은 다 등장합니다만, 고유명사의 경우 그 특성상 끊임없이 새로 생성되기 때문에 아무리 말뭉치를 잘 구축해둬도 시간이 조금만 흐르면 새로 등장한 고유명사는 다 놓치게 됩니다. 그래서 대부분의 형태소 분석기는 사용자가 직접 사전 내에 새로운 단어를 삽입하여 이런 문제를 완화하고자 하지요.

새로 추가된 고유명사는 해당 문자열이 오분석되는 것을 막기 위해 대개 일반 분석 결과보다 더 높은 우선순위를 가지게 됩니다. 즉, 기존의 분석 결과를 새로 추가된 고유명사가 덮어쓴다고 할까요.

입력 분석결과
도전무한지식 도전/NNG 무한/NNG 지식/NNG
도전무한지식을 봤다 도전/NNG 무한/NNG 지식/NNG 을/JKO 보/VV 았/EP 다/EF
사전에 `도전무한지식/NNP`을 삽입 후
도전무한지식 도전무한지식/NNP
도전무한지식 도전무한지식/NNP 을/JKO 보/VV 았/EP 다/EF

위의 예시에서 `도전무한지식`이라는 형태는 항상 `도전무한지식/NNP`으로 분석되게 되는데, 대부분의 경우 이렇게 기존 분석 결과를 새 고유명사가 덮어써도 큰 문제가 없습니다. 문제는 일부 고유명사는 고유명사인데 평범한 문장처럼 생기기도 해서 기계적으로 기존 분석 결과를 덮어쓰면 오분석이 크게 생긴다는 거죠. 예를 들어 MBC에서 방영된 드라마 <누구세요?>가 있겠습니다. 드라마 이름을 가리키는 '누구세요?'는 고유명사로 처리되어야 하지만, 일반적인 문장 내에세너느 고유 명사로 처리가 되면 안되는데요, 사전에 고유명사를 등록하면 부작용이 발생하게 됩니다.

입력 분석결과
당신 누구세요? 당신/NP 누구/NP 이/VCP 시/EP 어요/EF ?/SF
누구세요?는 2008년에 방영된 드라마다 누구/NP 이/VCP 시/EP 어요/EF ?/SF 이/VCP 는/ETM 2008/SN 년/NNB 에/JKB 방영/NNG 되/XSV ᆫ/ETM 드라마/NNG 하/XSA 다/EF
사전에 `누구세요?/NNP`를 삽입 후
당신 누구세요? 당신/NP 누구세요?/NNP
누구세요?는 2008년에 방영된 드라마다 누구세요?/NNP 이/VCP 는/ETM 2008/SN 년/NNB 에/JKB 방영/NNG 되/XSV ᆫ/ETM 드라마/NNG 하/XSA 다/EF

'당신 누구세요?'와 같은 문장에서도 `누구세요?`가 고유명사로 처리되는 문제가 발생했습니다. 고유명사를 사전에 등록하다 보면, 이와 같이 하나를 간신히 더 맞히지만, 다른 하나는 더 틀리게 되어 전체 분석 정확도는 결국 개선하지 못하게 되는 경우가 많습니다. (운이 나쁘면 오히려 분석 정확도가 더 떨어질 수도 있죠.) 그래서 사전에 고유명사를 등록하기에 앞서 이 단어를 등록하는게 어떤 결과를 가져올지 득과 실을 따져보는게 중요합니다. 매우 복잡한 문제지요...

언어모델 점수를 활용해보자

다행히도 이를 약간 우회할 수 있는 방법이 있습니다. 품사에 대한 정보를 학습한 언어모델의 경우 특정 위치에 어떤 품사가 등장할 확률이 높은지를 계산해낼 수 있습니다. 그래서 주변 문맥을 살펴보고 이 위치가 명사가 등장할만한 위치인지 아닌지 판단해서 더 적절한 선택을 할 수 있는거죠. 이를 위해서 다음 3가지 템플릿을 고안해봤습니다.

템플릿
__NNP__
바로 __NNP__가 그것이다.
그래서 __NNP__를 했다.

Kiwi에 위의 템플릿 문장을 입력하여 분석 점수를 구해보았습니다. 여기서 __NNP__는 빈자리를 채우기 위해서 넣은 녀석이구요, 알려진게 없는 새로운 단어로 보시면 되겠습니다. 이제 __NNP__에 위의 고유명사 단어들을 넣어서 분석 결과를 살펴보겠습니다.

템플릿 Kiwi 언어모델 점수 템플릿 Kiwi 언어모델 점수
도전무한지식 -43.45 누구세요? -14.09
바로 도전무한지식이 그것이다. -53.75 바로 누구세요?가 그것이다. -55.26
그래서 도전무한지식을 했다. -46.76 그래서 누구세요?를 했다. -47.99

`도전무한지식`과 `누구세요?`를 빈 자리에 넣어보면, "바로 __NNP__가 그것이다."와 "그래서 __NNP__를 했다." 템플릿에서는 두 고유명사 사이에 점수 차이가 거의 없습니다. 반면 "__NNP__"만 있는 템플릿에 넣은 경우에는 `누구세요?`의 점수가 압도적으로 큰 것을 볼 수 있습니다. 언어모델의 점수는 쉽게 말하자면 해당 단어열(혹은 문장)이 등장할 가능성인데요, 위의 결과에서 볼 수 있듯이 "도전무한지식"이라는 단어열이 단독으로 등장할 가능성은 굉장히 낮지만, "누구세요?"라는 단어열이 단독으로 등장할 가능성은 꽤 높다는 거죠. 따라서 `누구세요?`를 사전에 함부로 고유명사로 등재하면 오분석이 날 가능성이 크다는걸 미리 알 수 있습니다.

고유명사에 적절한 점수를 부여해 문제 해결하기

이를 응용해 Kiwi에서는 각 고유명사에 적절한 점수를 부여함으로써 이 문제를 어느 정도 해결하는 방법을 제공합니다. Kiwi에서는 사전에 사용자 단어를 등재할 때 그 단어의 점수를 부여할 수 있습니다. 단어점수는 해당 단어가 등장할때마다 언어모델 점수에 더해지는 값이라고 보면 되는데, 기본값은 0으로 그 단어가 아무리 등장해도 패널티를 제공하지 않습니다.

템플릿 Kiwi 언어모델 점수
__NNP__ -12.46
바로 __NNP__가 그것이다. -27.36
그래서 __NNP__를 했다. -25.67

위는 __NNP__에 0점을 부여한 경우 Kiwi 분석 결과의 언어모델 점수입니다. 만약 __NNP__에 -5점을 부여한다면 최종 결과값은 아래처럼 -5씩 더해져서 더 작은 값이 되지요.

템플릿 Kiwi 언어모델 점수
__NNP__ -12.46 - 5 = -17.67
바로 __NNP__가 그것이다. -27.36 - 5 = -32.36
그래서 __NNP__를 했다. -25.67 - 5 = -30.67

Kiwi는 최종 형태소 분석 결과가 여럿일 경우 그 중에서 언어모델 점수가 가장 높은 후보를 선택합니다. 따라서 모호성이 발생하는 고유명사라 해도 단어점수를 잘 조절해주면 맥락에 따라 적절한 결과가 나오도록 유도할 수 있습니다. 위의 `누구세요?` 사례를 다시 가져와서, `누구세요?`를 고유명사(NNP)로 사전에 등재할 때 그 단어점수를 $x$라고 설정했다고 해봅시다. 그럼 분석 결과는 아래와 같이 될겁니다.

입력 후보 Kiwi 언어모델 점수 후보 Kiwi 언어모델 점수
누구세요? 누구세요?/NNP -12.46 + $x$ 누구/NP 이/VCP 시/EP 어요/EF ?/SF -14.09
바로 누구세요?가 그것이다. 바로/MAG 누구세요?/NNP 가/JKS 그것/NP 이/JKS 다/EF ./SF -27.36 + $x$ 바로/MAG 누구/NP 이/VCP 시/EP 어요/EF ?/SF 가/VV 어/EC 그것/NP 이/JKS 다/EF ./SF -55.26
그래서 누구세요?를 했다. 그래서/MAJ 누구세요?/NNP 를/JKO 하/VV 었/EP 다/EF ./SF -25.67 + $x$ 그래서/MAJ 누구/NP 이/VCP 시/EP 어요/EF ?/SF 를/JKO 하/VV 었/EP 다/EF ./SF -47.99

`누구세요?`가 고유명사로 분석되는 경우는 왼쪽, 그렇지 않은 경우는 오른쪽에 표시해봤습니다. 이 중 최종 분석 결과로 선택되길 원하는 쪽을 굵게 표시해두었구요. `누구세요?`의 단어 점수 $x$의 값에 따라 왼쪽과 오른쪽 결과 중 하나가 선택됩니다. 원하는 쪽이 선택되려면 그 쪽의 언어모델 점수가 더 높아야하므로 다음과 같이 간단한 부등식을 세워볼 수 있겠죠?

$$-12.46 + x < -14.09 \:\:\:\:\: \rightarrow \:\:\: x < -1.63$$

$$-27.36 + x > -55.26 \:\:\:\:\: \rightarrow \:\:\: x > -27.9$$

$$-25.67 + x > -47.99 \:\:\:\:\: \rightarrow \:\:\: x > -22.32$$

최종적으로 $x$가 $-22.32 < x < -1.63$ 범위 내에 있으면 우리가 원하는 결과를 얻을 수 있다는 것을 알 수 있습니다. 지금은 긍정사례(고유명사로 분석되어야하는 예시) 2개와 부정사례(고유명사로 분석되지 말아야하는 예시) 1개만 가지고 범위를 산정을 했지만 더 많은 템플릿을 이용하면 좀 더 정확한 범위를 구해낼 수 있다는 것은 두말할 필요도 없습니다.

Kiwi 0.11.0에 내장된 사전에서는 위와 같은 방법을 이용해 고유명사의 점수를 새로 산정했습니다. 실제 점수가 어떤식으로 부여됐는지 보고싶으시다면 여기에서 확인할 수 있어요.

Python 코드로 시험해보기

위와 같이 "누구세요?"를 사전에 등록한 경우 "당신 누구세요?"와 "누구세요?는 2008년 방영된 드라마이다"에서도 잘 작동하는걸 볼 수 있습니다. 

자동화가 가능할까?

이 방법을 사용하려면 긍정사례와 부정사례를 사람이 직접 선정해주는 게 필요합니다. 위에서는 등록할 단어가 고유명사라는 점을 감안해 명사가 들어갈 법한 템플릿 문장을 사용했지요. 사용자가 이 템플릿을 생성하는게 가장 정확한 방법이겠지만 이게 번거롭다면 등록하려는 형태소의 품사를 이용해 해당 품사가 주로 등장하는 문장 패턴을 말뭉치에서 찾아주는것도 한 가지 방법이 될 수 있겠네요.

가능하면 자동화하여 Kiwi의 차기 업데이트에 최적의 단어 점수를 추정해주는 기능을 추가해보려고 현재 노력 중입니다. 많은 기대 부탁드려요~

관련글 더보기

댓글 영역

  • 프로필 사진
    2022.03.27 12:28 신고
    날로 발전하는Kiwi를 보며 또 감탄합니다. 이번 포스팅은 한국어 자연어 처리하는 사람들이라면 늘 겪었을 문제인데요, 정말 큰 도움이 되었습니다. 널리 공유하겠습니다. - 김병준