当前位置: 首页 > news >正文

支持高性能结构化数据提取的 Embedding 模型——NuExtract-v1.5

NuExtract 是一个用户友好型模型,设计用于从长文档中提取信息。它可以处理长达 20,000 个标记的输入,是合同、报告和其他商业通信的理想选择。NuExtract 的与众不同之处在于它能够处理和理解文档的整个上下文。这意味着它可以捕捉到可能分散在长文本不同部分的关系和信息。

NuExtract 具有高效性和可扩展性。它可以管理大量文本数据,而不需要更多的计算能力,这对于同时处理多个长文档来说非常有利。这种效率得益于它的文本到文本模型架构,也就是善于理解和总结文本的花哨说法。
NuExtract 的另一个亮点是它的多功能性。它可以使用 JSON 模板提取各种结构化信息。因此,无论是姓名、日期、地点还是其他重要细节,NuExtract 都能为你找到并组织这些信息。

总之,NuExtract 就像一个超级高效的全能助手,能帮你理清冗长复杂的文档,准确提取出你需要的信息。

多语言能力

我们收到的最常见请求之一是让 NuExtract 能够处理英语以外的语言。 为此,我们需要一个多语言数据集和一个多语言基础模型。 幸运的是,Phi-3.5 mini 最近在这方面取得了很大进展,现在可以处理阿拉伯语、中文、捷克语、丹麦语、荷兰语、英语、芬兰语、法语、德语、希伯来语、匈牙利语、意大利语、日语、韩语、挪威语、波兰语、葡萄牙语、俄语、西班牙语、瑞典语、泰语、土耳其语和乌克兰语。 我们选择 Phi-3.5 mini 作为 NuExtract 的基础。

对于训练数据集,我们需要原始文档。 我们再次从 C4 数据集中获取这些文档。 我们选择了 50% 的英文文档和 50% 的其他语言文档(主要是法语、德语、西班牙语、意大利语和葡萄牙语)。 为了让 NuExtract 能正确处理长文档,我们还加入了比原始 NuExtract 更长的文档。

我们需要对这些文档进行注释,这意味着要为每份文档生成模板和输出。 现在有一个重要的问题:模板应该使用哪种语言? 我们选择对一半的文档使用英文模板,而另一半文档则使用与文档相同的语言。 这样,当用户需要处理多种语言的文档时,就可以创建一个独特的英文模板。 然后,我们使用与 NuExtract 相同的自动注释程序。 下面是一个带有英文模板的法文文档示例:

在这里插入图片描述
请注意,与最初的 NuExtract 一样,该数据集仍然是纯粹的提取型:我们训练模型复制粘贴文档的部分内容,而不是生成任何新内容。 我们打算在下一个版本中增加抽象/重构能力。

无限语境

由于使用了 Phi-3.5 mini 作为基础模型,NuExtract 1.5 现在的上下文大小为 128k 标记(约 200 页),这对于绝大多数应用来说应该足够了。 尽管如此,仍然存在一个问题:使用这样的转换器模型处理长文档需要消耗大量内存(和计算量),因为每个标记都需要在其他标记之上进行处理。 以下是 NuExtract 在处理给定长度的序列时所需要的 GPU 内存:

在这里插入图片描述
我们可以看到,对于小于 10,000 个标记的序列,内存主要用于存储约 10GB 的模型。 然而,超过 10,000 个标记后,我们就进入了二次扩展阶段(存储标记-标记注意力分数)。 最大 128k 标记上下文需要 1TB 的 GPU 内存! 这意味着,对于小于10,000个字节的序列,像L4这样的标准GPU就可以为NuExtract提供服务,而对于更长的序列,我们则需要多个高端昂贵的GPU。

为了解决长序列的内存问题,我们采用了一种独创的解决方案:我们训练NuExtract,使其能够在获得先前信息的情况下从文档中提取信息。 为了让 NuExtract 1.5 具备这种能力,我们在数据集中添加了新的示例,这些示例都提供了先前的信息,例如

