Rasa學(xué)習(xí)筆記1--Rasa NLU

1. RASA整體結(jié)構(gòu)


上圖是RASA執(zhí)行的結(jié)構(gòu)圖讽挟,

  1. 一句話輸入懒叛,經(jīng)過Interpreter處理,使用NLU耽梅,將這句話進(jìn)行解析薛窥,結(jié)果就是一組字典,包括:原始句子眼姐,意圖诅迷,識(shí)別的實(shí)體等。
  2. 將上一步的結(jié)果傳入Tracker來追蹤對(duì)話狀態(tài)众旗。
  3. Policy接收上一步的狀態(tài)罢杉,然后決定下一步要采取的Action
  4. 這個(gè)Action再依據(jù)Tracker來生成最終的回復(fù)。

2. Rasa NLU


2.1 Pileine

在Rasa NLU中贡歧,一句話需要經(jīng)過一系列的組件(Component)來處理滩租,這個(gè)處理過程是組件依次執(zhí)行赋秀,并且下一個(gè)組件會(huì)使用上一個(gè)組件的結(jié)果,這個(gè)過程就被稱之為Pipeline.
通常一個(gè)pipeline會(huì)包含的組件有:預(yù)處理律想,實(shí)體抽取猎莲,意圖分類等。
下面是由一系列組件得到的結(jié)果技即,比如著洼,實(shí)體(entities)是有實(shí)體抽取組件得到的。

{
"text": "I am looking for Chinese food",
"entities": [
    {"start": 8, "end": 15, "value": "chinese", "entity": "cuisine", "extractor": "CRFEntityExtractor", "confidence": 0.864}
],
"intent": {"confidence": 0.6485910906220309, "name": "restaurant_search"},
"intent_ranking": [
    {"confidence": 0.6485910906220309, "name": "restaurant_search"},
    {"confidence": 0.1416153159565678, "name": "affirm"}
]

}

看一下初始化nlu模型中創(chuàng)造pipeline的代碼:

    def _build_pipeline(
    cfg: RasaNLUModelConfig, component_builder: ComponentBuilder
) -> List[Component]:
    """Transform the passed names of the pipeline components into classes"""
    pipeline = []
    # Transform the passed names of the pipeline components into classes
    for i in range(len(cfg.pipeline)):
        component_cfg = cfg.for_component(i)
        component = component_builder.create_component(component_cfg, cfg)
        pipeline.append(component)
    return pipeline
    

傳入RasaNLUModelConfig和ComponentBuilder類而叼,然后創(chuàng)造config中定義的所有Component類身笤,放進(jìn)pipeline中,pipeline其實(shí)就是一個(gè)list啦澈歉。

2.3 Component

每一個(gè)組件實(shí)例都可以執(zhí)行幾個(gè)特定的方法展鸡,而在一個(gè)pipeline中,這些方法會(huì)以固定的順序依次執(zhí)行埃难。
假設(shè)我們的pipeline中定義了三個(gè)組件:"pipeline": ["Component A", "Component B", "Last Component"]莹弊,下圖中顯示了在訓(xùn)練過程各組建方法的調(diào)用順序以及組建的生存周期:


Component類包含的方法有: create(),train(),persis(),process(),load()等。
Component是所有獨(dú)立組件的父類涡尘,每個(gè)獨(dú)立組建需要具體實(shí)現(xiàn)父類的每個(gè)方法忍弛。
當(dāng)用create()方法創(chuàng)造一個(gè)Component實(shí)例,一個(gè)context就別生成了(其實(shí)就是python里面的一個(gè)dict)考抄,然后我們就使用這個(gè)context在組建之間傳遞信息细疚。
所以,當(dāng)所有的組件訓(xùn)練完成并且持久化了川梅,最終的context字典就用來持久化最終這個(gè)模型的元數(shù)據(jù)(metadata)疯兼。

介紹幾個(gè)Component:

2.2.1 詞向量

2.2.2 特征提取器

列出一些可供選擇的Featurizers: MitieFeaturizer,SpacyFeaturizer贫途,NGramFeaturizer吧彪,RegexFeaturizer,CountVectorsFeaturizer丢早,具體介紹可以到官網(wǎng)教程上看姨裸。

