微信扫码
与创始人交个朋友
我要投稿
尽管大型模型在生成式问答领域已经取得了显著的成果,但因为大量数据是私有的,这些模型的训练和微调成本依旧高得惊人。因此,使用RAG(Retrieval-Augmented Generation)方法逐渐成为实现应用的一种关键途径。然而,对文档进行精确的chunk划分却是一项挑战。现实中,多数专业文档以PDF格式保存,若解析精度不高,将严重影响专业问答系统的性能。
可编辑PDF文档可以使用PDF解析工具进行解析,优劣势对比如下:
PDF解析后得到的文本数据丢失了段落信息,需要重新划分和重组段落。下面我们将探讨训练语义段落划分模型的策略,并介绍一款现成的开源分段模型工具。
经过pdf解析工具处理后,原始文档的段落信息会丢失,需要重新划分和重组段落。接下来将介绍一种语义分段模型的训练方法和一个开源分段模型。
语义分段训练策略的步骤流程如下:
from modelscope.outputs import OutputKeys
from modelscope.pipelines import pipeline
from modelscope.utils.constant import Tasks
p = pipeline(
task=Tasks.document_segmentation,
model='damo/nlp_bert_document-segmentation_chinese-base')
result = p(documents='移动端语音唤醒模型,检测关键词为“小云小云”。模型主体为4层FSMN结构,使用CTC训练准则,参数量750K,适用于移动端设备运行。模型输入为Fbank特征,输出为基于char建模的中文全集token预测,测试工具根据每一帧的预测数据进行后处理得到输入音频的实时检测结果。模型训练采用“basetrain + finetune”的模式,basetrain过程使用大量内部移动端数据,在此基础上,使用1万条设备端录制安静场景“小云小云”数据进行微调,得到最终面向业务的模型。后续用户可在basetrain模型基础上,使用其他关键词数据进行微调,得到新的语音唤醒模型,但暂时未开放模型finetune功能。')
print(result[OutputKeys.TEXT])
# 输出
'''
移动端语音唤醒模型,检测关键词为“小云小云”。模型主体为4层FSMN结构,使用CTC训练准则,参数量750K,适用于移动端设备运行。模型输入为Fbank特征,输出为基于char建模的中文全集token预测,测试工具根据每一帧的预测数据进行后处理得到输入音频的实时检测结果。
模型训练采用“basetrain + finetune”的模式,basetrain过程使用大量内部移动端数据,在此基础上,使用1万条设备端录制安静场景“小云小云”数据进行微调,得到最终面向业务的模型。后续用户可在basetrain模型基础上,使用其他关键词数据进行微调,得到新的语音唤醒模型,但暂时未开放模型finetune功能。
'''
以下是PaddleOCR的使用例子:
import cv2from paddleocr import PaddleOCRpaddleocr = PaddleOCR(lang='ch', show_log=False, enable_mkldnn=True) img = cv2.imread('1.jpg')result = paddleocr.ocr(img)for i in range(len(result[0])):print(result[0][i][1][0]) # 输出识别结果
对版式分析的表格区域,用表格解析模型转换为特定格式,如:csv、html、markdown等。常见开源模型有ppstructure。
如下:
import osimport cv2from paddleocr import PPStructure,save_structure_restable_engine = PPStructure(layout=False, show_log=True) save_folder = './output'img_path = 'table.jpg'img = cv2.imread(img_path)result = table_engine(img)save_structure_res(result, save_folder, os.path.basename(img_path).split('.')[0])for line in result:line.pop('img')print(line)
from PIL import Image
from pix2tex.cli import LatexOCR
model = LatexOCR()
img = Image.open('1.jpg')
print(model(img))
xy-cut方法:通过边界框的位置信息重新排序文档内容,就像整理散落的拼图,恢复它们原本的图案。
import numpy as np
def xy_cut(bboxes, direction="x"):
result = []
K = len(bboxes)
indexes = range(K)
if len(bboxes) <= 0:
return result
if direction == "x":
sorted_ids = sorted(indexes, key=lambda k: (bboxes[k][0], bboxes[k][1]))
sorted_boxes = sorted(bboxes, key=lambda x: (x[0], x[1]))
next_dir = "y"
else:
sorted_ids = sorted(indexes, key=lambda k: (bboxes[k][1], bboxes[k][0]))
sorted_boxes = sorted(bboxes, key=lambda x: (x[1], x[0]))
next_dir = "x"
curr = 0
np_bboxes = np.array(sorted_boxes)
for idx in range(len(sorted_boxes)):
if direction == "x":
if idx != K - 1 and sorted_boxes[idx][2] < sorted_boxes[idx + 1][0]:
rel_res = xy_cut(sorted_boxes[curr:idx + 1], next_dir)
result += [sorted_ids[i + curr] for i in rel_res]
curr = idx + 1
else:
if idx != K - 1 and sorted_boxes[idx][3] < sorted_boxes[idx + 1][1]:
rel_res = xy_cut(sorted_boxes[curr:idx + 1], next_dir)
result += [sorted_ids[i + curr] for i in rel_res]
curr = idx + 1
result += sorted_ids[curr:idx + 1]
return result
def augment_xy_cut(bboxes,
direction="x",
lambda_x=0.5,
lambda_y=0.5,
theta=5,
aug=False):
if aug is True:
for idx in range(len(bboxes)):
vx = np.random.normal(loc=0, scale=1)
vy = np.random.normal(loc=0, scale=1)
if np.abs(vx) >= lambda_x:
bboxes[idx][0] += round(theta * vx)
bboxes[idx][2] += round(theta * vx)
if np.abs(vy) >= lambda_y:
bboxes[idx][1] += round(theta * vy)
bboxes[idx][3] += round(theta * vy)
bboxes[idx] = [max(0, i) for i in bboxes[idx]]
res_idx = xy_cut(bboxes, direction=direction)
res_bboxes = [bboxes[idx] for idx in res_idx]
return res_idx, res_bboxes
bboxes = [[58.54924774169922, 1379.6373291015625, 1112.8863525390625, 1640.0870361328125],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ],
[ ]]
res_idx, res_bboxes = augment_xy_cut(bboxes, direction="y")
print(res_idx)
new_boxs = []
for i in res_idx:
new_boxs.append(bboxes[i])
print(new_boxs)
import torch
from model import LayoutLMv3ForBboxClassification
from collections import defaultdict
CLS_TOKEN_ID = 0
UNK_TOKEN_ID = 3
EOS_TOKEN_ID = 2
def BboxesMasks(boxes):
bbox = [[0, 0, 0, 0]] + boxes + [[0, 0, 0, 0]]
input_ids = [CLS_TOKEN_ID] + [UNK_TOKEN_ID] * len(boxes) + [EOS_TOKEN_ID]
attention_mask = [1] + [1] * len(boxes) + [1]
return {
"bbox": torch.tensor([bbox]),
"attention_mask": torch.tensor([attention_mask]),
"input_ids": torch.tensor([input_ids]),
}
def decode(logits, length):
logits = logits[1: length + 1, :length]
orders = logits.argsort(descending=False).tolist()
ret = [o.pop() for o in orders]
while True:
order_to_idxes = defaultdict(list)
for idx, order in enumerate(ret):
order_to_idxes[order].append(idx)
order_to_idxes = {k: v for k, v in order_to_idxes.items() if len(v) > 1}
if not order_to_idxes:
break
for order, idxes in order_to_idxes.items():
idxes_to_logit = {}
for idx in idxes:
idxes_to_logit[idx] = logits[idx, order]
idxes_to_logit = sorted(
idxes_to_logit.items(), key=lambda x: x[1], reverse=True
)
for idx, _ in idxes_to_logit[1:]:
ret[idx] = orders[idx].pop()
return ret
def layoutreader(bboxes):
inputs = BboxesMasks(bboxes)
logits = model(**inputs).logits.cpu().squeeze(0)
orders = decode(logits, len(bboxes))
return orders
if __name__ == '__main__':
bboxes = [[584, 0, 595, 1], [35, 120, 89, 133],
[35, 140, 75, 152]]
model_path = ""
model = LayoutLMv3ForBboxClassification.from_pretrained()
print(layoutreader(bboxes))
# [1, 2, 0]
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-07-18
2024-05-05
2024-06-20
2024-09-04
2024-05-19
2024-07-09
2024-07-09
2024-07-07
2024-06-13
2024-07-07