kochat_config.py

2021. 7. 13. 12:35NLU

PROC

PROC = {
    'logging_precision': 5,  # 결과 저장시 반올림 소수점 n번째에서 반올림
    'model_dir': BASE['root_dir'] + "saved{_}".format(_=_),  # 모델 파일, 시각화 자료 저장 경로
    'visualization_epoch': 50,  # 시각화 빈도 (애폭마다 시각화 수행)
    'save_epoch': 10  # 저장 빈도 (에폭마다 모델 저장)
}

proc은 Processor의 줄임말로, 다양한 모델들의 학습/테스트를 수행하는 함수인 fit()과 추론을 수행하는 함수인 predict() 등을 수행하는 클래스 집합입니다. 현재 지원하는 프로세서는 총 4가지로 아래에서 자세하게 설명합니다.

 

 

kochat/proc/

from abc import abstractmethod
from typing import Any

from kochat.decorators import proc


@proc
class BaseProcessor:
    def __init__(self, model: Any):
        """
        모든 프로세서의 부모클래스입니다.
        모델들의 이름과 파일 주소를 가지고 있고, 다양한 추상 메소드를 가지고 있습니다.
        학습 및 검증 등의 메소드의 이름은 sklearn과 동일하게 설정했습니다.

        :param model: 학습할 모델
        """

        super().__init__()
        self.train_data, self.test_data = None, None
        self.ood_train, self.ood_test = None, None
        self.model = model
        self.model_loaded = False

        # /saved/CLASS_NAME/
        self.model_dir = self.model_dir + \
                         self.__class__.__name__ + \
                         self.delimeter

        # /saved/CLASS_NAME/CLASS_NAME.xxx
        self.model_file = self.model_dir + \
                          self.__class__.__name__

    @abstractmethod
    def fit(self, *args, **kwargs):
        raise NotImplementedError

    @abstractmethod
    def predict(self, *args, **kwargs):
        raise NotImplementedError

    @abstractmethod
    def _load_model(self):
        raise NotImplementedError

    @abstractmethod
    def _save_model(self):
        raise NotImplementedError

    def _print(self, msg: str, name: str = None):
        """
        Processor는 내용 출력시 반드시 자신의 이름을 출력해야합니다.

        :param msg: 출력할 메시지
        :return: [XXProcessor] message
        """

        if name is None:
            name = self.__class__.__name__

        print('[{name}] {msg}'.format(name=name, msg=msg))

1. gensim_embedder.py

GensimEmbedder는 Gensim의 임베딩 모델을 학습시키고, 학습된 모델을 사용해 문장을 임베딩하는 클래스입니다. 자세한 사용법은 다음과 같습니다.

 

from kochat.data import Dataset
from kochat.proc import GensimEmbedder
from kochat.model import embed


dataset = Dataset(ood=True)

# 프로세서 생성
emb = GensimEmbedder(
    model=embed.FastText()
)

# 모델 학습
emb.fit(dataset.load_embed())

# 모델 추론 (임베딩)
user_input = emb.predict("서울 홍대 맛집 알려줘")

 

2. softmax_classifier.py

Softmax Score를 이용해 Fallback Detection을 수행

사실 SoftmaxClassifier를 실제 챗봇의 Intent Classification 기능을 위해 사용하는 것은 적절하지 못합니다.

SoftmaxClassifier는 아래 후술할 DistanceClassifier 와의 성능 비교를 위해 구현하였습니다. 

3. distance_classifier.py

SoftmaxClassifier와는 다르게 거리기반으로 작동하며, 일종의 Memory Network입니다. [batch_size, -1] 의 사이즈로 출력된 출력벡터와 기존 데이터셋에 있는 문장 벡터들 사이의 거리를 계산하여 데이터셋에서 가장 가까운 K개의 샘플을 찾고 최다 샘플 클래스로 분류하는 최근접 이웃 Retrieval 기반의 분류 모델입니다.

loss = 주로 margin기반 loss 적용하여 metric learning을 수행한다. => margin을 최대치로 벌리는 메커니즘 구현

최근접 이웃을 찾을 때, 다차원 검색트리인 KDTree 혹은 BallTree (KDTree의 개선 형태)를 통해서 거리를 계산하며 결과로 만들어진 트리 구조를 메모리에 저장한다. -> 대량의 데이터셋을 이용하면 속도가 매우 느리다.

from kochat.data import Dataset
from kochat.proc import BaseClassifier
from kochat.model import intent
from kochat.loss import CenterLoss


dataset = Dataset(ood=True)

# 프로세서 생성
clf = DistanceClassifier(
    model=intent.CNN(dataset.intent_dict),
    loss=CenterLoss(dataset.intent_dict)
)

# 되도록이면 DistanceClassifier는 Margin 기반의 Loss 함수를 이용해주세요
# 현재는 CenterLoss, COCOLoss, Cosface, GausianMixture 등의 
# 거리기반 Metric Learning 전용 Loss함수를 지원합니다.


# 모델 학습
clf.fit(dataset.load_intent(emb))

