

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 自定义标注工作流程
<a name="sms-custom-templates"></a>

这些主题可帮助您设置使用自定义标注模板的 Ground Truth 标注作业。自定义标签模板允许您创建自定义的工作人员门户用户界面，工作人员将使用此界面对数据进行标注。可以使用 HTML、CSS、、Li [quid 模板语言](https://shopify.github.io/liquid/)和 C [rowd HTML 元素](https://docs.aws.amazon.com/sagemaker/latest/dg/sms-ui-template-reference.html)创建模板。 JavaScript

## 概述
<a name="sms-custom-templates-overview"></a>

如果这是您第一次在 Ground Truth 中创建自定义标签工作流程，则以下列表是所需步骤的高度概括。

1. *设置员工队伍* - 要创建自定义标注工作流程，您需要一个员工队伍。本主题将向您介绍如何配置员工队伍。

1. *创建自定义模板* - 要创建自定义模板，您必须将输入清单文件中的数据正确映射到模板中的变量。

1. *使用可选处理 Lambda 函数* - 控制如何将输入清单中的数据添加到工作人员模板中，以及如何将工作人员注释记录在作业的输出文件中。

本主题还有三个 end-to-end演示，可帮助您更好地了解如何使用自定义标签模板。

**注意**  
以下链接中的示例都包含注释前和注释后 Lambda 函数。这些 Lambda 函数是可选的。
+ [演示模板：使用 `crowd-bounding-box` 的映像注释](sms-custom-templates-step2-demo1.md)
+ [演示模板：使用 `crowd-classifier` 的标注目的](sms-custom-templates-step2-demo2.md)
+ [使用 Amazon G SageMaker round Truth 构建自定义数据标签工作流程](https://aws.amazon.com/blogs/machine-learning/build-a-custom-data-labeling-workflow-with-amazon-sagemaker-ground-truth/)

**Topics**
+ [概述](#sms-custom-templates-overview)
+ [组建您的员工队伍](sms-custom-templates-step1.md)
+ [创建自定义工作人员任务模板](sms-custom-templates-step2.md)
+ [使用 Liquid 添加自动化](sms-custom-templates-step2-automate.md)
+ [使用自定义标签工作流程处理数据 AWS Lambda](sms-custom-templates-step3.md)
+ [演示模板：使用 `crowd-bounding-box` 的映像注释](sms-custom-templates-step2-demo1.md)
+ [演示模板：使用 `crowd-classifier` 的标注目的](sms-custom-templates-step2-demo2.md)
+ [使用 API 创建自定义工作流程](sms-custom-templates-step4.md)

# 组建您的员工队伍
<a name="sms-custom-templates-step1"></a>

在此步骤中，您使用控制台确定要使用的工作人员类型，并为工作人员类型进行所需的后续选择。此步骤假定您目前已经完成了[入门：使用 Ground Truth 创建边界框标注作业](sms-getting-started.md)部分中的步骤，并已选择**自定义标注任务**作为**任务类型**。

**配置人力。**

1. 首先从**工作人员类型**中选择一个选项。目前提供三种类型：
   + **公有**使用由 Amazon Mechanical Turk 提供支持的按需独立承包商人力。按任务对这些人力付费。
   + **私有**使用您的员工或承包商处理需要保留在组织内的数据。
   + **供应商**使用专门提供数据标签服务的第三方供应商，这些服务可通过 AWS Marketplace 获得。

1. 如果选择**公有**选项，将要求您设置**每个数据集对象的工作人员数量**。如果让多个工作人员对同一个对象执行同一个任务，则可能有助于提高结果的准确性。默认为三个。您可以提高或降低此数目，具体取决于所需的准确性。

   还要求您使用下拉菜单设置**每个任务的价格**。该菜单根据完成任务所需的时间建议价格点。

   确定这一点的推荐方法是首先通过**私有**人力对任务运行简短测试。测试提供了完成任务所需的时间的现实估计值。然后，您可以在**每个任务的价格**菜单上选择您估计所需的范围。如果平均时间超过 5 分钟，请考虑将任务拆分成更小的单位。

## 下一步
<a name="templates-step1-next"></a>

[创建自定义工作人员任务模板](sms-custom-templates-step2.md)

# 创建自定义工作人员任务模板
<a name="sms-custom-templates-step2"></a>

要创建自定义标注作业，您需要更新工作人员任务模板，将清单文件中的输入数据映射到模板中使用的变量，并将输出数据映射到 Amazon S3。要了解有关使用 Liquid 自动化的高级功能的更多信息，请参阅 [使用 Liquid 添加自动化](sms-custom-templates-step2-automate.md)。

以下各节将介绍每个必要步骤。

## 工作人员任务模板
<a name="sms-custom-templates-step2-template"></a>

*工作人员任务模板*是 Ground Truth 用来自定义工作人员用户界面 (UI) 的文件。你可以使用 HTML、CSS、、Li [quid 模板语言](https://shopify.github.io/liquid/)和 C [rowd HTML](https://docs.aws.amazon.com/sagemaker/latest/dg/sms-ui-template-reference.html) Elements 创建工作任务模板。 JavaScriptLiquid 用于自动化模板。Crowd HTML 元素用于包含常用注释工具，并提供向 Ground Truth 提交的逻辑。

使用以下主题了解如何创建工作人员任务模板。你可以在上看到一个包含示例 Ground Truth 工作人员任务模板的存储库[GitHub](https://github.com/aws-samples/amazon-sagemaker-ground-truth-task-uis)。

### 在 SageMaker AI 控制台中使用基础工作人员任务模板
<a name="sms-custom-templates-step2-base"></a>

您可以使用 Ground Truth 控制台中的模板编辑器开始创建模板。此编辑器包含大量预先设计好的基本模板。它支持自动填充 HTML 和 Crowd HTML 元素代码。

**要访问 Ground Truth 自定义模板编辑器，请执行以下操作：**

1. 按照 [创建标注作业（控制台）](sms-create-labeling-job-console.md) 中的说明进行操作。

1. 然后为标注作业的**任务类型**选择**自定义**。

1. 选择**下一步**后，然后您可以访问**自定义标注任务设置**部分的模板编辑器和基本模板。

1. （可选）从**模板**下的下拉菜单中选择一个基本模板。如果您想从头开始创建模板，请从下拉菜单中选择**自定义**，以获得最小的模板框架。

下面将介绍如何在本地可视化管理控制台中开发的模板。

#### 在本地可视化工作人员任务模板
<a name="sms-custom-template-step2-UI-local"></a>

您必须使用管理控制台测试模板如何处理传入数据。要测试模板 HTML 和自定义元素的外观，您可以使用浏览器。

**注意**  
不会解析变量。在本地查看内容时，您可能需要用样本内容替换它们。

下面的代码片段示例加载了呈现自定义 HTML 元素所需的代码。如果您希望在首选编辑器而非在控制台中开发您模板的外观，则使用此方法。

**Example**  

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>
```

### 创建简单的 HTML 任务示例
<a name="sms-custom-templates-step2-sample"></a>

现在您已经有了基本工作人员任务模板，您可以使用本主题创建一个简单的基于 HTML 的任务模板。

下面是输入清单文件中的一个条目示例。

```
{
  "source": "This train is really late.",
  "labels": [ "angry" , "sad", "happy" , "inconclusive" ],
  "header": "What emotion is the speaker feeling?"
}
```

在 HTML 任务模板中，我们需要将输入清单文件中的变量映射到模板中。示例输入清单中的变量将使用以下语法 **task.input.source**、**task.input.labels** 和 **task.input.header** 映射。

下面是一个用于推文分析的 HTML 工作人员任务模板简单示例。所有任务都以 `<crowd-form> </crowd-form>` 元素开始和结束。与标准 HTML `<form>` 元素类似，所有格式代码都应位于它们之间。Ground Truth 会根据模板中指定的上下文直接生成工作人员的任务，除非您实现了预注释 Lambda。Ground Truth 或 [注释前 Lambda](sms-custom-templates-step3-lambda-requirements.md#sms-custom-templates-step3-prelambda) 返回的 `taskInput` 对象就是模板中的 `task.input` 对象。

对于简单的推文分析任务，请使用 `<crowd-classifier>` 元素。它需要以下属性：
+ *名称* - 输出变量的名称。工作人员注释会保存到输出清单中的此变量名称中。
+ *类别* - JSON 格式的一系列可能的答案。
+ *标题* - 用于注释工具的标题

`<crowd-classifier>` 元素至少需要以下三个子元素。
+ *<classification-target>* - 工作人员将根据在上面 `categories` 属性中指定的选项进行分类的文本。
+ *<full-instructions>* - 工具中的“查看完整说明”链接中提供的说明。这可以留空，但建议您提供适当的说明来获得更好的结果。
+ *<short-instructions>* - 对于工具栏边栏中显示的任务的更简要说明。这可以留空，但建议您提供适当的说明来获得更好的结果。

此工具的简单版本如下。变量 **\$1\$1 task.input.source \$1\$1** 用于指定输入清单文件中的源数据。**\$1\$1 task.input.labels \$1 to\$1json \$1\$1** 是将数组转换为 JSON 表示法的变量筛选条件示例。`categories` 属性必须是 JSON。

**Example 在输入清单 json 样本中使用 `crowd-classifier`**  

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>
<crowd-form>
  <crowd-classifier
    name="tweetFeeling"
    categories="='{{ task.input.labels | to_json }}'"
    header="{{ task.input.header }}'"
  >
     <classification-target>
       {{ task.input.source }}
     </classification-target>

    <full-instructions header="Sentiment Analysis Instructions">
      Try to determine the sentiment the author
      of the tweet is trying to express.
      If none seem to match, choose "cannot determine."
    </full-instructions>

    <short-instructions>
      Pick the term that best describes the sentiment of the tweet.
    </short-instructions>

  </crowd-classifier>
</crowd-form>
```

您可以在 Ground Truth 标注作业创建工作流程中将代码复制并粘贴到编辑器中以预览该工具，或者试用[此代码的演示 CodePen。](https://codepen.io/MTGT/full/OqBvJw)

 [https://codepen.io/MTGT/full/OqBvJw](https://codepen.io/MTGT/full/OqBvJw) 

## 输入数据、外部资产和任务模板
<a name="sms-custom-templates-step2-template-input"></a>

以下各节将介绍外部资产的使用、输入数据格式要求以及何时考虑使用预注释 Lambda 函数。

### 输入数据格式要求
<a name="sms-custom-template-input-manifest"></a>

当您创建输入清单文件用于自定义 Ground Truth 标注作业时，必须将数据存储在 Amazon S3 中。输入清单文件还必须与运行自定义 Ground Truth 标签作业的位置相同 AWS 区域 。此外，它还可以存储在任何 Amazon S3 存储桶中，只要您在 Ground Truth 中运行自定义标注作业时使用的 IAM 服务角色可以访问这些存储桶。

输入清单文件必须使用换行符分隔的 JSON 或 JSON 行格式。每行都以标准换行符 **\$1n** 或 **\$1r\$1n** 分隔。每行也必须是有效的 JSON 对象。

此外，清单文件中的每个 JSON 对象都必须包含以下键之一：`source-ref` 或 `source`。键值的解释如下：
+ `source-ref` – 对象的来源是值中指定的 Amazon S3 对象。当对象是二进制对象（如图像）时，使用此值。
+ `source` – 对象的来源是值。当对象是文本值时，使用此值。

要了解有关格式化输入清单文件的更多信息，请参阅 [输入清单文件](sms-input-data-input-manifest.md)。

### 注释前 Lambda 函数
<a name="sms-custom-template-input-lambda"></a>

您可以选择指定一个*注释前 Lambda* 函数，以管理如何在标注前处理输入清单文件中的数据。如果您指定了 `isHumanAnnotationRequired` 键值对，则必须使用注释前 Lambda 函数。当 Ground Truth 向注释前 Lambda 函数发送一个 JSON 格式请求时，会使用以下架构。

**Example 以 `source-ref` 键值对标识的数据对象**  

```
{
  "version": "2018-10-16",
  "labelingJobArn": arn:aws:lambda:us-west-2:555555555555:function:my-function
  "dataObject" : {
    "source-ref": s3://input-data-bucket/data-object-file-name
  }
}
```

**Example 以 `source` 键值对标识的数据对象**  

```
{
      "version": "2018-10-16",
      "labelingJobArn" : arn:aws:lambda:us-west-2:555555555555:function:my-function
      "dataObject" : {
        "source": Sue purchased 10 shares of the stock on April 10th, 2020
      }
    }
```

下面是使用 `isHumanAnnotationRequired` 时 Lambda 函数的预期响应。

```
{
  "taskInput": {
    "source": "This train is really late.",
    "labels": [ "angry" , "sad" , "happy" , "inconclusive" ],
    "header": "What emotion is the speaker feeling?"
  },
  "isHumanAnnotationRequired": False
}
```

### 使用外部资产
<a name="sms-custom-template-step2-UI-external"></a>

Amazon G SageMaker round Truth 自定义模板允许嵌入外部脚本和样式表。例如，下面的代码块演示了如何将位于 `https://www.example.com/my-enhancement-styles.css` 的样式表添加到模板中。

**Example**  

```
<script src="https://www.example.com/my-enhancment-script.js"></script>
<link rel="stylesheet" type="text/css" href="https://www.example.com/my-enhancement-styles.css">
```

如果您遇到错误，请确保您的原始服务器随资产一起发送正确的 MIME 类型和编码标头。

例如，对于远程脚本，MIME 和编码类型为 `application/javascript;CHARSET=UTF-8`。

对于远程样式表，MIME 和编码类型为 `text/css;CHARSET=UTF-8`。

## 输出数据和任务模板
<a name="sms-custom-templates-step2-template-output"></a>

以下各节将介绍自定义标注作业的输出数据，以及何时考虑使用注释后 Lambda 函数。

### 输出数据
<a name="sms-custom-templates-data"></a>

自定义标注作业完成后，数据将保存在创建标注作业时指定的 Amazon S3 存储桶中。数据保存在 `output.manifest` 文件中。

**注意**  
*labelAttributeName*是一个占位符变量。在输出中，它要么是标注作业的名称，要么是您在创建标注作业时指定的标签属性名称。
+ `source` 或 `source-ref`：要求工作人员标注的字符串或 S3 URI。
+ `labelAttributeName`：包含[注释后 Lambda 函数](sms-custom-templates-step3-lambda-requirements.md#sms-custom-templates-step3-postlambda)中的合并标签内容的字典。如果未指定注释后 Lambda 函数，则此字典将为空。
+ `labelAttributeName-metadata`：由 Ground Truth 添加的自定义标注作业中的元数据。
+ `worker-response-ref`：保存数据的存储桶的 S3 URI。如果指定了注释后 Lambda 函数，则不会出现此键值对。

在此示例中，JSON 对象设置为便于阅读的格式；在实际输出文件中，JSON 对象位于单行上。

```
{
  "source" : "This train is really late.",
  "labelAttributeName" : {},
  "labelAttributeName-metadata": { # These key values pairs are added by Ground Truth
    "job_name": "test-labeling-job",
    "type": "groundTruth/custom",
    "human-annotated": "yes",
    "creation_date": "2021-03-08T23:06:49.111000",
    "worker-response-ref": "s3://amzn-s3-demo-bucket/test-labeling-job/annotations/worker-response/iteration-1/0/2021-03-08_23:06:49.json"
  }
}
```

### 使用注释后 Lambda 来整合工作人员的结果
<a name="sms-custom-templates-consolidation"></a>

默认情况下，Ground Truth 会将未处理的工作人员响应保存在 Amazon S3 中。要对响应的处理方式进行更精细的控制，您可以指定一个*注释后 Lambda 函数*。例如，如果多个工作人员对同一数据对象进行了标注，则可以使用注释后 Lambda 函数来合并注释。要了解有关创建注释后 Lambda 函数的更多信息，请参阅 [注释后 Lambda](sms-custom-templates-step3-lambda-requirements.md#sms-custom-templates-step3-postlambda)。

如果您要使用注释后 Lambda 函数，则必须在 `CreateLabelingJob` 请求中将其指定为 [https://docs.aws.amazon.com//sagemaker/latest/APIReference/API_AnnotationConsolidationConfig.html](https://docs.aws.amazon.com//sagemaker/latest/APIReference/API_AnnotationConsolidationConfig.html) 的一部分。

要了解有注释合并工作原理的更多信息，请参阅 [注释整合](sms-annotation-consolidation.md)。

# 使用 Liquid 添加自动化
<a name="sms-custom-templates-step2-automate"></a>

我们的自定义模板系统使用 [Liquid](https://shopify.github.io/liquid/) 进行自动化。它是开源内联标记语言。在 Liquid 中，单大括号之间的文本以及百分比符号是执行控制流或迭代等操作的指令或*标签*。双大括号之间的文本是一个变量或用于输出变量值的*对象*。

Liquid 最常见的用途是解析输入清单文件中的数据，并提取相关变量来创建任务。除非指定了注释前 Lambda，否则 Ground Truth 会自动生成任务。Ground Truth 或 [注释前 Lambda](sms-custom-templates-step3-lambda-requirements.md#sms-custom-templates-step3-prelambda) 返回的 `taskInput` 对象就是模板中的 `task.input` 对象。

输入清单中的属性将作为 `event.dataObject` 传递到模板中。

**Example 清单数据对象**  

```
{
  "source": "This is a sample text for classification",
  "labels": [ "angry" , "sad" , "happy" , "inconclusive" ],
  "header": "What emotion is the speaker feeling?"
}
```

**Example 使用变量的示例 HTML**  

```
<crowd-classifier 
  name='tweetFeeling'
  categories='{{ task.input.labels | to_json }}'
  header='{{ task.input.header }}' >
<classification-target>
  {{ task.input.source }}
</classification-target>
```

请注意，在上面的 `labels` 属性中添加了 ` | to_json`。这是一个筛选条件，用于将输入清单数组转换为数组的 JSON 表示形式。下一节将介绍变量筛选条件。

以下列表包括两种类型的 Liquid 标签，在自动化模板输入数据的处理时，这些标签可能会非常有用。如果您选择了以下标签类型之一，您将被重定向到 Liquid 文档。
+ [控制流](https://shopify.github.io/liquid/tags/control-flow/)：包括编程逻辑运算符，如 `if/else`、`unless` 和 `case/when`。
+ [迭代](https://shopify.github.io/liquid/tags/iteration/)：使您能够使用 for 循环之类的语句重复运行代码块。

  有关使用 Liquid 元素创建 for 循环的 HTML 模板的示例，请参阅中的.li [translation-review-and-correctionquid.htm](https://github.com/aws-samples/amazon-sagemaker-ground-truth-task-uis/blob/8ae02533ea5a91087561b1daecd0bc22a37ca393/text/translation-review-and-correction.liquid.html) l。 GitHub

有关更多信息和文档，请访问 [Liquid 主页](https://shopify.github.io/liquid/)。

## 变量筛选条件
<a name="sms-custom-templates-step2-automate-filters"></a>

除了标准的 [Liquid 筛选条件](https://shopify.github.io/liquid/filters/abs/)和操作之外，Ground Truth 还提供了几个额外的筛选条件。通过在变量名称之后放置竖线 (`|`) 字符，然后指定筛选条件名称，以应用筛选条件。筛选条件可以采用以下形式链接起来：

**Example**  

```
{{ <content> | <filter> | <filter> }}
```

### 自动转义和显式转义
<a name="sms-custom-templates-step2-automate-filters-autoescape"></a>

默认情况下，输入将进行 HTML 转义，以防止在变量文本和 HTML 之间产生混淆。您可以显式添加 `escape` 筛选条件，以使其对于正读取正在进行转义的模板源的用户更显而易见。

### escape\$1once
<a name="sms-custom-templates-step2-automate-escapeonce"></a>

`escape_once` 可确保您的代码已经转义，而不会再次重新转义。例如，确保 &amp; 不会变为 &amp;amp;。

### skip\$1autoescape
<a name="sms-custom-templates-step2-automate-skipautoescape"></a>

当您的内容要用作 HTML 时，`skip_autoescape` 很有用。例如，您可能在边界框的完整说明中有一些文本段落和一些图像。

**请谨慎使用 `skip_autoescape`**  
模板中的最佳实践是避免使用 `skip_autoescape` 传递功能代码或标记，除非您绝对确信您对正传递的内容具有严格的控制。如果您传递用户输入，就可能使您的工作人员遭受跨站点脚本攻击。

### to\$1json
<a name="sms-custom-templates-step2-automate-tojson"></a>

`to_json`会将你输入的内容编码为 JSON（JavaScript 对象表示法）。如果您向其提供对象，它会对该对象序列化。

### grant\$1read\$1access
<a name="sms-custom-templates-step2-automate-grantreadaccess"></a>

`grant_read_access` 获取 S3 URI 并将其编码为 HTTPS URL（具有针对该资源的短期访问令牌）。这样，就可以向工作人员显示存储在 S3 存储桶中但原本无法公开访问的照片、音频或视频对象。

### s3\$1presign
<a name="sms-custom-templates-step2-automate-s3"></a>

 `s3_presign` 筛选器的工作方式与 `grant_read_access` 筛选器相同，`s3_presign` 获取 Amazon S3 网址并将其编码为 HTTPS 网址（具有针对此资源的短期访问令牌）。这样，就可以向工作人员显示存储在 S3 存储桶中但原本无法公开访问的照片、音频或视频对象。

**Example 变量筛选器**  
Input  

```
auto-escape: {{ "Have you read 'James & the Giant Peach'?" }}
explicit escape: {{ "Have you read 'James & the Giant Peach'?" | escape }}
explicit escape_once: {{ "Have you read 'James &amp; the Giant Peach'?" | escape_once }}
skip_autoescape: {{ "Have you read 'James & the Giant Peach'?" | skip_autoescape }}
to_json: {{ jsObject | to_json }}                
grant_read_access: {{ "s3://amzn-s3-demo-bucket/myphoto.png" | grant_read_access }}
s3_presign: {{ "s3://amzn-s3-demo-bucket/myphoto.png" | s3_presign }}
```

**Example**  
Output  

```
auto-escape: Have you read &#39;James &amp; the Giant Peach&#39;?
explicit escape: Have you read &#39;James &amp; the Giant Peach&#39;?
explicit escape_once: Have you read &#39;James &amp; the Giant Peach&#39;?
skip_autoescape: Have you read 'James & the Giant Peach'?
to_json: { "point_number": 8, "coords": [ 59, 76 ] }
grant_read_access: https://s3.amazonaws.com/amzn-s3-demo-bucket/myphoto.png?<access token and other params>
s3_presign: https://s3.amazonaws.com/amzn-s3-demo-bucket/myphoto.png?<access token and other params>
```

**Example 自动化的分类模板。**  
要自动执行简单文本分类示例，请将推文文本替换为变量。  
文本分类模板如下，添加了自动化功能。 changes/additions 它们以粗体突出显示。  

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>
<crowd-form>
  <crowd-classifier 
    name="tweetFeeling"
    categories="['positive', 'negative', 'neutral', 'cannot determine']"
    header="Which term best describes this tweet?" 
  >
    <classification-target>
       {{ task.input.source }}
    </classification-target>

    <full-instructions header="Analyzing a sentiment">
      Try to determine the feeling the author 
      of the tweet is trying to express. 
      If none seem to match, choose "other."
    </full-instructions>

    <short-instructions>
      Pick the term best describing the sentiment 
      of the tweet. 
    </short-instructions>

  </crowd-classifier>
</crowd-form>
```
前面示例中的推文文本现已替换为一个对象。`entry.taskInput` 对象使用 `source`（或者在注释前 Lambda 中指定的其他名称）作为文本的属性名称，并通过双大括号将其直接插入 HTML 中。

# 使用自定义标签工作流程处理数据 AWS Lambda
<a name="sms-custom-templates-step3"></a>

在本主题中，您可以了解在创建自定义标注工作流程时如何部署可选的 [AWS Lambda](https://aws.amazon.com/lambda/) 函数。您可以指定两种类型的 Lambda 函数与自定义标注工作流程配合使用。
+ *注释前 Lambda*：在将每个数据对象发送给工作人员之前，此函数启动并预处理发送给标注作业的每个数据对象。
+ *注释后 Lambda*：该函数在工作人员提交任务后处理结果。如果为每个数据对象指定多个工作人员，则该函数可能包含用于合并注释的逻辑。

如果您是 Lambda 和 Ground Truth 的新用户，我们建议您按照以下方式使用本节中的页面：

1. 首先，查看[使用注释前和注释后 Lambda 函数使用 Lambda 函数](sms-custom-templates-step3-lambda-requirements.md)。

1. 然后，使用 [添加与 Ground Trut AWS Lambda h 一起使用所需的权限](sms-custom-templates-step3-lambda-permissions.md) 页面了解在 Ground Truth 自定义标注作业中使用注释前和注释后 Lambda 函数的安全和权限要求。

1. 接下来，您需要访问 Lambda 控制台或使用 Lambda APIs 来创建您的函数。使用[使用 Ground Truth 模板创建 Lambda 函数](sms-custom-templates-step3-lambda-create.md)部分以了解如何创建 Lambda 函数。

1. 要了解如何测试 Lambda 函数，请参阅[测试注释前和注释后 Lambda 函数](sms-custom-templates-step3-lambda-test.md)。

1. 创建预处理和后处理 Lambda 函数后，从 Ground Truth 控制台中自定义 HTML 代码编辑器后的 **Lambda 函数**部分选择它们。要了解如何在 `CreateLabelingJob` API 请求中使用这些函数，请参阅[创建标注作业 (API)](sms-create-labeling-job-api.md)。

有关包含注释前和注释后 Lambda 函数示例的自定义标注工作流教程，请参阅 [演示模板：使用 `crowd-bounding-box` 的映像注释](sms-custom-templates-step2-demo1.md)。

**Topics**
+ [使用注释前和注释后 Lambda 函数](sms-custom-templates-step3-lambda-requirements.md)
+ [添加与 Ground Trut AWS Lambda h 一起使用所需的权限](sms-custom-templates-step3-lambda-permissions.md)
+ [使用 Ground Truth 模板创建 Lambda 函数](sms-custom-templates-step3-lambda-create.md)
+ [测试注释前和注释后 Lambda 函数](sms-custom-templates-step3-lambda-test.md)

# 使用注释前和注释后 Lambda 函数
<a name="sms-custom-templates-step3-lambda-requirements"></a>

使用这些主题可以了解发送到注释前和注释后 Lambda 函数的请求语法，以及 Ground Truth 在自定义标注工作流程中使用的所需响应语法。

**Topics**
+ [注释前 Lambda](#sms-custom-templates-step3-prelambda)
+ [注释后 Lambda](#sms-custom-templates-step3-postlambda)

## 注释前 Lambda
<a name="sms-custom-templates-step3-prelambda"></a>

在将标注任务发送给工作人员之前，可以可选的调用注释前 Lambda 函数。

Ground Truth 向您的 Lambda 函数发送一个 JSON 格式的请求，以提供有关标注作业和数据对象的详细信息。

以下是 2 个 JSON 格式请求示例。

------
#### [ Data object identified with "source-ref" ]

```
{
    "version": "2018-10-16",
    "labelingJobArn": <labelingJobArn>
    "dataObject" : {
        "source-ref": <s3Uri>
    }
}
```

------
#### [ Data object identified with "source" ]

```
{
    "version": "2018-10-16",
    "labelingJobArn": <labelingJobArn>
    "dataObject" : {
        "source": <string>
    }
}
```

------

 以下列表包含注释前请求模式。每个参数的说明如下。
+ `version`（字符串）：这是 Ground Truth 内部使用的版本号。
+ `labelingJobArn`（字符串）：这是标注作业的 Amazon 资源名称 (ARN)。在使用 Ground Truth API 操作（如 `DescribeLabelingJob`）时，此 ARN 可用于引用标注作业。
+ `dataObject`（JSON 对象）：该键包含单一 JSON 行，可以来自您的输入清单文件，也可以来自 Amazon SNS。清单中的 JSON 行对象的大小最多可达 100 千字节，并且包含各种数据。对于非常基本的图像注释作业，`dataObject` JSON 可能只包含一个 `source-ref` 键，用于标识要注释的图像。如果数据对象（例如，一行文本）直接包含在输入清单文件中，则用 `source` 标识数据对象。如果您创建验证或调整作业，则此行可能包含来自前一个标注作业的标签数据和元数据。

以下标签示例显示了注释前请求的示例。这些示例请求中的每个参数都在选项卡式表下面进行了说明。

------
#### [ Data object identified with "source-ref" ]

```
{
    "version": "2018-10-16",
    "labelingJobArn": "arn:aws:sagemaker:us-west-2:111122223333:labeling-job/<labeling_job_name>"
    "dataObject" : {
        "source-ref": "s3://input-data-bucket/data-object-file-name"
    }
}
```

------
#### [ Data object identified with "source" ]

```
{
    "version": "2018-10-16",
    "labelingJobArn": "arn:aws:sagemaker:<aws_region>:111122223333:labeling-job/<labeling_job_name>"
    "dataObject" : {
        "source": "Sue purchased 10 shares of the stock on April 10th, 2020"
    }
}
```

------

作为返回对象，Ground Truth 需要如下格式的响应：

**Example 预期的返回数据**  

```
{
    "taskInput": <json object>,
    "isHumanAnnotationRequired": <boolean> # Optional
}
```

在前面的示例中，`<json object>` 需要包含自定义工作人员任务模板所需的*所有*数据。如果您正在执行一个边界框任务，其中指令始终保持不变，那么可能只是图像文件的 HTTP(S) 或 Amazon S3 资源。如果执行的是情绪分析任务，并且不同的对象可能有不同的选择，那么是作为字符串的对象引用和作为字符串数组的选项。

**`isHumanAnnotationRequired` 的含义**  
该值是可选的，因为它默认为 `true`。显式设置该值的主要使用案例是当您想要将此数据对象从人工标注范围中排除时。

如果清单中的对象多种多样，有些需要人工注释，有些则不需要，那么可以在每个数据对象中包含 `isHumanAnnotationRequired` 值。您可以在注释前 Lambda 中添加逻辑，以动态确定对象是否需要注释，并相应地设置该布尔值。

### 注释前 Lambda 函数的示例
<a name="sms-custom-templates-step3-prelambda-example"></a>

下面的基本注释前 Lambda 函数从初始请求访问 `dataObject` 中的 JSON 对象，并在 `taskInput` 参数中返回该对象。

```
import json

def lambda_handler(event, context):
    return {
        "taskInput":  event['dataObject']
    }
```

假设输入清单文件使用 `"source-ref"` 来标识数据对象，那么在与此注释前 Lambda 相同的标注作业中使用的工作人员任务模板必须包含类似下面的 Liquid 元素，以摄取 `dataObject`：

```
{{ task.input.source-ref | grant_read_access }}
```

如果输入清单文件使用 `source` 来标识数据对象，那么工作任务模板可以通过以下方式摄取 `dataObject`：

```
{{ task.input.source }}
```

下面的注释前 Lambda 示例包含一个逻辑，用于识别 `dataObject` 中使用的键，并在 Lambda 的返回语句中使用 `taskObject` 指向该数据对象。

```
import json

def lambda_handler(event, context):

    # Event received
    print("Received event: " + json.dumps(event, indent=2))

    # Get source if specified
    source = event['dataObject']['source'] if "source" in event['dataObject'] else None

    # Get source-ref if specified
    source_ref = event['dataObject']['source-ref'] if "source-ref" in event['dataObject'] else None

    # if source field present, take that otherwise take source-ref
    task_object = source if source is not None else source_ref

    # Build response object
    output = {
        "taskInput": {
            "taskObject": task_object
        },
        "humanAnnotationRequired": "true"
    }

    print(output)
    # If neither source nor source-ref specified, mark the annotation failed
    if task_object is None:
        print(" Failed to pre-process {} !".format(event["labelingJobArn"]))
        output["humanAnnotationRequired"] = "false"

    return output
```

## 注释后 Lambda
<a name="sms-custom-templates-step3-postlambda"></a>

当所有工作人员都注释了数据对象或达到 [https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_HumanLoopConfig.html#SageMaker-Type-HumanLoopConfig-TaskAvailabilityLifetimeInSeconds](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_HumanLoopConfig.html#SageMaker-Type-HumanLoopConfig-TaskAvailabilityLifetimeInSeconds)（以先到者为准）时，Ground Truth 将这些注释发送到您的注释后 Lambda。此 Lambda 通常用于[注释整合](sms-annotation-consolidation.md)。

**注意**  
要查看合并后 Lambda 函数的示例，[请参阅-recipe 存储](https://github.com/aws-samples/aws-sagemaker-ground-truth-recipe/blob/master/aws_sagemaker_ground_truth_sample_lambda/annotation_consolidation_lambda.py)库[aws-sagemaker-ground-truth中的](https://github.com/aws-samples/aws-sagemaker-ground-truth-recipe) GitHub annotation\$1consolidation\$1lambda.py。

以下代码块包含注释后请求模式。下面的项目符号列表中描述了每个参数。

```
{
    "version": "2018-10-16",
    "labelingJobArn": <string>,
    "labelCategories": [<string>],
    "labelAttributeName": <string>,
    "roleArn" : <string>,
    "payload": {
        "s3Uri": <string>
    }
 }
```
+ `version`（字符串）：Ground Truth 内部使用的版本号。
+ `labelingJobArn`（字符串）：标注作业的 Amazon 资源名称 (ARN)。在使用 Ground Truth API 操作（如 `DescribeLabelingJob`）时，此 ARN 可用于引用标注作业。
+ `labelCategories`（字符串列表）：包括在控制台中指定或包含在标签类别配置文件中的标签类别和其他属性。
+ `labelAttributeName`（字符串）：标注作业的名称或创建标注作业时指定的标签属性名称。
+ `roleArn`（字符串）：您在创建标注作业时指定的 IAM 执行角色的 Amazon 资源名称 (ARN)。
+ `payload`（JSON 对象）：包含 `s3Uri` 键的 JSON，该键标识该数据对象的注释数据在 Amazon S3 中的位置。下面的第二个代码块显示了此注释文件的示例。

以下代码块包含注释后请求的示例。此示例请求中的每个参数都在代码块下面进行了说明。

**Example 注释后 Lambda 请求**  

```
{
    "version": "2018-10-16",
    "labelingJobArn": "arn:aws:sagemaker:us-west-2:111122223333:labeling-job/labeling-job-name",
    "labelCategories": ["Ex Category1","Ex Category2", "Ex Category3"],
    "labelAttributeName": "labeling-job-attribute-name",
    "roleArn" : "arn:aws:iam::111122223333:role/role-name",
    "payload": {
        "s3Uri": "s3://amzn-s3-demo-bucket/annotations.json"
    }
 }
```

**注意**  
如果没有工作人员处理数据对象并且已经达到 `TaskAvailabilityLifetimeInSeconds`，则数据对象被标记为失败，并且不包括在注释后 Lambda 调用中。

下面的代码块包含负载模式。这是由注释后 Lambda 请求 `payload` JSON 对象中的 `s3Uri` 参数指示的文件。例如，如果前面的代码块是注释后 Lambda 请求，则下面的注释文件位于 `s3://amzn-s3-demo-bucket/annotations.json`。

下面的项目符号列表中描述了每个参数。

**Example 注释文件**  

```
[
    {
        "datasetObjectId": <string>,
        "dataObject": {
            "s3Uri": <string>,
            "content": <string>
        },
        "annotations": [{
            "workerId": <string>,
            "annotationData": {
                "content": <string>,
                "s3Uri": <string>
            }
       }]
    }
]
```
+ `datasetObjectId`（字符串）：标识 Ground Truth 为发送到标注作业的每个数据对象分配的唯一 ID。
+ `dataObject`（JSON 对象）：标注的数据对象。如果数据对象包含在输入清单文件中并使用 `source` 键（例如，字符串）进行标识，则 `dataObject` 包括一个用于标识数据对象的 `content` 键。否则，数据对象的位置（例如，链接或 S3 URI）用 `s3Uri` 标识。
+ `annotations`（JSON 对象列表）：此列表包含单一 JSON 对象，用于表示工作人员为该 `dataObject` 提交的每个注释。单一 JSON 对象包含唯一的 `workerId`，可用于标识提交该注释的工作人员。`annotationData` 键包含下列值之一：
  + `content`（字符串）：包含注释数据。
  + `s3Uri`（字符串）：包含一个 S3 URI，用于标识注释数据的位置。

下表包含了您可以在不同类型注释的负载中找到的内容示例。

------
#### [ Named Entity Recognition Payload ]

```
[
    {
      "datasetObjectId": "1",
      "dataObject": {
        "content": "Sift 3 cups of flour into the bowl."
      },
      "annotations": [
        {
          "workerId": "private.us-west-2.ef7294f850a3d9d1",
          "annotationData": {
            "content": "{\"crowd-entity-annotation\":{\"entities\":[{\"endOffset\":4,\"label\":\"verb\",\"startOffset\":0},{\"endOffset\":6,\"label\":\"number\",\"startOffset\":5},{\"endOffset\":20,\"label\":\"object\",\"startOffset\":15},{\"endOffset\":34,\"label\":\"object\",\"startOffset\":30}]}}"
          }
        }
      ]
    }
]
```

------
#### [ Semantic Segmentation Payload ]

```
[
    {
      "datasetObjectId": "2",
      "dataObject": {
        "s3Uri": "s3://amzn-s3-demo-bucket/gt-input-data/images/bird3.jpg"
      },
      "annotations": [
        {
          "workerId": "private.us-west-2.ab1234c5678a919d0",
          "annotationData": {
            "content": "{\"crowd-semantic-segmentation\":{\"inputImageProperties\":{\"height\":2000,\"width\":3020},\"labelMappings\":{\"Bird\":{\"color\":\"#2ca02c\"}},\"labeledImage\":{\"pngImageData\":\"iVBOR...\"}}}"
          }
        }
      ]
    }
  ]
```

------
#### [ Bounding Box Payload ]

```
[
    {
      "datasetObjectId": "0",
      "dataObject": {
        "s3Uri": "s3://amzn-s3-demo-bucket/gt-input-data/images/bird1.jpg"
      },
      "annotations": [
        {
          "workerId": "private.us-west-2.ab1234c5678a919d0",
          "annotationData": {
            "content": "{\"boundingBox\":{\"boundingBoxes\":[{\"height\":2052,\"label\":\"Bird\",\"left\":583,\"top\":302,\"width\":1375}],\"inputImageProperties\":{\"height\":2497,\"width\":3745}}}"
          }
        }
      ]
    }
 ]
```

------

注释后 Lambda 函数可能包含类似下面的逻辑，以循环访问请求中包含的所有注释。有关完整示例，请参阅 [aws-sagemaker-ground-truth-](https://github.com/aws-samples/aws-sagemaker-ground-truth-recipe) recipe GitHub 存储库[中的 annotation\$1consolidation\$1lambda.py](https://github.com/aws-samples/aws-sagemaker-ground-truth-recipe/blob/master/aws_sagemaker_ground_truth_sample_lambda/annotation_consolidation_lambda.py)。在此 GitHub示例中，您必须添加自己的注释合并逻辑。

```
for i in range(len(annotations)):
    worker_id = annotations[i]["workerId"]
    annotation_content = annotations[i]['annotationData'].get('content')
    annotation_s3_uri = annotations[i]['annotationData'].get('s3uri')
    annotation = annotation_content if annotation_s3_uri is None else s3_client.get_object_from_s3(
        annotation_s3_uri)
    annotation_from_single_worker = json.loads(annotation)

    print("{} Received Annotations from worker [{}] is [{}]"
            .format(log_prefix, worker_id, annotation_from_single_worker))
```

**提示**  
对数据运行合并算法时，可以使用 AWS 数据库服务来存储结果，也可以将处理后的结果传回 Ground Truth。您返回给 Ground Truth 的数据会以合并注释清单的形式存储在 S3 存储桶中，该存储桶是在标注作业配置过程中指定用于输出的。

作为返回对象，Ground Truth 需要如下格式的响应：

**Example 预期的返回数据**  

```
[
   {        
        "datasetObjectId": <string>,
        "consolidatedAnnotation": {
            "content": {
                "<labelattributename>": {
                    # ... label content
                }
            }
        }
    },
   {        
        "datasetObjectId": <string>,
        "consolidatedAnnotation": {
            "content": {
                "<labelattributename>": {
                    # ... label content
                }
            }
        }
    }
    .
    .
    .
]
```
此时，除了 `datasetObjectId` 之外，您发送到 S3 存储桶的所有数据都在 `content` 对象中。

在 `content` 中返回注释时，会在作业的输出清单中生成一个条目，如下所示：

**Example 输出清单中的标签格式**  

```
{  "source-ref"/"source" : "<s3uri or content>", 
   "<labelAttributeName>": {
        # ... label content from you
    },   
   "<labelAttributeName>-metadata": { # This will be added by Ground Truth
        "job_name": <labelingJobName>,
        "type": "groundTruth/custom",
        "human-annotated": "yes", 
        "creation_date": <date> # Timestamp of when received from Post-labeling Lambda
    }
}
```

由于自定义模板及其所收集数据的潜在复杂性，Ground Truth 不会对数据进行进一步处理。

# 添加与 Ground Trut AWS Lambda h 一起使用所需的权限
<a name="sms-custom-templates-step3-lambda-permissions"></a>

您可能需要配置以下部分或全部内容，才能在 Ground Truth 中创建和使用 AWS Lambda 。
+ 您需要向 IAM 角色或用户（统称为 IAM 实体）授予使用创建标注前和注释后 Lambda 函数的权限 AWS Lambda，并在创建标签任务时选择它们。
+ 配置标注作业时指定的 IAM 执行角色需要调用注释前和注释后 Lambda 函数的权限。
+ 注释后 Lambda 函数可能需要获得访问 Amazon S3 的权限。

使用以下部分了解如何创建 IAM 实体并授予上述权限。

**Topics**
+ [授予创建和选择 AWS Lambda 函数的权限](#sms-custom-templates-step3-postlambda-create-perms)
+ [授予 IAM 执行角色调用 AWS Lambda 函数的权限](#sms-custom-templates-step3-postlambda-execution-role-perms)
+ [授予注释后 Lambda 访问注释的权限](#sms-custom-templates-step3-postlambda-perms)

## 授予创建和选择 AWS Lambda 函数的权限
<a name="sms-custom-templates-step3-postlambda-create-perms"></a>

如果您不需要精细权限来开发注释前和注释后的 Lambda 函数，则可以将托管`AWSLambda_FullAccess`策略附加 AWS 到用户或角色。该策略授予使用所有 Lambda 功能的广泛权限，以及在 Lambda 与之交互的其他 AWS 服务中执行操作的权限。

要为安全敏感的用例创建更精细的策略，请参阅 AWS Lambda 开发人员指南中的文档中针对 [Lambda 的基于身份的 IAM 策略，了解如何创建适合](https://docs.aws.amazon.com/lambda/latest/dg/access-control-identity-based.html)您的用例的 IAM 策略。

**使用 Lambda 控制台的策略**

如果您想授予 IAM 实体使用 Lambda 控制台的权限，请参阅开发人员指南中的[使用 Lambda 控制台](https://docs.aws.amazon.com/lambda/latest/dg/security_iam_id-based-policy-examples.html#security_iam_id-based-policy-examples-console)。 AWS Lambda 

此外，如果您希望用户能够 AWS Serverless Application Repository 在 Lambda 控制台中使用访问和部署 Ground Truth 入门预注释和标注后函数，则必须指定要部署函数*`<aws-region>`*的位置（这应该与用于创建标签任务的 AWS 区域相同），并将以下策略添加到 IAM 角色。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "serverlessrepo:ListApplicationVersions",
                "serverlessrepo:GetApplication",
                "serverlessrepo:CreateCloudFormationTemplate"
            ],
            "Resource": "arn:aws:serverlessrepo:us-east-1:838997950401:applications/aws-sagemaker-ground-truth-recipe"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "serverlessrepo:SearchApplications",
            "Resource": "*"
        }
    ]
}
```

------

**在 Ground Truth 控制台中查看 Lambda 函数的策略**

要授予 IAM 实体在用户创建自定义标注作业时在 Ground Truth 控制台中查看 Lambda 函数的权限，该实体必须具有[授予 IAM 使用亚马逊 G SageMaker round Truth 控制台的权限](sms-security-permission-console-access.md)中所述的权限，包括[自定义标注工作流权限](sms-security-permission-console-access.md#sms-security-permissions-custom-workflow)部分中所述权限。

## 授予 IAM 执行角色调用 AWS Lambda 函数的权限
<a name="sms-custom-templates-step3-postlambda-execution-role-perms"></a>

如果您将 IAM 托管策略[AmazonSageMakerGroundTruthExecution](https://console.aws.amazon.com/iam/home?#/policies/arn:aws:iam::aws:policy/AmazonSageMakerGroundTruthExecution)添加到用于创建标签任务的 IAM 执行角色，则该角色有权列出和调用函数名称中包含以下字符串之一的 Lambda 函数：`GtRecipe`、、、`SageMaker``Sagemaker``sagemaker`、或。`LabelingFunction`

如果注释前或注释后 Lambda 函数名称不包括上一段中的任何术语，或者您需要比 `AmazonSageMakerGroundTruthExecution` 托管策略中更细粒度的权限，您可以添加与下面类似的策略，以授予执行角色调用注释前和注释后函数的权限。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "lambda:InvokeFunction",
            "Resource": [
                "arn:aws:lambda:us-east-1:111122223333:function:<pre-annotation-lambda-name>",
                "arn:aws:lambda:us-east-1:111122223333:function:<post-annotation-lambda-name>"
            ]
        }
    ]
}
```

------

## 授予注释后 Lambda 访问注释的权限
<a name="sms-custom-templates-step3-postlambda-perms"></a>

如[注释后 Lambda](sms-custom-templates-step3-lambda-requirements.md#sms-custom-templates-step3-postlambda)中所述，注释后 Lambda 请求包括注释数据在 Amazon S3 中的位置。此位置由 `payload` 对象中的 `s3Uri` 字符串标识。要处理传入的注释，即使是简单的传递函数，也需要为注释后 [Lambda 执行角色](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html)分配必要的权限，以便从 Amazon S3 读取文件。

您可以通过多种方式配置 Lambda 以访问 Amazon S3 中的注释数据。两种常见的方法是：
+ 允许 Lambda 执行角色担任注释后 Lambda 请求`roleArn`中标识的 SageMaker AI 执行角色。此 SageMaker AI 执行角色用于创建标签任务，并且可以访问存储注释数据的 Amazon S3 输出存储桶。
+ 授予 Lambda 执行角色直接访问 Amazon S3 输出存储桶的权限。

使用以下部分了解如何配置这些选项。

**向 Lambda 授予担任 SageMaker AI 执行角色的权限**

要允许 Lambda 函数担任 SageMaker AI 执行角色，您必须将策略附加到 Lambda 函数的执行角色，并修改 SageMaker AI 执行角色的信任关系以允许 Lambda 担任该角色。

1. 将以@@ [下 IAM 策略附加](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_manage-attach-detach.html)到您的 Lambda 函数的执行角色，以代入中确定的 SageMaker AI 执行角色。`Resource`将 `222222222222` 替换为 [AWS 账户 ID](https://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html)。将 `sm-execution-role` 替换为代入角色的名称。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": {
           "Effect": "Allow",
           "Action": "sts:AssumeRole",
           "Resource": "arn:aws:iam::222222222222:role/sm-execution-role"
       }
   }
   ```

------

1. [修改 SageMaker AI 执行角色的信任策略](https://docs.aws.amazon.com/IAM/latest/UserGuide/roles-managingrole-editing-console.html#roles-managingrole_edit-trust-policy)以包括以下内容`Statement`。将 `222222222222` 替换为 [AWS 账户 ID](https://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html)。将 `my-lambda-execution-role` 替换为代入角色的名称。

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Principal": {
                   "AWS": "arn:aws:iam::222222222222:role/my-lambda-execution-role"
               },
               "Action": "sts:AssumeRole"
           }
       ]
   }
   ```

------

**授予 Lambda 执行角色访问 S3 的权限**

您可以将类似于以下内容的策略添加到注释后 Lambda 函数执行角色，以授予其 S3 读取权限。*amzn-s3-demo-bucket*替换为您在创建标注任务时指定的输出存储桶的名称。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*"
        }
    ]
}
```

------

要在 Lambda 控制台中为 Lambda 执行角色添加 S3 读取权限，请使用以下过程。

**将 S3 读取权限添加到注释后 Lambda：**

1. 在 Lambda 控制台中打开[**函数**页面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 选择注释后函数的名称。

1. 选择**配置**，然后选择**权限**。

1. 选择**角色名称**，该角色的摘要页面就会在 IAM 控制台的新标签页中打开。

1. 选择**附加策略**。

1. 请执行以下操作之一：
   + 搜索并选择 **`AmazonS3ReadOnlyAccess`** 以授予函数读取账户中所有存储桶和对象的权限。
   + 如果需要更细粒度的权限，请选择**创建策略**并使用上一节中的策略示例来创建策略。请注意，创建策略后必须导航回执行角色摘要页面。

1. 如果使用了 `AmazonS3ReadOnlyAccess` 托管策略，请选择**附加策略**。

   如果您创建了新策略，请导航回 Lambda 执行角色摘要页面并附加刚创建的策略。

# 使用 Ground Truth 模板创建 Lambda 函数
<a name="sms-custom-templates-step3-lambda-create"></a>

您可以使用 Lambda 控制台、或使用您选择的支持的编程语言的 AWS CLI AWS 软件开发工具包创建 Lambda 函数。使用 AWS Lambda 开发者指南详细了解以下每个选项：
+ 要了解如何使用控制台创建 Lambda 函数，请参阅[使用控制台创建 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/getting-started-create-function.html)。
+ 要了解如何使用创建 Lambda 函数 AWS CLI，请参阅在命令行界面中使用 [AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-awscli.html)。 AWS 
+ 选择目录中的相关章节，了解用您选择的语言使用 Lambda 的更多信息。例如，选择[使用 Python](https://docs.aws.amazon.com/lambda/latest/dg/lambda-python.html)，了解有关将 Lambda 与 适用于 Python (Boto3) 的 AWS SDK结合使用的更多信息。

*Ground Truth 通过 AWS Serverless Application Repository （SAR）配方提供注释前和注释后的模板。*使用以下过程在 Lambda 控制台中选择 Ground Truth 配方。

**使用 Ground Truth SAR 配方创建注释前和注释后 Lambda 函数：**

1. 在 Lambda 控制台上打开[**函数**页面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 选择**创建函数**。

1. 选择**浏览无服务器应用程序存储库**。

1. 在搜索文本框中，输入 **aws-sagemaker-ground-truth-recipe**，然后选择该应用程序。

1. 选择**部署**。应用程序的部署可能需要几分钟时间。

   部署应用程序后，Lambda 控制台的**函数**部分会显示 `serverlessrepo-aws-sagema-GtRecipePreHumanTaskFunc-<id>` 和 `serverlessrepo-aws-sagema-GtRecipeAnnotationConsol-<id>` 这两个函数。

1. 选择其中一个函数，然后在**代码**部分添加自定义逻辑。

1. 完成更改后，选择**部署**来部署这些函数。

# 测试注释前和注释后 Lambda 函数
<a name="sms-custom-templates-step3-lambda-test"></a>

您可以在 Lambda 控制台中测试注释前和注释后 Lambda 函数。如果您是 Lambda 的新用户，可以使用《 AWS Lambda 开发人员指南》中的[使用控制台创建 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/getting-started-create-function.html#gettingstarted-zip-function)教程，了解如何在控制台中测试或*调用*您的 Lambda 函数。您可以使用本页上的章节来学习如何测试通过 AWS Serverless Application Repository (SAR) 提供的 Ground Truth 注释前和注释后模板。

**Topics**
+ [先决条件](#sms-custom-templates-step3-lambda-test-pre)
+ [测试注释前 Lambda 函数](#sms-custom-templates-step3-lambda-test-pre-annotation)
+ [测试注释后 Lambda 函数](#sms-custom-templates-step3-lambda-test-post-annotation)

## 先决条件
<a name="sms-custom-templates-step3-lambda-test-pre"></a>

您必须执行以下操作才能使用本页上描述的测试。
+ 您需要访问 Lambda 控制台，还需要创建和调用 Lambda 函数的权限。要了解如何设置这些权限，请参阅[授予创建和选择 AWS Lambda 函数的权限](sms-custom-templates-step3-lambda-permissions.md#sms-custom-templates-step3-postlambda-create-perms)。
+ 如果您尚未部署 Ground Truth SAR 配方，请使用[使用 Ground Truth 模板创建 Lambda 函数](sms-custom-templates-step3-lambda-create.md)中的步骤进行部署。
+ 要测试注释后 Lambda 函数，您必须在 Amazon S3 中拥有一个包含示例注释数据的数据文件。对于简单的测试，您可以将以下代码复制并粘贴到一个文件中，将此文件另存为 `sample-annotations.json` 并[将此文件上传到 Amazon S3](https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html)。请注意此文件的 S3 URI，您需要此信息来配置注释后 Lambda 测试。

  ```
  [{"datasetObjectId":"0","dataObject":{"content":"To train a machine learning model, you need a large, high-quality, labeled dataset. Ground Truth helps you build high-quality training datasets for your machine learning models."},"annotations":[{"workerId":"private.us-west-2.0123456789","annotationData":{"content":"{\"crowd-entity-annotation\":{\"entities\":[{\"endOffset\":8,\"label\":\"verb\",\"startOffset\":3},{\"endOffset\":27,\"label\":\"adjective\",\"startOffset\":11},{\"endOffset\":33,\"label\":\"object\",\"startOffset\":28},{\"endOffset\":51,\"label\":\"adjective\",\"startOffset\":46},{\"endOffset\":65,\"label\":\"adjective\",\"startOffset\":53},{\"endOffset\":74,\"label\":\"adjective\",\"startOffset\":67},{\"endOffset\":82,\"label\":\"adjective\",\"startOffset\":75},{\"endOffset\":102,\"label\":\"verb\",\"startOffset\":97},{\"endOffset\":112,\"label\":\"verb\",\"startOffset\":107},{\"endOffset\":125,\"label\":\"adjective\",\"startOffset\":113},{\"endOffset\":134,\"label\":\"adjective\",\"startOffset\":126},{\"endOffset\":143,\"label\":\"object\",\"startOffset\":135},{\"endOffset\":169,\"label\":\"adjective\",\"startOffset\":153},{\"endOffset\":176,\"label\":\"object\",\"startOffset\":170}]}}"}}]},{"datasetObjectId":"1","dataObject":{"content":"Sift 3 cups of flour into the bowl."},"annotations":[{"workerId":"private.us-west-2.0123456789","annotationData":{"content":"{\"crowd-entity-annotation\":{\"entities\":[{\"endOffset\":4,\"label\":\"verb\",\"startOffset\":0},{\"endOffset\":6,\"label\":\"number\",\"startOffset\":5},{\"endOffset\":20,\"label\":\"object\",\"startOffset\":15},{\"endOffset\":34,\"label\":\"object\",\"startOffset\":30}]}}"}}]},{"datasetObjectId":"2","dataObject":{"content":"Jen purchased 10 shares of the stock on Janurary 1st, 2020."},"annotations":[{"workerId":"private.us-west-2.0123456789","annotationData":{"content":"{\"crowd-entity-annotation\":{\"entities\":[{\"endOffset\":3,\"label\":\"person\",\"startOffset\":0},{\"endOffset\":13,\"label\":\"verb\",\"startOffset\":4},{\"endOffset\":16,\"label\":\"number\",\"startOffset\":14},{\"endOffset\":58,\"label\":\"date\",\"startOffset\":40}]}}"}}]},{"datasetObjectId":"3","dataObject":{"content":"The narrative was interesting, however the character development was weak."},"annotations":[{"workerId":"private.us-west-2.0123456789","annotationData":{"content":"{\"crowd-entity-annotation\":{\"entities\":[{\"endOffset\":29,\"label\":\"adjective\",\"startOffset\":18},{\"endOffset\":73,\"label\":\"adjective\",\"startOffset\":69}]}}"}}]}]
  ```
+ 您必须使用中的[授予注释后 Lambda 访问注释的权限](sms-custom-templates-step3-lambda-permissions.md#sms-custom-templates-step3-postlambda-perms)说明向注释后 Lambda 函数的执行角色授予权限，以代 SageMaker 入您用于创建标签任务的 AI 执行角色。注释后 Lambda 函数使用 SageMaker AI 执行角色来访问 S3 中的注解数据文件`sample-annotations.json`。



## 测试注释前 Lambda 函数
<a name="sms-custom-templates-step3-lambda-test-pre-annotation"></a>

使用以下过程来测试在部署 Gro AWS Serverless Application Repository und Truth (SAR) 配方时创建的预注解 Lambda 函数。

**测试 Ground Truth SAR 配方注释前 Lambda 函数**

1. 在 Lambda 控制台中打开[**函数**页面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 选择从 Ground Truth SAR 配方中部署的注释前函数。此函数的名称类似于 `serverlessrepo-aws-sagema-GtRecipePreHumanTaskFunc-<id>`。

1. 在**代码来源**部分中，选择**测试**旁边的箭头。

1. 选择**配置测试事件**。

1. 保持选中**创建新测试事件**选项。

1. 在**事件模板**下，选择 G **SageMakerround Truth PreHumanTask**。

1. 为您的测试指定**事件名称**。

1. 选择**创建**。

1. 再次选择**测试**旁边的箭头，您应该会看到您创建的测试已选中，在事件名称旁用点表示。如果未选中，请选择该测试。

1. 选择**测试**来运行测试。

运行测试后，您可以看到**执行结果**。在**函数日志**中，您应该会看到类似于以下内容的响应：

```
START RequestId: cd117d38-8365-4e1a-bffb-0dcd631a878f Version: $LATEST
Received event: {
  "version": "2018-10-16",
  "labelingJobArn": "arn:aws:sagemaker:us-east-2:123456789012:labeling-job/example-job",
  "dataObject": {
    "source-ref": "s3://sagemakerexample/object_to_annotate.jpg"
  }
}
{'taskInput': {'taskObject': 's3://sagemakerexample/object_to_annotate.jpg'}, 'isHumanAnnotationRequired': 'true'}
END RequestId: cd117d38-8365-4e1a-bffb-0dcd631a878f
REPORT RequestId: cd117d38-8365-4e1a-bffb-0dcd631a878f	Duration: 0.42 ms	Billed Duration: 1 ms	Memory Size: 128 MB	Max Memory Used: 43 MB
```

在此响应中，我们可以看到 Lambda 函数的输出与所需的注释前响应语法匹配：

```
{'taskInput': {'taskObject': 's3://sagemakerexample/object_to_annotate.jpg'}, 'isHumanAnnotationRequired': 'true'}
```

## 测试注释后 Lambda 函数
<a name="sms-custom-templates-step3-lambda-test-post-annotation"></a>

使用以下过程来测试在部署 Gro AWS Serverless Application Repository und Truth (SAR) 配方时创建的注释后 Lambda 函数。

**测试 Ground Truth SAR 配方注释后 Lambda**

1. 在 Lambda 控制台中打开[**函数**页面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 选择从 Ground Truth SAR 配方中部署的注释后函数。此函数的名称类似于 `serverlessrepo-aws-sagema-GtRecipeAnnotationConsol-<id>`。

1. 在**代码来源**部分中，选择**测试**旁边的箭头。

1. 选择**配置测试事件**。

1. 保持选中**创建新测试事件**选项。

1. 在**事件模板**下，选择 G **SageMakerround Truth AnnotationConsolidation**。

1. 为您的测试指定**事件名称**。

1. 对提供的模板代码进行如下修改：
   + 将中的 `roleArn` Amazon 资源名称 (ARN) 替换为您用于创建标签任务的 SageMaker AI 执行角色的 ARN。
   + 将 `s3Uri` 中的 S3 URI 替换为添加到 Amazon S3 的 `sample-annotations.json` 文件的 URI。

   进行这些修改后，您的测试应类似于以下内容：

   ```
   {
     "version": "2018-10-16",
     "labelingJobArn": "arn:aws:sagemaker:us-east-2:123456789012:labeling-job/example-job",
     "labelAttributeName": "example-attribute",
     "roleArn": "arn:aws:iam::222222222222:role/sm-execution-role",
     "payload": {
       "s3Uri": "s3://your-bucket/sample-annotations.json"
     }
   }
   ```

1. 选择**创建**。

1. 再次选择**测试**旁边的箭头，您应该会看到您创建的测试已选中，在事件名称旁用点表示。如果未选中，请选择该测试。

1. 选择**测试**来运行测试。

运行测试后，您应该会在**函数日志**中看到 `-- Consolidated Output --` 部分，其中包含 `sample-annotations.json` 中包括的所有注释的列表。

# 演示模板：使用 `crowd-bounding-box` 的映像注释
<a name="sms-custom-templates-step2-demo1"></a>

当您在 Amazon G SageMaker round Truth 控制台中选择使用自定义模板作为任务类型时，您将进入**自定义标签任务面板**。在该面板中，您可以从多个基本模板中进行选择。模板表示一些最常见的任务，并在您创建自定义标注任务的模板时提供样本。如果您没有使用控制台，或者作为其他补救措施，请参阅 [Amazon SageMaker AI Ground Truth 示例任务 UIs ](https://github.com/aws-samples/amazon-sagemaker-ground-truth-task-uis)，了解各种标签任务类型的演示模板存储库。

此演示适用于**BoundingBox**模板。该演示还适用于任务前后处理数据所需的 AWS Lambda 函数。在上面的 Github 存储库中，要查找与 AWS Lambda 函数配合使用的模板，请在模板`{{ task.input.<property name> }}`中查找。

**Topics**
+ [入门边界框自定义模板](#sms-custom-templates-step2-demo1-base-template)
+ [您自己的边界框自定义模板](#sms-custom-templates-step2-demo1-your-own-template)
+ [您的清单文件](#sms-custom-templates-step2-demo1-manifest)
+ [注释前 Lambda 函数](#sms-custom-templates-step2-demo1-pre-annotation)
+ [注释后 Lambda 函数](#sms-custom-templates-step2-demo1-post-annotation)
+ [标注作业的输出](#sms-custom-templates-step2-demo1-job-output)

## 入门边界框自定义模板
<a name="sms-custom-templates-step2-demo1-base-template"></a>

这是所提供的入门边界框模板。

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>

<crowd-form>
  <crowd-bounding-box
    name="boundingBox"
    src="{{ task.input.taskObject | grant_read_access }}"
    header="{{ task.input.header }}"
    labels="{{ task.input.labels | to_json | escape }}"
  >

    <!-- The <full-instructions> tag is where you will define the full instructions of your task. -->
    <full-instructions header="Bounding Box Instructions" >
      <p>Use the bounding box tool to draw boxes around the requested target of interest:</p>
      <ol>
        <li>Draw a rectangle using your mouse over each instance of the target.</li>
        <li>Make sure the box does not cut into the target, leave a 2 - 3 pixel margin</li>
        <li>
          When targets are overlapping, draw a box around each object,
          include all contiguous parts of the target in the box.
          Do not include parts that are completely overlapped by another object.
        </li>
        <li>
          Do not include parts of the target that cannot be seen,
          even though you think you can interpolate the whole shape of the target.
        </li>
        <li>Avoid shadows, they're not considered as a part of the target.</li>
        <li>If the target goes off the screen, label up to the edge of the image.</li>
      </ol>
    </full-instructions>

    <!-- The <short-instructions> tag allows you to specify instructions that are displayed in the left hand side of the task interface.
    It is a best practice to provide good and bad examples in this section for quick reference. -->
    <short-instructions>
      Use the bounding box tool to draw boxes around the requested target of interest.
    </short-instructions>
  </crowd-bounding-box>
</crowd-form>
```

此自定义模板使用 [Liquid 模板语言](https://shopify.github.io/liquid/)，双大括号之间的每个项都是一个变量。预注解 AWS Lambda 函数应提供一个名为的对象，`taskInput`并且可以像在模板`{{ task.input.<property name> }}`中一样访问该对象的属性。

## 您自己的边界框自定义模板
<a name="sms-custom-templates-step2-demo1-your-own-template"></a>

举例来说，假设您有大量的动物照片，您可以通过之前的图像分类作业知道图像中的动物种类。现在，您希望在其周围绘制一个边界框。

在入门示例中，有三个变量：`taskObject`、`header` 和 `labels`。

其中每个变量都表示在边界框的不同部分中。
+ `taskObject` 是要注释的照片的 HTTP(S) URL 或 S3 URI。添加的 `| grant_read_access` 是一种筛选器，可将 S3 URI 转换为具有对该资源的短暂访问权限的 HTTPS URL。如果您使用的是 HTTP(S) URL，则不需要该筛选器。
+ `header` 是照片上方要标注的文本，如“在照片中的鸟周围画一个框”。
+ `labels` 是一个数组，表示为 `['item1', 'item2', ...]`。这些标签可以由工作人员分配给他们绘制的不同边界框。您可以有一个或多个标签。

每个变量的名称都来自于注释前 Lambda 响应中的 JSON 对象，上述名称只是建议性的，请使用任何对您有意义的变量名，这样可以提高团队的代码可读性。

**仅在必要时才使用变量**  
如果某个字段不会改变，可以从模板中删除该变量并用该文本替换，否则就必须在清单中的每个对象中重复该文本作为值，或者将其编码到注释前 Lambda 函数中。

**Example ：最终的自定义边界框模板**  
为简单起见，此模板将具有一个变量、一个标签和非常基本的说明。假设您的清单中每个数据对象都有一个“animal”属性，那么这个值就可以在模板的两个部分中重复使用。  

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>
<crowd-form>
  <crowd-bounding-box
    name="boundingBox"
    labels="[ '{{ task.input.animal }}' ]"
    src="{{ task.input.source-ref | grant_read_access }}"
    header="Draw a box around the {{ task.input.animal }}."
  >
    <full-instructions header="Bounding Box Instructions" >
      <p>Draw a bounding box around the {{ task.input.animal }} in the image. If 
      there is more than one {{ task.input.animal }} per image, draw a bounding 
      box around the largest one.</p>
      <p>The box should be tight around the {{ task.input.animal }} with 
      no more than a couple of pixels of buffer around the 
      edges.</p>
      <p>If the image does not contain a {{ task.input.animal }}, check the <strong>
      Nothing to label</strong> box.
    </full-instructions>
    <short-instructions>
      <p>Draw a bounding box around the {{ task.input.animal }} in each image. If 
      there is more than one {{ task.input.animal }} per image, draw a bounding 
      box around the largest one.</p>
    </short-instructions>
  </crowd-bounding-box>
</crowd-form>
```
注意在整个模板中重复使用 `{{ task.input.animal }}`。如果您的清单中所有动物名称都以大写字母开头，您可以使用 `{{ task.input.animal | downcase }}`，在需要小写的句子中加入 Liquid 的内置筛选器之一。

## 您的清单文件
<a name="sms-custom-templates-step2-demo1-manifest"></a>

您的清单文件应提供您在模板中使用的变量值。您可以在注释前 Lambda 中对清单数据进行一些转换，但如果您不需要这样做，就可以保持较低的出错风险，而且 Lambda 运行速度也会更快。下面是模板的清单文件示例。

```
{"source-ref": "<S3 image URI>", "animal": "horse"}
{"source-ref": "<S3 image URI>", "animal" : "bird"}
{"source-ref": "<S3 image URI>", "animal" : "dog"}
{"source-ref": "<S3 image URI>", "animal" : "cat"}
```

## 注释前 Lambda 函数
<a name="sms-custom-templates-step2-demo1-pre-annotation"></a>

作为任务设置的一部分，请提供一个 AWS Lambda 函数的 ARN，该函数可用于处理清单条目并将其传递给模板引擎。

**命名 Lambda 函数**  
命名函数的最佳实践是使用以下四个字符串之一作为函数名称的一部分：`SageMaker`、`Sagemaker`、`sagemaker` 或 `LabelingFunction`。这同时适用于注释前函数和注释后函数。

使用控制台时，如果您的账户拥有的 AWS Lambda 函数，则系统将提供符合命名要求的函数下拉列表供您选择。

在这个非常基本的示例中，您只是传递来自清单的信息，而不对其进行任何额外的处理。这个注释前函数示例是为 Python 3.7 编写的。

```
import json

def lambda_handler(event, context):
    return {
        "taskInput": event['dataObject']
    }
```

来自清单的 JSON 对象将作为 `event` 对象的子对象提供。`taskInput` 对象内部的属性将作为变量提供给模板，因此只需将 `taskInput` 的值设置为 `event['dataObject']` 即可将清单对象中的所有值传递给模板，而无需单独复制它们。如果您希望向模板发送更多的值，可以将这些值添加到 `taskInput` 对象中。

## 注释后 Lambda 函数
<a name="sms-custom-templates-step2-demo1-post-annotation"></a>

作为作业设置的一部分，提供一个 AWS Lambda 函数的 ARN，当工作人员完成任务时，可以调用该函数来处理表单数据。这可以很简单，也可以很复杂。如果你想在答案出现时进行整合和评分，你可以应用你选择的评分 and/or 合并算法。如果您想要存储原始数据以进行脱机处理，则这是一个选项。

**提供对注释后 Lambda 的权限**  
注释数据将位于一个文件中，该文件由 `payload` 对象中的 `s3Uri` 字符串指定。要处理传入的注释，即使是简单的传递函数，也需要为 Lambda 分配 `S3ReadOnly` 访问权限，以使其能够读取注释文件。  
在创建 Lambda 的控制台页面中，滚动到**执行角色**面板。选择**从一个或多个模板中创建新角色**。指定角色的名称。从**策略模板**下拉列表中，选择 **Amazon S3 对象只读权限**。保存 Lambda，将保存并选择该角色。

下面是 Python 2.7 中的示例。

```
import json
import boto3
from urlparse import urlparse

def lambda_handler(event, context):
    consolidated_labels = []

    parsed_url = urlparse(event['payload']['s3Uri']);
    s3 = boto3.client('s3')
    textFile = s3.get_object(Bucket = parsed_url.netloc, Key = parsed_url.path[1:])
    filecont = textFile['Body'].read()
    annotations = json.loads(filecont);
    
    for dataset in annotations:
        for annotation in dataset['annotations']:
            new_annotation = json.loads(annotation['annotationData']['content'])
            label = {
                'datasetObjectId': dataset['datasetObjectId'],
                'consolidatedAnnotation' : {
                'content': {
                    event['labelAttributeName']: {
                        'workerId': annotation['workerId'],
                        'boxesInfo': new_annotation,
                        'imageSource': dataset['dataObject']
                        }
                    }
                }
            }
            consolidated_labels.append(label)
    
    return consolidated_labels
```

注释后 Lambda 通常会在事件对象中接收成批的任务结果。该批次将是 Lambda 应该遍历的 `payload` 对象。您发回的将是一个符合 [API 合约](sms-custom-templates-step3.md)的对象。

## 标注作业的输出
<a name="sms-custom-templates-step2-demo1-job-output"></a>

您将在指定的目标 S3 存储桶中以标注作业命名的文件夹中找到作业的输出。它将位于名为 `manifests` 的子文件夹中。

对于边界框任务，您在输出清单找到的输出将有点类似于下面的演示。该示例已清理以供打印。实际输出将是每条记录一行。

**Example ：输出清单中的 JSON**  

```
{
  "source-ref":"<URL>",
  "<label attribute name>":
    {
       "workerId":"<URL>",
       "imageSource":"<image URL>",
       "boxesInfo":"{\"boundingBox\":{\"boundingBoxes\":[{\"height\":878, \"label\":\"bird\", \"left\":208, \"top\":6, \"width\":809}], \"inputImageProperties\":{\"height\":924, \"width\":1280}}}"},
  "<label attribute name>-metadata":
    {
      "type":"groundTruth/custom",
      "job_name":"<Labeling job name>",
      "human-annotated":"yes"
    },
  "animal" : "bird"
}
```
请注意原始清单中的 `animal` 附加属性是如何与 `source-ref` 和标注数据同级传递到输出清单的。输入清单中的任何属性，无论是否在模板中使用，都将传递到输出清单中。

# 演示模板：使用 `crowd-classifier` 的标注目的
<a name="sms-custom-templates-step2-demo2"></a>

如果您选择自定义模板，将转到**自定义标注任务面板**。在该面板上，您可以从多个表示一些更常见任务的入门模板中进行选择。这些模板为构建自定义标注任务的模板提供了一个起点。

在此演示中，您将使用**目的检测**模板，该模板使用 `crowd-classifier` 元素和在任务前后处理数据所需的 AWS Lambda 函数。

**Topics**
+ [入门目的检测自定义模板](#sms-custom-templates-step2-demo2-base-template)
+ [您的目的检测自定义模板](#sms-custom-templates-step2-demo2-your-template)
+ [注释前 Lambda 函数](#sms-custom-templates-step2-demo2-pre-lambda)
+ [注释后 Lambda 函数](#sms-custom-templates-step2-demo2-post-lambda)
+ [您的标注作业输出](#sms-custom-templates-step2-demo2-job-output)

## 入门目的检测自定义模板
<a name="sms-custom-templates-step2-demo2-base-template"></a>

这是作为起点提供的目的检测模板。

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>

<crowd-form>
  <crowd-classifier
    name="intent"
    categories="{{ task.input.labels | to_json | escape }}"
    header="Pick the most relevant intention expressed by the below text"
  >
    <classification-target>
      {{ task.input.utterance }}
    </classification-target>
    
    <full-instructions header="Intent Detection Instructions">
        <p>Select the most relevant intention expressed by the text.</p>
        <div>
           <p><strong>Example: </strong>I would like to return a pair of shoes</p>
           <p><strong>Intent: </strong>Return</p>
        </div>
    </full-instructions>

    <short-instructions>
      Pick the most relevant intention expressed by the text
    </short-instructions>
  </crowd-classifier>
</crowd-form>
```

此自定义模板使用 [Liquid 模板语言](https://shopify.github.io/liquid/)，双大括号之间的每个项都是一个变量。预注解 Lamb AWS da 函数应提供一个`taskInput`名为的对象，并且可以像在模板中`{{ task.input.<property name> }}`一样访问该对象的属性。

## 您的目的检测自定义模板
<a name="sms-custom-templates-step2-demo2-your-template"></a>

在入门模板中，有两个变量：`crowd-classifier` 元素开始标签中的 `task.input.labels` 属性和 `classification-target` 区域内容中的 `task.input.utterance`。

除非您需要为不同的语篇提供不同的标签集，否则避免使用变量而只使用文本将节省处理时间，并减少出错的可能性。本演示中使用的模板将删除该变量，但类似 `to_json` 的变量和筛选器将在 [`crowd-bounding-box` 演示]()文章中进行更详细的说明。

### 元素样式设计
<a name="sms-custom-templates-step2-demo2-instructions"></a>

这些自定义元素中有时会被忽略的两个部分是 `<full-instructions>` 和 `<short-instructions>` 区域。好的说明会产生好的结果。

在包含这些区域的元素中，`<short-instructions>` 自动显示在工作人员屏幕左侧的“说明”窗格中。`<full-instructions>` 链接自该窗格顶部附近的“查看完整说明”链接。单击链接可打开一个模式窗格，其中包含更详细的说明。

你不仅可以使用 HTML、CSS，而且 JavaScript 在这些章节中，如果你认为自己能提供一套强有力的说明和示例，帮助工作人员以更快的速度和准确度完成任务，那么我们鼓励你这样做。

**Example 试试样品 JSFiddle**  
[https://jsfiddle.net/MTGT_Fiddle_Manager/bjc0y1vd/35/](https://jsfiddle.net/MTGT_Fiddle_Manager/bjc0y1vd/35/)  
 试用 [`<crowd-classifier>` 任务示例](https://jsfiddle.net/MTGT_Fiddle_Manager/bjc0y1vd/35/)。该示例由呈现 JSFiddle，因此所有模板变量都替换为硬编码值。单击“查看完整说明”链接，查看一组具有扩展 CSS 样式的示例。您可以分叉项目，尝试自己对 CSS 的更改、添加示例图像或添加扩展 JavaScript 功能。

**Example ：最终的自定义目的检测模板**  
该模板使用 [`<crowd-classifier>` 任务示例](https://jsfiddle.net/MTGT_Fiddle_Manager/bjc0y1vd/35/)，但为 `<classification-target>` 添加了一个变量。如果您尝试在一系列不同的标注作业中保持一致的 CSS 设计，可以像在任何其他 HTML 文档中一样，使用 `<link rel...>` 元素包含外部样式表。  

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>

<crowd-form>
  <crowd-classifier
    name="intent"
    categories="['buy', 'eat', 'watch', 'browse', 'leave']"
    header="Pick the most relevant intent expressed by the text below"
  >
    <classification-target>
      {{ task.input.source }}
    </classification-target>
    
    <full-instructions header="Emotion Classification Instructions">
      <p>In the statements and questions provided in this exercise, what category of action is the speaker interested in doing?</p>
          <table>
            <tr>
              <th>Example Utterance</th>
              <th>Good Choice</th>
            </tr>
            <tr>
              <td>When is the Seahawks game on?</td>
              <td>
                eat<br>
                <greenbg>watch</greenbg>
                <botchoice>browse</botchoice>
              </td>
            </tr>
            <tr>
              <th>Example Utterance</th>
              <th>Bad Choice</th>
            </tr>
            <tr>
              <td>When is the Seahawks game on?</td>
              <td>
                buy<br>
                <greenbg>eat</greenbg>
                <botchoice>watch</botchoice>
              </td>
            </tr>
          </table>
    </full-instructions>

    <short-instructions>
      What is the speaker expressing they would like to do next?
    </short-instructions>  
  </crowd-classifier>
</crowd-form>
<style>
  greenbg {
    background: #feee23;
    display: block;
  }

  table {
    *border-collapse: collapse; /* IE7 and lower */
    border-spacing: 0; 
  }

  th, tfoot, .fakehead {
    background-color: #8888ee;
    color: #f3f3f3;
    font-weight: 700;
  }

  th, td, tfoot {
      border: 1px solid blue;
  }

  th:first-child {
    border-radius: 6px 0 0 0;
  }

  th:last-child {
    border-radius: 0 6px 0 0;
  }

  th:only-child{
    border-radius: 6px 6px 0 0;
  }

  tfoot:first-child {
    border-radius: 0 0 6px 0;
  }

  tfoot:last-child {
    border-radius: 0 0 0 6px;
  }

  tfoot:only-child{
    border-radius: 6px 6px;
  }

  td {
    padding-left: 15px ;
    padding-right: 15px ;
  }

  botchoice {
    display: block;
    height: 17px;
    width: 490px;
    overflow: hidden;
    position: relative;
    background: #fff;
    padding-bottom: 20px;
  }

  botchoice:after {
    position: absolute;
    bottom: 0;
    left: 0;  
    height: 100%;
    width: 100%;
    content: "";
    background: linear-gradient(to top,
       rgba(255,255,255, 1) 55%, 
       rgba(255,255,255, 0) 100%
    );
    pointer-events: none; /* so the text is still selectable */
  }
</style>
```

**Example ：您的清单文件**  
如果您正在手动为这样的文本分类任务准备清单文件，请按以下方式格式化数据。  

```
{"source": "Roses are red"}
{"source": "Violets are Blue"}
{"source": "Ground Truth is the best"}
{"source": "And so are you"}
```

这有别于用于“[演示模板：使用 `crowd-bounding-box` 的映像注释](sms-custom-templates-step2-demo1.md)”演示的清单文件，在后者中，`source-ref` 用作属性名而非 `source`。使用`source-ref`指定 S3 URIs 表示必须转换为 HTTP 的图像或其他文件。否则，应将 `source` 视为含上面的文本字符串来使用。

## 注释前 Lambda 函数
<a name="sms-custom-templates-step2-demo2-pre-lambda"></a>

作为任务设置的一部分，提供的 ARN，可以调用 AWS Lambda 它来处理您的清单条目并将其传递给模板引擎。

此 Lambda 函数必须包含以下四个字符串之一作为函数名的一部分：`SageMaker`、`Sagemaker`、`sagemaker` 或 `LabelingFunction`。

这同时适用于注释前和注释后 Lambda 函数。

在使用控制台时，如果您的账户拥有 Lambdas，则会提供一个符合命名要求的函数下拉列表，供您选择。

在这个非常基本的示例中，只有一个变量，主要是传递函数。下面是一个使用 Python 3.7 的标注前 Lambda 示例。

```
import json

def lambda_handler(event, context):
    return {
        "taskInput":  event['dataObject']
    }
```

`event` 的 `dataObject` 属性包含来自清单中的数据对象的属性。

本演示只是一个变量的简单传递，您只是将该变量作为 `taskInput` 值直接传递。如果将具有这些值的属性添加到 `event['dataObject']` 对象，则它们可作为格式为 `{{ task.input.<property name> }}` 的 Liquid 变量用于 HTML 模板。

## 注释后 Lambda 函数
<a name="sms-custom-templates-step2-demo2-post-lambda"></a>

作为作业设置的一部分，提供一个 Lambda 函数的 ARN，当工作人员完成任务时，可以调用该函数来处理表单数据。这可以很简单，也可以很复杂。如果您想在收到数据时进行答案合并和评分，您可以应用自己选择的评分或合并算法。如果您想要存储原始数据以进行脱机处理，则这是一个选项。

**设置对注释后 Lambda 函数的权限**  
注释数据将位于一个文件中，该文件由 `payload` 对象中的 `s3Uri` 字符串指定。要处理传入的注释，即使是简单的传递函数，也需要为 Lambda 分配 `S3ReadOnly` 访问权限，以使其能够读取注释文件。  
在创建 Lambda 的控制台页面中，滚动到**执行角色**面板。选择**从一个或多个模板中创建新角色**。指定角色的名称。从**策略模板**下拉列表中，选择 **Amazon S3 对象只读权限**。保存 Lambda，将保存并选择该角色。

以下示例适用于 Python 3.7。

```
import json
import boto3
from urllib.parse import urlparse

def lambda_handler(event, context):
    consolidated_labels = []

    parsed_url = urlparse(event['payload']['s3Uri']);
    s3 = boto3.client('s3')
    textFile = s3.get_object(Bucket = parsed_url.netloc, Key = parsed_url.path[1:])
    filecont = textFile['Body'].read()
    annotations = json.loads(filecont);
    
    for dataset in annotations:
        for annotation in dataset['annotations']:
            new_annotation = json.loads(annotation['annotationData']['content'])
            label = {
                'datasetObjectId': dataset['datasetObjectId'],
                'consolidatedAnnotation' : {
                'content': {
                    event['labelAttributeName']: {
                        'workerId': annotation['workerId'],
                        'result': new_annotation,
                        'labeledContent': dataset['dataObject']
                        }
                    }
                }
            }
            consolidated_labels.append(label)

    return consolidated_labels
```

## 您的标注作业输出
<a name="sms-custom-templates-step2-demo2-job-output"></a>

注释后 Lambda 通常会在事件对象中接收成批的任务结果。该批次将是 Lambda 应该遍历的 `payload` 对象。

您将在指定的目标 S3 存储桶中以标注作业命名的文件夹中找到作业的输出。它将位于名为 `manifests` 的子文件夹中。

对于目的检测任务，输出清单中的输出将有点类似于下面的演示。这个示例已进行清理并加宽间距，以便于阅读。实际输出将经过更多压缩，以便机器读取。

**Example ：输出清单中的 JSON**  

```
[
  {
    "datasetObjectId":"<Number representing item's place in the manifest>",
     "consolidatedAnnotation":
     {
       "content":
       {
         "<name of labeling job>":
         {     
           "workerId":"private.us-east-1.XXXXXXXXXXXXXXXXXXXXXX",
           "result":
           {
             "intent":
             {
                 "label":"<label chosen by worker>"
             }
           },
           "labeledContent":
           {
             "content":"<text content that was labeled>"
           }
         }
       }
     }
   },
  "datasetObjectId":"<Number representing item's place in the manifest>",
     "consolidatedAnnotation":
     {
       "content":
       {
         "<name of labeling job>":
         {     
           "workerId":"private.us-east-1.6UDLPKQZHYWJQSCA4MBJBB7FWE",
           "result":
           {
             "intent":
             {
                 "label": "<label chosen by worker>"
             }
           },
           "labeledContent":
           {
             "content": "<text content that was labeled>"
           }
         }
       }
     }
   },
     ...
     ...
     ...
]
```

这应该有助于您创建和使用自己的自定义模板。

# 使用 API 创建自定义工作流程
<a name="sms-custom-templates-step4"></a>

在创建了自定义 UI 模板（步骤 2）和处理 Lambda 函数（步骤 3）时，您应该将模板放在 Amazon S3 存储桶中，并且文件名格式为：`<FileName>.liquid.html`。使用 [https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateLabelingJob.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateLabelingJob.html) 操作配置您的任务。您将使用存储在 S3 上 `<filename>.liquid.html` 文件中的自定义模板 ([创建自定义工作人员任务模板](sms-custom-templates-step2.md)) 的位置作为 [https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_HumanTaskConfig.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_HumanTaskConfig.html) 对象内 [https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_UiConfig.html](https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_UiConfig.html) 对象中 `UiTemplateS3Uri` 字段的值。

对于中描述的 AWS Lambda 任务[使用自定义标签工作流程处理数据 AWS Lambda](sms-custom-templates-step3.md)，注释后任务的 ARN 将用作`AnnotationConsolidationLambdaArn`字段的值，注释前任务将用作该字段的值 `PreHumanTaskLambdaArn.` 