SpacyFeaturizer就是將一句話變成一個(gè)向量

2.2.3 意圖分類器

  • KeywordIntentClassifier,只使用關(guān)鍵字來進(jìn)行意圖識(shí)別怨酝。
  • MitieIntentClassifier傀缩, 是MITIE中提供的分類器,使用SVM农猬,輸入需要分詞Tokenizers和featurizer赡艰。
  • SklearnIntentClassifier, 是sklearn中提供的一個(gè)svm分類器斤葱,另外會(huì)使用grid search進(jìn)行參數(shù)優(yōu)化搜索瞄摊。輸入需要featurizer勋又。
  • EmbeddingIntentClassifier,
    這個(gè)分類器的實(shí)現(xiàn)是基于StarSpace,就是將輸入和對(duì)應(yīng)的label映射到相同空間换帜,然后最大化他們之間的相似度楔壤。具體的實(shí)現(xiàn)中另外增加了一層隱層并使用dropout。輸入需要featurizer惯驼。
StarSpace模型
  • 模型解釋:StarSpace模在于學(xué)習(xí)entities蹲嚣,而每一個(gè)entity是由一組離散的特征(features)組成,這些特征構(gòu)成一個(gè)特征字典祟牲。比如隙畜,當(dāng)把一篇document或者一個(gè)sentence看作一個(gè)entity,組成他的特征就是詞代或者n-grams说贝∫槎瑁或者,當(dāng)把一個(gè)人看作entity乡恕,他就能通過一組文章言询、電影、喜歡的東西等來描述傲宜。
    StarSpace將不同類別的entity通過embedding映射到相同空間运杭,這樣,就可以比較任何不同類別的entity函卒。
    令特征字典D有特征F辆憔,他是一個(gè)D*d維的矩陣,其中F_i表示第i個(gè)特征(一行)报嵌,就是一個(gè)d維的向量虱咧。然后,我們embed一個(gè)實(shí)體a的表示為:\sum_{i\in{a}}F_i

  • 模型初始化:首先給特征字段中的每個(gè)特征分配一個(gè)d維的向量锚国。然后一個(gè)實(shí)體有一組特征組成腕巡,也就是由一組上述d維向量。
    訓(xùn)練模型:需要學(xué)習(xí)如何取比較實(shí)體跷叉。然后最小化下面的loss function:


