自定義nlu組件(詳細(xì)版)

Enhancing Rasa NLU models with Custom Components

源文地址:https://blog.rasa.com/enhancing-rasa-nlu-with-custom-components/?_ga=2.115773509.2118304263.1591599801-549374689.1567321116

自定義組件增強(qiáng)nlu模型

我們認(rèn)為自定義的機(jī)器學(xué)習(xí)模型對(duì)于構(gòu)建成功的AI助手至關(guān)重要。開(kāi)源的rasa給你為意圖分類和實(shí)體提取構(gòu)建好的nlu模型提供給你一個(gè)堅(jiān)實(shí)基礎(chǔ)享潜,但是如果你想用你自己自定義組件來(lái)增強(qiáng)現(xiàn)有的rasa nlu模型娇掏,我們做了很多的工作使得rasa nlu模塊化,這樣你就可以做到這一點(diǎn)湃鹊。想要學(xué)習(xí)如何去實(shí)現(xiàn)它村缸?在這篇文章汉形,你將學(xué)習(xí)到如何如何自定義組件并且將其添加到nlu管道讓你的AI助手到達(dá)一個(gè)新的水平权均。

概要

1.介紹rasa nlu管道

2.介紹自定義組件

3.添加自定義的情感分析組件到rasa nlu

  • 建立自定義情感分析組件類

  • 如果我想使用一個(gè)預(yù)先訓(xùn)練好的情緒分析模型呢?

4.總結(jié)

5.資源

介紹rasa nlu管道

一個(gè)處理管道是rasa nlu模型的主要的基本構(gòu)成要素胁勺。它定義傳入的用戶消息在產(chǎn)生模型輸出之前必須經(jīng)過(guò)處理階段。這些階段可以是符號(hào)化薄腻,特征化岛马,意圖分類棉姐,實(shí)體提取,模式匹配等等啦逆。默認(rèn)的伞矩,rasa nlu已經(jīng)給你自帶了一些預(yù)先構(gòu)建的組件。下面是一個(gè)rasa nlu的管道配置夏志。

pipeline:

  • name: "SpacyNLP"

  • name: "SpacyTokenizer"

  • name: "SpacyFeaturizer"

  • name: "RegexFeaturizer"

  • name: "CRFEntityExtractor"

  • name: "EntitySynonymMapper"

  • name: "SklearnIntentClassifier"

一旦定義了管道乃坤,每個(gè)組件都會(huì)被一個(gè)接一個(gè)的調(diào)用,并且產(chǎn)生的輸出要么直接添加到rasa nlu模型的輸出沟蔑,或者是被用做其他管道的輸入湿诊。這是非常重要的,如何在配置文件中定義組件瘦材。例如厅须,如果你在你的管道中定義了三個(gè)組件[‘Component1’, ‘Component2’, ‘Component3’],component1的方法將在第一個(gè)被調(diào)用食棕,下面這個(gè)圖片展示了組件的生命周期:

img

組件通過(guò)三個(gè)主要的階段:

  • 創(chuàng)建:訓(xùn)練之前初始化組件

  • 訓(xùn)練:組件使用上下文和前面組件的輸出對(duì)自己進(jìn)行訓(xùn)練

  • 持久化:保存訓(xùn)練組件到磁盤朗和,以備將來(lái)使用

在初始化第一個(gè)組件之前错沽,創(chuàng)建一個(gè)所謂的上下文,用于組件之間傳遞信息眶拉。例如千埃,一個(gè)組件可以計(jì)算訓(xùn)練數(shù)據(jù)的特征向量,將其儲(chǔ)存在上下文中忆植,并且可以從上下文中檢索那些特征向量并進(jìn)行意圖分類放可。一旦所有組件創(chuàng)建,訓(xùn)練和持久化完成朝刊,就會(huì)創(chuàng)建描述整個(gè)nlu模型的模型元數(shù)據(jù)耀里。

介紹自定義組件

