You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
IoT-For-Beginners/translations/zh/6-consumer/lessons/2-language-understanding/README.md

28 KiB

理解语言

本课的手绘笔记概览

手绘笔记由 Nitya Narasimhan 提供。点击图片查看更大版本。

课前测验

课前测验

简介

在上一课中你将语音转换为文本。为了将其用于编写智能计时器程序你的代码需要理解所说的内容。你可以假设用户会说固定短语例如“设置一个3分钟的计时器”并解析该表达式以确定计时器的时长但这对用户来说并不友好。如果用户说“设置一个计时器时间为3分钟”你或我可以理解他们的意思但你的代码却无法理解因为它期待的是固定短语。

这就是语言理解的作用所在它使用AI模型来解释文本并返回所需的细节。例如它可以同时理解“设置一个3分钟的计时器”和“设置一个计时器时间为3分钟”并知道需要设置一个3分钟的计时器。

在本课中,你将学习语言理解模型,如何创建、训练它们,以及如何在代码中使用它们。

本课内容包括:

语言理解

人类已经使用语言进行交流数十万年。我们通过词语、声音或动作进行交流,并理解所说的内容,包括词语、声音或动作的含义以及它们的上下文。我们能够理解真诚和讽刺,使得相同的词语在不同的语气下表达不同的意思。

想一想你最近的一些对话。哪些部分的对话对计算机来说可能很难理解,因为它需要上下文?

语言理解也称为自然语言理解是人工智能领域的一部分属于自然语言处理NLP。它涉及阅读理解试图理解词语或句子的细节。如果你使用过语音助手例如Alexa或Siri那么你已经使用过语言理解服务。这些服务是幕后AI服务将“Alexa播放Taylor Swift的最新专辑”转换为我女儿在客厅里随着她最喜欢的音乐跳舞。

💁 尽管计算机取得了许多进步,但它们在真正理解文本方面仍有很长的路要走。当我们提到计算机的语言理解时,并不是指任何接近人类交流的高级能力,而是指从一些词语中提取关键细节。

作为人类我们无需思考就能理解语言。如果我让另一个人“播放Taylor Swift的最新专辑”他们会本能地知道我的意思。对于计算机来说这就困难得多。它需要将词语从语音转换为文本并解析以下信息

  • 需要播放音乐
  • 音乐是由艺术家Taylor Swift创作的
  • 具体的音乐是一整张专辑,包含多首按顺序排列的曲目
  • Taylor Swift有许多专辑因此需要按时间顺序排序最新发布的专辑是所需的

想一想你在提出请求时说过的一些句子,例如点咖啡或让家人递给你某样东西。试着将这些句子分解为计算机需要提取的信息。

语言理解模型是AI模型旨在从语言中提取特定细节然后通过迁移学习针对特定任务进行训练就像你使用一小组图像训练自定义视觉模型一样。你可以使用一个模型然后通过你希望它理解的文本对其进行训练。

创建语言理解模型

LUIS标志

你可以使用LUISLanguage Understanding Intelligent Service创建语言理解模型这是微软认知服务的一部分。

任务 - 创建一个创作资源

要使用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,并将文化设置为你的语言。

    💁 有一个预测资源字段。你可以创建一个单独的资源用于预测但免费创作资源每月允许1000次预测足够开发使用因此可以留空。

  4. 阅读创建应用后出现的指南,了解训练语言理解模型所需的步骤。完成后关闭该指南。

意图和实体

语言理解基于意图实体。意图是词语的目的,例如播放音乐、设置计时器或点餐。实体是意图所指的内容,例如专辑、计时器的时长或食物类型。模型解释的每个句子至少应有一个意图,并可选地包含一个或多个实体。

一些示例:

