

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用註釋前與註釋後 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 Resource Name 或 ARN。當利用 Ground Truth API 作業 (例如 `DescribeLabelingJob`) 時，此 ARN 可用於參照標籤工作。
+ `dataObject` (JSON 物件)：此索引鍵包含單一 JSON 行，可能是從您的輸入資訊清單檔案或從 Amazon SNS 傳送。資訊清單中的 JSON line 物件最大為 100 KB，並且可包含各式各樣的資料。對於非常基本的影像註釋工作，`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 return 陳述式的 `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 函式範例，請參閱 GitHub 儲存庫 [aws-sagemaker-ground-truth-recipe](https://github.com/aws-samples/aws-sagemaker-ground-truth-recipe) 的 [annotation\_consolidation\_lambda.py](https://github.com/aws-samples/aws-sagemaker-ground-truth-recipe/blob/master/aws_sagemaker_ground_truth_sample_lambda/annotation_consolidation_lambda.py)。

下列程式碼區塊包含註釋後請求結構描述。每個參數皆詳述於下列項目符號清單。

```
{
    "version": "2018-10-16",
    "labelingJobArn": {{<string>}},
    "labelCategories": [{{<string>}}],
    "labelAttributeName": {{<string>}},
    "roleArn" : {{<string>}},
    "payload": {
        "s3Uri": {{<string>}}
    }
 }
```
+ `version` (字串)：Ground Truth 內部使用的版本號碼。
+ `labelingJobArn` (字串)：標籤工作的 Amazon Resource Name 或 ARN。當利用 Ground Truth API 作業 (例如 `DescribeLabelingJob`) 時，此 ARN 可用於參照標籤工作。
+ `labelCategories` (字串清單)：包括您在主控台指定的標籤類別與其他屬性，或包含在標籤類別組態檔案的標籤類別與其他屬性。
+ `labelAttributeName` (字串)：標籤工作的名稱，或在建立標籤工作時指定的標籤屬性名稱。
+ `roleArn` (字串)：在建立標籤工作時針對 IAM 執行角色指定的 Amazon Resource Name (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 物件清單)：此清單包含工作者針對此 `dataObject` 所提交每個註釋的單一 JSON 物件。單一 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 函式可能包含類似以下內容的邏輯，以便循環檢視並存取請求所包含的所有註釋。如需完整範例，請參閱 GitHub 儲存庫 [aws-sagemaker-ground-truth-recipe](https://github.com/aws-samples/aws-sagemaker-ground-truth-recipe) 的 [annotation\_consolidation\_lambda.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}}
                }
            }
        }
    }
    .
    .
    .
]
```
此時，所有傳送到您 S3 儲存貯體的資料 (除了 `datasetObjectId` 之外) 位於 `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 不會針對資料提供進一步處理。