解釋上述公式:

  1. positive entity pairs(a, b)是從正例集合E^+中生成逸雹,而這個(gè)數(shù)據(jù)集不同任務(wù)不同营搅。
  2. negetive entiies b是從負(fù)例集合E^-中生成云挟。k-negative sampling的策略可以是每次從batch中任意選取k個(gè)label。
  3. 相似度函數(shù)sim(.,.)可以使用cosine similarity或者inner product,對(duì)于小數(shù)量label(比如分類任務(wù))转质,兩者效果相似园欣。但是,一般來講休蟹,cosine similarity更適用于大數(shù)據(jù)label(比如句子和文檔相似度)沸枯。
  4. L is the loss function that compares the positive pair (a, b) with the negative pairs.
  • 模型的使用:
    我們可以直接使用學(xué)習(xí)到的函數(shù) sim(.,.) 來計(jì)算entity之間的相似度日矫。比如,對(duì)于分類任務(wù)绑榴,對(duì)于輸入a哪轿,直接計(jì)算 max_{\hat}sim(a, \hat翔怎),\hat窃诉表示所有可能的label。對(duì)于ranking任務(wù)赤套,可以直接使用相似度進(jìn)行排序飘痛。

  • 各任務(wù)的使用(構(gòu)造E_+E_-

  1. text classification
  2. multilabel classification
  3. information retrieval and document embeddings
    如果有現(xiàn)成監(jiān)督學(xué)習(xí)數(shù)據(jù)集,a是搜索關(guān)鍵詞容握,b是相關(guān)的文檔宣脉,而b^-是不相關(guān)的文檔。如果只有非監(jiān)督數(shù)據(jù)集剔氏,a表示文檔中任選的關(guān)鍵詞塑猖,而b表示文檔中剩下的詞語。
  4. Learning Word Embeddings
    一個(gè)window的詞語作為a介蛉,中間的一個(gè)詞語看作b萌庆。
  5. Learning Sentence Embeddings
    相同文檔中選取sentence pair看作a, b。而b^-來自其他文檔中币旧。
  • Rasa中的實(shí)現(xiàn)

_create_tf_embed_nn()用來創(chuàng)建encoder部分践险,a和b的encoder是相同的網(wǎng)絡(luò)。其實(shí)Rasa中就是使用多層的神經(jīng)網(wǎng)絡(luò)吹菱。

    def _create_tf_embed_nn(
        self, x_in: "Tensor", is_training: "Tensor", layer_sizes: List[int], name: Text
    ) -> "Tensor":
        """Create nn with hidden layers and name"""

        reg = tf.contrib.layers.l2_regularizer(self.C2)
        x = x_in
        for i, layer_size in enumerate(layer_sizes):
            x = tf.layers.dense(
                inputs=x,
                units=layer_size,
                activation=tf.nn.relu,
                kernel_regularizer=reg,
                name="hidden_layer_{}_{}".format(name, i),
            )
            x = tf.layers.dropout(x, rate=self.droprate, training=is_training)

        x = tf.layers.dense(
            inputs=x,
            units=self.embed_dim,
            kernel_regularizer=reg,
            name="embed_layer_{}".format(name),
        )
        return x

_tf_loss()d用來定義網(wǎng)絡(luò)的loss巍虫。主要包括三個(gè)部分:1. positive similarity, 2. negtive similarity, 3. similarity between intent.
網(wǎng)絡(luò)的默認(rèn)超慘設(shè)置

  • mu_pos=0.8,這個(gè)參數(shù)表示對(duì)于正例對(duì)(a,b),你要盡量讓a,b之間的相似度等于mu_pos鳍刷,這個(gè)值在0.0-1.0之間占遥。
  • mu_neg=-0.4,表示負(fù)例對(duì)最大相似度,值在-1.0-1.0之間输瓜。

另外loss還包括意圖embedding之間相似度,意思是要讓相同意圖的編碼盡量相似瓦胎。

    def _tf_loss(self, sim: "Tensor", sim_emb: "Tensor") -> "Tensor":
        """Define loss"""

        # loss for maximizing similarity with correct action
        loss = tf.maximum(0.0, self.mu_pos - sim[:, 0])

        if self.use_max_sim_neg:
            # minimize only maximum similarity over incorrect actions
            max_sim_neg = tf.reduce_max(sim[:, 1:], -1)
            loss += tf.maximum(0.0, self.mu_neg + max_sim_neg)
        else:
            # minimize all similarities with incorrect actions
            max_margin = tf.maximum(0.0, self.mu_neg + sim[:, 1:])
            loss += tf.reduce_sum(max_margin, -1)

        # penalize max similarity between intent embeddings
        max_sim_emb = tf.maximum(0.0, tf.reduce_max(sim_emb, -1))
        loss += max_sim_emb * self.C_emb

        # average the loss over the batch and add regularization losses
        loss = tf.reduce_mean(loss) + tf.losses.get_regularization_loss()
        return loss

2.2.4 selector

先看一個(gè)例子:

{
    "text": "What is the recommend python version to install?",
    "entities": [],
    "intent": {"confidence": 0.6485910906220309, "name": "faq"},
    "intent_ranking": [
        {"confidence": 0.6485910906220309, "name": "faq"},
        {"confidence": 0.1416153159565678, "name": "greet"}
    ],
    "response_selector": {
      "faq": {
        "response": {"confidence": 0.7356462617, "name": "Supports 3.5, 3.6 and 3.7, recommended version is 3.6"},
        "ranking": [
            {"confidence": 0.7356462617, "name": "Supports 3.5, 3.6 and 3.7, recommended version is 3.6"},
            {"confidence": 0.2134543431, "name": "You can ask me about how to get started"}
        ]
      }
    }
}

使用與意圖識(shí)別相同的模型 EmbeddingIntentClassifier,將用戶輸入與回答的內(nèi)容嵌入到相同的空間進(jìn)行比較尤揣。只是訓(xùn)練意圖識(shí)別模型的時(shí)候label是意圖分布搔啊,而訓(xùn)練response selector 模型的時(shí)候,label就是所有答案分布北戏。
可以直接用于構(gòu)建一個(gè)答案檢索模型负芋,從一組答案中直接預(yù)測(cè)答案。
另外嗜愈,此組件可以通過配置retrieval_intent旧蛾,從而只在指定意圖上訓(xùn)練response selector 模型莽龟。

2.2.5 Entity Extraction

3. 代碼解析

訓(xùn)練入口:

training_data = load_data(ROOT_DIR + training_data_file) # 加載數(shù)據(jù),封裝成TrainingData
trainer = Trainer(config.load(ROOT_DIR + config_file)) # 初始化Trainer锨天,傳入config(RasaNLUModelConfig)和訓(xùn)練數(shù)據(jù)(TrainingData),構(gòu)建pipeline
trainer.train(training_data)
model_path = os.path.join(model_directory, model_name)
model_directory = trainer.persist(model_path, fixed_model_name="nlu")

開始訓(xùn)練Trainer.train():

def train(self, data: TrainingData, **kwargs: Any) -> "Interpreter":
    ...
    for i, component in enumerate(self.pipeline):
        logger.info("Starting to train component {}".format(component.name))
        component.prepare_partial_processing(self.pipeline[:i], context)
        updates = component.train(working_data, self.config, **context)
        logger.info("Finished training component.")
        if updates:
            context.update(updates)
    return Interpreter(self.pipeline, context)
pipeline:
  - name: "SpacyNLP"
  - name: "SpacyTokenizer"
  - name: "SpacyFeaturizer"
  - name: "EmbeddingIntentClassifier"
  - name: "CRFEntityExtractor"
  - name: "EntitySynonymMapper"

self.pipeline中順序放置config中的所有Component,比如上面的pipeline毯盈,每個(gè)component都是繼承Component類。然后順序地每個(gè)Component執(zhí)行各自的train函數(shù)病袄,每個(gè)Component執(zhí)行后的改變:1.數(shù)據(jù)改變更新到working_data中奶镶。2.conponent自己改變(訓(xùn)練參數(shù))。
比如SpacyNLP會(huì)將語料變成vector等陪拘,SpacyTokenizer將語料分詞厂镇,SpacyFeaturizer把語料數(shù)字化(這里就是自己而去SpacyNLP中產(chǎn)生的vector),EmbeddingIntentClassifier訓(xùn)練意圖分類器模型左刽,CRFEntityExtractor訓(xùn)練實(shí)體識(shí)別模型捺信,EntitySynonymMapper進(jìn)行加載訓(xùn)練語料中的同義詞對(duì)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末欠痴,一起剝皮案震驚了整個(gè)濱河市迄靠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喇辽,老刑警劉巖掌挚,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異菩咨,居然都是意外死亡吠式,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門抽米,熙熙樓的掌柜王于貴愁眉苦臉地迎上來特占,“玉大人,你說我怎么就攤上這事云茸∈悄浚” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵标捺,是天一觀的道長懊纳。 經(jīng)常有香客問我,道長亡容,這世上最難降的妖魔是什么嗤疯? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮萍倡,結(jié)果婚禮上身弊,老公的妹妹穿的比我還像新娘辟汰。我一直安慰自己列敲,他們只是感情好阱佛,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著戴而,像睡著了一般凑术。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上所意,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天淮逊,我揣著相機(jī)與錄音,去河邊找鬼扶踊。 笑死泄鹏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秧耗。 我是一名探鬼主播备籽,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼分井!你這毒婦竟也來了车猬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤尺锚,失蹤者是張志新(化名)和其女友劉穎珠闰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瘫辩,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡伏嗜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了伐厌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片阅仔。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖弧械,靈堂內(nèi)的尸體忽然破棺而出八酒,到底是詐尸還是另有隱情,我是刑警寧澤刃唐,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布羞迷,位于F島的核電站,受9級(jí)特大地震影響画饥,放射性物質(zhì)發(fā)生泄漏衔瓮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一抖甘、第九天 我趴在偏房一處隱蔽的房頂上張望热鞍。 院中可真熱鬧,春花似錦、人聲如沸薇宠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽澄港。三九已至椒涯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間回梧,已是汗流浹背废岂。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狱意,地道東北人湖苞。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像详囤,于是被迫代替她去往敵國和親袒啼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容