跳至主要内容

理解語言

本課程的手繪筆記概述

手繪筆記由 Nitya Narasimhan 提供。點擊圖片查看大圖。

課前測驗

課前測驗

簡介

在上一課中,你將語音轉換為文字。為了將其用於編程智能計時器,你的代碼需要理解所說的內容。你可以假設用戶會說固定的短語,例如「設置三分鐘計時器」,並解析該表達式以獲取計時器應設置的時間,但這對用戶來說並不友好。如果用戶說「設置計時器三分鐘」,你或我會理解他們的意思,但你的代碼不會,它會期望一個固定的短語。

這就是語言理解的作用,使用 AI 模型來解釋文本並返回所需的詳細信息,例如能夠理解「設置三分鐘計時器」和「設置計時器三分鐘」,並理解需要設置一個三分鐘的計時器。

在本課中,你將學習語言理解模型,如何創建它們、訓練它們以及如何從代碼中使用它們。

在本課中我們將涵蓋:

語言理解

人類已經使用語言進行交流數十萬年。我們用詞語、聲音或動作進行交流並理解所說的內容,不僅是詞語、聲音或動作的意思,還有它們的上下文。我們理解真誠和諷刺,允許相同的詞語根據我們的語氣表達不同的意思。

✅ 想一想你最近的一些對話。計算機理解這些對話有多困難,因為它需要上下文?

語言理解,也稱為自然語言理解,是人工智能領域的一部分,稱為自然語言處理(或 NLP),涉及閱讀理解,試圖理解詞語或句子的細節。如果你使用語音助手如 Alexa 或 Siri,你已經使用了語言理解服務。這些是將「Alexa,播放泰勒·斯威夫特的最新專輯」轉換為我女兒在客廳裡隨著她最喜歡的音樂跳舞的幕後 AI 服務。

💁 儘管計算機取得了很大的進步,但在真正理解文本方面仍有很長的路要走。當我們提到計算機的語言理解時,我們並不是指任何接近人類交流的東西,而是指提取關鍵細節的一些詞語。

作為人類,我們在不經意間理解語言。如果我要求另一個人「播放泰勒·斯威夫特的最新專輯」,他們會本能地知道我的意思。對於計算機來說,這更困難。它需要將詞語從語音轉換為文本,並找出以下信息:

  • 需要播放音樂
  • 音樂是由泰勒·斯威夫特演唱的
  • 具體的音樂是一整張專輯,按順序播放多首曲目
  • 泰勒·斯威夫特有很多專輯,所以需要按時間順序排序,最新發行的專輯是所需的

✅ 想一想你在提出請求時說過的一些其他句子,例如點咖啡或要求家人遞給你某物。試著將它們分解為計算機需要提取的信息片段,以理解句子。

語言理解模型是訓練從語言中提取某些細節的 AI 模型,然後使用遷移學習為特定任務進行訓練,就像你使用一小組圖像訓練自定義視覺模型一樣。你可以採用一個模型,然後使用你希望它理解的文本進行訓練。

創建語言理解模型

LUIS 標誌

你可以使用 LUIS 創建語言理解模型,LUIS 是微軟的一項語言理解服務,屬於認知服務的一部分。

任務 - 創建一個創作資源

要使用 LUIS,你需要創建一個創作資源。

  1. 使用以下命令在你的 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 創作資源。

任務 - 創建一個語言理解應用

  1. 在瀏覽器中打開 LUIS 入口網站 luis.ai,並使用你一直在使用的 Azure 帳戶登錄。

  2. 按照對話框中的說明選擇你的 Azure 訂閱,然後選擇你剛剛創建的 smart-timer-luis-authoring 資源。

  3. 對話應用 列表中,選擇 新應用 按鈕創建一個新應用。將新應用命名為 smart-timer,並將 文化 設置為你的語言。

    💁 有一個預測資源字段。你可以創建一個單獨的資源僅用於預測,但免費的創作資源每月允許 1,000 次預測,應該足夠開發使用,因此你可以將其留空。

  4. 閱讀創建應用後出現的指南,以了解訓練語言理解模型所需的步驟。完成後關閉此指南。

意圖和實體

