第3章
語言了解智能服務
語言了解智能服務(LUIS)是我和我的團隊廣泛使用的NLU系統,也是對自然語言進行意圖分類和實體抽取的完美工具。開發者可以通過
https://luis.ai通路LUIS,使用微軟賬戶登入之後,網站将首先向開發者展示一個關于如何建立LUIS應用程式的頁面,本章将基于該頁面開始介紹LUIS。點選頁面下方的Create LUIS app(建立LUIS應用)按鈕将會跳轉到LUIS應用頁面,點選Create new app(建立新應用)按鈕并輸入應用的名稱,便會建立一個LUIS應用。在該建立的新應用中,開發者可以通過LUIS的應用程式接口來建立、訓練、測試和釋出模型。
在本章中,我們将建立一個LUIS應用,并用它支援我們建立Calendar Concierge Bot,Calendar Concierge Bot支援增加、編輯、删除約會,管理月曆上的空餘時間。通過本章的實踐,開發者可以了解到LUIS多種多樣的功能。在本章結束時,我們将開發一個既可以內建到機器人中又可以自我不斷訓練改進的LUIS應用。
首先,我們在LUIS中建立一個新LUIS應用CalendarBotModel,當我們在LUIS頁面點選Create new app按鈕時,會出現如圖3-1所示的彈窗,在視窗中填寫應用的名稱和描述域。另外LUIS支援多個國家的多種語言,開發者可以在視窗選項中根據需要選擇相應的語言,不同的語言需要不同的語言模型和不同的優化方法。截至寫作本書時,LUIS支援巴西葡萄牙語、中文、荷蘭語、英語、法語、加拿大法語、德語、意大利語、日語、韓語、西班牙語和墨西哥西班牙語。随着LUIS的不斷成熟,更多的語言将會被LUIS支援。