在这里插入图片描述
持续提取示例。 输出结果来自文本、模板和之前提取的信息。 请注意,这里的温度值会被覆盖。 (注:此示例仅供参考,不作为训练集的一部分)。

有了这样的例子,模型就应该学会合并以前的信息和新信息。 这种合并并非易事,有时会出现信息冲突。

这种 "延续 "能力允许我们在通过滑动上下文窗口处理文本时,通过迭代重新注入当前信息状态来处理任意长的文档,这让人联想到递归神经网络。 这个过程的好处在于,内存占用受窗口大小的限制。 下面是一个 10k 的提取窗口所需的内存,假设输出大小恒定为 2k 左右:

在这里插入图片描述
使用 NuExtract 的 GPU 内存需求比较:全提取窗口和 10k 标记提取窗口,2k 标记输出。

我们看到,无论文档大小如何,内存现在都小于 30GB。

这种策略的缺点是需要多次生成输出,如果滑动窗口太小,性能就会下降(见结果部分)。 此外,这种方法只有在输出比文档小很多的情况下才会起作用,而长文档通常就是这种情况。

英语性能

我们先来看看训练有素的模型在英语基准测试中的性能。 该基准由来自 12 个提取问题的 600 个示例组成,涵盖各种使用情况。 在现阶段,它仍然是一个实验性基准,但对于比较模型已经非常有用(我们计划在完成后公开发布)。 请注意,该基准还测试了 NuExtract 尚不具备的抽象能力。

在这里插入图片描述
我们可以看到,NuExtract 1.5 比原来的 NuExtract 要好得多。 此外,NuExtract 甚至比 GPT-4o 还要好一些!

现在我们来看看模型访问输入-输出示例时的结果。 我们使用与之前相同的基准,并在 12 个问题中的每个问题的 45 个示例上对 NuExtract 1.5 进行微调。 我们还通过将所有 45 个示例都放入提示中(又称上下文学习)来对 GPT-4o 进行基准测试,之所以能做到这一点,是因为我们的基准示例都很短,通常只有 1k 个词组,这意味着提示内容约为 50k 个词组:

在这里插入图片描述
不出所料,所有模型都大幅提高了性能(阴影部分)。 我们可以看到,GPT-4o 现在比 NuExtract 1.5 好,但好得不多。 值得注意的另一点是,NuExtract 1.5 比 NuExtract 1.5 tiny 要好得多,这暗示着更大的 NuExtract 很大程度上可以击败 GPT-4o。 有待证实…

总体而言,NuExtract 1.5 和 GPT-4o 在零次和多次运行情况下的性能非常相似。 令人惊讶的是,一个小 500 倍且不具备抽象能力的模型竟然能与如此强大的前沿模型相媲美。 我们认为这有三个原因。 首先,通过只关注结构化提取任务,NuExtract 能够重新分配一些权重以提高文本理解能力。 其次,训练程序能够迫使 NuExtract 精确地遵循模板,并只返回 JSON 输出。 最后但并非最不重要的一点是,通过强制模型提取部分输入文本并在必要时训练其返回空结果,我们的训练大大减少了幻觉。

多语言性能

现在让我们来看看多语言基准的性能(每种语言包含 250 个文档,由英语基准的一部分翻译而来):

在这里插入图片描述
我们看到,NuExtract 1.5 比原始 NuExtract 要好得多,但在这种情况下,GPT-4o 仍然更好。 我们认为,模型的大小对多语言性相当重要(我们无法将微小的 NuExtract 训练成多语言模型的事实证实了这一点)。 我们可能会用更大的 NuExtract 来填补这一空白。

长文档性能

最后,让我们来看看长文档的性能。 我们首先测试的是 8k-10ktoken 范围内的文档(约 20 页),因为我们无需滑动窗口即可轻松处理这些文档:

