hyunwoongko/kss

kss 3.0

hyunwoongko opened this issue · 6 comments

pecab 프로젝트가 끝나고 나면 kss 3.0 프로젝트를 시작한다.
kss 3.0은 기존의 휴리스틱 기반의 알고리즘 + mecab 형태소 분석기를 기반으로 한다.
이를 통해 얻을 수 있는 장점은 다음과 같다.

  • EC/EF 케이스 문제를 거의 완벽하게 해결 가능하다.
  • 따옴표나 괄호 등에서 발생하는 문제도 해결 가능하다.
  • 종결어미를 더 이상 임의로 설정하지 않아도 된다.

즉 kss 3.0은 휴리스틱 + 형태소 분석 기반으로 탈바꿈 하는 것.

단점으로는 속도가 지금보다 더 느려질 것이라는 것.
최대한 쓸모 없는 루프를 제거하여 속도를 그나마 빠르게 만드는 것이 관건일 듯.

@hyunwoongko
안녕하세요~
저는 CRF + 룰 기반으로 문장분리기를 만들어서 사용 중입니다.
저도 언어 범용으로 사용될 수 있는 휴리스틱 등을 고민 중인데, 3.0 만드실 때 같이 이야기 해보시면 어떨지요!

말씀해주신 패키지 잘 사용해봤습니다. pre-trained CRF가 제공되고 추가로 간단한 룰이 포함되어있는 것으로 보이네요. 일단 협업에 대해서 저는 매우 긍정적이구요. 만약 진행하게 된다면 (통계 알고리즘을 함께 사용하게 된다면), 제가 한국어 룰부분에서 작업하고 재명님이 통계 알고리즘 등에서 기여해주시면 좋을 것 같습니다. 다만 kss는 패키지 이름부터 Korean sentence splitter이기 때문에 일단은 한국어에 집중하는 것이 좋을 것 같습니다. 어떠신지요?

@hyunwoongko
답변 감사합니다~
제가 중점적으로 생각했던 협업 포인트는 3.0 버전을 계획하실 때 언어 범용적인 (또는, 비교적 적은 노력으로 다른 언어에도 적용 가능할) 룰/휴리스틱들이 있을 지에 대한 논의입니다.
예컨대, 저는 문장 분리할 때, 아래와 같은 언어 범용적인 휴리스틱들을 사용하고 있습니다:

  • 문장 내, 또는 문장 사이 두 개 이상의 공백에 대한 대응 (하나로 치환한 뒤, 문장 분리 후 다시 복원).
  • prevent_word_split=True 시, 단어 중간에서 쪼개지는 경우 방지.
  • segment_regex를 통해 분리해야 할 경우 대응.
  • prevent_regex를 통해 분리하지 말아야 할 경우 대응.

룰 베이스인 KSS에서는 필요 없는 부분일 수도 있겠네요.
만약 3.0 버전에서 형태소 분석 정보를 활용하신다면 품사 태그에 따라 분리해야 할 경우들을 파악해야 할텐데, 이때 룰들을 통계기반으로 뽑아 보실 수 있을 것 같습니다.
(다만 저는 개인적으로는 데이터 기반 방식을 더 선호해서, 좀 더 문맥 정보를 활용할 수 있으며, CPU로도 빠르게 돌릴 수 있는 가벼운 (multilingual) 뉴럴넷을 차기 모델로 생각 중입니다.)

또 다른 협업 포인트로는 문장 분리에 대한 평가셋 구축도 있을 듯 합니다.
EVALUATION.md를 보니 KSS는 몇 개의 문서들에 대한 정성 평가를 진행하시는 것 같고, 저도 모델 학습 후 가지고 있는 테스트 문장들에 대해 눈으로만 확인하고 있습니다.
평가해야 할 경우(특정 문장 패턴)들을 정하고, 정량적인 수치를 구하는 테스트 케이스들을 같이 구축할 수 있을 것 같아요.

  1. 제가 약간 말씀하신 의도를 잘못 이해했던 것 같네요. 재명님께서 말씀하신 "3.0 만드실 때 같이 이야기 해보자"라는 말이 제게는 kss 3.0을 같이 만들자는 것 처럼 들렸는데, 그게 아니라 제가 3.0을 만들 때 현재 재명님이 만들고 계시는 sentsplit 라이브러리에도 적용할 수 있을만한 언어 범용적인 휴리스틱에 대해 같이 고민해보면 좋을 것 같다는 의견이시군요.
  2. 우선은 kss는 한국어 문장분리 라이브러리이기 때문에 당장에는 언어를 확장할 계획은 없구요. 따라서 다른 언어들에 적용 가능한 범용적인 휴리스틱에 대해서도 현재로서는 많이 고민하고 있지 않습니다. 제가 kss를 만들고 여러 이슈를 해결하면서 느낀건 문장분리에 있어서 적용할 수 있는 언어 범용적인 휴리스틱이 그렇게 많지는 않구요. 문장분리라는 것 자체가 언어를 상당히 많이 탑니다.
  3. 말씀하신 것 이외의 언어 범용 휴리스틱을 이야기하자면 구두점, 괄호, 따옴표 등의 지점에서의 처리 등을 생각해볼 수 있는데요. 아래 예시들을 추가로 고려해보시면 좋을 것 같습니다.