# 모델 추론 (인텐트 분류)
clf.predict(dataset.load_predict("오늘 서울 날씨 어떨까", emb))

self.distance_estimator = DistanceEstimator(self.grid_search) 부분은

distance_estimator.py에 있다. 

 

 

4. fallback_detector.py

SoftmaxClassifier DistanceClassifier 모두 Fallback Detection 기능을 구현되어있습니다. 

1. OOD 데이터가 없는 경우 : 직접 config의 Threshold를 맞춰야합니다.

2. OOD 데이터가 있는 경우 : 머신러닝을 이용하여 Threshold를 자동 학습합니다.

바로 여기에서 OOD 데이터셋이 사용됩니다.

 

FallbackDetector는 각 Classifier안에 내장 되어있기 때문에 별다른 추가 소스코드 없이 Dataset ood 파라미터만 True로 설정되어있다면 Classifier학습이 끝나고나서 자동으로 학습되고, predict()시 저장된 FallbackDetector가 있다면 자동으로 동작합니다. 또한 FallbackDetector로 사용할 모델은 아래처럼 config에서 사용자가 직접 설정할 수 있으며 GridSearch를 지원하여 여러개의 모델을 리스트에 넣어두면 Kochat 프레임워크가 현재 데이터셋에 가장 적합한 FallbackDetector를 자동으로 골라줍니다.

from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC


INTENT = {
    # ... (생략)

    # 폴백 디텍터 후보 (선형 모델을 추천합니다)
    'fallback_detectors': [
        LogisticRegression(max_iter=30000),
        LinearSVC(max_iter=30000)

        # 가능한 max_iter를 높게 설정해주세요
        # sklearn default가 max_iter=100이라서 수렴이 안됩니다...
    ]
}

 FallbackDetector로는 위 처럼 선형 모델인 선형 SVM, 로지스틱 회귀 등을 주로 이용합니다. 물론 위의 리스트에 RandomForestClassifier()나 BernoulliNB(), GradientBoostingClassifier() 등 다양한 sklearn 모델을 입력해도 동작은 하지만, 일반적으로 선형모델이 가장 우수하고 안정적인 성능을 보였습니다.

 

OOD 데이터셋이 필요하다는 치명적인 단점이 있지만, 차후 버전에서는 BERT와 Markov Chain을 이용해 OOD 데이터셋을 자동으로 빠르게 생성하는 모델을 구현하여 추가할 예정입니다. (이 업데이트 이후부터는 OOD 데이터셋이 필요 없어집니다.)

만약 OOD 데이터셋이 없다면 사용자가 직접 Threshold를 설정해야 하므로 눈으로 샘플들이 어느정도 score 혹은 거리를 갖는지 확인해야합니다. 따라서 Kochat은 Calibrate 모드를 지원합니다.

distanceclassifier
softmaxclassifier

 calibrate 모드를 여러번 진행하셔서 스스로 계산한 threshold와 원하는 criteria를 아래처럼 config에 설정하면 ood 데이터셋 없이도 FallbackDetector를 이용할 수 있습니다.

 

 

5. entity_recognizer.py

EntityRecongnizer는 엔티티 검출을 담당하는 Entity 모델들을 학습/테스트 시키고 추론하는 클래스입니다. Entity 검사의 경우 문장 1개당 라벨이 여러개(단어 갯수와 동일)입니다. 문제는 Outside 토큰인 'O'가 대부분이기 때문에 전부다 'O'라고만 예측해도 거의 90% 육박하는 정확도가 나오게 됩니다. 또한, 패드시퀀싱한 부분도 'O'로 처리 되어있는데, 이 부분도 맞은것으로 생각하고 Loss를 계산합니다.

이러한 문제를 해결하기 위해 Kochat은 F1 Score, Recall, Precision 등 NER의 성능을 보다 정확하게 평가 할 수 있는 강력한 Validation 및 시각화 지원과 Loss 함수 계산시 PAD부분에 masking을 적용할 수 있습니다. (mask 적용 여부 역시 config에서 설정 가능합니다.) 사용법은 아래와 같습니다.

from kochat.data import Dataset
from kochat.proc import EntityLSTM
from kochat.model import entity
from kochat.loss import CRFLoss


dataset = Dataset(ood=True)

# 프로세서 생성
rcn = EntityRecognizer(
    model=entity.LSTM(dataset.intent_dict),
    loss=CRFLoss(dataset.intent_dict)
    # Conditional Random Field를 Loss함수로 지원합니다.
)


# 모델 학습
rcn.fit(dataset.load_entity(emb))

# 모델 추론 (엔티티 검출)
rcn.predict(dataset.load_predict("오늘 서울 날씨 어떨까", emb))

LOSS

 

GENSIM

 

https://github.com/hyunwoongko/kochat/blob/master/docs/04_usage.md

 

hyunwoongko/kochat

Opensource Korean chatbot framework. Contribute to hyunwoongko/kochat development by creating an account on GitHub.

github.com

 

'NLU' 카테고리의 다른 글

mecab 설치(Linux)  (0) 2022.02.22