Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chronicles #15

Open
53 tasks done
eubinecto opened this issue Mar 9, 2022 · 3 comments
Open
53 tasks done

Chronicles #15

eubinecto opened this issue Mar 9, 2022 · 3 comments

Comments

@eubinecto
Copy link
Owner

eubinecto commented Mar 9, 2022

v1.1

open

This is the version where kiwi is used as the underlying analyser.

There were more versions of v1.x but v1.1 is the only one that I started to keep track of with the issue. So there is unfortunately v1.1 only for this branch for versions. We are moving to khaiii anyways, so this shouldn't be a big problem.

v2.1

open

As for this branch of versions, we are moving away from kiwi to use khaiii. We are moving away from kiwi because kiwi makes more problems than it solves problems. This is mainly because it does not preserve the original lexicons:

kiwi does not preserve the original lexicons
image

Here, Tuner distorts the completely fine 가까우니까 into 가깝으니까, when it does need to do that. This is because kiwi does not preserve a given text and just lemmatizes everything. Yeah, it does return start and end indices, but these would be very often inaccurate (e.g. overlapping indices).

In contrast, khaiii does preserve the lexicons as well as lemmatize them at the same time.

from khaiii import KhaiiiApi


def main():
    api = KhaiiiApi()
    for word in api.analyze("시끄럽게 코고는 소리에 놀라서 난 잠이 깼다."):
        print(word.lex)  # lexicon
        print([str(morph) for morph in word.morphs])  # morphemes


"""
# 굉장히 빠르고 정확하다! 띄어쓰기를 훼손하지도 않고... 심플하고... 정확히 내가 바라던 것인 것 같다.
konlpy, kiwi에 걸쳐... 여기에 종착하게 되는 것인가?
이걸 사용하면 훨씬 쉬울 것! lemma와 구성성분이 따로 있으므로..!

시끄럽게	시끄럽/VA + 게/EC
코고는	코/NNG + 골/VV + 는/ETM
소리에	소리/NNG + 에/JKB
놀라서	놀라/VV + 아서/EC
난	나/NP + ㄴ/JX
잠이	잠/NNG + 이/JKS
깼다.	깨/VV + 었/EP + 다/EF + ./SF
"""

So we are moving to khaiii.
This is the first version of using khaiii. What should we do?

v2.2

open

Here, we refine the rules to cover "chunks".
e.g. allows the rules to cover patterns with more than one morphemes.

다/EF:
 1:  어
 2: 어요
 3: 습니다
이/VCP+다/EF:
 1: 이야
 2: 이에요
 3: 입니다

v2.3

open

Politetune was meant to be used as a study aid for L2 learners of Korean. It therefore needs explanation for
the reasons for the output. Display the linage of the steps you take. Plus, from here on out, the Tuner is robustly tested with function-by-function tests

v2.4

open

As for this version, the rules aren't significantly changed, but the explanations for rules get some updates.

for instance, the question "What is your visibility?" should change to:

How do you find the environment you are speaking in?"
Comfortable and informal vs. Formal
1 = banmal
2 = yo form
3 = upnida form 

and the reasons for each case are refined:

friends and junior:
  Comfortable and informal:
    politeness: 1
    reason: A comfortable and informal situation is a very relaxed situation for all, so friends and juniors will use the intimate style (banmal). 
  formal:
    politeness: 2
    reason: If there are observers around or the situation is more formal, then the speaker is not completely relaxed. Therefore, it is most appropriate to use the formal (-yo) form. 

boss at work:
  Comfortable and informal:
    politeness: 2
    reason: In a less formal situation, for example a company dinner, employees feel a little more relaxed around their bosses, and thus they may use the formal (-yo) form. 
  formal:
    politeness: 3
    reason: In a highly formal environment, e.g. an important meeting, employees will always use the honorific (-bnida) form. This shows the appropriate respect in a high-profile context. 

adult family:
  Comfortable and informal:
    politeness: 1
    reason: With in a relaxed setting, using the intimate style (banmal) is standard, even if a family member is older than you. 
  formal:
    politeness: 2
    reason: If someone outside of the family, e.g. a neighbour, is part of the conversation too, then it is common to use the formal (-yo)¬ form towards family members to seem polite in front of others. 

plus, you should fix some errors in formatting the explanations.