>>> from sentsplit.segment import SentSplit
>>> sp = SentSplit("ko")

>>> # 어떤 언어든 따옴표 내부에서는 문장을 분절하지 않아야합니다. 
>>> # 그러나 따옴표는 그 외에 아포스트로피나 시간, 인치 등의 단위를 나타낼 때도 사용되므로 이들을 잘 구분해야 합니다.
>>> sp.segment("MBC 새 월화드라마 ‘아이템’의 제작발표회에서 배우 주지훈이 '감독 님이 적토마 같다고 해서 이게 욕인지, 칭찬인지 한참 헷갈렸다. '며 소감을 전했다.")
["MBC 새 월화드라마 ‘아이템’의 제작발표회에서 배우 주지훈이 '감독님이 적토마 같다고 해서 이게 욕인지, 칭찬인지 한참 헷갈렸다.", " '며 소감을 전했다."]

>>> # 어떤 언어든 괄호 내부에서는 문장을 분절하지 않아야합니다.
>>> sp.segment("그래. (이런, 걸려버렸다. 이러면 안되는데...) 알았어 그렇게 할게.")
['그래. (이런, 걸려버렸다.', ' 이러면 안되는데...) 알았어 그렇게 할게.']
  1. 현재 제 관점은 언어 범용적인 알고리즘을 설계하는 것 보다는 "하나의 언어에서라도 잘 되는 것을 만들어보자." 이구요. 사실 여러 언어가 아니라 한가지 언어에 대한 문장 분리 알고리즘을 설계하는 것도 매우 어려운 과제라고 생각합니다. 당연히 여러 언어에서 잘 되면 좋겠지만 현재는 한 언어에서도 잘 안되는 것이 현실이기도 하구요. 아래에 제가 고민했던 한국어 문장분리의 몇 가지 문제들에 대해 적어봤는데요. 일부는 제가 만들고 있는 kss에서도 해결되지 않은 문제들입니다.
>>> from sentsplit.segment import SentSplit
>>> sp = SentSplit("ko")

>>> # 종결어미(EF) / 연결어미(EC) 구분 문제는 한국어 문장분리에 있어서 가장 어려운 문제 중 하나입니다.
>>> sp.segment("이다정 선수는 좋은 모습을 보이다 최근 부진을 겪고있다.")
['이다정 선수는 좋은 모습을 보이다', ' 최근 부진을 겪고있다.']

>>> # 형용사나 동사가 포함된 고유명사의 처리도 어려운 부분 중 한 가지입니다.
>>> sp.segment("지난 16일에 방송인 김제동은 MBC FM4U 굿모닝FM 김제동입니다 에서 가수 이효리와 예상치못한 통화 연결을 진행했다.")
['지난 16일에 방송인 김제동은 MBC FM4U 굿모닝FM 김제동입니다', ' 에서 가수 이효리와 예상치못한 통화 연결을 진행했다.']