句子 意图 实体
“播放Taylor Swift的最新专辑” 播放音乐 Taylor Swift的最新专辑
“设置一个3分钟的计时器” 设置计时器 3分钟
“取消我的计时器” 取消计时器
“点3个大号菠萝披萨和一个凯撒沙拉” 点餐 3个大号菠萝披萨凯撒沙拉

回想你之前想到的句子,这些句子的意图和实体是什么?

要训练LUIS首先需要设置实体。这些实体可以是固定术语列表也可以从文本中学习。例如你可以提供菜单中可用食物的固定列表并为每个词提供变体或同义词例如茄子eggplant作为茄子的变体。LUIS还提供了可用的预定义实体例如数字和位置。

对于设置计时器你可以使用预定义的数字实体为时间创建一个实体并为单位如分钟和秒创建另一个实体。每个单位可以有多个变体以涵盖单数和复数形式例如minute和minutes。

定义实体后,你需要创建意图。这些意图是通过你提供的示例句子(称为话语)由模型学习的。例如,对于设置计时器意图,你可以提供以下句子:

  • 设置一个1秒计时器
  • 设置一个计时器时间为1分12秒
  • 设置一个3分钟计时器
  • 设置一个9分30秒计时器

然后你需要告诉LUIS这些句子的哪些部分映射到实体

句子“设置一个计时器,时间为1分12秒”分解为实体

句子设置一个计时器时间为1分12秒的意图是设置计时器。它还有2个实体每个实体有2个值

时间 单位
1分钟 1 分钟
12秒 12

为了训练一个好的模型,你需要提供一系列不同的示例句子,以涵盖人们可能提出相同请求的多种方式。

💁 与任何AI模型一样训练时使用的数据越多且越准确模型效果越好。

想一想你可能用不同方式提出相同请求并期望人类理解的情况。

任务 - 向语言理解模型添加实体

对于计时器你需要添加2个实体——一个用于时间单位分钟或秒另一个用于分钟或秒的数量。

你可以在微软文档的快速入门在LUIS门户中构建应用中找到使用LUIS门户的说明。

  1. 在LUIS门户中选择实体选项卡并通过选择添加预定义实体按钮添加数字预定义实体,然后从列表中选择数字

  2. 使用创建按钮创建一个新的实体。将实体命名为时间单位,并将类型设置为列表。在标准化值列表中添加分钟,并在同义词列表中添加单数和复数形式。每添加一个同义词后按回车键将其添加到列表中。

    标准化值 同义词
    分钟 分钟,分钟们
    秒,秒们

任务 - 向语言理解模型添加意图

  1. 意图选项卡中,选择创建按钮以创建一个新意图。将此意图命名为设置计时器

  2. 在示例中,输入不同方式设置计时器的句子,包括分钟、秒以及分钟和秒的组合。示例可以包括:

    • 设置一个1秒计时器
    • 设置一个4分钟计时器
    • 设置一个四分钟六秒计时器
    • 设置一个9分30秒计时器
    • 设置一个计时器时间为1分12秒
    • 设置一个计时器时间为3分钟
    • 设置一个计时器时间为3分1秒
    • 设置一个计时器,时间为三分一秒
    • 设置一个计时器时间为1分1秒
    • 设置一个计时器时间为30秒
    • 设置一个计时器时间为1秒

    混合使用数字的文字形式和数字形式,以便模型学习处理两者。

  3. 每输入一个示例LUIS会开始检测实体并会下划线并标记它找到的任何实体。

    LUIS对示例中的数字和时间单位进行下划线标记

任务 - 训练和测试模型

  1. 配置好实体和意图后,可以使用顶部菜单中的训练按钮训练模型。选择此按钮,模型应在几秒钟内完成训练。训练期间按钮会变灰,完成后会重新启用。

  2. 从顶部菜单中选择测试按钮以测试语言理解模型。输入文本,例如设置一个计时器时间为5分4秒,然后按回车键。句子会出现在你输入的文本框下方的一个框中,下面会显示最高意图,即检测到的概率最高的意图。此意图应为设置计时器。意图名称后会显示检测到正确意图的概率。

  3. 选择检查选项以查看结果的详细信息。你会看到最高得分意图及其百分比概率,以及检测到的实体列表。

  4. 完成测试后关闭测试窗格。