語言理解基於 意圖實體。意圖是詞語的意圖,例如播放音樂、設置計時器或訂購食物。實體是意圖所指的對象,例如專輯、計時器的時長或食物的種類。模型解釋的每個句子應至少有一個意圖,並且可以選擇性地有一個或多個實體。

一些例子:

句子意圖實體
"播放泰勒·斯威夫特的最新專輯"播放音樂泰勒·斯威夫特的最新專輯
"設置三分鐘計時器"設置計時器三分鐘
"取消我的計時器"取消計時器
"訂購三個大號菠蘿披薩和一份凱撒沙拉"訂購食物三個大號菠蘿披薩凱撒沙拉

✅ 使用你之前想到的句子,該句子的意圖和任何實體是什麼?

要訓練 LUIS,首先你需要設置實體。這些可以是固定的術語列表,或從文本中學習。例如,你可以提供菜單中可用食物的固定列表,並提供每個詞語的變體(或同義詞),例如 egg plantaubergine 作為 aubergine 的變體。LUIS 還有一些預構建的實體可以使用,例如數字和位置。

對於設置計時器,你可以有一個實體使用預構建的數字實體來表示時間,另一個實體表示單位,例如分鐘和秒。每個單位都有多個變體,以涵蓋單數和複數形式 - 例如 minute 和 minutes。

一旦定義了實體,你就可以創建意圖。這些是基於你提供的示例句子(稱為話語)由模型學習的。例如,對於 設置計時器 意圖,你可以提供以下句子:

  • 設置一個一秒計時器
  • 設置一個一分鐘十二秒的計時器
  • 設置一個三分鐘計時器
  • 設置一個九分鐘三十秒的計時器

然後你告訴 LUIS 這些句子的哪些部分對應於實體:

句子設置一個一分鐘十二秒的計時器分解為實體

句子 設置一個一分鐘十二秒的計時器 的意圖是 設置計時器。它還有 2 個實體,每個實體有 2 個值:

時間單位
1 分鐘1分鐘
12 秒12

要訓練一個好的模型,你需要一系列不同的示例句子,以涵蓋人們可能要求同一件事的多種不同方式。

💁 與任何 AI 模型一樣,你用來訓練的數據越多且越準確,模型就越好。

✅ 想一想你可能會用不同的方式要求同一件事並期望人類理解。

任務 - 向語言理解模型添加實體

對於計時器,你需要添加 2 個實體 - 一個表示時間單位(分鐘或秒),一個表示分鐘或秒的數量。

你可以在 Microsoft docs 上的 LUIS 入口快速入門:在 LUIS 入口中構建應用文檔 中找到使用 LUIS 入口的說明。

  1. 從 LUIS 入口中,選擇 實體 標籤,並通過選擇 添加預構建實體 按鈕,然後從列表中選擇 number 來添加 number 預構建實體。

  2. 使用 創建 按鈕創建一個新的實體。將實體命名為 time unit 並將類型設置為 列表。將 minutesecond 的值添加到 標準化值 列表中,並將單數和複數形式添加到 同義詞 列表中。每添加一個同義詞後按 return 鍵將其添加到列表中。

    標準化值同義詞
    minuteminute, minutes
    secondsecond, seconds

任務 - 向語言理解模型添加意圖

  1. 意圖 標籤中,選擇 創建 按鈕創建一個新的意圖。將此意圖命名為 set timer

  2. 在示例中,輸入使用分鐘、秒以及分鐘和秒組合設置計時器的不同方式。示例可以是:

    • 設置一個一秒計時器
    • 設置一個四分鐘計時器
    • 設置一個四分鐘六秒計時器
    • 設置一個九分鐘三十秒計時器
    • 設置一個一分鐘十二秒的計時器
    • 設置一個三分鐘計時器
    • 設置一個三分鐘一秒的計時器
    • 設置一個三分鐘一秒的計時器
    • 設置一個一分鐘一秒的計時器
    • 設置一個三十秒的計時器
    • 設置一個一秒的計時器

    混合使用數字和文字,以便模型學會處理兩者。

  3. 當你輸入每個示例時,LUIS 會開始檢測實體,並會下劃線並標記它找到的任何實體。

    示例中數字和時間單位被 LUIS 下劃線