使用預(yù)構(gòu)建的rasa nlu組件,你可以自由的定制模型坞古。但是在有些情況下备韧,你想要添加的組件并沒(méi)有在rasa nlu中預(yù)先實(shí)現(xiàn)劫樟。例如痪枫,你可能想添加情感分析讓你的助手根據(jù)用戶的心情產(chǎn)生不同的響應(yīng),或者是希望添加一個(gè)拼寫檢查器來(lái)糾正用戶信息拼寫錯(cuò)誤叠艳,然后對(duì)意圖進(jìn)行分類并提取實(shí)體并用于API調(diào)用或數(shù)據(jù)庫(kù)查找奶陈。向nlu管道添加自定義組件是使用必需的方法實(shí)現(xiàn)自定義組件類,并在Rasa NLU管道配置文件中引用它的過(guò)程附较。通常吃粒,您可能要使用兩種類型的自定義組件:

  • 已經(jīng)預(yù)訓(xùn)練模型的組件(例如:在不同的數(shù)據(jù)集或包上訓(xùn)練,如 python libraries, .pkl files, etc)

  • 在你的rasa nlu數(shù)據(jù)上訓(xùn)練的組件拒课,并在你更改訓(xùn)練示例或添加更多訓(xùn)練示例時(shí)得到改進(jìn)

在這篇文章的下一步徐勃,你將學(xué)習(xí)如何在實(shí)踐中實(shí)現(xiàn)這兩種情況。

添加自定義的情感分析組件到rasa nlu

我們拿一個(gè)情感分析的實(shí)際例子添加到rasa nlu管道中早像。首先僻肖, 你應(yīng)該學(xué)習(xí)如何去設(shè)計(jì)它,當(dāng)你添加更多的訓(xùn)練數(shù)據(jù)時(shí)提高你組件的性能卢鹦。因?yàn)榍楦蟹治鍪怯斜O(jiān)督的分類問(wèn)題臀脏,這意味著對(duì)于這個(gè)特例,你將必須在nlu訓(xùn)練數(shù)據(jù)中分配更多的標(biāo)簽—情感的性質(zhì)(積極冀自,消極揉稚,中性)。其中一個(gè)方法是將這些新的標(biāo)簽儲(chǔ)存在一個(gè)單獨(dú)的文件中熬粗。例如搀玖,你的rasa nlu訓(xùn)練數(shù)據(jù)如下:

intent: feedback

  • It’s very helpful

  • I had the best experience speaking with you

  • no feedback

  • ok

  • You are the most stupid bot I have ever seen

  • the worst

對(duì)應(yīng)的標(biāo)簽如下:
pos
pos
neu
neu
neg
neg

接下來(lái),這都是關(guān)于構(gòu)建實(shí)際組件的驻呐。我們開(kāi)始如何來(lái)實(shí)現(xiàn)灌诅!

建立自定義情感分析組件類

自定義組件類將定義如何訓(xùn)練組件葛超,哪些詳細(xì)信息作為輸入,以及成哪些詳細(xì)信息作為輸出延塑。定義組件绣张,創(chuàng)建一個(gè)新的文件(如:sentiment.py),并且開(kāi)始設(shè)置你自定義組件類的名字以及描述該組件的細(xì)節(jié)如下:

  • name: 組件命名

  • provides: 自定義組件產(chǎn)生哪些輸出

  • require: 該組件需要消息的哪些屬性

  • defaults: 一個(gè)組件的默認(rèn)配置參數(shù)

  • language_list:與組件兼容的語(yǔ)言列表

在下面的例子中,自定義組件類命名為 SentimentAnalyzer 关带,組件的真實(shí)名字為 sentiment侥涵。為了對(duì)話管理模型訪問(wèn)該組件的細(xì)節(jié),并使它能基于用戶情緒驅(qū)動(dòng)對(duì)話宋雏,情感分析的結(jié)果將作為實(shí)體進(jìn)行保留芜飘。處于這個(gè)原因,情感分析的組件配置包括組件提供的entities磨总。因?yàn)榍楦心P徒邮茏址鳛檩斎豚旅鳎赃@些細(xì)節(jié)可以從其他負(fù)責(zé)符號(hào)化的管道組件獲取。這就是為什么下面的組件配置聲明自定義組件需要的tokens蚪燕。最后娶牌,因?yàn)檫@個(gè)例子包含情感分析模型僅僅在英文運(yùn)行,語(yǔ)言列表中包括en馆纳。

定義好之后诗良,你可以繼續(xù)實(shí)現(xiàn)這個(gè)類的主要方法:

  • _init_: 組件初始化

  • train: 該方法負(fù)責(zé)訓(xùn)練組件

  • process: 該方法分析傳入的用戶信息

  • persist: 該方法保存訓(xùn)練后的組件到磁盤上供以后使用

下面的代碼顯示了對(duì)這個(gè)特定例子的方法的實(shí)現(xiàn)。讓我們逐步介紹鲁驶。

  • _init_:方法使用組件的配置初始化自定義組件類鉴裹,在管道配置文件中引用自定義組件時(shí)定義。

  • train():前面的組件產(chǎn)生分詞作為輸入钥弯,訓(xùn)練數(shù)據(jù)径荔,由加載情緒標(biāo)簽和格式化數(shù)據(jù),形成一個(gè)情感分類脆霎。

  • process():該函數(shù)用于將新用戶消息的分詞和情感分析模型預(yù)測(cè)作為實(shí)體消息類总处。

  • persist():方法訓(xùn)練情感模型保存為 .pkl文件,供以后使用绪穆。

  • load() :方法定義如何加載持久化的情感模型辨泳。

from rasa.nlu.components import Component
from rasa.nlu import utils
from rasa.nlu.model import Metadata

import nltk
from nltk.classify import NaiveBayesClassifier
import os

import typing
from typing import Any, Optional, Text, Dict

SENTIMENT_MODEL_FILE_NAME = "sentiment_classifier.pkl"


class SentimentAnalyzer(Component):
    """A custom sentiment analysis component"""
    name = "sentiment"
    provides = ["entities"]
    requires = ["tokens"]
    defaults = {}
    language_list = ["en"]
    print('initialised the class')

    def __init__(self, component_config=None):
        super(SentimentAnalyzer, self).__init__(component_config)

    def train(self, training_data, cfg, **kwargs):
        """Load the sentiment polarity labels from the text
           file, retrieve training tokens and after formatting
           data train the classifier."""

        with open('labels.txt', 'r') as f:
            labels = f.read().splitlines()

        training_data = training_data.training_examples  # list of Message objects
        tokens = [list(map(lambda x: x.text, t.get('tokens'))) for t in training_data]
        processed_tokens = [self.preprocessing(t) for t in tokens]
        labeled_data = [(t, x) for t, x in zip(processed_tokens, labels)]
        self.clf = NaiveBayesClassifier.train(labeled_data)

    def convert_to_rasa(self, value, confidence):
        """Convert model output into the Rasa NLU compatible output format."""

        entity = {"value": value,
                  "confidence": confidence,
                  "entity": "sentiment",
                  "extractor": "sentiment_extractor"}

        return entity

    def preprocessing(self, tokens):
        """Create bag-of-words representation of the training examples."""

        return ({word: True for word in tokens})

    def process(self, message, **kwargs):
        """Retrieve the tokens of the new message, pass it to the classifier
            and append prediction results to the message class."""

        if not self.clf:
            # component is either not trained or didn't
            # receive enough training data
            entity = None
        else:
            tokens = [t.text for t in message.get("tokens")]
            tb = self.preprocessing(tokens)
            pred = self.clf.prob_classify(tb)

            sentiment = pred.max()
            confidence = pred.prob(sentiment)

            entity = self.convert_to_rasa(sentiment, confidence)

            message.set("entities", [entity], add_to_output=True)

    def persist(self, file_name, model_dir):
        """Persist this model into the passed directory."""
        classifier_file = os.path.join(model_dir, SENTIMENT_MODEL_FILE_NAME)
        utils.json_pickle(classifier_file, self)
        return {"classifier_file": SENTIMENT_MODEL_FILE_NAME}

    @classmethod
    def load(cls,
             meta: Dict[Text, Any],
             model_dir=None,
             model_metadata=None,
             cached_component=None,
             **kwargs):
        file_name = meta.get("classifier_file")
        classifier_file = os.path.join(model_dir, file_name)
        return utils.json_unpickle(classifier_file)

就是這樣! 您剛剛實(shí)現(xiàn)了一個(gè)自定義組件,它解析傳入的用戶消息玖院,并將情感作為一個(gè)名為“sentiment”的實(shí)體返回菠红。要使用這個(gè)組件,請(qǐng)確保在Rasa NLU管道配置文件中引用它难菌。你引用自定義組件试溯,可以像引用python模塊一樣引用它 —module_name.class_name。由于此自定義組件需要tokens郊酒,所以應(yīng)該將其添加到生成tokens的組件之后遇绞。下面的示例管道配置意味著键袱,將在SpacyTokenizer之后調(diào)用sentiment組件的方法。

pipeline:

- name: "SpacyNLP"

- name: "SpacyTokenizer"

- name: "sentiment.SentimentAnalyzer"

- name: "SpacyFeaturizer"

- name: "RegexFeaturizer"

- name: "CRFEntityExtractor"

- name: "EntitySynonymMapper"

-  name: "SklearnIntentClassifier" 

在使用定制的情感分析組件訓(xùn)練Rasa NLU模型之后摹闽,您可以測(cè)試如何去執(zhí)行它!

注意: 要確保Rasa獲取您的組件蹄咖,確保將項(xiàng)目目錄添加到PYTHONPATH中。要做到這一點(diǎn)付鹿,你可以運(yùn)行:

export PYTHONPATH=/path_to_your_project_dir/:$PYTHONPATH

下面是一個(gè)帶有自定義情感分析組件的Rasa NLU模型的示例澜汤,當(dāng)助手被一個(gè)相當(dāng)不禮貌的用戶打招呼時(shí),輸出是什么樣的:

 {  
  'intent':{
  'name':'greet',
  'confidence':0.44503513568867775
  },
  'entities':[
  {
  'value':'neg',
  'confidence':0.9933702940854111,
  'entity':'sentiment',
  'extractor':'sentiment_extractor'
  }
  ],
  'intent_ranking':[
  {
  'name':'greet',
  'confidence':0.44503513568867775
  },
  {
  'name':'chitchat',
  'confidence':0.20129539551108508
  },
  {
  'name':'inform',
  'confidence':0.09576408290307896
  },
  {
  'name':'goodbye',
  'confidence':0.08987117551991658
  },
  {
  'name':'decline',
  'confidence':0.08840002616908385
  },
  {
  'name':'affirm',
  'confidence':0.04842063587016189
  },
  {
  'name':'restaurant',
  'confidence':0.03121354833799584
  }
  ],
  'text':'Hello stupid bot'
 }

如果我想使用一個(gè)預(yù)先訓(xùn)練好的情緒分析模型呢?

上面的自定義組件示例包括一個(gè)相當(dāng)簡(jiǎn)單的sentiment模型舵匾,當(dāng)您添加更多的NLU訓(xùn)練示例時(shí)俊抵,它將得到改進(jìn)。如果你更喜歡使用預(yù)先訓(xùn)練過(guò)的模型坐梯,自定義組件類的實(shí)現(xiàn)會(huì)非常相似徽诲,除了一些細(xì)節(jié):

  • 您不必實(shí)現(xiàn)train()和persist()方法類,因?yàn)槟慕M件已經(jīng)經(jīng)過(guò)了訓(xùn)練和持久化(可能作為python模塊或持久化模型)吵血。

  • 您可以在process()方法中更改傳遞給模型的細(xì)節(jié)谎替。例子: 你的預(yù)先訓(xùn)練情感模型將未經(jīng)處理的文本消息作為輸入,而不是tokens践瓷。

為了說(shuō)明這種情況院喜,讓我們修改之前實(shí)現(xiàn)的自定義組件的代碼亡蓉,代替訓(xùn)練自定義的情感模型晕翠,我們使用一個(gè)由NLTK自然語(yǔ)言工具包提供的預(yù)訓(xùn)練的情感分析器模型:

from rasa.nlu.components import Component
from rasa.nlu import utils
from rasa.nlu.model import Metadata

import nltk
from nltk.sentiment.vader import SentimentIntensityAnalyzer
import os

class SentimentAnalyzer(Component):
    """A pre-trained sentiment component"""

    name = "sentiment"
    provides = ["entities"]
    requires = []
    defaults = {}
    language_list = ["en"]

    def __init__(self, component_config=None):
        super(SentimentAnalyzer, self).__init__(component_config)

    def train(self, training_data, cfg, **kwargs):
        """Not needed, because the the model is pretrained"""
        pass

    def convert_to_rasa(self, value, confidence):
        """Convert model output into the Rasa NLU compatible output format."""

        entity = {"value": value,
                  "confidence": confidence,
                  "entity": "sentiment",
                  "extractor": "sentiment_extractor"}

        return entity

    def process(self, message, **kwargs):
        """Retrieve the text message, pass it to the classifier
            and append the prediction results to the message class."""

        sid = SentimentIntensityAnalyzer()
        res = sid.polarity_scores(message.text)
        key, value = max(res.items(), key=lambda x: x[1])

        entity = self.convert_to_rasa(key, value)

        message.set("entities", [entity], add_to_output=True)

    def persist(self, model_dir):
        """Pass because a pre-trained model is already persisted"""

        pass

在這種情況下,train()和persist()方法都是pass砍濒,因?yàn)槟P鸵呀?jīng)被預(yù)先訓(xùn)練并持久化為NLTK方法淋肾。另外,由于模型將未處理的文本作為輸入爸邢,所以process()方法檢索實(shí)際的消息并將它們傳遞給模型樊卓,由模型執(zhí)行所有處理工作并進(jìn)行預(yù)測(cè)。

總結(jié)

本教程中杠河,學(xué)習(xí)了如何創(chuàng)建自定義組件并將其添加到 Rasa NLU pipeline 中碌尔,你可以添加任意自定義組件,但重要的是要了解它們?nèi)绾闻c其他處理組件配合使用券敌,以及它們應(yīng)該產(chǎn)生什么輸出唾戚,將某些內(nèi)容傳遞給 pipeline 中的其他組件或者向模型的輸出添加某些內(nèi)容。

有用的資源

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末待诅,一起剝皮案震驚了整個(gè)濱河市叹坦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌卑雁,老刑警劉巖募书,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绪囱,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡莹捡,警方通過(guò)查閱死者的電腦和手機(jī)鬼吵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)篮赢,“玉大人而柑,你說(shuō)我怎么就攤上這事『沙眩” “怎么了媒咳?”我有些...
    開(kāi)封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)种远。 經(jīng)常有香客問(wèn)我涩澡,道長(zhǎng),這世上最難降的妖魔是什么坠敷? 我笑而不...
    開(kāi)封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任妙同,我火速辦了婚禮,結(jié)果婚禮上膝迎,老公的妹妹穿的比我還像新娘粥帚。我一直安慰自己,他們只是感情好限次,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布芒涡。 她就那樣靜靜地躺著,像睡著了一般卖漫。 火紅的嫁衣襯著肌膚如雪费尽。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天羊始,我揣著相機(jī)與錄音旱幼,去河邊找鬼。 笑死突委,一個(gè)胖子當(dāng)著我的面吹牛柏卤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匀油,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼缘缚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了钧唐?” 一聲冷哼從身側(cè)響起忙灼,我...
    開(kāi)封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后该园,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酸舍,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年里初,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了啃勉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡双妨,死狀恐怖淮阐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情刁品,我是刑警寧澤泣特,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站挑随,受9級(jí)特大地震影響状您,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜兜挨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一膏孟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拌汇,春花似錦柒桑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至傅联,卻和暖如春先改,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蒸走。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留貌嫡,地道東北人比驻。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像岛抄,于是被迫代替她去往敵國(guó)和親别惦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355