任务 - 发布模型

要从代码中使用此模型你需要发布它。从LUIS发布时可以发布到测试环境或生产环境。在本课中测试环境即可。

  1. 在LUIS门户中选择顶部菜单中的发布按钮。

  2. 确保选择了测试槽,然后选择完成。发布应用后会看到通知。

  3. 你可以使用curl进行测试。要构建curl命令你需要三个值——端点、应用IDApp ID和API密钥。这些值可以从顶部菜单中选择的管理选项卡中访问。

    1. 设置部分复制应用ID
  4. Azure Resources 部分中,选择 Authoring Resource,然后复制 Primary KeyEndpoint URL

  5. 在命令提示符或终端中运行以下 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 Resources 部分中的 Endpoint URL。

    <app id> 替换为 Settings 部分中的 App ID。

    <primary key> 替换为 Azure Resources 部分中的 Primary Key。

    <sentence> 替换为您想要测试的句子。

  6. 此调用的输出将是一个 JSON 文档,其中详细说明了查询、最高意图以及按类型分类的实体列表。

    {
        "query": "set a timer for 45 minutes and 12 seconds",
        "prediction": {
            "topIntent": "set timer",
            "intents": {
                "set timer": {
                    "score": 0.97031575
                },
                "None": {
                    "score": 0.02205793
                }
            },
            "entities": {
                "number": [
                    45,
                    12
                ],
                "time-unit": [
                    [
                        "minute"
                    ],
                    [
                        "second"
                    ]
                ]
            }
        }
    }
    

    上述 JSON 是通过查询 set a timer for 45 minutes and 12 seconds 得到的:

    • set timer 是最高意图,概率为 97%。
    • 检测到两个 number 实体,分别是 4512
    • 检测到两个 time-unit 实体,分别是 minutesecond

使用语言理解模型

一旦发布LUIS 模型可以通过代码调用。在之前的课程中,您使用了 IoT Hub 来处理与云服务的通信,发送遥测数据并监听命令。这种方式是非常异步的——一旦发送了遥测数据,代码不会等待响应,如果云服务宕机,您也不会知道。

对于智能计时器,我们希望立即获得响应,以便告诉用户计时器已设置,或者提醒他们云服务不可用。为此,我们的 IoT 设备将直接调用一个 Web 端点,而不是依赖 IoT Hub。

与其从 IoT 设备直接调用 LUIS您可以使用无服务器代码并采用不同类型的触发器——HTTP 触发器。这允许您的函数应用监听 REST 请求并对其作出响应。这个函数将成为您的设备可以调用的 REST 端点。

💁 尽管您可以直接从 IoT 设备调用 LUIS但使用类似无服务器代码的方式更好。这样当您想更换调用的 LUIS 应用(例如训练了更好的模型或不同语言的模型)时,您只需更新云端代码,而无需重新部署到可能成千上万甚至数百万的 IoT 设备上。