任務 - 訓練和測試模型

  1. 配置好實體和意圖後,你可以使用頂部菜單中的 訓練 按鈕訓練模型。選擇此按鈕,模型應在幾秒鐘內訓練完成。訓練期間按鈕會變灰,完成後會重新啟用。

  2. 從頂部菜單中選擇 測試 按鈕以測試語言理解模型。輸入 設置一個五分鐘四秒的計時器 並按回車鍵。句子將出現在你輸入文本框下方的框中,並在其下方顯示 頂部意圖,即以最高概率檢測到的意圖。這應該是 set timer。意圖名稱後面會跟隨檢測到的意圖的概率。

  3. 選擇 檢查 選項以查看結果的詳細信息。你將看到最高得分的意圖及其概率百分比,以及檢測到的實體列表。

  4. 測試完成後關閉 測試 窗格。

任務 - 發佈模型

要從代碼中使用此模型,你需要發佈它。從 LUIS 發佈時,你可以發佈到測試環境或產品環境。在本課中,測試環境就足夠了。

  1. 從 LUIS 入口中,選擇頂部菜單中的 發佈 按鈕。

  2. 確保選擇 測試槽,然後選擇 完成。應用發佈後你會看到通知。

  3. 你可以使用 curl 測試此功能。要構建 curl 命令,你需要三個值 - 端點、應用 ID(App ID)和 API 密鑰。這些可以從頂部菜單中選擇的 管理 標籤中訪問。

    1. 設置 部分複製 App ID

    2. Azure 資源 部分選擇 創作資源,並複製 主密鑰端點 URL

  4. 在命令提示符或終端中運行以下 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> 替換為你要測試的句子。

  5. 此調用的輸出將是一個 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 實體,分別是 4512
    • 檢測到兩個 time-unit 實體,分別是 minutesecond

使用語言理解模型

一旦發佈,LUIS 模型可以從代碼中調用。在之前的課程中,你使用了 IoT 中心來處理與雲服務的通信,發送遙測數據並監聽命令。這是非常異步的 - 一旦發送遙測數據,你的代碼不會等待響應,如果雲服務宕機,你也不會知道。

對於智能計時器,我們希望立即獲得響應,以便我們可以告訴用戶計時器已設置,或提醒他們雲服務不可用。為此,我們的 IoT 設備將直接調用 Web 端點,而不是依賴 IoT 中心。

與其從 IoT 設備調用 LUIS,你可以使用具有不同觸發類型的無服務器代碼 - HTTP 觸發器。這允許你的函數應用監聽 REST 請求並對其進行響應。此函數將是一個 REST 端點,你的設備可以調用。

💁 雖然你可以直接從 IoT 設備調用 LUIS,但最好使用無服務器代碼。這樣當你想更改調用的 LUIS 應用時,例如當你訓練了一個更好的模型或用不同的語言訓練模型時,你只需更新雲代碼,而不需要重新部署代碼到可能成千上萬或數百萬的 IoT 設備。

任務 - 創建無服務器函數應用

  1. 創建一個名為 smart-timer-trigger 的 Azure 函數應用,並在 VS Code 中打開它

  2. 使用以下命令從 VS Code 終端內添加一個名為 speech-trigger 的 HTTP 觸發器:

    func new --name text-to-timer --template "HTTP trigger"

    這將創建一個名為 text-to-timer 的 HTTP 觸發器。

  3. 通過運行函數應用測試 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.

