在 Amazon Bedrock 上使用零样本大型语言模型进行自定义命名实体识别 机器学习博客
在Amazon Bedrock上使用零shot大型语言模型进行自定义命名实体识别
重点摘要
本文介绍了零shot命名实体识别NER的概念及其在Amazon Bedrock上的实现过程。通过使用大型语言模型LLMs,用户可以在不需专门微调的情况下,快速从文本中提取感兴趣的实体信息,从而在海量文档中提高效率。
命名实体识别NER是从结构化或非结构化文本中提取信息即“实体”的过程。手动识别文档中特定信息类型的所有提及非常耗时且劳动密集。传统的神经网络模型如RNN和LSTM及现代的基于变换器的模型如BERT通常需要针对每种自定义实体类型进行昂贵的微调,这使得在许多应用中采纳和扩展这些方法成为一种负担。而大型语言模型的新能力则使得高精度的NER能够跨越各种实体类型进行,实现零shot识别。
解决方案概述
在本解决方案中,我们通过以下关键服务实现零shot NER:
服务描述Amazon Textract从输入文档中提取文本信息。Amazon Comprehend可选识别预定义的实体,例如人名、日期和数值。用户可以使用此功能来限制感兴趣实体的上下文。Amazon Bedrock调用LLM从给定上下文中识别感兴趣的实体。
以下图示说明了解决方案架构:
主要输入为文档图像和目标实体。目标是找到文档中目标实体的值。如果选择了截断路径,则流水线使用Amazon Comprehend来缩减上下文。LLM的输出经过后处理以生成实体值对的输出。
例如,如果输入文档是AWS维基页面,目标实体为AWS服务名称和地理位置,期望的输出格式如下:
AWS服务名称 lt在维基页面中提到的所有AWS服务名称gt地理位置 lt维基页面中的所有地理位置名称gt接下来的部分将描述实现此任务的三个主要模块。本文使用了AWS SageMaker笔记本mlt3medium实例以及Amazon Textract、Amazon Comprehend和Amazon Bedrock。
提取上下文
上下文是从文档中提取的信息,其中包含要查询实体的值。当使用完整文档完整上下文时,上下文显著增加了输入token的数量。我们提供了使用整个文档或用户定义的相关部分的本地上下文的选项。
首先,我们使用Amazon Textract从整个文档中提取上下文。以下代码使用amazontextractcaller库作为Textract API调用的包装器。您需要先安装该库:
bashpython m pip install amazontextractcaller
然后,对于单页文档如PNG或JPEG文件,使用以下代码提取完整上下文:
蜜蜂加速器软件优势pythonfrom textractcallertcall import calltextract TextractFeatures from textractprettyprintertprettyprint import gettextfromlayoutjson
documentname = sampledata/syntheticsampledatapng
调用Textract
layouttextractjson = calltextract( inputdocument=documentname features=[TextractFeaturesLAYOUT])
从JSON响应中提取文本
fullcontext = gettextfromlayoutjson(textractjson=layouttextractjson)[1]
请注意,PDF输入文档在使用calltextract函数时必须存储在S3桶中。对于多页TIFF文件,请务必设置forceasyncapi=True。
截断上下文可选
当用户定义的自定义实体稀疏,相较于完整上下文时,我们提供了识别相关本地上下文的选项,然后在本地上下文中查找自定义实体。因此,我们利用Amazon Comprehend进行通用实体提取,假设用户定义的自定义实体是某个默认Amazon Comprehend实体的子集,例如“名称”、“地点”、“日期”或“组织”。例如,“城市”是“地点”的子集。我们通过AWS SDK for Python (Boto3)提取默认通用实体,代码如下:
pythonimport pandas as pdcomprehendclient = boto3client(comprehend)genericentities = comprehendclientdetectentities(Text=fullcontext LanguageCode=en)dfentities = pdDataFramefromdict(genericentities[Entities])
输出为一个包含实体类型“Type”、值“Text”及其他信息如“Score”、“BeginOffset”、“EndOffset”的字典列表。更多细节请参见DetectEntities。以下是Amazon Comprehend实体提取的示例输出,展示提取的通用实体值对以及其在文本中的位置。
json{ Entities [ { Text AWS Score 098 Type ORGANIZATION BeginOffset 21 EndOffset 24 } { Text US East Score 097 Type LOCATION BeginOffset 1100 EndOffset 1107 } ] LanguageCode en}
提取的通用实体列表可能比查询实体更为详尽,因此需要一个过滤步骤。例如,当查询实体为“AWS revenue”而通用实体包含“quantity”、“location”、“person”等等时。为了只保留相关的通用实体,我们定义映射并应用过滤,代码如下:
pythonqueryentities = [XX]userdefinedmap = {XX QUANTITY YY PERSON}entitiestokeep = [v for kv in userdefinedmapitems() if k in queryentities]dffiltered = dfentitiesloc[dfentities[Type]isin(entitiestokeep)]
识别出了一组通用实体值对后,我们希望保留每个对周围的本地上下文,并掩盖其他所有信息。我们通过对“BeginOffset”和“EndOffset”施加缓冲来实现:
pythonStrBuff EndBuff = 20 10dfoffsets = dffilteredapply(lambda row pdSeries({BeginOffset max(0 row[BeginOffset]StrBuff) EndOffset min(row[EndOffset] EndBuff len(fullcontext))}) axis=1)resetindex(drop=True)
我们还合并任何重叠的偏移量以避免上下文重复:
pythonfor index in dfoffsetsiterrows() if (index gt 0) and (dfoffsetsiloc[index][BeginOffset] lt= dfoffsetsiloc[index1][EndOffset]) dfoffsetsiloc[index][BeginOffset] = dfoffsetsiloc[index1][BeginOffset]dfoffsets = dfoffsetsgroupby([BeginOffset])last()resetindex()
最后,我们通过使用缓冲和合并的偏移量截断完整上下文:
pythontruncatedtext = /njoin([fullcontext[row[BeginOffset]row[EndOffset]] for row in dfoffsetsiterrows()])
另一个截断步骤是使用Amazon Textract的布局特征将上下文缩小为文档中的相关文本块。布局是Amazon Textract新功能,可以从文档中提取段落、标题、列表、页眉、页脚等元素。一旦确定了相关文本块,就可以进行我们提到的缓冲偏移量截断。
提取实体值对
根据完整上下文或本地上下文作为输入,下一步是使用LLM自定义提取实体值。我们提出了一个通用提示模板,以通过Amazon Bedrock提取自定义实体。自定义实体的示例包括产品代码、SKU编号、员工ID、产品ID、收入和运营地点。它提供了有关NER任务和期望输出格式的通用说明。LLM的提示输入包括四个组成部分:初始指令、自定义实体作为查询实体、上下文和LLM输出的期望格式。以下是基线提示的示例。自定义实体作为列表纳入查询实体。此过程具有灵活性,可以处理可变数量的实体。
pythonprompt = 根据以下文本,识别这些命名实体: “{queryentities}”文本 “{context}”按以下格式响应: “{output format}”
使用上述提示,我们可以通过InvokeModel调用指定的Amazon Bedrock模型,代码如下。有关Amazon Bedrock上可用模型和提示策略的完整列表,请参见Amazon Bedrock基础模型ID按需吞吐量。
pythonimport jsonbedrockclient = boto3client(servicename=bedrockruntime)body = jsondumps({ prompt fnnHuman {prompt}nnAssistant maxtokenstosample 300 temperature 01 topp 09 })modelId = anthropicclaudev2accept = application/jsoncontentType = application/json
response = bedrockclientinvokemodel(body=body modelId=modelId accept=accept contentType=contentType)responsebody = jsonloads(responseget(body)read())print(responsebodyget(completion))
尽管这里描述的整体解决方案旨在处理非结构化数据如文档和电子邮件和结构化数据如表格,但还有另一种方法可以在结构化数据上进行实体提取,即使用Amazon Textract查询功能。当提供查询时,Amazon Textract可以通过指定自然语言问题的方式使用查询或自定义查询来提取实体。有关更多信息,请参见使用Amazon Textract的新Queries功能指定和提取文档中的信息。
用例
为了展示示例用例,我们使用Anthropic ClaudeV2在Amazon Bedrock上生成有关AWS的一些文本如图所示,将其保存为图像以模拟扫描文档,然后使用所提出的解决方案识别文本中的一些实体。由于此示例由LLM生成,内容可能并不完全准确。我们使用以下提示生成文本:“生成关于Amazon AWS的10个段落,其中包含AWS服务名称的示例、一些数值以及美元金额值、列表项和实体值对。”
接下来我们提取以下目标实体的值:
AWS运营的国家AWS年收入如解决方案架构所示,图像首先发送到Amazon Textract以提取内容作为文本。接着有两种选择:
无截断 使用完整文本及目标实体为LLM创建提示有截断 使用Amazon Comprehend检测通用实体、识别目标实体的候选位置,并将文本截断到这些实体的邻近区域在此示例中,我们要求Amazon Comprehend识别location和quantity实体,并对输出进行后处理以限制文本到已识别实体的邻域。在下图中,location实体周围的上下文被标记为紫色,而quantity实体周围的上下文被标记为黄色。由于高亮文本是截断后唯一保留的文本,这种方法可以减少输入到LLM的token数量,从而最终节省成本。在此示例中,采用截断和总缓冲大小为30的情况下,输入token数量几乎减少了50。由于LLM的成本是输入token和输出token数量的函数,因此输入token导致的成本降低了近50。更多细节请参见Amazon Bedrock定价
根据实体和可选截断上下文,以下提示被发送给LLM:
pythonprompt = 根据以下文本,识别这些命名实体: AWS运营的国家,AWS年收入
文本 “{可选截断的上下文}”
按以下格式响应:
AWS运营的国家:lt文本中所有AWS运营的国家实体gt
AWS年收入:lt文本中所有AWS年收入实体gt
以下表格显示了Anthropic ClaudeV2在Amazon Bedrock上针对不同文本输入的响应再次强调,作为输入的文档由LLM生成,可能并不完全准确。即使在移除近50上下文后,LLM仍能生成正确响应。
输入文本LLM响应完整上下文AWS运营的国家:useast1在维吉尼亚北部,euwest1在爱尔兰,apsoutheast1在新加坡 AWS年收入:620亿截断上下文AWS运营的国家:useast1在维吉尼亚北部,euwest1在爱尔兰,apsoutheast1在新加坡 AWS年收入:620亿年收入结论
在本文中,我们探讨了LLM在进行命名实体识别时的潜力,而无需专门微调。您可以使用此管道在大规模提取结构化和非结构化文本文档中的信息。此外,选用的截断方式有可能在保持性能的同时减少文档大小,从而降低LLM的token输入。尽管零shot LLM已经证明能够进行NER,我们认为尝试fewshot LLM也是值得探索的。如果您想开始在AWS上进行LLM之旅,请参考Amazon Bedrock用户指南。
关于作者
苏吉莎马丁是生成性AI创新中心GAIIC的应用科学家。她在构建涉及计算机视觉和自然语言处理的机器学习解决方案方面具有专业知识,尤其是在高度自主系统中进行以人为中心的情境感知和知识融入学习方面积累了丰富的经验。
马修罗德斯是生成性AI创新中心GAIIC的数据科学家。他专注于构建涉及自然语言处理和计算机视觉等概念的机器学习管道。
亚敏塔杰尔登是生成性AI创新中心GAIIC的应用科学家。他拥有计算机科学和机器学习的广泛背景,特别关注深度学习、预测解释方法、模型漂移检测、概率生成模型及人工智能在医疗领域的应用。