what are there extra ` symbols?
image

v2.5

open

v2.6

open

We need rigorous test cases to decide whether or not to write conjugations myself, or keep using soynlp's conjugate function.

v2.6.1

open

v2.6.2

open

v3.0.0

open

migrating from khaiii to kiwi & packaging the library with hatch

v3.1.0

open

Styler tested against noisy data. __call__ accepting a list of sentences rather than a text (delegating sentence splits to the user).

v3.2.2

All rules are replaced with regular expressions. They are programmatically populated. This is a step towards a neuro-symbolic approach to the style transfer problem.

v3.2.3

add_rules function for populating rules. Explain how it works in README.md

v3.3.1

Neuro-symbolic approach: starting up with baselines (add Word2VecScorer, GPTScorer along with HeuristicScorer)

@eubinecto eubinecto pinned this issue May 13, 2022
@eubinecto eubinecto changed the title Progress Chronicles May 13, 2022
@eubinecto eubinecto changed the title Chronicles Chronicles May 13, 2022
@eubinecto
Copy link
Owner Author

eubinecto commented May 23, 2022

Ideas 💡

On neuro-symbolic approach

나중에 -> rules + distributed hypothesis를 동시에 할 수 있는 방법은 없나?
Neuro-symbolic approach를 여기에 적용해볼 수는 없나?


On allowing a set of EF's rather than only one
존댓말도 하나만 허용할 것이 아니라, 여러 개를 허용하는 편이 나을 것 같다
image

즉 set을 출력하는 것이 되어야 한다. 무엇이 정답인지는 사용자가 알아서 맥락에 맞춰서 판단하도록 하면된다.

즉.. 테스트가 이렇게 바뀌어야 한다
image

On writing conjugation algorithms on my own
  1. conjugate 함수 - 그냥 soynlp 처럼 if를 가득 만든다음에, set 을 출력하도록 하는게 나을수도.
  2. 나중에 conjugate은 새로운 리포로 파내자. 그게 나을 것. (다만 이때는, neuro-symbolic 접근을?)

아니다. 굳이 이럴 필요 없음. kiwi.join() 함수로 시원하게 해결함. 이런 강력한
함수를 만들어주셔서 정말 감사합니다 ㅎㅎ


On programmatically populating rules

fetch_honorifics -> programmatically populate rules

later -> 이미 한번 규칙을 정해두면, 다른 방향으로도 규칙을 자동으로 populate 하도록 하면 훨씬 좋을 것 같다. 그렇게 최종 출력은 set으로 하기. set.add에서 중복되는게 생기더라도 알아서 케이스를 정리해줄 것.
하지만 중복을 허용하기 위해선 맥락에 맞는 lm_search가 필요하다. 이게 먹히기 위해선.. masked language modeling이 필요할 것. 너무 사이즈가 커지면 영 그러므로.. DistillBERT를 사용하는 것도 그 경우에는 고려해야 한다.


  • experimental 브랜치에서 실험 진행 중.

On refactoring the rules with a hierarchy

honorifics.yaml -> define the rules in hierarchy, maybe?

  1. first, apply only the single-morpheme pattern, but with multiple candidates (어 -> (습니다 / 읍시다 / 읍니까) )
  2. then, you apply double-morpheme pattern to rule out some candidates (just get the conjunctions using python's set operations) ( 어 + . -> (습니다 / 읍시다) + .)
  3. apply n-morpheme pattern, in this order.
  4. At the end, after everything is filtered out, when you are left with those that are completely ambiguous, use a language model to pop the most natural one out of the final candidates (자 + 주 + 우 + [mask] + . -> 자 + 주 + 우 + ( 읍시다: 0.8, 습니다: 0.2) + .)
    • for this, you could use BERT, but that is too heavy. Using Skipgram would be a great starting point. (using gensim should be fine)
    • where do you get the dataset for this? do we have formal dataset? -> sejong corpus maybe? That is something to think about.

Here is a proof-of-concept:

# 1st-order rules (1-morpheme-pattern)
(?<tgt>어/EF):
  - [어요/EF, 죠/EF]
  - [ㅂ니다/EF, ㅂ시다/EF, ㅂ니까/EF]  # "어"만 있을 땐, 의문형, 평서형 전부 가능 

# 2nd-order rules (2-morpheme-pattern)  
(?P<tgt>어/EF)+?/SF:    # use match & extract
  - [어요/EF, 죠/EF]
  - [ㅂ니까/EF]  # ?로 끝나는 경우, 의문형만 가능
(?P<tgt>어ㅏ/EF)+[.!]/SF:
  - [어요/EF, 죠/EF]
  - [ㅂ니다/EF]  # . 로 끝나는 경우, 평서형만 가능. 그리고 권유/청유의 경우는 없음.
이/VCP+(?P<tgt>어/EF):
  - [에요/EF, 죠/EF]
  - [ㅂ니다/EF]  #   "입시다" 따윈 없으므로 , 오직 ㅂ니다만 가능.
# 3rd-order rules - not sure if we will need 3rd-order rules. Most of the patterns should be captured within  this range.
# after the 1st-order rule is applied
하/XX + 었/XX + 어/EF + ?/SF ->  하 + 었 + [ㅂ니다, ㅂ시다, ㅂ니까] + ?
# after the 2nd-order rules are applied 
#  [ㅂ니다, ㅂ시다,  ㅂ니까] U [ ㅂ니까] =  [ㅂ니까]
하/XX + 었/XX + 어/EF + ?/SF ->  하 + 었 + [ㅂ니까] + ?
# you pop the most appropriate one using a language model (e.g. skipgram)
# If there is only one candidate, just pop the one
하/XX + 었/XX + 어/EF + ?/SF  ->  하 +었 + ㅂ니까 + ?

On evaluating the performance of `Styler`

You'd need to evaluate the performance of Styler. Evaluate your performance in terms of:

  • accuracy
  • speed

Since politely runs with rules, it should be extremely fast & interpretable.


On training a Skipgram model for implementing neuro-symblic approach

Train Trigram Skipgram model on every possible corpus you have (any corpus that are likely to have a diverse distribution of ban / jon / formal EF's).

데이터는 이 분들이 구축한 데이터를 사용하면?


On writing a paper out of the neuro-symbolic approach

언어모델 + 정규표현식 조합까지 마무리를 하면, 그 결과를 논문으로 정리해서 학회에 제출하는 것도 나쁘지 않을 것 같다.
seq2seq로 풀고자 시도를 한 사람들은 있지만, 규칙과 언어모델을 혼합해 쓰고자한 사람들은 없었음.
이 경우,

  • skipgram
  • kobert
  • kobart
    등, 현존하는 다양한 모델을 실험해보는 것이 좋을 것.

On the danger of proliferation of heuristics

존댓말 규칙의 경우, 계속 이런식으로 휴리스틱을 사용하는 것보다, 존댓말 규칙을 잘 정리한 문서를 찾아서 그 알고리즘을 그대로 옮기는 편이 나을 것.
휴리스틱에만 의존하면, RoI가 높은 일반화 규칙을 찾기가 어렵다. 하지만 이미 연구를 통해 보편적인 규칙을 찾아낸 논문이 있다면, 그 논문을 참조하는게 현명하다.

규칙을 그냥 생각대로, 막무가내로, 휴리스틱으로만 하는 것보단, 연구된 체계를 따라가는편이 훨씬 더 신뢰가 갈 것.

예를 들면 이런 존대의 체계를 따르는 것 (Brown, 2011)
image

그리고 특수 존대형도, 이미 누군가 열심히 분석해 놓은게 있다면, 마다할 필요가 없다.

동사의 존대형 (Brown, 2011)
image
명사의 존대형 (Brown, 2011)
image

On adding static typing to the build workflow

Github Actions 워크 플로우에 mypy를 사용한 static type check를 넣어도 좋을듯!


On using BERT for neuro-symbolic approach

이미 학습된 버트를 그대로 사용하는 것은 불가능하다. BPE, WordPiece는 morpheme-aware하지 않기 때문. 꼭 형태소를 보존해야하나? 물론 subword 토큰에 맞춰서 정규표현식을 만드는 것이 가능은 할 것. 하지만 보다 더 정확한 정규표현식은 품사 정보를 추가했을 때 가능하다. 형태소만을 쓰기보단 형태소/품사를 패턴으로 써야 동음이의어 등의 문제를 피해갈 수 있다. 흔히 쓰이는 subword tokenizers는 학습되는 토크나이저므로, 학습에 쓰인 데이터가 다르면 토크나이징 규칙도 다르다. 그래서 골치 아프다. kiwi같은 pos tagger가 있어도 토큰 정렬이 안되기 때문에 나로썬 무용지물이다.

그래서 만약 neuro-symbolic 접근에 버트를 사용하고 싶다면, 내가 직접 kiwi + transformers 라이브러리의 결합으로 "KiwiBERT"를 사전학습 시키는 수 밖에 없다. OOV 문제로 인해 분명 성능은 떨어지겠지만, 규칙으로 크게 보완할 수 있다면 차라리 나을수도 있다. 앞서 언급한 이유로 인해 다른 KoBERT는 형태소/품사 규칙으로 보완하는게 쉽지가 않으니까.

그런데 문제가 있다. attention_mask, token_type_ids 텐서를 구축하려면 어쩔 수 없이 tokenizersTokenizer 가 필요하다. Tokenizer의 규칙은 kiwi로 대체하되, BERT 사전학습에 필요한 텐서 구축은 그대로 가져가는 방법은 없을까?

konlpyBertTokenizer를 결합하려고 시도한 분은 있다. 최종 결과를 보면 이렇게 나온다:

compose(bert_wordpiece_tokenizer.encode(sent_ko).tokens)
# ['신종', '코로나바이러스', '감염증', '(', '코로나', '##1', '##9', ')', '사태', '##가', '심각', '##합', '##니다']

compose(konlpy_bert_wordpiece_tokenizer.encode(sent_ko, add_special_tokens=False).tokens)
# ['신종', '코로나바이러스', '감염증', '(', '코로나', '19', ')', '사태', '가', '심각', '하', 'ᄇ니다']

compose(konlpy_bert_tokenizer.tokenize(sent_ko))
# ['신종', '코로나바이러스', '감염증', '(', '코로나', '19', ')', '사태', '가', '심각', '하', 'ᄇ니다']

트릭은 pre_tokenizerkonlpy를 설정하는 것. 나도 저걸 비스무리하게 따라한다면, pre_tokenizerkiwi를 설정하고,
decode를 overide 해서 kiwi.join()을 집어넣으면, 얼추 비스무리하게 만들 수 있을 것 같다는 생각이 든다.

이건 politely에서 하지말고, 따로 리포를 만들어서 해야할듯. 그 리포는 우선 politely에서 실험 & 평가 후, 즉 검증을 거친 후 공개하는 편이 나을 것.

이미 카카오에서 morpheme-aware tokenization을 시도했었다. 하지만 가중치를 사용하는 방법이 그리 간편하지는 않다. KiwiBERT를 만든다면 -> pip3 install kiwipiepy만 선행되면 바로 huggingface에서 쓸 수 있도록 만들면, morpheme-aware language model의 접근성도 늘리고 좋을듯!


잠시만. 생각이 달라졌다. 굳이 kiwiBERT를 만들필요는 없다. 조금의 전처리만 거친다면, kiwi tokenization 결과 <-> subword tokenization 결과를 대응시키는게 가능하긴 할 것이다. 기존의 BERT를 사용할 수 있을 것. variable-length 문제야 뭐.. k 개의 마스크로 해결할 수 있을 것 같기도 하고.


On the name of the new approach: "neuro-symbolic" or "guided"

Neuro-symbolic은 이름이 너무... 과대포장하는 느낌이다. 차라리 Guided Masked Language Modeling with Regex가 나을 것 같다.

왜 guided? BERTopic의 이 문서를 보면서 그런 생각이 들었다
image

내가 하고자하는 것도 특정 맥락이 주어졌을 때, 빈칸에 들어갈 후보군을 미리 정해주는 것이라고 볼 수 있으니. 어쩌면 guided라는 말이 더 적절할 수도 있다.

기존에는 BERT를 fine-tuning하지 않고 그대로 사용할 생각만 했었는데. 규칙을 설정해두고 파인튜닝을 하는 방법도 고려해볼만한하다. 재밌을 것 같다. 정해진 규칙을 벗어나지 않는 선에서 모호한 부분을 보완해줄 수 있을 것이다. 아, 이거 빨리 데이터 구축하고 실험해보고 싶다.


On adding two tokens to `mask`
먹+(어) -> 드+시+어요

"어"가 "시+어요"로 바뀌어야 한다. 토큰이 하나만 들어가면 되는게 아니다.


On mlm vs. generation

Style Transfer는 어차피 대부분... MLM보단 generation으로 해결한다 - (seq2seq).
그렇다면 나도 generation으로 접근하는 편이 낫지 않을까?


On the problems with subword tokenizer

일단 토크나이저라는 문제가 있으니까.... 우선 SkipGram으로 실험을 해보는 편이 나을 것 같다.
장기적으로는 symbolic rule로 장규표현식을 쓰는 것이 목표다. 하지만 첫단추는 word-level LM으로 접근해보자.


On the problems with subword tokenizer

Regular expression을 쓴다고는 해도, 여전히 inductive reasoning만 가능하다.
Inductive reasoning을 도와주는 도구니까. 그런데.. deductive reasoning도 가능하다고 볼 수 있는걸까?


On using language models

언어모델을 어떻게 써야할까? kiwi의 접근과 비슷한 접근을 하면 될 것 같다.

>> kiwi.analyze('테스트입니다.', top_n=5)
[([Token(form='테스트', tag='NNG', start=0, len=3), Token(form='이', tag='VCP', start=3, len=1), Token(form='ᆸ니다', tag='EF', start=4, len=2)], -25.217018127441406), 
 ([Token(form='테스트입니', tag='NNG', start=0, len=5), Token(form='다', tag='EC', start=5, len=1)], -40.741905212402344), 
 ([Token(form='테스트입니', tag='NNG', start=0, len=5), Token(form='다', tag='MAG', start=5, len=1)], -41.81024932861328), 
 ([Token(form='테스트입니', tag='NNG', start=0, len=5), Token(form='다', tag='EF', start=5, len=1)], -42.300254821777344), 
 ([Token(form='테스트', tag='NNG', start=0, len=3), Token(form='입', tag='NNG', start=3, len=1), Token(form='니다', tag='EF', start=4, len=2)], -45.86524200439453)
]

kiwi를 보면, 우선 가능한 모든 문장의 후보군을 만든다. 그러고 나서 각 문장 중 어떤 것이 가장 "자연스러운"지 , 그 점수를 부여한다. 나도 그런식으로 접근하면 된다. 모든 후보군을 만든다음에, koGPT로 각 문장의 점수를 부여하자. 이렇게 하면.. 토크나이저가 호환되지 않는 문제는 해결되긴한다. 연산량이 늘긴하겠지만. 아무래도 fine-tuning이 필요하긴하다. Formality 데이터 구축 사례를 찾아보고, GPT게열 모델을 그 데이터에 맞게 fine-tuning해보자.

굉장히 computationally intensive할 것 같다. 하지만 규칙만 잘 설정하면,
크게 걱정할 일은 없다.

  • 일단 정규표현식으로 모든 문장 후보를 뽑는다. (permute 사용하기)
  • 각 문장의 "naturalness"를 계산
  • 가장 점수가 높은 것을 출력
  • 원하면 모든 후보를 다 열람해볼수도 있음.

@eubinecto
Copy link
Owner Author

eubinecto commented Jul 15, 2022

어떤 규칙이 가치있는 규칙일까?

최소한의 규칙으로 최대한의 사례를 설명하는 규칙이 가치있는 규칙이다.

사과가 나무에서 떨어진다는 규칙을 발견했다. 아무도 관심을 가지지 않는다.
달은 지구로 떨어지지 않는다는 규칙을 발견했다. 아무도 관심을 가지지 않는다.

하지만 "두 물체 사이에는 반드시 중력이 작용한다"는 보편적인 규칙 을 발견한 뉴턴은 지금까지도 전설적인 과학자로 촉망받는다. 모든 규칙이 다 가치가 있는 것이 아니다. 최소한의 규칙으로 최대한의 사례를 설명하는 규칙이 가치가 있다. 지구와 사과사이에 중력이 작용하기에 사과는 지구로 떨어진다. 달과 지구 사이에도 중력이 작용하기에 달도 계속 지구로 떨어지고 있다. 하지만 중력은 거리의 세제곱에 반비례하기에 멀리 떨어져 공전하고 있는 달의 중력은 원심력과 평형을 이루고, 이 때문에 하늘에 떠있는 것처럼보인다. 어찌됐든 두 사례 모두, 중력이라는 보편적인 규칙으로 설명가능하다. 규칙의 구체성보단 규칙의 범용성이 높을수록 규칙으로서의 가치가 있다. coverage/complexity가 높을수록 가치있는 규칙이다.

"entities should not be multiplied beyond necessity" - the principle of parsimony

그게 "사고절약의 원리"이다. 필요 이상으로 복잡해지면 안된다. 타당함이 비슷하다면 가능하면 더 단순한, 범용성이 높은 이론(규칙)이 우선시 되어야 한다. 물론 단순함이 타당함을 의미하지는 않는다. 창조론이 진화론보다 더 단순하다고 해서 더 타당한 것은 아니다. "신이 모든 것을 만들었어요"라는 주장보다야 복잡하지만, 창조론과는 달리 진화론은 주장을 뒷받침하는 과학적 근거가 존재한다. 하지만 뒷받침하는 근거가 비슷하다면, 보통 더 단순한 쪽이 더 정답에 가깝다. 그게 사고절약의 원리, aka 오캄의 면도날이다.

나는 왜 이런 theoretical mumbo-jumbo를 늘어놓고 있나? 지금 v3.1.1의 규칙을 보면:

이${SEP}VCP${DLM}다${SEP}EF${DLM}(\.${SEP}SF|!${SEP}SF):
1: 이${SEP}VCP${DLM}다${SEP}EF${DLM}\1
2: 이${SEP}VCP${DLM}에요${SEP}EF${DLM}\1
3: 이${SEP}VCP${DLM}습니다${SEP}EF${DLM}\1
말${SEP}VX${DLM}어${SEP}EF${DLM}(\.${SEP}SF|!${SEP}SF):
1: 말${SEP}VX${DLM}어${SEP}EF${DLM}\1
2: 말${SEP}VX${DLM}어요${SEP}EF${DLM}\1
3: 마${SEP}VX${DLM}십시오${SEP}EF${DLM}\1
말${SEP}VX${DLM}어요${SEP}EF${DLM}(\.${SEP}SF|!${SEP}SF):
1: 말${SEP}VX${DLM}어${SEP}EF${DLM}\1
2: 말${SEP}VX${DLM}어요${SEP}EF${DLM}\1
3: 마${SEP}VX${DLM}십시오${SEP}EF${DLM}\1
보${SEP}VX${DLM}어${SEP}EF${DLM}(\.${SEP}SF|!${SEP}SF):
1: 보${SEP}VX${DLM}어${SEP}EF${DLM}\1
2: 보${SEP}VX${DLM}어요${SEP}EF${DLM}\1
3: 보${SEP}VX${DLM}읍시다${SEP}EF${DLM}\1
보${SEP}VX${DLM}어요${SEP}EF${DLM}(\.${SEP}SF|!${SEP}SF):
1: 보${SEP}VX${DLM}어${SEP}EF${DLM}\1
2: 보${SEP}VX${DLM}어요${SEP}EF${DLM}\1
3: 보${SEP}VX${DLM}읍시다${SEP}EF${DLM}\1
시${SEP}EP${DLM}어요${SEP}EF${DLM}(\.${SEP}SF|!${SEP}SF):
1: 어${SEP}EF${DLM}\1
2: 시${SEP}EP${DLM}어요${SEP}EF${DLM}\1
3: 십${SEP}EP${DLM}시오${SEP}EF${DLM}\1
시${SEP}EP${DLM}어요${SEP}EF${DLM}(\?${SEP}SF):
1: 어${SEP}EF${DLM}\1
2: 시${SEP}EP${DLM}어요${SEP}EF${DLM}\1
3: 시${SEP}EP${DLM}읍니까${SEP}EF${DLM}\1

내 규칙에는 범용성이 없다. "사과는 나무에서 떨어진다", "이파리도 나무에서 떨어진다", "야구공을 던지면 다시 떨어진다" 만 늘어놓고 있다. 물론 그런 사례만 수천개 수십억개를 모으면 힘겹게 힘겹게 if-else로 가득한 중력 시뮬레이터 A를 만들 수 있을 것이다. 하지만 A 를 기술력이 높은 시뮬레이터라고 보기엔 부적절하다. 그냥 노가다로 때운 기술이 더 적절한 표현이다. 기술력은 F = G * m1 * m2 / r^2 한 줄로 A를 대체하고 심지어 더 많은 사례를 커버하는, 그런 범용적인 중력엔진 B를 만들었을 때 나온다. 최소한의 규칙으로 최대한의 사례를 설명하는 B가 A보다 훨씬 기술력이 좋은 중력 시뮬레이터다. B가 A보다 coverage/complexity이 높다.

그런면에서, 위 규칙보단, 현재 experimental 브랜치에서 실험 중인 아래 한줄이 더 기술력이 높은 규칙이라고 볼 수 있다.

RULES: Dict[str, Tuple[set, set, set]] = {ALL: (CASUAL, POLITE, FORMAL)}

ALL EF에 대하여 1이면 CASUAL에 속한 것을, 2이면 POLITE에 속한 것을 , 3이면 FORMAL에 속한 것을 선택한다. 어떤 종결어미가 오던 적용할 수 있는 규칙이다. 즉 존댓말의 "중력이론"이다.

최소한의 규칙으로 최대한의 사례를 설명하는 규칙이다.

보편적인 규칙을 찾을 수 있다면, 왜 굳이 머신러닝이 필요할까?

예외처리는 머신러닝으로 해결해야 기술력을 유지할 수 있다.

하지만 자연어는 물리처럼 딱 떨어지지 않는다. "중력이론"이 애매모호하게 작용할 때가 있다. 예를 들어, 위 규칙을 바탕으로 저는 쓰레기를 주워요자, 같이 쓰레기를 주워요를 습니다체로 바꾸면 결과가 다음과 같이 나온다.

print(styler(["저는 쓰레기를 주워요."], 3))
print(styler(["자, 같이 쓰레기를 주워요."], 3))
>>> [저는 쓰레기를 줍습니다.]
>>> [, 같이 쓰레기를 줍습니다.]

첫번째는 맞지만, 두번째는 틀리다. 두번째는 권유가 아닌 청유이므로, 자, 같이 쓰레기를 주웁시다가 더 적절하다.

아쉽게도 우리의 "중력이론"으로는 설명할 수 없는, 애매모호한 사례가 나와버렸다. 이 문제를 어떻게 해결해야할까? 또 규칙을 추가할까? " 자, 로 시작하는 경우, 습니다가 아닌 읍시다를 쓰도록 한다" - 물론 그런 예외를 추가해서 해결할 수는 있을 것이다. 하지만 그런 예외처리식 규칙은 여러분, 같이 쓰레기를 주웁시다, 아, 그냥 같이 쓰레기를 주웁시다, 거기 당신, 저와 함꼐 쓰레기를 주웁시다 와 같은 문장에 대응하지 못한다. 즉, 그다지 범용적이지 못하다. 제품의 기술력이 내려간다. (자|여러분|거기 당신)으로 개선할수는 있더라도, 그런식으로 예외를 닥치는 대로 계속 추가하다보면 if-else 덩어리가 되기 십상이다. 인공지능이 아니라 인간지능이 되어버린다. coverage/complexity가 0에 수렴하기 시작한다.

그러기 시작할 때 머신러닝을 써야한다. "어? 나 지금 예외처리만 10번째 인가?" 싶을 때, 우리는 기술력을 유지하기 위해 직접 예외를 처리하는 것을 것을 중단해야한다. 대신 머신러닝 모델이 알아서 "청유를 하는 경우 습시다를 쓴다"는 예외를 데이터로부터 학습하도록 유도해야한다. 물론 그런 규칙은 잠재공간에 말그대로 "잠재"되어 있기 때문에, 해석은 불가능하다. 하지만 애초에 애매모호한 규칙은 우리에게도 해석이 명료하지 않다. "청유를 하는 경우"가 언제인지 청유라는 단어만으로는 정의가 되지 않는다. 어차피 명료한 해석이 힘든 규칙이라면 "해석이 불가능하다"는 머신러닝의 단점은 큰 문제가 아니게 된다. 그렇기에 머신러닝은 애매모호한 에외처리에 더욱 더 적절한 접근이다. coverage/complexity를 올리면서도 해석력에 큰 타격이 없다. 제품의 기술력을 올려준다.

예외처리는 머신러닝으로 해결해야 기술력을 유지할 수 있다.

결론

image

우선 최대한 보편적인 규칙을 적용하되, 예외처리는 머신러닝으로 해결함으로서 높은 기술력을 유지하자.

@eubinecto
Copy link
Owner Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant