轉自:http://rowl1ng.com/%E6%8A%80%E6%9C%AF/chatbot.html
重要資料
chatbot三步走:nlu model->dialogue policy->agent
- 本項目的github地址:Rasa_wechat
- 視頻講解(正文+編程+QA):bilibili
- Rasa_NLU官方文檔
- Rasa_Core官方文檔
- wxpy文檔
- 關於機器學習的數學基礎和理論介紹,我整理在機器學習Gitbook
研究背景
- 老式chatbot基於大量規則庫,不好維護。ps: 一個比較有意思例子是僞春菜。
- 主流架構爲”NLU自然語言理解+DM對話管理+NLG自然語言生成”,也就是上圖展示的除ASR和TTS的部分。
- NLU負責基礎自然語言處理,主要目標是意圖識別與實體識別;
- DM負責對話狀態維護、數據庫查詢等;
- NLG負責生成交互的自然語言。
- 機器學習尤其是深度學習在不斷改進NLU、DM和NLG,乃至顛覆整個架構:
- 每一個模塊都換成DL模型,甚至再加入User Simulator做強化學習,進行端到端的訓練;
- Memory Networks:將整個知識庫都encode在一個複雜的深度網絡中,然後再和encode過的問題結合起來decode生成答案,可參考Siraj Raval的視頻。這個工作最多還是應用在機器閱讀理解上,在垂直領域任務導向的chatbot上的成功應用還有待觀察。
步入正題
現在的chatbot一種是純聊天(比如小黃雞),一種是針對特定商業應用(比如智能客服),這裏介紹的其實更偏向後一種。
我們這裏要用的Rasa_NLU以及後面介紹的Rasa_Core是rasa.ai提供的開源工具,支持Python 2和3,可以本地部署,自己針對實際需求訓練和調整模型,在商業chatbot設計上有頗多考量。此外,我們加上了微信的python接口wxpy
來實現微信端的交互,其流程圖如下:
(圖片來自Rasa_Core官網)
最上面的Rasa_NLU
就是最開始講到的負責自然語言理解的部分,而最下面的Rasa_Core
則是在得到了intent
和entities
之後負責生成next_action
以及自然語言的回覆。最左邊的一問一答則由wxpy
來完成監聽消息和發送消息的任務。
用僞代碼表示的話:
#輸入
input_string=""
#意圖識別
intent_object=intent(input_string)
#回覆生成
response=policy(intent_object)
#返回用戶
print(response)
把大象塞進冰箱的第一步是?
打開冰箱門。先不要着急,首先你得明確想做一個什麼樣的機器人。比如我想做一個”你媽喊你回家吃飯
“,就是當我說”我餓了”,機器人能像我媽一樣問我想吃啥,或者叮囑我早睡早起少吃麻辣燙。
mkdir mom && cd mom
現在我們需要兩種材料,分別對應NLU和對話管理模塊:
- 訓練數據:nlu examples + dialogue stories
- 配置文件:nlu config + dialogue domain
mom/
├── data/
│ ├── stories.md # dialogue training data
│ └── nlu.md # nlu training data
├── domain.yml # dialogue configuration
└── nlu_model_config.json # nlu configuration
下面先來介紹NLU的部分。
自然語言理解:Rasa NLU
針對用戶的問題,NLU模塊的任務是:
- 意圖識別 (Intent):在句子級別進行分類,明確意圖;
- 實體識別 (Entity):在詞級別找出用戶問題中的關鍵實體,進行實體槽填充(Slot Filling)。
舉個例子,當我說“我想吃羊肉泡饃”,NLU模塊就可以識別出用戶的意圖是“尋找餐館”,而關鍵實體是“羊肉泡饃”。有了意圖和關鍵實體,就方便了後面對話管理模塊進行後端數據庫的查詢或是有缺失信息而來繼續多輪對話補全其它缺失的實體槽。
已有的NLU工具,大多是以服務的方式,通過調用遠程http的restful API來對目標語句進行解析完成上述兩個任務,例如Google的API.ai, Microsoft的Luis.ai, Facebook的Wit.ai等。
事實上,申請到這類API的話用幾行代碼即可完成一個chatbot,亦可參考使用圖靈機器人和api.ai相關接口。如果想從零開始動手實現NLU,推薦閱讀Do-it-yourself NLP for bot developers。
遺憾的是,Rasa_NLU官方現在支持任何語言啦!這裏暫時參考基於中文的Rasa NLU來訓練自己的中文NLU模型,不過仍然建議認真閱讀Rasa_NLU官方文檔。
中文Rasa NLU的安裝:
$ git clone https://github.com/crownpku/rasa_nlu_chi.git
$ cd rasa_nlu_chi
$ python setup.py install
語料獲取和預處理
爲了增大覆蓋面,我們往往需要收集大量的詞彙,比如維基百科和百度百科,同時結合自己的應用場景選擇特定領域的語料(比如我爲了測試加上了百度文庫裏的中國移動常見問題)。下載並處理中文維基語料的過程參考用Rasa NLU構建自己的中文NLU系統這篇博文。
在獲得並處理好語料以後,中文特色是先進行分詞:
# 安裝jieba分詞
$ pip install jieba
# 將一個語料文件分詞,以空格爲分隔符
$ python -m jieba -d " " ./test > ./test_cut
把所有分好詞的語料文件放在同一個文件路徑下,接下來訓練MITIE模型。
訓練詞表示模型:MITIE的wordprep
經小夥伴提醒:這個MITIE庫據說以後不對外支持了,可以採用了spacy庫來替代它進行意圖識別和實體提取~
MITIE(MIT Information Extraction)是MIT的 NLP 團隊發佈的一個信息抽取庫和工具。目前包含:
- 命名實體抽取(Named-Entity-Recognize,NER)
- 二元關係檢測功能(Bianry relation detection)
另外也提供了訓練自定義抽取器和關係檢測器的工具。它的主要工作在於:
- distributional word embeddings:簡單說來就是將每個詞映射到向量空間,向量之間的距離代表詞之間的相似度,且在語義、語法兩種意義上。關於詞向量最新的研究可以看Learned in translation: contextualized word vectors;
- Structural Support Vector Machines
儘管 MITIE 是 C++ 寫的,但它也提供了其他語言的調用 API 。先編譯成動態庫再用 Python 調用即可:
conda install libgcc
sudo apt-get install g++
pip install git+https://github.com/mit-nlp/MITIE.git
或者
MITIE\mitielib>mkdir build
MITIE\mitielib>cd build
MITIE\mitielib\build>cmake ..
MITIE\mitielib\build>cmake --build . --config Release --target install
當使用python調用時,如果報錯說找不到mitie這個python包,可以手動把mitie的路徑加到系統路徑中:
import os
parent = os.path.dirname(os.path.realpath(__file__))
sys.path.append('../../MITIE/mitielib')
我們使用wordprep工具來訓練所有詞向量特徵,後面的命名實體模型和關係模型都是建立在它的基礎上,使用 cmake
構建一下就可直接使用:
\MITIE\tools\wordrep>mkdir build
\MITIE\tools\wordrep>cd build
\MITIE\tools\wordrep\build>cmake ..
\MITIE\tools\wordrep\build>cmake --build . --config Release
之後訓練模型得到total_word_feature_extractor.dat
:
$ ./wordrep -e /path/to/your/folder_of_cutted_text_files
這個過程很漫長,也很佔內存,建議在服務器上用nohup
跑。項目文件中包含我基於中文維基和中國移動常見問題訓練好的total_word_feature_extractor.dat
。
訓練NLU模型:rasa_nlu.train
首先需要構建示例,作爲意圖識別和實體識別的訓練數據:mom/data/nlu.json
。舉個例子:
{
"text": "這附近哪裏有吃麻辣燙的地方",
"intent": "restaurant_search",
"entities": [
{
"start": 7,
"end": 10,
"value": "麻辣燙",
"entity": "food"
}
]
}
text
(required):待處理的句子示例。intent
(optional):這個句子應該關聯的意圖。entities
(optional) :start
和end
共同定義實體範圍,在上面的例子中,"text": "這附近哪裏有吃麻辣燙的地方"
, 那麼text[7:10] == '麻辣燙'
。實體還可以擴展到多個詞, 而且value
不一定要是你句子中的詞,這樣一來,就能將同義詞、誤拼映射到同一個值上,比如下面這個例子:
[
{
"text": "in the center of NYC",
"intent": "search",
"entities": [
{
"start": 17,
"end": 20,
"value": "New York City",
"entity": "city"
}
]
},
{
"text": "in the centre of New York City",
"intent": "search",
"entities": [
{
"start": 17,
"end": 30,
"value": "New York City",
"entity": "city"
}
]
}
]
如果嫌手動輸入太麻煩,可以使用 rasa-nlu-trainer進行可視化編輯:
$ npm i -g rasa-nlu-trainer
$ rasa-nlu-trainer -s 示例文件路徑
此外,rasa也支持markdown格式的訓練語料,比如:
## intent:greeting
- hey
- hello
- moin
## intent:goodbye
- bye
- goodbye
- see you later
## intent:mood_affirm
- yes
- indeed
- correct
## intent:mood_deny
- no
- never
- no way
## intent:mood_great
- wonderful
- I am amazing
- I am going to save the world
## intent:mood_unhappy
- my day was horrible
- I am sad
有了示例數據,我們還需要mom/nlu_model_config.json
來配置流水線(pipeline)。這裏考慮中文支持,配置的Rasa NLU的工作流水線如下:
# MITIE+Jieba+sklearn:
[“nlp_mitie”, “tokenizer_jieba”, “ner_mitie”, “ner_synonyms”, “intent_featurizer_mitie”, “intent_classifier_sklearn”]
nlp_mitie
:初始化MITIE,所有mitie組件都依賴於它;tokenizer_jieba
:用jieba來做分詞;ner_mitie
:MITIE的命名實體識別;ner_synonyms
:如果在示例中通過value
屬性定義了同義詞,就將這些value映射到相同value上intent_featurizer_mitie
:提取意圖的特徵,作爲意圖分類器intent_classifier_sklearn
的輸入;intent_classifier_sklearn
:使用sklearn做意圖分類。
更多pipeline內容詳見官方文檔pipeline介紹。 根據config訓練NLU模型:
$ python -m rasa_nlu.train -c mom/nlu_model_config.json
更方便的做法是python調用:
# train_nlu.py :train NLU model
from rasa_nlu.converters import load_data
from rasa_nlu.config import RasaNLUConfig
from rasa_nlu.model import Trainer
# 訓練模型
def train():
# 示例數據
training_data = load_data('data/examples/rasa/demo-rasa_zh.json')
# pipeline配置
trainer = Trainer(RasaNLUConfig("sample_configs/config_jieba_mitie_sklearn.json"))
trainer.train(training_data)
model_directory = trainer.persist('./projects/default/') # 返回nlu模型的儲存位置;如果config文件中沒有project_name,模型會存儲在默認的 /models/default 文件夾下
# 識別意圖
def predict(model_directory):
from rasa_nlu.model import Metadata, Interpreter
# 用nlu模型初始化interpreter; `model_directory`爲nlu模型位置
interpreter = Interpreter.load(model_directory, RasaNLUConfig("sample_configs/config_jieba_mitie_sklearn.json"))
# 使用加載的interpreter處理文本
print (interpreter.parse(u"我想吃麻辣燙"))
train
完成後就會得到一個類似model_20171013-153447
的文件存在 /models/your_project_name
文件夾裏。項目文件中提供訓練好的NLU模型:/rasa_nlu_chi/models/rasa_nlu_test/model_20171013-153447
。使用的話注意改一下model目錄下metadata.json
的mitie_file
路徑。
測試效果除了使用python來predict(model_directory)
,還可以啓動rasa_nlu的HTTP服務:
$ curl -XPOST localhost:5000/parse -d '{"q":"我發燒了該吃什麼藥?", "project": "rasa_nlu_test", "model": "model_20170921-170911"}' | python -mjson.tool
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 652 0 552 100 100 157 28 0:00:03 0:00:03 --:--:-- 157
{
"entities": [
{
"end": 3,
"entity": "disease",
"extractor": "ner_mitie",
"start": 1,
"value": "發燒"
}
],
"intent": {
"confidence": 0.5397186422631861,
"name": "medical"
},
"intent_ranking": [
{
"confidence": 0.5397186422631861,
"name": "medical"
},
{
"confidence": 0.16206323981749196,
"name": "restaurant_search"
},
{
"confidence": 0.1212448457737397,
"name": "affirm"
},
{
"confidence": 0.10333600028547868,
"name": "goodbye"
},
{
"confidence": 0.07363727186010374,
"name": "greet"
}
],
"text": "我發燒了該吃什麼藥?"
}
以上返回的內容結合了流水線中各個組件的結果,我們可以根據自己的需求設計流水線以及利用返回結果。
現在回到我們的chatbot目錄,來講剩下的dialogue部分的domain.yml
和stories.md
:
mom/
├── data/
│ ├── stories.md # dialogue training data
│ └── nlu.md # nlu training data
├── domain.yml # dialogue configuration
└── nlu_model_config.json # nlu configuration
對話管理:Rasa Core
Rasa Core是一個用來搭建對話系統的框架,具體可查看Rasa Core官方文檔(似乎要科學上網才能訪問)。它的具體工作流程如下:
- 外面來的信息首先經由interpreter轉成text、intent、entities
- tracker負責記錄對話狀態,接收interpreter的結果
- policy收到當前狀態信息
- policy選擇下一步action
- 所選擇的action被tracker記錄
- 輸出回覆
安裝
git clone https://github.com/RasaHQ/rasa_core.git
cd rasa_core
pip install -r requirements.txt
python setup.py install
推薦國內用戶從國內鏡像(比如豆瓣 PYPI 鏡像源https://pypi.doubanio.com/simple/
)下載安裝,否則pip install -r requirements.txt
可能會各種連接失敗。
更改pip源速度快了好多~
運行helloworld示例來檢驗是否正常安裝成功:
python examples/hello_world/run.py
Bot loaded. Type hello and press enter :
hello
hey there!
定義意圖和動作:domain.yml
Rasa基於intents
、entities
和當前對話的內部狀態,從actions
中選擇下一步採取的行動。比如機器人選擇utter_greet
的話,就會從templates
中找出相應的句子作爲回覆(可以填充變量)。而這些都需要我們在domain.yml中預先定義好。
ActionListen
是一個特殊的action,意味着等待用戶,直到說別的內容。當然你還可以定義你自己的action,作爲python類來調用。
舉個例子:
#創建文件common_domain.yml,複製如下代碼
intents:#定義意圖
- greet
- goodbye
- chat
entities:
- action
templates:#表示對於相應的意圖採取什麼樣的回覆
utter_greet:
- "hello!"
utter_goodbye:
- "byebye :("
utter_chat:
- "It seems like funny!"
actions:#定義bot可以採取的動作
- utter_greet
- utter_goodbye
- utter_chat
intents
:NLU模型識別的意圖;entities
:NLU模型識別的實體;actions
:機器人說和做的內容,比如問候對方、調用某個API、查詢數據庫等;slots
:用來跟蹤上下文和多輪對話的關鍵信息,具體參考slot types;templates
:說話模板。
定義解釋器(interpreter):
interpreter用來處理消息,包括執行NLU和把消息轉爲格式化信息。其實就是上一個part所講的訓練NLU model的過程。這裏假定我們已經有了NLU model。
訓練你的對話模型
我們通過domain.yml
定義好了action
、教會了小寶寶牙牙學語(各種模板),還要告訴ta什麼時候說什麼話(基於會話歷史訓練概率模型,來預測需要採取的action
)。有兩種”教學方法”(訓練方式):
- 念故事書:如果你有標記好的對話數據,可以直接做有監督學習(supervised learning);
- 面對面聊天::但大多數人沒有監督學習條件,此時推薦從無到有的交互式學習(interactive learning)。在交互學習模式下,你的chatbot每做出一個決策,你都要即時給出反饋,這有點強化學習的意思,但強化學習是在對話結束後給反饋。
第二種交互式學習中,當你的chatbot答錯時,你需要示範給它正確答案,此時模型會立即自我更新,這樣就很難“重蹈覆轍”了。當你結束交互訓練時,對話數據會被記錄並添加到你的訓練數據中。這裏主要介紹第一種,我們將故事寫在stories.md
中:
## happy path <!-- 故事名 - just for debugging -->
* _greet
- utter_greet
* _mood_great <!-- user utterance, in format _intent[entities] -->
- utter_happy
## sad path 1 <!-- this is already the start of the next story -->
* _greet
- utter_greet <!-- action of the bot to execute -->
* _mood_unhappy
- utter_cheer_up
- utter_did_that_help
* _mood_affirm
- utter_happy
## sad path 2
* _greet
- utter_greet
* _mood_unhappy
- utter_cheer_up
- utter_did_that_help
* _mood_deny
- utter_goodbye
## say goodbye
* _goodbye
- utter_goodbye
Wizard-of-Oz(WOz):自己(wizard)扮演chatbot,wizard能通過搜索接口訪問數據庫,接收用戶的輸入並決定下一步說什麼。WOz收集到的對話數據可用於對話系統各個組件的研究,從NLU到NLG,或者不同領域端到端的對話系統,從而降低爲每個領域人工設計新系統的成本。
關於故事格式可以參考官方文檔的stories部分。
使用Python APIAgent
我們可以方便地訓練、加載、使用模型:
# script/train_dm.py
from rasa_core.agent import Agent
from rasa_core.policies.memoization import MemoizationPolicy
# 訓練policy模型
def train_mom_dm():
agent = Agent("../mom/domain.yml",
policies=[MemoizationPolicy()])
agent.train(
training_data_file,
max_history=3,
epochs=100,
batch_size=50,
augmentation_factor=50,
validation_split=0.2
)
agent.persist(model_path)
看到這裏想必你已經非常疲憊了吧,來看個漫畫輕鬆一下:
這是《Understanding Comics》裏解釋漫畫原理的一頁,這裏借它來說明訓練 policy模型的原理,先掃一眼訓練模型的代碼:
class MomPolicy(KerasPolicy):
def _build_model(self, num_features, num_actions, max_history_len):
"""Build a keras model and return a compiled model.
:param max_history_len: The maximum number of historical turns used to
decide on next action"""
from keras.layers import LSTM, Activation, Masking, Dense
from keras.models import Sequential
n_hidden = 32 # size of hidden layer in LSTM
# Build Model
batch_shape = (None, max_history_len, num_features)
model = Sequential()
model.add(Masking(-1, batch_input_shape=batch_shape))
model.add(LSTM(n_hidden, batch_input_shape=batch_shape))
model.add(Dense(input_dim=n_hidden, output_dim=num_actions))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
logger.debug(model.summary())
return model
這裏的LSTM其實就是處理漫畫這樣的sequence數據的關鍵道具,想象一下,我們的對話模型每句話說完就是一幀圖像(當前對話狀態),這樣一幀一幀輸入到LSTM中就是對每個時刻的對話狀態進行學習,最終的目標是訓練出policy,這樣下次再看到“睜眼”,就能猜到下一秒應該是“閉眼”了。
現在我們有了NLU模型和policy模型,只需要再加上微信接口,即輸入
和返回用戶
的過程。
微信後臺
python操作微信號:wxpy
wxpy可用來實現各種微信個人號的自動化操作。具體的使用參見wxpy文檔,應用實例可參考connector-wechat-bot。這裏其實只用了收發消息的接口,“智能”的部分交由後文的Rasa_Core完成。
from wxpy import *
# 初始化機器人,掃碼登陸
bot = Bot(console_qr=True, cache_path=True)
由於代碼部署在服務器上,不能通過終端打開圖片,參數console_qr=True
表示在終端內顯示二維碼;cache_path=True
啓用緩存,來保存自己的登錄狀態。
自己加自己好友方便以後做測試:
# 在 Web 微信中把自己加爲好友
bot.self.add()
bot.self.accept()
# 發送消息給自己
bot.self.send('能收到嗎?')
wxpy提供了註冊消息的方法,可以將各種類型的消息註冊並自定義處理方式。我們就是利用它來監聽任何發送給自己的消息:
from rasa_core.agent import Agent
from rasa_core.interpreter import RasaNLUInterpreter
@bot.register(bot.self, except_self=False)
def reply_self(msg):
ans = agent.handle_message(msg.text)
# 自己訓練好的NLU模型路徑
nlu_model_path = '/home/luoling/rasa_nlu_chi/models/rasa_nlu_test/model_20171013-153447'
# agent = 自己訓練好的policy模型 + NLU模型作爲interpreter
agent = Agent.load("../babi/models/policy/current", interpreter=RasaNLUInterpreter(nlu_model_path))
重頭戲分別是負責語言理解的nlu_model
和負責對話管理的agent
,將在下面兩部分展開介紹。
最後別忘了讓程序保持運行:
# 進入 Python 命令行、讓程序保持運行
embed()
python搭建微信公衆號後臺
目前還在測試階段,大部分時間無法正常使用,抱歉~
我參考微信公衆號搭chatbot加上了公衆號的支持,使用的原材料如下:
- 內存足夠(tensorflow跑起來佔400M左右)的VPS(我選的bandwagon 20G那個,一年$49.9,有更便宜的請務必告訴我)
- 微信訂閱號
最後的效果歡迎關注公衆號測試:
整體來看
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import logging
import numpy as np
from rasa_core import utils
from rasa_core.actions.action import ACTION_LISTEN_NAME
from rasa_core.agent import Agent
from rasa_core.channels.console import ConsoleInputChannel
from rasa_core.domain import TemplateDomain
from rasa_core.interpreter import NaturalLanguageInterpreter
from rasa_core.policies import Policy
from rasa_core.tracker_store import InMemoryTrackerStore
logger = logging.getLogger(__name__)
class CommonPolicy(Policy):
def predict_action_probabilities(self, tracker, domain):
# type: (DialogueStateTracker, Domain) -> List[float]
#將對應的意圖與動作綁定
responses = {
"greet": 2,
"goodbye": 3,
"chat": 4,
}
if tracker.latest_action_name == ACTION_LISTEN_NAME:
key = tracker.latest_message.intent["name"]
action = responses[key] if key in responses else 4
return utils.one_hot(action, domain.num_actions)
else:
return np.zeros(domain.num_actions)
class HelloInterpreter(NaturalLanguageInterpreter):
def parse(self, message):
# intent = "greet" if 'hello' in message else "default"
global intent
#進行意圖識別
if 'hello' in message:
intent='greet'
elif 'goodbye' in message:
intent='goodbye'
else:
intent='chat'
return {
"text": message,
"intent": {"name": intent, "confidence": 1.0},
"entities": []
}
def run_hello_world(serve_forever=True):
default_domain = TemplateDomain.load("./common_domain.yml")#加載多個domain怎麼辦
agent = Agent(default_domain,
policies=[CommonPolicy()],
interpreter=HelloInterpreter(),
tracker_store=InMemoryTrackerStore(default_domain))
if serve_forever:
# Attach the commandline input to the controller to handle all
# incoming messages from that channel
agent.handle_channel(ConsoleInputChannel())
return agent
if __name__ == '__main__':
run_hello_world()
Todo List
Future Work
rasa擴展
- 目前對中文entity的處理還有問題(認“salad”但不認“麻辣燙”)
- 實現微信上的交互式訓練,包括向提問人學習如何提問(能主動發起會話);
- 如果能導出微信聊天數據的話就有很多dialogue了。讀取歷史聊天信息作爲訓練數據,充分發揮聊天app的優勢,難點在於非結構數據的結構化;
- 增量式學習,在增加新語料時不用從頭再來;
- 基於google搜索結果和QA模型做chatbot的百事通功能。
微信擴展:
- 表情包推薦功能
- 結合語音判斷情緒,作爲輔助信息
- 個奇怪的問題:機器不會主動來”關心”你,這套體系更偏向商業應用,即解決用戶的問題
- NLG:自然語言生成
- intent定義:現在還是很生硬的人工編輯,有沒有可能自動地從對話中去提煉intent和action
- 目前的conversation representation是binary vector,是否能在語義空間做改進?類似encoder decoder那種
- 對抗式訓練,做兩個chatbot相互交流,不過得有一個objective function。忍不住想到一個世紀難題:把一個健身房教練和理髮店造型師放一間房裏,到底誰會先讓誰辦卡……
Reference
補充:QA系統
QA(Question Answering)即問答系統,目前研究集中在自然語言問答和視覺問答,分別基於給定的文字和圖像回答特定問題。在Chatbot(聊天機器人)和智能客服中應用廣泛。
技術特點在於對問題(Question)和給定內容(Context)進行編碼(encode),並從中解碼(decode)出答案,事實上,相似模型也可應用在基於樣例的語音關鍵詞檢測(Query-by-Example Spoken Term Detection)中,即對搜索內容(Query)和搜索對象(Context)進行編碼,從中解碼出關關鍵詞(Query)出現與否以及關鍵詞的出現位置。