在这里插入图片描述
结果令人印象深刻: NuExtract 1.5 优于 GPT-4o! 我们应该注意到,这一机制中的基准并不像较小文档那样完整和多样化,但它仍然表明 NuExtract 1.5 非常善于处理长文档(这也证明了 Phi-3.5 mini 对长上下文的正确处理)。 我们还发现,NuExtract 1.5 tiny 比 NuExtract 1.5 差很多,目前我们还不能确定这仅仅是由于模型大小造成的,还是由于使用的基础模型造成的。 现在我们测试更长的文档,在 10k-20k tokens 范围内。 这次我们必须设置 10k 的提取窗口,以保持内存可控:

在这里插入图片描述
同样,NuExtract 1.5 是性能最好的模型,即使在提取窗口缩小的情况下也是如此,这表明之前的结果并非偶然。 这也表明–至少在 10k 个词组的窗口大小下–延续策略运行良好。 现在我们来分析提取窗口大小对性能的影响。 我们再次使用 8k-10k 个词组的基准:

在这里插入图片描述
我们可以看到,NuExtract 1.5 的性能随着提取窗口大小的减小而降低,但幅度不大! NuExtract 1.5 的性能比 GPT-4 差,但仍比 NuExtract 1.5 的微小窗口好得多。 使用小窗口可减少内存:全窗口为 20GB,而 2k 窗口为 10GB(其中大部分是模型权重)。 对于较长的序列,这一比例会变得更大。

使用这样的延续程序并不完美,当然也有改进的方法,但它避免了在所需内存大于 GPU 内存时简单地失败。 我们的推理模块(企业解决方案的一部分,请联系我们😊)会根据给定的 GPU 内存自动调整窗口大小。

numind/NuExtract-v1.5

NuExtract-v1.5 是对 Phi-3.5-mini-instruct 的微调,在一个用于结构化信息提取的私有高质量数据集上进行了训练。 它支持长文档和多种语言(英语、法语、西班牙语、德语、葡萄牙语和意大利语)。 要使用该模型,请提供输入文本和描述所需提取信息的 JSON 模板。

注:该模型经过训练,优先提取纯文本,因此在大多数情况下,该模型生成的所有文本都与原文一致。

还提供基于 Qwen2.5-0.5B 的微小(0.5B)版本: NuExtract-tiny-v1.5

import json
from transformers import AutoModelForCausalLM, AutoTokenizerdef predict_NuExtract(model, tokenizer, texts, template, batch_size=1, max_length=10_000, max_new_tokens=4_000):template = json.dumps(json.loads(template), indent=4)prompts = [f"""<|input|>\n### Template:\n{template}\n### Text:\n{text}\n\n<|output|>""" for text in texts]outputs = []with torch.no_grad():for i in range(0, len(prompts), batch_size):batch_prompts = prompts[i:i+batch_size]batch_encodings = tokenizer(batch_prompts, return_tensors="pt", truncation=True, padding=True, max_length=max_length).to(model.device)pred_ids = model.generate(**batch_encodings, max_new_tokens=max_new_tokens)outputs += tokenizer.batch_decode(pred_ids, skip_special_tokens=True)return [output.split("<|output|>")[1] for output in outputs]model_name = "numind/NuExtract-v1.5"
device = "cuda"
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.bfloat16, trust_remote_code=True).to(device).eval()
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)text = """We introduce Mistral 7B, a 7–billion-parameter language model engineered for
superior performance and efficiency. Mistral 7B outperforms the best open 13B
model (Llama 2) across all evaluated benchmarks, and the best released 34B
model (Llama 1) in reasoning, mathematics, and code generation. Our model
leverages grouped-query attention (GQA) for faster inference, coupled with sliding
window attention (SWA) to effectively handle sequences of arbitrary length with a
reduced inference cost. We also provide a model fine-tuned to follow instructions,
Mistral 7B – Instruct, that surpasses Llama 2 13B – chat model both on human and
automated benchmarks. Our models are released under the Apache 2.0 license.
Code: <https://github.com/mistralai/mistral-src>
Webpage: <https://mistral.ai/news/announcing-mistral-7b/>"""template = """{"Model": {"Name": "","Number of parameters": "","Number of max token": "","Architecture": []},"Usage": {"Use case": [],"Licence": ""}
}"""prediction = predict_NuExtract(model, tokenizer, [text], template)[0]
print(prediction)