建立應用後,将進入LUIS中與BUILD相關的内容頁面,如圖3-2所示。可以看到,裡面隻有空的意圖,我們将在訓練意圖時對意圖進行更詳細的介紹。此外,讀者還将看到Review endpoint utterances連結,這是LUIS的主動學習功能,我們将在後續章節中進行探讨。
注意在開始書寫本書時,LUIS應用限定使用500個意圖、30個實體和50個清單實體。而在最初釋出LUIS的時候,其僅支援在一個應用中最多使用10個意圖和10個實體。LUIS所支援的意圖和實體等最新數量可以通過參考連結進行查閱。
頁面的頂部從左到右分别是:開發者開發的應用名稱、目前活動的版本,以及DASHBOARD(儀表闆)、BUILD(建構)、PUBLISH(釋出)和SETTING(設定)。開發者還可以通過點選頁面頂部最右側的按鈕,分别對模型進行訓練和測試。在建構Calendar Concierge Bot應用時,我們将逐一對這些功能進行介紹。
3.1 意圖分類
前一章介紹了意圖分類的概念,本節我們将在開發實踐中深入了解意圖分類。回顧一下,在本章我們打算建立一個LUIS應用程式CalendarBotModel,它能讓我們添加、編輯或删除月曆條目,顯示月曆摘要并檢視我們月曆中可用的空閑時間。我們将建立以下意圖:
- AddCalendarEntry
- RemoveCalendarEntry
- EditCalendarEntry
- ShowCalendarSummary
- CheckAvailability
回到圖3-2頁面的BUILD部分,我們在左側窗格中點選選擇Intents項。可以發現此時隻有一個為None的意圖,當使用者的輸入與任何其他意圖都不比對時就稱為None意圖。在機器人中,我們可以通過使用None意圖來告訴使用者他們詢問的問題超過了機器人所擅長的知識領域并提醒使用者該機器人能實作的功能有哪些。
對意圖進行分類的一般流程是在頁面中建立意圖,然後向LUIS提供一些能表示該意圖的話語執行個體,圖3-3展示了建立意圖的過程。接着,我們可以在相應的文本框中輸入話語執行個體;我們不斷輸入話語執行個體,并不斷點選回車對輸入進行确認。在輸入足夠多的話語執行個體後,點選Save(儲存)按鈕,此時便完成了一個意圖的添加,如圖3-4所示。
LUIS還允許開發者在使用者界面上搜尋、删除某個話語執行個體,以及為話語執行個體重新配置設定意圖,開發者在開發過程中會逐漸摸索到更多的功能。
在建立其餘的意圖之前,我們先對LUIS應用進行檢驗,確定到目前為止LUIS應用可以被訓練和測試。頁面右上方的Train(訓練)按鈕為紅色時,表明LUIS應用已經被編輯修改并且修改之後沒有重新訓練。點選Train按鈕時,重新訓練應用的請求将被發送到LUIS伺服器,開始重新訓練,同時開發者會在頁面上收到應用正在被訓練以及像“0/2 completed”這樣的進度消息。在進度消息中,2表示目前應用包含的需要分類的意圖有兩個。在本章的開發執行個體中,截至目前的開發程度,一個意圖是None,另一個意圖是AddCalendarEntry。訓練完成後,Train按鈕将變為綠色,表示該應用程式此時是最新的。
針對每個話語執行個體,我們還可以檢視剛才訓練的應用對哪個意圖的打分最高,如圖3-5所示。這些得分資料非常重要,因為我們可以從中很容易地看出有時話語被标記在一個意圖上,但應用在對話語的意圖進行分類時,卻将最高分數配置設定給了别的意圖。在訓練集上的運作結果與訓練标簽之間的差異通常表明模型中存在導緻錯誤結果的東西。我們将在3.14節對這個問題和其他類似情況進行探讨。現在,似乎成功訓練完所有的話語,并在AddCalendarEntry意圖上産生結果為1的得分,在None意圖上産生0.05~0.07的得分(如圖3-6所示);這些得分取決于開發者具體輸入的話語執行個體和微軟LUIS開發團隊對LUIS版本的更新。
訓練完意圖之後,我們可以使用Train按鈕旁邊的Test按鈕來測試模型,看一下它對輸入的各種測試話語的運作結果(如圖3-7所示)。Batch testing panel支援批量的運作測試話語,我們在開發本執行個體中依舊使用互動模型(interactive mode)。
LUIS将每個話語輸入到訓練階段所訓練的意圖分類模型中運作,每一個意圖都會得到一個介于0到1之間的打分,得分最高的意圖被突出顯示。注意這一打分并不是該話語屬于該意圖的機率,它依賴于LUIS使用的算法,通常用于表示話語輸入和意圖之間的距離。如果對于一個輸入,LUIS在多個意圖上給出的打分都很接近,則說明我們可能還需要對LUIS應用進行更多的訓練。
在應用訓練結束并經過上面的測試之後,似乎一切順利。事實上,我們可以用幾個奇怪的語句進行測試,發現應用的運作結果并不正确,如圖3-8所示。
這是因為在上面的開發實踐中,我們使用了一些話語執行個體作為訓練資料來對AddCalendarEntry意圖進行訓練,但我們沒有為None意圖提供任何訓練資料,是以我們再為None意圖加一些話語并重新訓練、測試。現在,我們再胡亂地輸入一些沒有意義的測試語句,如圖3-9所示,此時便解決了圖3-8中所示的問題。在開發階段,我們做不到一勞永逸地解決所有的類似問題,這需要讓應用不斷地線上上運作并分析使用者的使用回報。這提醒開發者,使用與應用中的意圖相關的話語來訓練應用和使用不相關的話語來訓練應用同等重要,開發者應該兼顧這兩種資料。
剛才我們已經添加了AddCalendarEntry意圖,接下來我們将添加剩下的意圖。圖3-10、圖3-11、圖3-12和圖3-13分别展示了CheckAvailability意圖、EditCalendarEntry意圖、DeleteCalendarEntry意圖和ShowCalendarSummary意圖的一些話語執行個體。
一旦建立完所有意圖并添加了話語樣本,我們就會訓練應用并在訓練結束後檢查預測的意圖是否準确。另外值得注意的是,對于一個話語樣本而言,盡管得分最高的意圖是該話語正确的意圖分類結果,但這個分值可能很低(如圖3-14所示),這表明我們還需要進一步提升訓練效果。事實上,用如此有限的詞彙和資料集就能徹底訓練好一個意圖是不可能的,對一個意圖達到好的識别效果需要耐心和工程優化思想。在下面的練習中,我們将為應用添加更多話語。
練習3-1
訓練LUIS的意圖
前面的幾個例子展示了将一些話語執行個體輸入到所訓練的意圖中。我們的開發任務是建立一個LUIS應用、為LUIS應用建立符合其功能的一系列意圖以及用足夠的話語樣例來訓練LUIS應用,直到所有意圖的得分都超過0.8為止。
- 建立下列意圖并為每個意圖輸入至少10個話語執行個體:
- 為None意圖添加更多的話語,添加的話語集中在話語内容本身沒有意義或者話語内容對于本應用而言無意義。比如“I like coffee”,這句話本身有意義,但對于LUIS應用的幾個意圖(如AddCalendarEntry)而言沒有意義。
- 訓練LUIS應用并觀察每個話語執行個體在每個意圖上的得分。測試時,使用互動測試模式。
- 得分是多少?超過0.8了嗎?如果分值比較低則說明訓練效果不好,是以繼續為每個意圖分别添加話語執行個體,重新訓練,直到分值超過0.8。觀察一下每個意圖總共需要添加多少個話語才能使LUIS應用達到可用的訓練效果。
在完成這些練習之後,讀者便具備建構、訓練和測試LUIS意圖的開發經驗了。
3.2 釋出LUIS應用
顯然,截至目前我們還沒有完成LUIS應用的開發,還有很多細節我們也沒有展開探索,我們甚至沒有看到真實的使用者使用資料。但是,我們可以并行地開發LUIS應用和消費者級的應用。讓經過訓練的應用程式可以通過HTTP通路的過程稱為應用程式釋出。
在頁面最上方的導航欄,BUILD的旁邊可以找到PUBLISH(釋出)。點選PUBLISH,便會跳轉到部署LUIS應用的頁面,如圖3-15所示。LUIS支援開發者用兩種模式部署應用:Staging slot和Production slot。staging表示我們還在開發和測試LUIS應用,還處于開發環境中;production則表明應用已經釋出到線上的生産環境中。設計兩種部署模式的思想是讓開發者既可以維護一個釋出在生産環境中的穩定版本,同時又能在staging中繼續開發新的版本,增加新的功能。
在頁面的“Publish to”下拉選項中,我們選擇“Staging slot”,釋出之後我們可以通過HTTP端點通路LUIS應用。
cURL是一個通過HTTP(在許多其他協定中)傳輸資料的指令行工具,在我們使用cURL測試生成的端點之前,你可能已經注意到,在釋出設定頁面下有一個Add Key按鈕和一組key選項,用于選擇部署地區。開發者必須提供一個key才能使LUIS應用能夠被通路,同時LUIS通過該訂閱的key向開發者使用API進行收費。由于LUIS在多個地區均有部署,是以key必須和所屬地區進行關聯。key通過使用微軟Azure Portal建立,Azure是微軟提供的雲服務。我們将在第5章介紹使用Azure注冊和部署機器人。通過Add Key按鈕可以将key和應用關聯,幸運的是,LUIS提供了一個免費的入門key(starter key),可以用于在Staging slot中釋出的應用程式。
将LUIS應用釋出到Staging slot之後,我們會立即得到應用版本号和應用最新釋出時間的資訊,此時Starter_Key中的URL便可以正常通路。通過URL查詢參數還可以獲得更多詳細資訊(我們将馬上介紹這部分内容)以及加入Bing(必應)拼寫檢查(參見3.11節)。首先,看一下URL的内容。
URL内容的第一行是部署在美國西部地區的Azure上的認知服務的service endpoint(服務端點),具體來講就是我們的LUIS應用的service endpoint。查詢參數的含義如下:
- subscription key:開發者訂閱的key,在本開發教程中指的是starter key。該key也可以通過Ocp-Apim-Subscription-Key的頭部進行傳遞。
- staging:true表示使用Staging slot,false表示使用Production slot。如果此參數的值為空白,則LUIS認為使用的是Production slot。
- verbose:true表示傳回所有意圖和得分,false表示僅傳回得分最高的意圖。
- time zone offset:用于幫助解析不同格式的日期時間,在介紹内建的Datetime實體時我們會介紹時間解析。
- q:表示使用者自定義的查詢。
我們可以通過發送請求和API互動,也可以通過使用curl看到響應。curl是一個支援多種傳輸協定的用于資料轉換的指令行工具。我們使用curl在HTTPS上轉換資料,如需了解更多關于curl的内容,可以通路
https://curl.haxx.se/。我們所使用的curl指令如下,注意其中的-H參數,我們将訂閱的key作為HTTP頭部進行傳遞。
查詢的結果如下,格式為JSON,它會對我們的LUIS應用中的每一個意圖進行打分。
可能你會想,剛才說我們最多可以有500個意圖,那麼該響應中意圖的數量明顯不合邏輯。的确如此,将查詢參數verbose設定為false将産生緊湊的JSON清單,并進行傳回。
一旦準備好将應用部署到生産環境中,就可以把LUIS應用釋出到Production slot,并且從URL請求中移除staging參數。最簡單的方式是讓你的開發和測試配置檔案指向Staging slot URL,讓生産釋出的配置檔案指向Production slot URL。
開發者可以使用任何自己順手的HTTP工具,此外微軟還提供了一個快速使用終端(easy-to-use console)用于測試LUIS API,具體使用請查詢網上線上的API文檔。
練習3-2
釋出LUIS應用
此練習是釋出練習3-1中的LUIS應用,并且通過curl通路它。
- 按照前面章節的步驟,将LUIS應用釋出到Staging slot。
- 使用curl從作為樣例輸入的話語和其他你能想到的話語中得到JSON資料格式響應的預測意圖。
- 確定curl指令使用的是所釋出應用的ID和入門key。
将LUIS應用釋出到slot的過程非常直接,但熟悉使用curl對HTTP端點進行檢測非常重要,因為後續開發中我們需要經常使用它來通路端點,以檢測LUIS應用的傳回結果。
3.3 實體抽取
目前為止,我們開發了一個簡單的基于意圖的LUIS應用,但除了能讓LUIS應用識别使用者話語中的意圖并告訴機器人之外,我們還沒有使用LUIS進行其他更深入的開發。通過上面的開發執行個體,LUIS可以通過識别AddCalendarEntry意圖來告訴使用者想要增加一個月曆,但我們更希望能自動增加月曆的具體日期、時刻、地點、持續時間以及對象。我們可以讓機器人在識别到AddCalendarEntry意圖時就按順序依次詢問所有的這些細節,但這種開發太愚笨和煩瑣,尤其是在使用者的話語已經很好地将時間、地點等細節内容表達完整時,比如下面的話語:
如果此時采用上面的方法,仍然依次詢問使用者有關時間、地點等細節資訊,并要求使用者再次輸入這些資料,那使用者體驗會變得非常差。機器人應該能立即識别話語中的時間“tomorrow at 6pm”以及會議所邀請的人“Huck”。
如何保證“tomorrow at 6pm”“a week from now”和“next month”這些内容對于機器而言是可閱讀的呢?這就需要引入實體識别(entity recognition)。幸運的是,LUIS内建了很多實體,我們可以将它們直接添加到LUIS應用中,這樣LUIS應用便可以提取出日期時間(datetime)這一實體。
如果回到前面圖3-2關于“BUILD”的那部分内容,并且在BUILD頁面點選左側頂部的“Entities”,那麼我們将看到一個空的實體清單,如圖3-16所示。我們可以選擇添加三種不同的實體,在本執行個體中我們選擇添加預建實體(prebuilt entity),即點選“Create new entity”(建立實體)。我們将在本章的後續章節中介紹自定義的一般實體以及預建領域實體(prebuilt domain entity)。
預建實體是一個預先訓練的定義,可以在話語中被識别出來。實體在輸入中被自動标記,我們無法更改識别預建實體的方式。在應用程式中,我們可以利用大量邏輯,最好在建構實體之前了解微軟已經建構了什麼。
LUIS提供了很多不同的預建實體,但不是所有的實體對每種語言(人類語言)都可用。LUIS官方文檔中提供了不同預建實體對不同語言的支援,如圖3-17所示。
一些實體還包括值消解(value resolution),值消解就是接收文本輸入并将其轉換成計算機可以解釋的一個值。比如,“one hundred thousand”被解析成100000,“next May 10th”被解析成05/10/2019(相對于2018年而言),等等。
我們回頭看LUIS傳回的JSON結果,可以發現其中包含了一個名為entities的空數組。該空數組是從使用者的話語輸入中識别出的實體的占位符(placeholder)。LUIS應用從輸入中識别實體沒有數量限制,可以識别任意數量的實體,識别出的每一個實體的資料格式如下:
被消解的對象會依據所識别到的不同實體類型的差異來包含一些額外的屬性資訊。下面我們将介紹各種不同的預建實體類型、它們所支援的一些特性,以及允許開發者做哪些事情。
3.3.1 Age、Dimension、Money和Temperature
Age實體可以讓LUIS應用識别檢測出輸入中的年齡表達,比如“five months old”“100 years”和“2 days old”。傳回的結果對象包括數字格式的值和機關名稱參數,如日、月或年,在結果對象的“resolution”中。
任意長度、重量、體積和面積都可以使用Dimension實體來檢測,輸入可以是“10 miles”“1 centimeter”和“50 square meters”等多種多樣的變化形式。和Age實體一樣,Dimension實體也包含值和機關。
Currency實體可以幫助LUIS應用檢測識别出使用者輸入中的錢,在Currency實體的傳回對象裡同樣包含機關和值兩個屬性。
Temperature實體可以幫助識别輸入中的溫度,同樣也将機關和值兩個屬性包含在了傳回結果的resolution中。
3.3.2 DatetimeV2
DatetimeV2是一個強大的分層次的實體,它替代了之前版本的datetime實體。層次實體(hierarchical entity)定義了分類和分類的成員,當某些實體相似且密切相關但具有不同含義時,使用層次實體是非常合理的。此外,DatetimeV2實體将時間解析為機器可以閱讀的格式,比如TIMEX格式(代表“時間表示”;TIMEX3是TimesML的一部分),以及yyyy:MM:dd、HH:mm:ss和yyyy:MM:dd HH:mm:ss(三種格式分别對應date、time和datatime)。DatetimeV2 datetime類實體的例子如下:
DatetimeV2實體可以識别不同類、不同格式的時間。下面再給出一些實體的例子,它們分别表示其他各類DatetimeV2實體,并給出識别之後的傳回對象。
第一個例子顯示的是“builtin.datetimeV2.date”類實體,它對應輸入中存在的日期資訊,比如“yesterday”“next Monday”和“August 23, 2015”:
第二個例子顯示的是“builtin.datetimeV2.time”類實體,它對應輸入中存在的時刻資訊,比如“1pm”“5:43am”“8:00”或“half past eight in the morning”:
第三個例子顯示的是“builtin.datetimeV2.daterange”類實體,它對應輸入中存在的以日期為粒度的時間段資訊,比如“next week”“last year”或“feb 1 until feb 20th”:
第四個例子顯示的是“builtin.datetimeV2.timerange”類實體。顧名思義,它對應輸入中存在的以某一時刻為起點和終點的時間段資訊,比如“1 to 5p”或“1 to 5pm”:
第五個例子顯示的是“builtin.datetimeV2.datetimerange”類實體。顧名思義,它也對應輸入中的時間段,但該時間段的起點和終點同時包括日期和時刻兩部分内容,比如“tomorrow morning”或“last night”:
第六個例子顯示的是“builtin.datetimeV2.duration”類實體,它對應輸入中的持續時間資訊,比如“for an hour”“20 minutes”或“all day”。此時,值的機關被解析為秒:
builtin.datetimeV2.set類實體表示一系列日期組成的集合,比如“daily”“monthly”
“every week”“every Thursday”。該類型的解析和上面幾個datetimeV2類型的實體有所不同,實體中timex的解析主要包括兩種方式。第一種,timex字元串符合Pn這種模式,其中[n]是數字,[u]是日期的機關—D表示天、M表示月、W表示周、Y表示年。Pn表示“every n units”,比如P4W表示每四個星期、P2Y表示每兩年;第二種,timex字元串按照日期的格式和Xs的模式表達任意的值,比如XXXX-10表示每個十月份、XXXX-WXX-6表示某一年中任意一周的周六。
如果輸入中存在含義模糊不清的日期或時間,那麼LUIS将傳回多個解析的選項。舉一個例子,如果今天是July 21,我們輸入的話語是“July 21”,那麼LUIS将傳回今年和去年的July 21。同樣,對于時間而言,如果輸入話語中沒有明确a.m.或p.m.,那麼LUIS會把a.m.和p.m.的時間都傳回。兩種模糊不清的具體例子如下:
DateimeV2實體功能十分強大,展示了LUIS強大的自然語言了解能力。
3.3.3 Email、Phone Number和URL
Email、Phone Number和URL這三個類型的實體都是基于本文的。LUIS可以從使用者的輸入中識别出這些實體,LUIS完成此操作非常友善,開發者完全不必自己在系統中通過正規表達式的方法來實作這三類實體的識别。我們通過三個例子分别來展示LUIS識别這三類實體的傳回結果:
3.3.4 Number、Percentage和Ordinal
LUIS可以抽取和處理數字(Number)與百分數(Percentage),使用者的輸入既可以是數字的形式(比如100)也可以是文本(比如one hundred)的形式,甚至可以處理像“thirty-eight and a half”這類形式複雜的數字。
LUIS的序數詞(Ordinal)實體能識别話語輸入中的序數詞,序數詞實體同樣支援數字或者文本形式的輸入。
3.4 實體訓練
我們繼續回到Bot應用程式開發,
并應用剛才學到的一些東西。正如在編寫與月曆相關的Bot應用程式時,我們選擇的最明顯的預建實體是datetimeV2。在LUIS的Entity頁面中,點選“Manage prebuilt entities”,并選擇datetimeV2,如圖3-18所示。
在添加實體之後,我們開始訓練模型。在互動式測試UI中,當輸入“add calendar entry tomorrow at 5pm”時,我們将看到如圖3-19所示的結果。
可以看到,整個過程非常簡單。接
着,我們再次将LUIS應用釋出到Staging slot,并使用curl運作相同的查詢,我們收到以下JSON:
到現在,我們可以在LUIS應用的任何意圖中識别出datetime實體了,datetime實體會和LUIS應用的所有意圖都關聯,而不僅是和AddCalendarEntry這一個意圖相關。此外,我們将繼續添加Email預建實體,再次訓練并釋出到Staging slot。我們可以嘗試一下“meet with [email protected] at 5p tomorrow”這樣的話語輸入,并獲得我們所期望的結果。
練習3-3
添加對Datetime和Email實體識别的支援
我們會在該練習中将剛才學習的預建實體加入到我們正在開發的LUIS應用Calendar-BotModel中。
- 添加email和datetimeV2預建實體到LUIS應用中,并且重新訓練模型。
- 轉到AddCalendarEntry意圖中,輸入一些包含Datetime和Email的話語,檢視LUIS是否識别了這些實體并将其高亮顯示。
- 将LUIS應用釋出到Staging slot。
- 使用curl指令檢視傳回的JSON結果。
預建的實體非常容易使用。作為進一步的練習,在模型中添加一些其他預建實體,以了解它們如何工作以及如何在不同類型的輸入中擷取它們。如果你想阻止LUIS識别它們,則隻需将它們從LUIS應用程式的實體中删除。
3.5 自定義實體
預建實體無需任何額外的訓練就可以為我們的模型做很多事情。在我們的CalendarBotModel LUIS應用程式中,月曆條目(calendar entry)裡包含一些我們感興趣的屬性。但如果說我們需要的一切都可以由現有的預建實體提供,那不太現實。
我們通常希望為會議提供一個會議主題(不僅是類似“與Bob會面”這麼簡單)和會議位置。會議主題和位置都是任意字元串,那麼此時我們如何實作實體抽取的目标呢?
LUIS支援開發者訓練自定義實體來檢測這些概念,并從使用者的輸入中抽取它們的值,這就是實體抽取算法的強大功能所在。在自定義實體中,我們可以決定LUIS何時應該将詞語識别為實體,何時應該忽略它們。NLP算法考慮上下文。例如,給定多個話語樣本,我們可以教LUIS并確定它不會混淆Starbucks(星巴克)與Starbuck—小說《Moby Dick》中的角色名。
我們可以在LUIS中使用四種不同類型的自定義實體:簡單、複合、層次和清單。下面我們分别介紹每一類自定義實體。
3.5.1 簡單實體
簡單的自定義實體是諸如月曆條目或預建構的電子郵件(Email)、電話号碼(Phone Number)和URL之類的實體,使用者輸入中的詞語可以基于其在話語中的位置和它周圍詞語的上下文而被識别成相應類型的實體。LUIS可以輕松建立和訓練簡單實體,我們首先建立一個名為“Subject”的簡單實體。
當我們要告訴月曆機器人關于條目的主題名稱時,我們應該想清楚。假設我們希望接受諸如“meet with Kim about mortgage application at 5pm”這樣的輸入。在這個例子中,Subject實體将是“mortgage application”,下面我們來實作一下。
回到Entity頁面并單擊Create new entity按鈕以建立一個名為Subject的簡單實體,如圖3-20所示。
點選完成之後,該條目會被添加到LUIS應用的實體清單裡,訓練實體的過程與訓練意圖在相同的頁面中,我們點選跳轉到AddCalendarEntry意圖的頁面,并添加“meet with Kim about mortgage application at 5pm”話語,如圖3-21所示。注意,此時這隻是一個普通的話語,沒有自定義的簡單實體被識别。
現在,我們移動滑鼠到詞語mortgage和application上會發現詞語可以被標明,點選詞語mortgage和application,此時短語“mortgage application”被標明,同時頁面會在浮窗中枚舉展示你LUIS應用程式中所有的自定義實體;標明出現的Subject實體。此時,輸入到LUIS中的話語将如圖3-22所示。
儲存話語并重新訓練應用程式。由于我們目前隻提供一個話語輸入,是以目前LUIS在确定Subject實體方面的效果還沒那麼出色。實體識别比意圖分類更難做,它需要更多輸入樣本,我們可以在話語編輯器(utterance editor)裡向月曆條目意圖添加更多的話語輸入。圖3-23中展示了添加的一些輸入樣本。
注意,在添加完之後,此時沒有Subject實體被檢測到,我們再次強調,系統能夠識别實體的前提是有相當多的輸入樣本被輸入并訓練。我添加了十多句在某一位置具有Subject實體的話語,如圖3-24所示,并在具有該實體的詞彙或短語上标記了自己定義的簡單實體。我們的話語應該精心設計,以確定向LUIS提供盡可能多的變化。通常,每個變體還需要包括一些樣本以保證算法訓練的模型可以足夠準确地在話語的上下文中找到特定實體。
在使用訓練資料訓練完模型後,我們通過頁面的互動式測試工具發現模型在實體識别方面變好了很多。現在,我們随機地輸入一句測試話語“hi let us meet about lawn care and harmonicas at 1:45p”,便會看到如圖3-25所示的結果,實體都被識别出來了。但是,如果我們變換一下輸入的長度或者換用同義表達,那麼LUIS可能無法正确識别這些實體。這意味着我們還需要添加訓練資料,進一步訓練實體識别模型;我們會将此作為練習留給讀者。
盡管表達方式的變化導緻模型可能對某些輸入中的實體無法識别,但我們現在很好地掌握了自定義的簡單實體—月曆Subject實體的定義、使用和訓練。事實上,開發者很難考慮到使用者對一句話所有可能的表達方式,但LUIS應用程式開發的方式就是這樣。是以,在釋出此應用程式前,必須反複地進行互動測試,檢視傳回的JSON結果,這非常重要。
可以看到,time實體被正确地識别,Subject實體傳回相關的實體值。此外Subject實體還傳回了一個得分,這裡的得分與前文所述的意圖得分含義相似,它是相對理想實體的距離度量。與意圖不同的是,LUIS不會傳回所有的實體及其得分,而僅傳回分數高于門檻值的簡單實體和分層實體;對于預建實體,此分數是隐藏的。
訓練實體的好處在于,即使包含實體的話語樣本在AddCalendarEntry意圖中定義,這些實體也會被其他意圖共享。意圖和實體并不直接互相關聯。比如,我們輸入“cancel meeting about olympic hockey”,它在互動式測試工具中的傳回結果如圖3-26所示。
對于該輸入,另一個觀察結果是在識别為DeleteCalendarEntry意圖方面得分較低(0.64)。這是因為我們在AddCalendarEntry意圖中添加了更多的話語,而在DeleteCalendarEntry和EditCalendarEntry中添加的話語樣例要少得多。我們可以繼續添加一些包含Subject實體的同義替換表達作為輸入樣例,然後重新訓練模型,就可以改善這一點。
練習3-4
訓練Subject實體并增強我們的LUIS應用
我們将通過本練習掌握提升LUIS應用對實體識别的方法。
- 添加自定義簡單實體Subject。
- 在意圖中添加包含Subject實體的話語,并互動式地進行訓練和測試,反複疊代這個過程,直到LUIS應用對實體的識别結果滿足開發者的要求。
- 一開始,至少保證在LUIS中輸入25到30個話語樣本,同時確定為每個話語樣本提供多個同義語句。
- 後續輸入中,確定所有的意圖都具有15到20個話語樣本作為輸入,同時每個意圖對應的輸入話語要包含所有的實體。
- 訓練并将LUIS應用釋出到Staging slot。
- 使用curl工具檢視傳回的JSON結果。
訓練自定義實體相對而言更有難度一點,但經過反複的互動訓練,我們會看到LUIS逐漸可以識别這些自定義的實體。注意話語輸入中需要明确訓練的實體:Subject實體和實體後面的日期、時間等。開發者可能已經注意到訓練資料的數量非常重要,像LUIS這樣的自然語言了解系統獲得的訓練資料越多,效果就越好。如果LUIS最終的訓練結果與你的期望有差距,那麼很可能不是LUIS的性能問題,而是你的LUIS應用需要更多的訓練資料來進行訓練。
我們要建立的第二個自定義簡單實體名為Location。和前面建立的Subject實體類似,Location實體可以是任意與位置相關的文本内容,是以我們需要使用許多訓練樣本來訓練LUIS。
接下來我們将嘗試在AddCalendarEntry意圖中添加訓練話語,所添加的話語采用下面的這些形式:
此外,我們還應該在話語中添加一些datetime執行個體。因為我們要讓LUIS能區分Location和Subject兩個實體的識别,是以訓練Location實體将變得更加棘手。Location和Subject都可以是任意與它們含義(位置、主題)相同的詞語,是以在訓練這兩個實體時,需要給LUIS提供大量訓練資料。在正在開發的LUIS應用程式中,我們添加了30多個話語,這些話語中要麼僅包含Location實體,要麼既有Location實體又有其他的實體。經過多次訓練、測試之後,我們得到了滿意的結果;當輸入“meet for dinner at the diner tomorrow at 8pm”之後,得到了如下的JSON傳回結果:
我們建議開發者在實體識别的訓練階段投入較多的精力進行調優,這對了解自然語言和訓練自然語言了解系統(比如LUIS應用)的複雜性和模糊性非常有幫助。
練習3-5
訓練Location實體
在本練習中,我們将向LUIS應用中添加Location實體,通過本練習,讀者會發現這比之前隻單獨訓練Subject實體要花費更多的時間。
- 按照前面章節内容的步驟,添加Subject實體。
- 向AddCalendarEntry意圖中添加包含Location内容的話語。訓練并通過頁面的互動式測試工具進行測試。
- 向LUIS中添加至少35到40個話語樣本,應用中設計的意圖越多,則需要的話語樣本就越多。在添加話語的過程中,同時訓練和測試LUIS應用。注意輸入的話語樣本的多樣性,通過同義表達來使話語變化。
該練習有助于提升LUIS應用(在一個話語中存在多個實體的時候)對實體的識别能力。
3.5.2 複合實體
到目前為止,我們完成了對LUIS大部分内容的實踐。使用前面介紹的意圖分類和簡單實體抽取,我們初步開發了一個和月曆相關的LUIS應用程式。雖然我們讨論了一些簡單實體,但很快也會遇到一些複雜的自然語言了解場景。沒有像LUIS那樣的工具,實作這些語言了解任務将非常複雜和困難。
現在我們再來看一個自然語言了解中的新場景。我們的LUIS應用目前支援使用者輸入如下形式的話語:
但如果使用者想一次性添加多個月曆條目該怎麼辦?比如使用者想輸入如下形式的話語:
如果我們對LUIS應用訓練得足夠充分,那麼當然可以處理這類輸入,并且LUIS應用會識别出兩個Subject實體、兩個Location實體和兩個datetime實體。對于輸入“meet at culture for coffee at 11am and at the off?ice for a code review at noon”,傳回的JSON結果如下:
但是,我們如何區分哪些實體分在哪一組裡呢?每個Location實體分别和哪個Subject實體比對并分在一個組?使用JSON裡的startIndex屬性似乎有效,但并不能確定對每一個輸入都有效。
幸運的是,LUIS可以将實體分組成複合實體(composite entity)。不必像上面的傳回結果那樣煩瑣,LUIS将向我們傳回:每個實體分别屬于哪一個複合實體。這樣,我們就能很容易地看出有兩個獨立的AddCalendar請求:一個是“11 a.m. coffee at Culture”,另一個是“a code review in the office at noon”。
複合實體可以在LUIS的Entity頁面中建立。圖3-27展示了在LUIS中建立複合實體的過程,點選Create new entity按鈕,在Entity name中輸入所要建立的複合實體的名字,在Entity type選項上選擇Composite實體類型,在Child entity選項上為建立的複合實體添加子實體。我們使用CalendarEntry作為該複合實體的名字。
在建立CalendarEntry複合實體之後,我們需要訓練LUIS應用,使其能識别複合實體。回顧AddCalendarEntry意圖,訓練LUIS應用最簡單的方式是使用大量包含三種實體并将其打包成複合實體的話語來進行訓練。圖3-28提供了一個這樣的例子。
CalendarEntry;這是典型的複合實體的例子
點選第一個Location實體,會出現一個浮窗,浮窗裡的選項包括重新标記實體或将其打包到複合實體中。我們點選“Wrap in composite entity”選項,并點選選擇我們建立的CalendarEntry複合實體,如圖3-29所示。
接着移動滑鼠至Subject實體和datetimeV2實體,重複上述過程。注意完成之後下劃線會擴充到剛才所操作的每一個實體,如圖3-30所示。
接着标記第二個CalendarEntry實體,完成之後結果如圖3-31所示。
對于後續輸入的包含三類實體的其他話語,我們同樣按照上面的過程對實體進行标記,并對LUIS應用進行訓練和釋出。在完成所有這些步驟之後,LUIS便可以識别複合實體了。我們隻展示識别結果中相關的屬性,如下所示。
練習3-6
複合實體
在本練習中,我們将回顧:向LUIS應用中添加複合實體。
- 建立名為CalendarEntry的複合實體,并且指定其子實體(child entity)為datetimeV2、Subject和Location實體。
- 對包含datetimeV2、Subject和Location三種實體的話語進行實體标注(label),并對LUIS應用進行訓練。
- 再輸入一些标注為CalendarEntry複合實體的話語樣本,對LUIS應用進行訓練。
複合實體是幾種實體的組合,它支援LUIS應用對更複雜的表達進行封裝,相當于把幾種标注的實體分成一組、打包封裝。
3.5.3 層次實體
層次實體支援開發者定義實體和該實體的子實體。開發者可以把層次實體視為在實體之間定義父/子類型關系。我們之前遇到過這種類型的實體,比如datetimeV2實體。datetimeV2實體包括daterange、set和time等諸多子類型實體。
LUIS支援開發者輕松地建立自定義的子類型實體。假設我們想在模型中添加支援将月曆條目可見性指定為公共或私有的功能,那麼我們可能添加如下的話語:
話語中的詞彙“private”“invisible”是用于表明月曆條目是否可見的簡單實體。但是,這種情況下建立層次實體比使用簡單實體更加高效。我們能否通過隻看Visibility屬性的值來确定它是否應該是私人會議?如果開發者堅持選擇“是”或者“否”作為唯一的答案,那麼答案為“是”。但需要注意的是,自然語言具有模糊和不确定的特性,一個意思可以有多種表達。比如對于私人月曆條目,使用者的話語中可能說的是“invisible”“private”“privately”
“hidden”,同樣的道理,對于公開的月曆條目,使用者的表達也可能多種多樣。如果我們采取這種提供一組封閉表達的方法(即在代碼中寫死),那麼我們将不得不在每次出現新表達時更改代碼。應該使用層次實體而不是簡單實體的原因是層次實體在上下文中的統計模型可以被子類型共享。一旦層次實體被識别出來,下一步識别子實體的過程本質上就變成了一個分類問題。在上述這類話語場景中,比起使用兩個簡單實體,使用層次實體能更好地發揮LUIS的性能。而且,這種方式也比手動寫大量規則的代碼具有更高的開發效率。
圖3-32展示了如何建立一個新的層次實體的過程。我們通路LUIS的Entity頁面,點選Create new entity,然後從Entity type下拉選項中選擇Hierarchical。接着,我們對parent entity進行命名并且添加child entity。完成這些之後,仍然是進入意圖頁面,添加話語并訓練LUIS應用。我們選擇進入之前的AddCalendarEntry意圖并添加一些話語。
在開始識别輸入中的實體之前,需要對輸入進行标注,讓LUIS非常清楚它在何處以及如何遇到表示公開和私人的修飾符。圖3-33顯示我們輸入了10條話語,并進行了标注。
一旦完成訓練并釋出應用之後,我們可以通過curl工具來看一下LUIS傳回的測試結果,如下所示:
3.5.4 清單實體
到目前為止,我們可以從使用者的輸入中識别出預建實體、簡單實體、複合實體和層次實體。每次我們添加一類新的實體并訓練LUIS應用時,我們都會注意到正在被訓練的模型數量有所增加,這是因為LUIS應用中每一個意圖/實體對都與一個模型對應。到目前為止,我們至少應該有10個模型,每個模型在我們訓練LUIS應用時都會被重建。
清單實體和上述實體不同,LUIS應用不需要使用清單實體進行訓練,是以清單實體與機器學習無關。清單實體由一系列的術語和這些術語的同義詞組成,比如,我們想定義City,則可以添加New York,以及它的一些同義詞NY、The Big Apple、The City That Never Sleeps、Gotham、New Amsterdam等。LUIS會将這些替代詞統統解析為New York。
在建立清單實體類型之後,我們會重定向到清單實體編輯器頁面,在這裡開發者可以為剛才建立的該類清單實體添加典型術語(canonical term)以及它的同義詞。該頁面還支援使用者添加新的術語和同義詞,并且會額外地推薦一些和已添加的術語密切相關的術語。清單實體最多支援20?000個術語(含同義詞),每個LUIS應用最多支援50個清單實體。圖3-34展示了一個自定義清單實體的例子。
由于清單實體不需要LUIS應用訓練學習,是以清單之外的詞語不會被識别出來。比如,LUIS看到輸入中的“Gotham”時,會将其識别為New York,但對于“Gohtam”則不會被LUIS識别。顧名思義,清單實體其實就是一個查詢清單。
在使用清單實體API時,LUIS會将識别出的實體高亮顯示,并傳回清單實體的典型名稱。這允許我們消費應用程式,以忽略術語的所有可能的同義詞,并根據典型名稱執行邏輯。清單實體在開發者提前知道某一内容的所有可能值時會非常好用。
3.5.5 正規表達式實體
LUIS支援開發者建立正規表達式實體。正規表達式實體就像清單實體那樣,和上下文無關。比如,如果我們期望始終使用文法KB143230(KB後面有6位數字)來呈現某一知識,那麼我們可以建立一個帶有kb[0-9]{6,6}正規表達式的實體。經過訓練之後,話語輸入中任何比對到該正規表達式的内容都将被識别為該正規表達式實體。
3.6 預建域
通過上面的實踐,我們對建構NLU模型的一些挑戰已經有所了解。可用一些機器學習工具快速地進行開發,但我們必須保證使用了品質好的資料來進行訓練。人類需要浸入到一門語言中并進行多年的日常使用,才能真正了解一門語言,但現在我們假設的是LUIS應用僅使用10個樣例進行學習便能從話語輸入中識别出實體。是以,在遇到LUIS無法識别和了解的情況時,我們需要讓LUIS學習新的内容。
為了實作這一目标,很多NLU平台提供了預模組化型和預建域。從本質上講,LUIS和其他平台的建立者希望為我們提供一些開發優勢和捷徑,讓我們可以輕松地将這些域包含在我們的應用程式中并訓練LUIS。圖3-35展示了一些預建構的模型。
我們可以通過在BUILD頁面中點選左下角的“Prebuilt Domains”連結,進而找到預建域。在撰寫本書時,這一功能尚處于預覽階段,而當讀者閱讀此書時則可能已經做了修改。LUIS包括一系列域,比如相機、家庭自動化、遊戲、音樂甚至類似于我們一直在學習開發的月曆。事實上,我們會在練習3-7中完成這些。“Learn more”文本連結會跳轉到一個頁面,該頁面較長的描述了每個域所引入的意圖和實體,以及不同的語言都支援哪些域。
在開發者向應用中添加了一個域之後,LUIS會将該域下的所有意圖和實體加入所開發的LUIS應用中,以使開發的LUIS應用的功能更強大。但有時我們可能需要去掉某些意圖或添加新意圖以補充預先建構的意圖;或者我們還需要使用更多樣本來訓練預建構的域。我們建議開發者将預建構的域視為基礎,我們的目标是在預建構域的基礎上擴充它們以建構更出色的體驗。
LUIS的一個轉折點
LUIS幾年來已經更疊了多個版本,甚至在作者撰寫本書期間LUIS還更改過UI和一些功能。LUIS曾經包含Cortana應用(微軟小娜),任何開發者都可以利用已知的App ID,并使用他們的訂閱密鑰來進入。Cortana應用内定義了許多預建構的意圖和實體,但它是一個封閉的系統,是以開發者無法對它進行個性化的定制或者增強。從那以後,微軟就擺脫了在LUIS中内建Cortana這一功能,轉而支援預建域。但是,将自己的模型公開和共享以便其他開發者可以通過使用自己訂閱的密鑰來調用該共享的模型的理念并沒有被去掉,開發者仍然可以通過Settings頁面獲得該功能。
練習3-7
使用預建域
在本練習中,我們将使用預建域Calendar來建立一個LUIS應用,該應用和我們在前文内容中建立的應用功能相似。
- 建立一個新的LUIS應用。
- 在LUIS頁面中導航到prebuilt domains連結,并添加Calendar域。
- 訓練LUIS應用。
- 使用互動式測試檢測應用在識别意圖和實體方面的性能如何?在設計和性能方面和我們之前開發的應用相比如何?
預建域非常有用,但LUIS需要充足的訓練才能産生一個性能優越的模型。
3.7 短語清單
到目前為止,我們一直通過學習和實踐多種方法來增強應用。有時我們發現訓練好的模型性能并不滿足我們的要求,可能話語中的實體識别準确率并沒達到我們的要求。可能我們建構的LUIS應用程式是專門用來處理一些内部術語的,它們與LUIS應用目前使用的語言有很大的差異;也可能我們無法做到用實體的所有可能值來訓練LUIS,因為我們希望實體具有一定的靈活性。
在這種情況下,提升LUIS性能的方法是使用短語清單。短語清單是訓練LUIS應用時使用的“暗示”,而不是“寫死”的規則。短語清單支援我們向LUIS提供一系列具有相關性的詞彙和短語,這樣一組詞語就是一種“暗示”,LUIS就會用相似的方式識别所有具有相關性的詞語。在實體值未被正确識别的情況下,我們可以将所有已知的可能值作為短語清單輸入并将清單标記為可交換(exchangeable),這就提示了LUIS?:在一個實體的上下文中,這些值都會以相同的方式被處理。如果我們試圖用可能不熟悉的單詞來提高LUIS的詞彙量,那麼短語清單不會被标記為不可交換(nonexchangeable)。
現在假設我們想提高這個Calendar模型識别私有實體的性能。畢竟,表示我們想要私有會議的方式有很多。最開始,我們可以添加一個包含各種表示私有含義的詞語的短語清單。圖3-36展示的是LUIS中添加短語清單的頁面,具體操作是先在BUILD頁面通過選擇Phrase Lists跳轉到該頁面,然後點選Create new phrase list。
每個短語清單都需要一個命名和一些值,我們在Value區域逐一地把短語清單包含的值輸入進去,點選回車時便完成了輸入。Related Values包含的是Value區域的同義詞,它們由LUIS自動加載。接着我們點選下方的checkbox将短語清單的值選擇為可交換(interchangeable)。
在訓練之前,我們首先不使用短語清單,然後試着輸入一些包含私有會議資訊的話語。如果我們輸入類似“Meet in private”“Meet in secret”或者“Create a hidden meeting”這樣的話語,那麼LUIS并不能識别實體。但是,如果我們使用短語清單并進行訓練,此時便會發現LUIS可以将這些實體從話語中識别出來。
練習3-8
訓練功能
在本練習中,我們将通過添加功能來提升LUIS應用的性能。
- 向LUIS應用中添加Visibility(Calendar條目的可見性,表明是公開還是私有)層次實體。
- 添加短語清單以提升LUIS對私有Visibility實體的識别性能。
- 測試“将短語清單設定為interchangeable”對LUIS應用識别實體性能産生的影響。
短語清單是LUIS中一項十分強大的功能,能幫助LUIS應用在識别不同實體時獲得更好的性能。
練習3-9
添加Invitee實體
到目前為止,我們的Calendar中還沒有識别會議參加者實體的功能,在本練習中我們将解決這個問題。
- 添加一個新實體,并命名為Invitee。
- 複查之前的每一個話語輸入,将Invitee實體标注出來。
- 如果需要更多的訓練,則再加入一些包含Invitee實體的輸入。
- 将Invitee實體添加到CalendarEntry複合實體中。
- 訓練LUIS應用,并確定所有的意圖、實體的識别效果依然能達到要求。
如果經過本次練習之後,我們開發的LUIS應用識别實體和意圖的性能很好,那麼讀者已經可以熟練使用LUIS了。
3.8 主動學習
我們花了數周時間訓練模型,然後進行了好多輪測試,接着将應用程式部署到生産環境中,最後開啟Bot服務。下一步呢?我們如何才能知道我們訓練和釋出的LUIS應用是不是它能達到的最好性能呢?我們怎樣才能知道是否有一些使用者輸入了意料之外的話語,讓機器人無法了解并導緻了一次非常差的使用者體驗呢?bug報告自然有效,但那樣的話我們必須得到出現bug時的回報。我們能否在問題發生時就立馬發現呢?此時我們可以利用LUIS的主動學習功能來達到這個目的。
回顧一下,監督學習是從有标簽的資料中進行學習,非監督學習是從沒有标簽的資料中進行學習,半監督學習則是介于監督學習和非監督學習之間。主動學習是一種半監督學習,學習算法要求監督者為新的資料打标簽。對于一個LUIS處理不了的輸入,它可能會要求熟悉該應用的開發者為這個新的使用者輸入進行資料标注。這提高了模型的性能,并且随着時間的推移,通過使用真實的使用者輸入作為樣本資料來進行訓練,也會使我們開發的LUIS應用更加智能。
開發者可以通過BUILD頁面中的“Review endpoint utterances”連結來使用LUIS的主動學習功能(如圖3-37所示)。在訓練完LUIS應用之後,我們繼續使用端點(endpoint)來測試不同話語輸入的結果。LUIS将其主動依賴于針對端點的輸入,而不是互動式測試功能。
3.9 儀表闆概覽
到目前為止,我們已經訓練完LUIS應用了,并且進行了測試,此時LUIS儀表闆提供的資料同樣值得注意。儀表闆讓我們能對LUIS應用的整體狀态有一個快速了解,包括它的使用情況、我們已經訓練的資料量等。
在儀表闆中,最上方的資訊是我們上一次訓練和釋出LUIS應用的資訊,如圖3-38所示。另外,我們還能得到目前使用的意圖和實體的數量資訊、建立的清單實體數量以及到目前為止标記的話語數量。
儀表闆展示的第二部分内容是使用者通過不同API來使用LUIS應用的情況,如圖3-39所示。我們可以監測各個端點的點選數,并且時間範圍可以從上一周持續到上一年。這部分資料隻有在将LUIS應用釋出到Production slot時才能擷取。
儀表闆中最後一部分内容是意圖和實體的統計情況,如圖3-40所示。圖中展示的是,每個意圖所使用的訓練話語占據所有訓練話語的百分比分布。我們明顯可以看到有4個意圖使用的話語明顯比其他意圖使用的話語更多。實體和意圖一樣,也可以通過儀表闆進行展示。注意,不平衡的分布并不表示需要針對某一意圖或者實體進行更多的訓練。
3.10 LUIS應用管理與版本更新
到目前為止,我們的開發流程主要是:添加話語樣本、訓練LUIS應用、釋出LUIS應用。在開發階段,我們反複重複這一流程;但是,一旦将LUIS應用釋出到生産環境中,我們便應該謹慎處理這些應用,添加一個新的意圖或者實體可能給LUIS應用中的其他部分帶來無法預料的影響。是以,最好的方法是在生産環境之外開發已經存在的LUIS應用,這樣我們可以獨立于生産環境之外對新意圖或實體進行測試。
我們在前面的章節中介紹了Staging slot和Production slot,并且也已嘗試過不必将應用釋出到production端點而對應用中新增的功能進行測試。LUIS應用管理的一個基本規則是在Staging slot中存放LUIS應用的開發版本和測試版本,在Production slot中存放LUIS應用的生産版本。一旦開發中的版本經過測試已經适合上線,那麼釋出到生産環境時,我們便可将它從Staging slot移動到Production slot。但如果我們發現生産版本中的LUIS應用存在一些錯誤該怎麼辦?或者我們想将Production slot中的LUIS應用進行卷回操作該怎麼辦?此時,我們需要使用LUIS的版本管理功能。
LUIS支援開發者在任意時間建立應用的版本号。到目前為止,我們一直工作在版本0.1中。在适合将版本0.1釋出到生産環境時,我們将其釋出并克隆,得到一個新版本0.2。我們再将版本0.2設定為活躍狀态(Active),此時我們就工作在版本0.2中了。如果在開發過程中不小心将還未成熟的版本0.2釋出到了生産環境中,那麼我們可以輕松地卷回到版本0.1,并繼續釋出版本0.1。一旦版本0.2已經适合釋出到生産環境,我們便可将其部署釋出到Production slot,然後克隆版本0.2,又産生新的版本0.3,同時我們将新版本0.3設定為Active,并且也可以在需要的時候将LUIS應用的釋出版卷回到版本0.2。如此循環,完成版本更新。整個工作流程如圖3-41所示。
我們可以通過設定(Settings)頁面通路LUIS應用的版本資訊。圖3-42和圖3-43展示的是将版本0.1克隆到版本0.2之後該頁面顯示的一些資訊。
注意在關閉版本0.1之後,它在Staging slot中依舊存在,隻是版本0.2才是Active版本。LUIS不支援分支操作,如果多個開發者想更改同一個版本,那麼它們不能各自克隆一個版本,然後在修改之後再合并分支。要想實作類似于Git的分支操作,則需要通過點選頁面上的Export Version按鈕,下載下傳LUIS App JSON,如圖3-42所示,然後利用源代碼管理工具進行類似于branch和merge指令的分支操作,最後點選Import new version按鈕從JSON檔案中上傳一個最新的版本。
在該頁面中,開發者也可以将項目的共同開發人員加入進來,這樣開發者所在的組織的同僚可以協助開發者對LUIS應用進行開發、訓練和測試。在完成本書的寫作時,該功能還沒有加入一些特殊權限的管理,是以除了添加或移除别的共同開發者之外,所有加入的開發者都能對LUIS應用做任何操作(如圖3-44所示)。
3.11 拼寫檢查
拼寫檢查是內建在LUIS中的一個非常好的功能,它能自動修複使用者輸入中的拼寫錯誤。使用者的輸入往往非常多樣和雜亂,是以拼寫錯誤非常常見。
拼寫檢查通過在Bing的拼寫檢查器服務上運作使用者查詢,擷取可能更改的查詢并修複拼寫錯誤,并在LUIS上運作經過修複的查詢。該功能可以通過加入查詢參數spellCheck和bing-spell-check-subscription-key實作,其中subscription key(訂閱密鑰)可以在Azure Portal中擷取。我們将在第5章介紹Azure Portal,并在第10章使用LUIS的拼寫檢查API。
拼寫檢查非常有用,但開發者也需要注意,如果所開發的LUIS應用中包含具體領域的詞語、術語的實體,或者某些并不嚴格遵循英語規範的詞語,那麼LUIS處理的查詢中可能被替換過詞語,是以無法識别對應的實體。比如,LUIS可能将一個詞語分解成多個詞彙進行處理,這顯然不是我們想看到的。又比如,假設某個LUIS應用處理的是金融領域的内容,那麼LUIS應用可能會改變該領域中的一些術語,比如将VEA(Vanguard ETF)改成VA進行處理。而在美國,VA一般指的是弗吉尼亞州。很顯然,VEA和VA的含義差别非常大,是以建議謹慎合理地使用拼寫檢查功能。
拼寫檢查在LUIS的傳回結果中就能看到,也就是傳回結果中的alteredQuery域和query域是一起傳入到LUIS模型中的。一個典型的curl請求和JSON響應如下所示:
3.12 導入/導出LUIS應用
LUIS應用可以以JSON檔案的形式導出,同樣也可以将應用再導入到LUIS中。JSON檔案中既包括自定義的意圖、實體以及應用使用的預建實體,也包括短語清單。此外,被導出的LUIS應用中還包括大量的話語樣本以及在上面标注的意圖示簽、每個實體在話語中的起始位置。在LUIS的My Apps頁面點選Export App按鈕,或者在Settings頁面點選Export Version,即可完成LUIS應用的導出,如圖3-41所示。
雖然導出的應用程式的格式特定于LUIS,但我們可以用其他工具編寫代碼來解析LUIS應用中的資料。從代碼管理的角度來看,最好導出LUIS應用程式并将JSON檔案放到源代碼管理中,因為釋出操作是不可逆轉的。開發團隊如果遵循這種政策:在Production slot中釋出應用就表明建立了新的應用程式版本,那麼就不會有上述問題。
我們在工作中收到的最多的問題就是“為什麼不能将一個應用導入到一個已經存在的應用中?”。原因在于,這種需要智能合并的方式比較難以實作,特别是存在不同意圖或完全不同内涵的同名意圖的情況下。由于每個應用程式都有不同的語義,是以這種合并将是一項非常艱難的任務。我們建議使用Git來管理和合并應用程式JSON代碼,或使用LUIS Authoring API建立自定義代碼進行合并。
3.13 使用LUIS Authoring API
在談到LUIS及其相容性時,開發者時常會考慮這些功能能否通過API完成,答案是肯定的。LUIS的Authoring API(創作API)支援開發者通過使用API完成我們之前在UI(LUIS應用的網頁頁面)上所進行的所有任務。Authoring API主要包括以下内容:
- App:添加、管理、移除和釋出LUIS應用。
- Example:向某個版本的LUIS應用中上傳一些話語樣本。
- Feature:在某個版本的LUIS應用中添加、管理或者移除短語或模式。
- Model:添加、管理或移除自定義的意圖分類和實體抽取;添加/移除預建實體;添加/移除預建域。
- Permission:添加、管理和移除應用中的使用者。
- Train:排列用于訓練的應用版本,并擷取LUIS應用的訓練狀态。
- User:管理LUIS應用的訂閱密鑰以及外部的key。
- Version:添加和移除版本;将key與版本關聯;導出、導入和克隆某個版本的LUIS應用。
LUIS的API非常豐富,支援應用訓練、自定義的主動學習,還支援CI/CD類型的場景。API Reference Docs(API參考文檔)非常适合用于了解和學習LUIS Authoring API。
3.14 解決遇到的問題
我們一直專注于LUIS本身,以及通過将自定義意圖分類器和自定義實體抽取器與預建實體和預建域相結合來建立應用程式的過程。在這個過程中,我們發現機器學習模型有時性能并不好,這是因為我們一定會遇到一些奇怪的應用場景,在這些場景中意圖識别和實體抽取會很困難。我們在這裡列舉一些問題:
- 最容易遇見的問題之一是訓練完模型之後沒有釋出。在測試LUIS應用時一定要確定已将LUIS應用釋出到了Staging slot,并且確定在調用API時根據需要傳遞staging标志位。
- 如果某個意圖被錯誤地識别,則應為該意圖提供更多的話語樣本。如果問題持續存在,則應轉而分析意圖本身是各自獨立的意圖還是可以合并的意圖。此外,我們還要確定使用一些和我們所開發的LUIS應用無關的話語來訓練None意圖。測試資料非常适用于此目的。
- 如果應用在識别實體方面有困難,則應該檢查我們建立的實體。有些實體通常是意圖中同一位置的單字修飾符,就像我們的Visibility(可見性)實體那樣。另一方面,還有些更微妙的實體可以在話語中的任何位置(通常是某些詞語的字首或者字尾)。總體而言,實體識别遇到的問題主要可以通過以下幾種方法來解決:
- 添加更多的話語樣本,并且保證話語樣本之間具有表達上的變化和差異。
- 檢視實體是否應該設定成清單實體,可以通過兩個原則來确定:實體是不是一個查詢清單?LUIS應用在識别此類型的實體時是否需要具有一定的适應性,以适應該實體的多種變化?
- 考慮使用短語清單來顯示LUIS實體的外觀。
- 如果LUIS對某兩個實體識别較差,那麼檢查一下這兩個實體是否隻是由于上下文語境的原因而使得它們在表達上有一點差異。如果是這樣,則将它們設定為層次實體比較好。
- 如果使用者經常使用一些由多個實體組成的進階概念,則最好使用複合實體。
建立一個LUIS應用不僅需要開發技術,更需要調優,開發者可能需要花費大量時間在一些實體上進行優化。同時,請用統計學的觀點來看待這個過程,LUIS應用必須先使用大量的話語樣本進行訓練,繼而才能開始了解話語輸入。最後,無論是使用LUIS還是任何其他NLU系統,我們都應明白這一點:作為人,我們可能将智能和語言了解看得理所當然;但對一個應用程式而言,能夠快速地訓練出像LUIS這樣的語言了解應用已經很令人驚訝了。
3.15 結束語
經過本章的學習之後,我們已經具備了使用LUIS工具建立NLU模型的開發經驗。概括地說,本章主要是通過使用預建實體、自定義意圖和自定義實體來建立LUIS應用。我們對各種預建構的實體進行了探索和使用,并且嘗試使用了LUIS提供的預建域。我們學習了訓練LUIS應用、測試LUIS應用、将LUIS應用釋出到不同類型的slot以及使用curl測試LUIS應用中的API端點。我們還使用短語清單以及LUIS的主動學習功能來進一步提升模型的性能。本章最後部分,我們還學習了版本更新、合作開發、在LUIS應用中內建拼寫檢查、将LUIS應用導入和導出、使用Authoring API、通用問題定位(common troubleshooting)技術。
另外,需要重申的是,我們在本章學習的一切概念和技術在LUIS之外的其他NLU平台上同樣适用。無論是在機器人還是在語音助理中,訓練意圖和實體以及優化模型都是非常強大的技巧。下一步,我們該思考如何建立機器人,并且仍将使用LUIS,因為我們所開發的機器人中使用的工具就是LUIS。