任務 - 使用語言理解模型

  1. LUIS 的 SDK 可通過 Pip 包獲得。將以下行添加到 requirements.txt 文件中以添加對此包的依賴:

    azure-cognitiveservices-language-luis
  2. 確保 VS Code 終端已激活虛擬環境,並運行以下命令以安裝 Pip 包:

    pip install -r requirements.txt

    💁 如果遇到錯誤,可能需要使用以下命令升級 pip:

    pip install --upgrade pip
  3. 將 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 資源 部分的主密鑰。

  4. 將以下導入添加到 __init__.py 文件中:

    import json
    import os
    from azure.cognitiveservices.language.luis.runtime import LUISRuntimeClient
    from msrest.authentication import CognitiveServicesCredentials

    這將導入一些系統庫以及與 LUIS 交互的庫。

  5. 刪除 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 應用交互。

  6. 此 HTTP 觸發器將以 JSON 格式傳遞要理解的文本,文本位於名為 text 的屬性中。以下代碼從 HTTP 請求的正文中提取該值,並將其記錄到控制台。將此代碼添加到 main 函數中:

    req_body = req.get_json()
    text = req_body['text']
    logging.info(f'Request - {text}')
  7. 通過發送預測請求來請求 LUIS 的預測 - 包含要預測的文本的 JSON 文檔。使用以下代碼創建此請求:

    prediction_request = { 'query' : text }
  8. 然後可以使用發佈到的測試槽將此請求發送到 LUIS:

    prediction_response = client.prediction.get_slot_prediction(app_id, 'Staging', prediction_request)
  9. 預測響應包含頂部意圖 - 具有最高預測分數的意圖,以及實體。如果頂部意圖是 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 = 0

    number 實體將是一個數字數組。例如,如果你說 "設置一個四分鐘十七秒的計時器。",則 number 數組將包含 2 個整數 - 4 和 17。

    time unit 實體將是一個字符串數組的數組,每個時間單位作為數組中的字符串數組。例如,如果你說 "設置一個四分鐘十七秒的計時器。",則 time unit 數組將包含 2 個單值數組 - ['minute']['second']

    這些實體的 JSON 版本為 "設置一個四分鐘十七秒的計時器。" 是:

    {
    "number": [4, 17],
    "time unit": [
    ["minute"],
    ["second"]
    ]
    }

    此代碼還定義了計時器總時間(以秒為單位)的計數。這將由實體的值填充。

  10. 實體不是鏈接的,但我們可以對它們做一些假設。它們將按說話的順序排列,因此可以使用數組中的位置來確定哪個數字與哪個時間單位匹配。例如:

    • "設置一個三十秒的計時器" - 這將有一個數字,30,和一個時間單位,second,因此單個數字將匹配單個時間單位。
    • "設置一個兩分鐘三十秒的計時器" - 這將有兩個數字,230,以及兩個時間單位,minutesecond,因此第一個數字將對應於第一個時間單位(2 分鐘),第二個數字對應於第二個時間單位(30 秒)。

    以下代碼獲取數字實體中的項目數,並使用該數來提取每個數組中的第一個項目,然後是第二個,依此類推。將此代碼添加到 if 塊內。

    for i in range(0, len(numbers)):
    number = numbers[i]
    time_unit = time_units[i][0]

    對於 "設置一個四分鐘十七秒的計時器。",這將循環兩次,給出以下值:

    循環次數numbertime_unit
    04minute
    117second
  11. 在此循環內,使用數字和時間單位計算計時器的總時間,為每分鐘添加 60 秒,並為任何秒數添加秒數。

    if time_unit == 'minute':
    total_seconds += number * 60
    else:
    total_seconds += number
  12. 在此循環實體之外,記錄計時器的總時間:

    logging.info(f'Timer required for {total_seconds} seconds')
  13. 需要將秒數返回為 HTTP 響應。在 if 塊的末尾,添加以下代碼:

    payload = {
    'seconds': total_seconds
    }
    return func.HttpResponse(json.dumps(payload), status_code=200)

    此代碼創建一個包含計時器總秒數的有效負載,將其轉換為 JSON 字符串並作為 HTTP 結果返回,狀態碼為 200,表示調用成功。

  14. 最後,在 if 塊之外,處理未識別意圖的情況,返回錯誤代碼:

    return func.HttpResponse(status_code=404)

    404 是 未找到 的狀態碼。

  15. 運行函數應用並使用 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 設備使用

  1. 要讓你的 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 地址:

      獲取 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 設備與你的計算機在同一網絡上時有效。

  2. 通過使用 curl 訪問端點進行測試。


🚀 挑戰

有很多方法可以請求同一件事,例如設置計時器。想出不同的方法來做到這一點,並將它們作為示例添加到你的 LUIS 應用中。測試這些方法,看看你的模型能夠應對多種請求計時器的方式。

課後測驗

課後測驗

回顧與自學

作業

取消計時器