理解語言
手繪筆記由 Nitya Narasimhan 提供。點擊圖片查看大圖。
課前測驗
簡介
在上一課中,你將語音轉換為文字。為了將其用於編程智能計時器,你的代碼需要理解所說的內容。你可以假設用戶會說固定的短語,例如「設置三分鐘計時器」,並解析該表達式以獲取計時器應設置的時間,但這對用戶來說並不友好。如果用戶說「設置計時器三分鐘」,你或我會理解他們的意思,但你的代碼不會,它會期望一個固定的短語。
這就是語言理解的作用,使用 AI 模型來解釋文本並返回所需的詳細信息,例如能夠理解「設置三分鐘計時器」和「設置計時器三分鐘」,並理解需要設置一個三分鐘的計時器。
在本課中,你將學習語言理解模型,如何創建它們、訓練它們以及如何從代碼中使用它們。
在本課中我們將涵蓋:
語言理解
人類已經使用語言進行交流數十萬年。我們用詞語、聲音或動作進行交流並理解所說的內容,不僅是詞語、聲音或動作的意思,還有它們的上下文。我們理解真誠和諷刺,允許相同的詞語根據我們的語氣表達不同的意思。
✅ 想一想你最近的一些對話。計算機理解這些對話有多困難,因為它需要上下文?
語言理解,也稱為自然語言理解,是人工智能領域的一部分,稱為自然語言處理(或 NLP),涉及閱讀理解,試圖理解詞語或句子的細節。如果你使用語音助手如 Alexa 或 Siri,你已經使用了語言理解服務。這些是將「Alexa,播放泰勒·斯威夫特的最新專輯」轉換為我女兒在客廳裡隨著她最喜歡的音樂跳舞的幕後 AI 服務。
💁 儘管計算機取得了很大的進步,但在真正理解文本方面仍有很長的路要走。當我們提到計算機的語言理解時,我們並不是指任何接近人類交流的東西,而是指提取關鍵細節的一些詞語。
作為人類,我們在不經意間理解語言。如果我要求另一個人「播放泰勒·斯威夫特的最新專輯」,他們會本能地知道我的意思。對於計算機來說,這更困難。它需要將詞語從語音轉換為文本,並找出以下信息:
- 需要播放音樂
- 音樂是由泰勒·斯威夫特演唱的
- 具體的音樂是一整張專輯,按順序播放多首曲目
- 泰勒·斯威夫特有很多專輯,所以需要按時間順序排序,最新發行的專輯是所需的
✅ 想一想你在提出請求時說過的一些其他句子,例如點咖啡或要求家人遞給你某物。試著將它們分解為計算機需要提取的信息片段,以理解句子。
語言理解模型是訓練從語言中提取某些細節的 AI 模型,然後使用遷移學習為特定任務進行訓練,就像你使用一小組圖像訓練自定義視覺模型一樣。你可以採用一個模型,然後使用你希望它理解的文本進行訓練。
創建語言理解模型
你可以使用 LUIS 創建語言理解模型,LUIS 是微軟的一項語言理解服務,屬於認知服務的一部分。
任務 - 創建一個創作資源
要使用 LUIS,你需要創建一個創作資源。
-
使用以下命令在你的
smart-timer
資源組中創建一個創作資源:az cognitiveservices account create --name smart-timer-luis-authoring \
--resource-group smart-timer \
--kind LUIS.Authoring \
--sku F0 \
--yes \
--location <location>將
<location>
替換為創建資源組時使用的位置。⚠️ LUIS 並非在所有地區都可用,因此如果你收到以下錯誤:
InvalidApiSetId: The account type 'LUIS.Authoring' is either invalid or unavailable in given region.
請選擇其他地區。
這將創建一個免費層的 LUIS 創作資源。
任務 - 創建一個語言理解應用
-
在瀏覽器中打開 LUIS 入口網站 luis.ai,並使用你一直在使用的 Azure 帳戶登錄。
-
按照對話框中的說明選擇你的 Azure 訂閱,然後選擇你剛剛創建的
smart-timer-luis-authoring
資源。 -
從 對話應用 列表中,選擇 新應用 按鈕創建一個新應用。將新應用命名為
smart-timer
,並將 文化 設置為你的語言。💁 有一個預測資源字段。你可以創建一個單獨的資源僅用於預測,但免費的創作資源每月允許 1,000 次預測,應該足夠開發使用,因此你可以將其留空。
-
閱讀創建應用後出現的指南,以了解訓練語言理解模型所需的步驟。完成後關閉此指南。
意圖和實體
語言理解基於 意圖 和 實體。意圖是詞語的意圖,例如播放音樂、設置計時器或訂購食物。實體是意圖所指的對象,例如專輯、計時器的時長或食物的種類。模型解釋的每個句子應至少有一個意圖,並且可以選擇性地有一個或多個實體。
一些例子:
句子 | 意圖 | 實體 |
---|---|---|
"播放泰勒·斯威夫特的最新專輯" | 播放音樂 | 泰勒·斯威夫特的最新專輯 |
"設置三分鐘計時器" | 設置計時器 | 三分鐘 |
"取消我的計時器" | 取消計時器 | 無 |
"訂購三個大號菠蘿披薩和一份凱撒沙拉" | 訂購食物 | 三個大號菠蘿披薩,凱撒沙拉 |
✅ 使用你之前想到的句子,該句子的意圖和任何實體是什麼?
要訓練 LUIS,首先你需要設置實體。這些可以是固定的術語列表,或從文本中學習。例如,你可以提供菜單中可用食物的固定列表,並提供每個詞語的變體(或同義詞),例如 egg plant 和 aubergine 作為 aubergine 的變體。LUIS 還有一些預構建的實體可以使用,例如數字和位置。
對於設置計時器,你可以有一個實體使用預構建的數字實體來表示時間,另一個實體表示單位,例如分鐘和秒。每個單位都有多個變體,以涵蓋單數和複數形式 - 例如 minute 和 minutes。
一旦定義了實體,你就可以創建意圖。這些是基於你提供的示例句子(稱為話語)由模型學習的。例如,對於 設置計時器 意圖,你可以提供以下句子:
設置一個一秒計時器
設置一個一分鐘十二秒的計時器
設置一個三分鐘計時器
設置一個九分鐘三十秒的計時器
然後你告訴 LUIS 這些句子的哪些部分對應於實體:
句子 設置一個一分鐘十二秒的計時器
的意圖是 設置計時器
。它還有 2 個實體,每個實體有 2 個值:
時間 | 單位 | |
---|---|---|
1 分鐘 | 1 | 分鐘 |
12 秒 | 12 | 秒 |
要訓練一個好的模型,你需要一系列不同的示例句子,以涵蓋人們可能要求同一件事的多種不同方式。
💁 與任何 AI 模型一樣,你用來訓練的數據越多且越準確,模型就越好。
✅ 想一想你可能會用不同的方式要求同一件事並期望人類理解。
任務 - 向語言理解模型添加實體
對於計時器,你需要添加 2 個實體 - 一個表示時間單位(分鐘或秒),一個表示分鐘或秒的數量。
你可以在 Microsoft docs 上的 LUIS 入口快速入門:在 LUIS 入口中構建應用文檔 中找到使用 LUIS 入口的說明。
-
從 LUIS 入口中,選擇 實體 標籤,並通過選擇 添加預構建實體 按鈕,然後從列表中選擇 number 來添加 number 預構建實體。
-
使用 創建 按鈕創建一個新的實體。將實體命名為
time unit
並將類型設置為 列表。將minute
和second
的值添加到 標準化值 列表中,並將單數和複數形式添加到 同義詞 列表中。每添加一個同義詞後按return
鍵將其添加到列表中。標準化值 同義詞 minute minute, minutes second second, seconds
任務 - 向語言理解模型添加意圖
-
從 意圖 標籤中,選擇 創建 按鈕創建一個新的意圖。將此意圖命名為
set timer
。 -
在示例中,輸入使用分鐘、秒以及分鐘和秒組合設置計時器的不同方式。示例可以是:
設置一個一秒計時器
設置一個四分鐘計時器
設置一個四分鐘六秒計時器
設置一個九分鐘三十秒計時器
設置一個一分鐘十二秒的計時器
設置一個三分鐘計時器
設置一個三分鐘一秒的計時器
設置一個三分鐘一秒的計時器
設置一個一分鐘一秒的計時器
設置一個三十秒的計時器
設置一個一秒的計時器
混合使用數字和文字,以便模型學會處理兩者。
-
當你輸入每個示例時,LUIS 會開始檢測實體,並會下劃線並標記它找到的任何實體。
任務 - 訓練和測試模型
-
配置好實體和意圖後,你可以使用頂部菜單中的 訓練 按鈕訓練模型。選擇此按鈕,模型應在幾秒鐘內訓練完成。訓練期間按鈕會變灰,完成後會重新啟用。
-
從頂部菜單中選擇 測試 按鈕以測試語言理解模型。輸入
設置一個五分鐘四秒的計時器
並按回車鍵。句子將出現在你輸入文本框下方的框中,並在其下方顯示 頂部意圖,即以最高概率檢測到的意圖。這應該是set timer
。意圖名稱後面會跟隨檢測到的意圖的概率。 -
選擇 檢查 選項以查看結果的詳細信息。你將看到最高得分的意圖及其概率百分比,以及檢測到的實體列表。
-
測試完成後關閉 測試 窗格。
任務 - 發佈模型
要從代碼中使用此模型,你需要發佈它。從 LUIS 發佈時,你可以發佈到測試環境或產品環境。在本課中,測試環境就足夠了。
-
從 LUIS 入口中,選擇頂部菜單中的 發佈 按鈕。
-
確保選擇 測試槽,然後選擇 完成。應用發佈後你會看到通知。
-
你可以使用 curl 測試此功能。要構建 curl 命令,你需要三個值 - 端點、應用 ID(App ID)和 API 密鑰。這些可以從頂部菜單中選擇的 管理 標籤中訪問。
-
從 設置 部分複製 App ID
-
從 Azure 資源 部分選擇 創作資源,並複製 主密鑰 和 端點 URL
-
-
在命令提示符或終端中運行以下 curl 命令:
curl "<endpoint url>/luis/prediction/v3.0/apps/<app id>/slots/staging/predict" \
--request GET \
--get \
--data "subscription-key=<primary key>" \
--data "verbose=false" \
--data "show-all-intents=true" \
--data-urlencode "query=<sentence>"將
<endpoint url>
替換為 Azure 資源 部分的端點 URL。將
<app id>
替換為 設置 部分的 App ID。將
<primary key>
替換為 Azure 資源 部分的主密鑰。將
<sentence>
替換為你要測試的句子。 -
此調用的輸出將是一個 JSON 文檔,詳細說明查詢、頂部意圖和按類型分解的實體列表。
{
"query": "設置一個四十五分鐘十二秒的計時器",
"prediction": {
"topIntent": "set timer",
"intents": {
"set timer": {
"score": 0.97031575
},
"None": {
"score": 0.02205793
}
},
"entities": {
"number": [
45,
12
],
"time-unit": [
[
"minute"
],
[
"second"
]
]
}
}
}上面的 JSON 來自查詢
設置一個四十五分鐘十二秒的計時器
:set timer
是頂部意圖,概率為 97%。- 檢測到兩個 number 實體,分別是
45
和12
。 - 檢測到兩個 time-unit 實體,分別是
minute
和second
。
使用語言理解模型
一旦發佈,LUIS 模型可以從代碼中調用。在之前的課程中,你使用了 IoT 中心來處理與雲服務的通信,發送遙測數據並監聽命令。這是非常異步的 - 一旦發送遙測數據,你的代碼不會等待響應,如果雲服務宕機,你也不會知道。
對於智能計時器,我們希望立即獲得響應,以便我們可以告訴用戶計時器已設置,或提醒他們雲服務不可用。為此,我們的 IoT 設備將直接調用 Web 端點,而不是依賴 IoT 中心。
與其從 IoT 設備調用 LUIS,你可以使用具有不同觸發類型的無服務器代碼 - HTTP 觸發器。這允許你的函數應用監聽 REST 請求並對其進行響應。此函數將是一個 REST 端點,你的設備可以調用。
💁 雖然你可以直接從 IoT 設備調用 LUIS,但最好使用無服務器代碼。這樣當你想更改調用的 LUIS 應用時,例如當你訓練了一個更好的模型或用不同的語言訓練模型時,你只需更新雲代碼,而不需要重新部署代碼到可能成千上萬或數百萬的 IoT 設備。
任務 - 創建無服務器函數應用
-
創建一個名為
smart-timer-trigger
的 Azure 函數應用,並在 VS Code 中打開它 -
使用以下命令從 VS Code 終端內添加一個名為
speech-trigger
的 HTTP 觸發器:func new --name text-to-timer --template "HTTP trigger"
這將創建一個名為
text-to-timer
的 HTTP 觸發器。 -
通過運行函數應用測試 HTTP 觸發器。運行時,你將在輸出中看到列出的端點:
Functions:
text-to-timer: [GET,POST] http://localhost:7071/api/text-to-timer通過在瀏覽器中加載 http://localhost:7071/api/text-to-timer URL 來測試此功能。
This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.
任務 - 使用語言理解模型
-
LUIS 的 SDK 可通過 Pip 包獲得。將以下行添加到
requirements.txt
文件中以添加對此包的依賴:azure-cognitiveservices-language-luis
-
確保 VS Code 終端已激活虛擬環境,並運行以下命令以安裝 Pip 包:
pip install -r requirements.txt
💁 如果遇到錯誤,可能需要使用以下命令升級 pip:
pip install --upgrade pip
-
將 LUIS API 密鑰、端點 URL 和 App ID 的新條目添加到
local.settings.json
文件中,這些值來自 LUIS 入口的 管理 標籤:"LUIS_KEY": "<primary key>",
"LUIS_ENDPOINT_URL": "<endpoint url>",
"LUIS_APP_ID": "<app id>"將
<endpoint url>
替換為 Azure 資源 部分的端點 URL。這將是https://<location>.api.cognitive.microsoft.com/
。將
<app id>
替換為 設置 部分的 App ID。將
<primary key>
替換為 Azure 資源 部分的主密鑰。 -
將以下導入添加到
__init__.py
文件中:import json
import os
from azure.cognitiveservices.language.luis.runtime import LUISRuntimeClient
from msrest.authentication import CognitiveServicesCredentials這將導入一些系統庫以及與 LUIS 交互的庫。
-
刪除
main
方法的內容,並添加以下代碼:luis_key = os.environ['LUIS_KEY']
endpoint_url = os.environ['LUIS_ENDPOINT_URL']
app_id = os.environ['LUIS_APP_ID']
credentials = CognitiveServicesCredentials(luis_key)
client = LUISRuntimeClient(endpoint=endpoint_url, credentials=credentials)這將加載你在
local.settings.json
文件中添加的 LUIS 應用的值,使用你的 API 密鑰創建一個憑據對象,然後創建一個 LUIS 客戶端對象以與你的 LUIS 應用交互。 -
此 HTTP 觸發器將以 JSON 格式傳遞要理解的文本,文本位於名為
text
的屬性中。以下代碼從 HTTP 請求的正文中提取該值,並將其記錄到控制台。將此代碼添加到main
函數中:req_body = req.get_json()
text = req_body['text']
logging.info(f'Request - {text}') -
通過發送預測請求來請求 LUIS 的預測 - 包含要預測的文本的 JSON 文檔。使用以下代碼創建此請求:
prediction_request = { 'query' : text }
-
然後可以使用發佈到的測試槽將此請求發送到 LUIS:
prediction_response = client.prediction.get_slot_prediction(app_id, 'Staging', prediction_request)
-
預測響應包含頂部意圖 - 具有最高預測分數的意圖,以及實體。如果頂部意圖是
set timer
,則可以讀取實體以獲取計時器所需的時間:if prediction_response.prediction.top_intent == 'set timer':
numbers = prediction_response.prediction.entities['number']
time_units = prediction_response.prediction.entities['time unit']
total_seconds = 0number
實體將是一個數字數組。例如,如果你說 "設置一個四分鐘十七秒的計時器。",則number
數組將包含 2 個整數 - 4 和 17。time unit
實體將是一個字符串數組的數組,每個時間單位作為數組中的字符串數組。例如,如果你說 "設置一個四分鐘十七秒的計時器。",則time unit
數組將包含 2 個單值數組 -['minute']
和['second']
。這些實體的 JSON 版本為 "設置一個四分鐘十七秒的計時器。" 是:
{
"number": [4, 17],
"time unit": [
["minute"],
["second"]
]
}此代碼還定義了計時器總時間(以秒為單位)的計數。這將由實體的值填充。
-
實體不是鏈接的,但我們可以對它們做一些假設。它們將按說話的順序排列,因此可以使用數組中的位置來確定哪個數字與哪個時間單位匹配。例如:
- "設置一個三十秒的計時器" - 這將有一個數字,
30
,和一個時間單位,second
,因此單個數字將匹配單個時間單位。 - "設置一個兩分鐘三十秒的計時器" - 這將有兩個數字,
2
和30
,以及兩個時間單位,minute
和second
,因此第一個數字將對應於第一個時間單位(2 分鐘),第二個數字對應於第二個時間單位(30 秒)。
以下代碼獲取數字實體中的項目數,並使用該數來提取每個數組中的第一個項目,然後是第二個,依此類推。將此代碼添加到
if
塊內。for i in range(0, len(numbers)):
number = numbers[i]
time_unit = time_units[i][0]對於 "設置一個四分鐘十七秒的計時器。",這將循環兩次,給出以下值:
循環次數 number
time_unit
0 4 minute 1 17 second - "設置一個三十秒的計時器" - 這將有一個數字,
-
在此循環內,使用數字和時間單位計算計時器的總時間,為每分鐘添加 60 秒,並為任何秒數添加秒數。
if time_unit == 'minute':
total_seconds += number * 60
else:
total_seconds += number -
在此循環實體之外,記錄計時器的總時間:
logging.info(f'Timer required for {total_seconds} seconds')
-
需要將秒數返回為 HTTP 響應。在
if
塊的末尾,添加以下代碼:payload = {
'seconds': total_seconds
}
return func.HttpResponse(json.dumps(payload), status_code=200)此代碼創建一個包含計時器總秒數的有效負載,將其轉換為 JSON 字符串並作為 HTTP 結果返回,狀態碼為 200,表示調用成功。
-
最後,在
if
塊之外,處理未識別意圖的情況,返回錯誤代碼:return func.HttpResponse(status_code=404)
404 是 未找到 的狀態碼。
-
運行函數應用並使用 curl 測試它。
curl --request POST 'http://localhost:7071/api/text-to-timer' \
--header 'Content-Type: application/json' \
--include \
--data '{"text":"<text>"}'將
<text>
替換為你的請求文本,例如設置一個兩分鐘二十七秒的計時器
。你將在函數應用中看到以下輸出:
Functions:
text-to-timer: [GET,POST] http://localhost:7071/api/text-to-timer
For detailed output, run func with --verbose flag.
[2021-06-26T19:45:14.502Z] Worker process started and initialized.
[2021-06-26T19:45:19.338Z] Host lock lease acquired by instance ID '000000000000000000000000951CAE4E'.
[2021-06-26T19:45:52.059Z] Executing 'Functions.text-to-timer' (Reason='This function was programmatically called via the host APIs.', Id=f68bfb90-30e4-47a5-99da-126b66218e81)
[2021-06-26T19:45:53.577Z] Timer required for 147 seconds
[2021-06-26T19:45:53.746Z] Executed 'Functions.text-to-timer' (Succeeded, Id=f68bfb90-30e4-47a5-99da-126b66218e81, Duration=1750ms)curl 的調用將返回以下內容:
HTTP/1.1 200 OK
Date: Tue, 29 Jun 2021 01:14:11 GMT
Content-Type: text/plain; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
{"seconds": 147}計時器的秒數在
"seconds"
值中。
💁 你可以在 code/functions 文件夾中找到此代碼。
任務 - 使你的函數可供你的 IoT 設備使用
-
要讓你的 IoT 設備調用你的 REST 端點,它需要知道 URL。當你之前訪問它時,你使用了
localhost
,這是一個訪問本地機器上 REST 端點的快捷方式。要讓你的 IoT 設備獲得訪問權限,你需要將其發佈到雲端,或者獲取你的 IP 地址以本地訪問。⚠️ 如果你使用的是 Wio Terminal,運行函數應用本地會更容易,因為會有依賴庫,這意味著你不能像以前那樣部署函數應用。運行本地函數應用並通過你的計算機 IP 地址訪問它。如果你確實想部署到雲端,後續課程中將提供相關信息。
-
發佈函數應用 - 按照之前課程中的說明將你的函數應用發佈到雲端。發佈後,URL 將是
https://<APP_NAME>.azurewebsites.net/api/text-to-timer
,其中<APP_NAME>
是你的函數應用的名稱。確保也發佈你的本地設置。在處理 HTTP 觸發器時,它們默認由函數應用密鑰保護。要獲取此密鑰,運行以下命令:
az functionapp keys list --resource-group smart-timer \
--name <APP_NAME>從
functionKeys
部分複製default
條目的值。{
"functionKeys": {
"default": "sQO1LQaeK9N1qYD6SXeb/TctCmwQEkToLJU6Dw8TthNeUH8VA45hlA=="
},
"masterKey": "RSKOAIlyvvQEQt9dfpabJT018scaLpQu9p1poHIMCxx5LYrIQZyQ/g==",
"systemKeys": {}
}此密鑰需要作為查詢參數添加到 URL 中,因此最終的 URL 將是
https://<APP_NAME>.azurewebsites.net/api/text-to-timer?code=<FUNCTION_KEY>
,其中<APP_NAME>
是你的函數應用的名稱,<FUNCTION_KEY>
是你的默認函數密鑰。💁 你可以使用
authlevel
設置在function.json
文件中更改 HTTP 觸發器的授權類型。你可以在 Microsoft docs 上的 Azure 函數 HTTP 觸發器文檔的配置部分 中閱讀更多相關信息。 -
本地運行函數應用,並使用 IP 地址訪問 - 你可以獲取計算機在本地網絡上的 IP 地址,並使用該地址構建 URL。
查找你的 IP 地址:
- 在 Windows 10 上,請參考 查找你的 IP 地址指南
- 在 macOS 上,請參考 如何在 Mac 上查找 IP 地址指南
- 在 Linux 上,請參考 如何在 Linux 中查找 IP 地址指南 中的查找私有 IP 地址部分
獲取 IP 地址後,你將能夠在
http://<IP_ADDRESS>:7071/api/text-to-timer
訪問函數,其中<IP_ADDRESS>
是你的 IP 地址,例如http://192.168.1.10:7071/api/text-to-timer
。💁 請注意這使用端口 7071,因此在 IP 地址後需要有
:7071
。💁 這僅在你的 IoT 設備與你的計算機在同一網絡上時有效。
-
-
通過使用 curl 訪問端點進行測試。
🚀 挑戰
有很多方法可以請求同一件事,例如設置計時器。想出不同的方法來做到這一點,並將它們作為示例添加到你的 LUIS 應用中。測試這些方法,看看你的模型能夠應對多種請求計時器的方式。
課後測驗
回顧與自學
- 在 Microsoft docs 上的語言理解 (LUIS) 文檔頁面 閱讀更多關於 LUIS 及其功能的內容
- 在 維基百科上的自然語言理解頁面 閱讀更多關於語言理解的內容
- 在 Microsoft docs 上的 Azure 函數 HTTP 觸發器文檔 中閱讀更多關於 HTTP 觸發器的內容