任务 - 创建无服务器函数应用

  1. 创建一个名为 smart-timer-trigger 的 Azure Functions 应用,并在 VS Code 中打开它。

  2. 在此应用中添加一个名为 speech-trigger 的 HTTP 触发器,使用以下命令从 VS Code 终端中运行:

    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. local.settings.json 文件中为您的 LUIS API Key、Endpoint URL 和 App ID 添加新条目,这些信息可以从 LUIS 门户的 MANAGE 选项卡中获取:

    "LUIS_KEY": "<primary key>",
    "LUIS_ENDPOINT_URL": "<endpoint url>",
    "LUIS_APP_ID": "<app id>"
    

    <endpoint url> 替换为 MANAGE 选项卡中 Azure Resources 部分的 Endpoint URL。格式为 https://<location>.api.cognitive.microsoft.com/

    <app id> 替换为 MANAGE 选项卡中 Settings 部分的 App ID。

    <primary key> 替换为 MANAGE 选项卡中 Azure Resources 部分的 Primary Key。

  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 Key 的凭据对象,然后创建一个 LUIS 客户端对象以与您的 LUIS 应用交互。

  6. 这个 HTTP 触发器将通过 JSON 格式传递要理解的文本,文本位于名为 text 的属性中。以下代码从 HTTP 请求的正文中提取该值,并将其记录到控制台中。将此代码添加到 main 函数中:

    req_body = req.get_json()
    text = req_body['text']
    logging.info(f'Request - {text}')
    
  7. 通过发送预测请求(包含要预测的文本的 JSON 文档)向 LUIS 请求预测。使用以下代码创建此请求:

    prediction_request = { 'query' : text }
    
  8. 然后可以将此请求发送到 LUIS使用您的应用发布到的 staging 插槽:

    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 实体将是一个数字数组。例如,如果您说 "Set a four minute 17 second timer.",那么 number 数组将包含两个整数 - 4 和 17。

    time unit 实体将是一个字符串数组的数组,每个时间单位作为数组中的一个字符串。例如,如果您说 "Set a four minute 17 second timer.",那么 time unit 数组将包含两个数组,每个数组中有一个值 - ['minute']['second']

    "Set a four minute 17 second timer." 的这些实体的 JSON 版本为:

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

    此代码还定义了一个计时器总时间(以秒为单位)的计数器。该计数器将由实体中的值填充。

  10. 实体之间没有直接关联,但我们可以对它们做一些假设。它们将按照语音中的顺序排列,因此可以使用数组中的位置来确定哪个数字对应哪个时间单位。例如:

    • "Set a 30 second timer" - 这将有一个数字 30 和一个时间单位 second,因此单个数字将匹配单个时间单位。
    • "Set a 2 minute and 30 second timer" - 这将有两个数字 230,以及两个时间单位 minutesecond因此第一个数字对应第一个时间单位2 分钟第二个数字对应第二个时间单位30 秒)。

    以下代码获取数字实体中的项目数量,并使用该数量从每个数组中提取第一个项目,然后是第二个,依此类推。将此代码添加到 if 块中。

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

    对于 "Set a four minute 17 second timer.",这将循环两次,给出以下值:

    循环计数 number time_unit
    0 4 minute
    1 17 second
  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 字符串,并以状态码 200表示调用成功作为 HTTP 结果返回。

  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> 替换为您的请求文本,例如 set a 2 minutes 27 second timer

    您将看到函数应用的以下输出:

    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建议本地运行函数应用因为会有一些依赖库导致无法像之前那样部署函数应用。如果您确实想部署到云端后续课程将提供相关信息。

    • 发布 Functions 应用 - 按照之前课程中的说明将函数应用发布到云端。发布后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> 是您的默认函数密钥。

      💁 您可以通过修改 function.json 文件中的 authlevel 设置更改 HTTP 触发器的授权类型。您可以在 Microsoft 文档中 Azure Functions HTTP 触发器文档的配置部分 中阅读更多内容。

    • 本地运行函数应用并通过 IP 地址访问 - 您可以获取计算机在本地网络中的 IP 地址,并使用该地址构建 URL。

      查找您的 IP 地址:

      一旦您获取了 IP 地址,您将能够通过 http:// <IP地址> :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应用中。测试这些表达方式看看你的模型能否处理多种请求计时器的方式。

课后测验

课后测验

复习与自学

作业

取消计时器

免责声明
本文档使用AI翻译服务 Co-op Translator 进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原文档的原始语言版本为权威来源。对于关键信息,建议使用专业人工翻译。我们对因使用此翻译而引起的任何误解或误读不承担责任。