滑动窗口提示:

import jsonMAX_INPUT_SIZE = 20_000
MAX_NEW_TOKENS = 6000def clean_json_text(text):text = text.strip()text = text.replace("\#", "#").replace("\&", "&")return textdef predict_chunk(text, template, current, model, tokenizer):current = clean_json_text(current)input_llm =  f"<|input|>\n### Template:\n{template}\n### Current:\n{current}\n### Text:\n{text}\n\n<|output|>" + "{"input_ids = tokenizer(input_llm, return_tensors="pt", truncation=True, max_length=MAX_INPUT_SIZE).to("cuda")output = tokenizer.decode(model.generate(**input_ids, max_new_tokens=MAX_NEW_TOKENS)[0], skip_special_tokens=True)return clean_json_text(output.split("<|output|>")[1])def split_document(document, window_size, overlap):tokens = tokenizer.tokenize(document)print(f"\tLength of document: {len(tokens)} tokens")chunks = []if len(tokens) > window_size:for i in range(0, len(tokens), window_size-overlap):print(f"\t{i} to {i + len(tokens[i:i + window_size])}")chunk = tokenizer.convert_tokens_to_string(tokens[i:i + window_size])chunks.append(chunk)if i + len(tokens[i:i + window_size]) >= len(tokens):breakelse:chunks.append(document)print(f"\tSplit into {len(chunks)} chunks")return chunksdef handle_broken_output(pred, prev):try:if all([(v in ["", []]) for v in json.loads(pred).values()]):# if empty json, return previouspred = prevexcept:# if broken json, return previouspred = prevreturn preddef sliding_window_prediction(text, template, model, tokenizer, window_size=4000, overlap=128):# split text into chunks of n tokenstokens = tokenizer.tokenize(text)chunks = split_document(text, window_size, overlap)# iterate over text chunksprev = templatefor i, chunk in enumerate(chunks):print(f"Processing chunk {i}...")pred = predict_chunk(chunk, template, prev, model, tokenizer)# handle broken outputpred = handle_broken_output(pred, prev)# iterateprev = predreturn pred

http://www.mrgr.cn/news/67539.html

相关文章:

  • Python自动化运维项目管理实践:从需求分析到项目交付
  • 数据结构acwing和洛谷p8085作业
  • C#-值类型、引用类型
  • (蓝桥杯C/C++)——基础算法(上)
  • Centos 7离线安装ntpd服务
  • CISAW-PIS——个人信息安全
  • 【Python】遇到pandas 和numpy版本不兼容怎么办?
  • 船舶终端设备维修服务设计
  • uniapp开发APP后台保活机制
  • leetcode 3255 长度为 K 的子数组的能量值 II 中等
  • 五个高质量的视频素材下载网站,助力创作更高效
  • wxWidgets GUI设计教程 - 常用控件与复杂布局
  • 脉冲全闭环EtherCAT运动控制器的固件升级
  • linux驱动-i2c子系统框架学习(2)
  • 【测试语言篇二】Python进阶篇:lambda函数、异常和错误处理、Json处理、随机数、星号操作符
  • 钉钉调试微应用整理2
  • 海云安入选软件供应链安全十大代表厂商,软件供应链安全创新成果获认可
  • (十四)JavaWeb后端开发——MyBatis
  • 【Python】轻松解析JSON与XML:Python标准库的json与xml模块
  • 深度学习经典模型之Network in Network
  • 【单例模式】饿汉式与懒汉式以及线程安全
  • 嵌入向量模型与BM25算法结合:并行检索获取多种结果
  • 常见几种GB 9706.1-2020医疗器械试验工装,您有所了解吗?
  • 使用stream遍历对象集合,取出所有对象的某字段,并以逗号拼接起来
  • 【TabBar嵌套Navigation案例-常见问题按钮-WebView-加载JavaScript Objective-C语言】
  • 杭州电商运营公司排名:怎么找到适合自己的电商代运营公司