>>> # 다양한 종결어미에서의 문장 분리 여부를 결정하는 것은 매우 어려운 일입니다.
>>> sp.segment("참돔 마스까와는 특히 맛이 매우 좋다 또한 제철 생선 5~6가지 구성에 평소 접하지 못했던 부위까지 색다르게 즐길 수 있다")
['참돔 마스까와는 특히 맛이 매우 좋다 또한 제철 생선 5~6가지 구성에 평소 접하지 못했던 부위까지 색다르게 즐길 수 있다'] => '좋다'
>>> sp.segment("김신입: 그건 그렇긴 하죠 그렇게 하면 되잖아요.")
['김신입: 그건 그렇긴 하죠 그렇게 하면 되잖아요.'] => '하죠'
>>> sp.segment("노는게 제일좋아 친구들 모여라 언제나 즐거워 개구쟁이 뽀로로")
['노는게 제일좋아 친구들 모여라 언제나 즐거워 개구쟁이 뽀로로'] => '좋아', '모여라', '즐거워'
>>> sp.segment("래퍼들 나 때문에 관뒀기 때문임 그러니 너가 짐싸기 전에 말하지")
['래퍼들 나 때문에 관뒀기 때문임 그러니 너가 짐싸기 전에 말하지'] => '때문임'
  1. 이러한 부분을 처리하려면 당연하게도 언어 특화적으로 갈 수 밖에 없구요. 언어범용적인 특성들만 고민한다면 이러한 포인트에서는 문장 분리가 어려울 것이고, 결론적으로는 범용성은 높지만 정확도는 비교적 떨어지는 알고리즘이 될 것이라는 것이 제 견해입니다.
  2. 제가 작년 카카오브레인에서 일하던 시절에 저희 팀에서 문장분리 모델이 필요해서 대규모 문장분리 데이터를 구축하고, 몇몇 Transformer 인코더 모델 기반으로 문장분리 모델을 만들어본적도 있는데요. 사실 이게 룰기반 문장분리기에 비해 잘 작동한다는 느낌은 딱히 없었고, 오히려 무겁고 잘 안된다는 느낌을 받았어요.
  3. 당연히 저도 룰베이스 보다는 데이터 드리븐 모델링을 선호하는데요. 이게 데이터 드리븐으로 생각한대로 잘 되면 참 좋은데, 현대 뉴럴 모델들이나 통계 모델들이 Dataset 전체에 대한 Maximum likelihood를 계산하는 방향으로만 학습하다보니 당연히 분리해야 할 부분에서는 문장분리가 비교적 잘 이루어지지만 일부 세부적인 케이스들에 대해서는 오류를 일으키는 경우가 굉장히 많았고 이런 부분들에 대해서는 룰기반 분리기보다 못하다라는 생각이 들더라구요. (뉴럴 모델은 일부 주요 종결어미에만 너무 크게 의존하는 느낌이였습니다.)
  4. 그러나 문장 분리라는 태스크는 고민해야할 부분이 정말 많고 심지어 어떤 경우에는 사람마다 의견이 갈리기도 하며 한국어의 경우는 맞춤법과는 달리 문장분리에 대해서는 명확히 정해진 규칙도 없습니다. 따라서 저도 결국에는 룰만 가지고는 절대 수준높은 분리기를 만들 수 없다고 생각하고 있구요. 여러 방법론들을 적절히 섞어서 사용해야한다는 생각을 가지고 있습니다.
  5. 추후에는 kss에도 결국엔 룰 이외의 기법들을 적용해야 한다는 생각을 가지고 있기도 하구요.kss는 일단 3.0에서는 룰 기반 처리를 할 때 형태소 정보를 함께 사용해보자 라는 생각을 가지고 있습니다. 형태소를 뽑아내는 것은 통계 기반(CRF)이지만, 결국 문장 분리 자체는 룰로 만들 예정이구요. 4.0 이후 버전에서는 통계 알고리즘이나 머신러닝 알고리즘도 고민해볼 생각입니다.

예시까지 들어주시고, 세세한 코멘트 감사합니다!
3. 저는 보통 문장분리를 번역모델 등 ML 모델 학습의 전처리로 많이 사용하는데요, 괄호나 따옴표가 끊어지더라도, 안에 있는 문장들이 적절한 길이에서 분리가 되어야 더 나은 번역문 또는 임베딩 표현을 얻을 수 있었습니다. 만약 괄호나 따옴표의 보존이 필요한 use case라면 prevent_regexes를 통해 해당 후처리 룰을 추가하면 될 것 같네요.
4. "종결어미(EF) / 연결어미(EC)"와 "다양한 종결어미에서의 문장 분리"에 대한 문제는 정말 어렵죠.. 제 경험으론 CRF 모델로도 컨텍스트가 충분치 않다고 판단되어 뉴럴모델들을 고민하고 있습니다. 룰로 전부 커버하기에도 한계가 있으니까요. "다양한 종결어미에서의 문장 분리"에 대해서는 현재 상위 100가지 정도의 종결 어미 형태에 대해 구두점을 제거하고 만든 데이터를 모델학습에 추가해주는데요, "형용사나 동사가 포함된 고유명사의 처리" 이슈와 trade-off 관계가 존재하기에 어려운 문제 같습니다. (참고로 들어주신 예시 문장들 사이에 추가된 공백("헷갈렸다. '며", "김제동입니다 에서")을 제거하면 기대대로 동작합니다.)
5. 세세한 디테일까지 확실히 고려하려면 언어 특화적인 부분이 필요하다는 점, 저도 동의합니다. 다만 확장성을 위해 학습모델 + 소수의 룰기반으로 방향을 잡았고, 아직 sentsplit에는 특정 언어에만 해당하는 룰이 전혀 없네요.

저와 같은 고민을 하고 계신 분을 만나게 되어 반가웠습니다. 저도 업데이트나 새로운 결과가 있으면 종종 공유드릴게요~