# PPOCR-GLM **Repository Path**: openislands/paddleocrglm ## Basic Information - **Project Name**: PPOCR-GLM - **Description**: 开放群岛开源社区大模型SIG联合组长单位之一百度飞桨团队推出基于文心大模型的全新OCR跨模态抽取解决方案——PP-ChatOCR。本项目在飞桨团队的基础上,使用开放群岛开源社区大模型SIG组长智谱AI的开源ChatGLM2-6B模型底座,实现使用全开源模型(PaddleOCR + ChatGLM2-6B)打造开源版本端到端的解决方案。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2023-08-01 - **Last Updated**: 2024-04-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 关于开放群岛开源社区大模型SIG 深圳数据交易所在开放群岛开源社区联合发起成立了大模型SIG,首批发起单位包括智谱AI、百度、阿里魔搭社区、华为昇思社区、腾讯云、启智社区等26家单位,旨在以大模型为中间键件,实现数据要素和算力资源的高效配置。大模型SIG首批发起单位汇集了算力提供方、训练数据提供方、大模型厂商、行业应用方以及第三方法律服务机构,以“高性能模型底座+高质量垂直行业数据”双轮驱动的方式,最大程度发挥数据要素的行业应用价值。未来,大模型SIG会持续推动高质量科研数据、行业公共数据合规有序流通,以大模型为核心技术底座,赋能千行百业AI+应用。 # 项目介绍 在日常生活中,大家经常会遇到图像关键信息自动抽取的场景,比如身份证拍照上传自动识别、发票拍照上传自动报销等。 在这个领域,现有的 AI 技术方案已经能解决一部分需求,但是依然存在一些痛点,比如发票的种类样式极其繁多,基于 OCR 文字识别+规则后处理的方案无法有效覆盖全部样式,即泛化性很差。如果要强行覆盖全部样式,成本又太高。 针对这样的问题,开放群岛开源社区大模型SIG联合组长单位之一飞桨团队推出基于文心大模型的全新解决方案——PP-ChatOCR,首先使用PaddleOCR进行文本识别,其次通过Prompt Engineering的方式向文心大模型(LLM)发出请求,得到结构化数据返回。 本项目在飞桨团队的基础上,使用开放群岛开源社区大模型SIG组长智谱AI的ChatGLM2模型底座,实现使用全开源模型(PaddleOCR + ChatGLM2)打造开源版本端到端的解决方案。 本项目使用的数据样例为开放群岛开源社区发起单位之一深圳数据交易所数据交易所颁发的"数据交易合规师"认证证书,已获得本人授权。关于数据交易合规师项目详情,请参考https://finance.eastmoney.com/a/202307252791767016.html # 项目Demo ## 1. 检查PaddleOCR版本 ```python import paddleocr print(paddleocr.__version__) ``` ## 2. 使用PaddleOCR端到端的解决方案完成文字识别 ```python from PIL import Image image_path = '/root/sample03.jpg' image = Image.open(image_path) image.show() ``` ![输入图片说明](sample03.jpg) 在上图中,我需要识别出姓名、学员编号、证书名称、认证星级、认证期限。 ```python from paddleocr import PaddleOCR, draw_ocr # Paddleocr目前支持的多语言语种可以通过修改lang参数进行切换 # 例如`ch`, `en`, `fr`, `german`, `korean`, `japan` ocr = PaddleOCR(use_angle_cls=True, lang="ch") # need to run only once to download and load model into memory img_path = '/root/sample03.jpg' result = ocr.ocr(img_path, cls=True) for idx in range(len(result)): res = result[idx] for line in res: print(line) # 显示结果 # 如果本地没有simfang.ttf,可以在doc/fonts目录下下载 from PIL import Image result = result[0] image = Image.open(img_path).convert('RGB') boxes = [line[0] for line in result] txts = [line[1][0] for line in result] scores = [line[1][1] for line in result] im_show = draw_ocr(image, boxes, txts, scores, font_path='/root/PaddleOCR/doc/fonts/simfang.ttf') im_show = Image.fromarray(im_show) im_show.save('result.jpg') ``` [2023/08/14 13:04:42] ppocr DEBUG: Namespace(alpha=1.0, benchmark=False, beta=1.0, cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='/root/.paddleocr/whl/cls/ch_ppocr_mobile_v2.0_cls_infer', cls_thresh=0.9, cpu_threads=10, crop_res_save_dir='./output', det=True, det_algorithm='DB', det_box_type='quad', det_db_box_thresh=0.6, det_db_score_mode='fast', det_db_thresh=0.3, det_db_unclip_ratio=1.5, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0.8, det_limit_side_len=960, det_limit_type='max', det_model_dir='/root/.paddleocr/whl/det/ch/ch_PP-OCRv4_det_infer', det_pse_box_thresh=0.85, det_pse_min_area=16, det_pse_scale=1, det_pse_thresh=0, det_sast_nms_thresh=0.2, det_sast_score_thresh=0.5, draw_img_save_dir='./inference_results', drop_score=0.5, e2e_algorithm='PGNet', e2e_char_dict_path='./ppocr/utils/ic15_dict.txt', e2e_limit_side_len=768, e2e_limit_type='max', e2e_model_dir=None, e2e_pgnet_mode='fast', e2e_pgnet_score_thresh=0.5, e2e_pgnet_valid_set='totaltext', enable_mkldnn=False, fourier_degree=5, gpu_id=0, gpu_mem=500, help='==SUPPRESS==', image_dir=None, image_orientation=False, ir_optim=True, kie_algorithm='LayoutXLM', label_list=['0', '180'], lang='ch', layout=True, layout_dict_path=None, layout_model_dir=None, layout_nms_threshold=0.5, layout_score_threshold=0.5, max_batch_size=10, max_text_length=25, merge_no_span_structure=True, min_subgraph_size=15, mode='structure', ocr=True, ocr_order_method=None, ocr_version='PP-OCRv4', output='./output', page_num=0, precision='fp32', process_id=0, re_model_dir=None, rec=True, rec_algorithm='SVTR_LCNet', rec_batch_num=6, rec_char_dict_path='/root/miniconda3/lib/python3.8/site-packages/paddleocr/ppocr/utils/ppocr_keys_v1.txt', rec_image_inverse=True, rec_image_shape='3, 48, 320', rec_model_dir='/root/.paddleocr/whl/rec/ch/ch_PP-OCRv4_rec_infer', recovery=False, return_word_box=False, save_crop_res=False, save_log_path='./log_output/', scales=[8, 16, 32], ser_dict_path='../train_data/XFUND/class_list_xfun.txt', ser_model_dir=None, show_log=True, sr_batch_num=1, sr_image_shape='3, 32, 128', sr_model_dir=None, structure_version='PP-StructureV2', table=True, table_algorithm='TableAttn', table_char_dict_path=None, table_max_len=488, table_model_dir=None, total_process_num=1, type='ocr', use_angle_cls=True, use_dilation=False, use_gpu=True, use_mp=False, use_npu=False, use_onnx=False, use_pdf2docx_api=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, use_visual_backbone=True, use_xpu=False, vis_font_path='./doc/fonts/simfang.ttf', warmup=False) [2023/08/14 13:04:47] ppocr DEBUG: dt_boxes num : 19, elapse : 1.2302138805389404 [2023/08/14 13:04:47] ppocr DEBUG: cls num : 19, elapse : 0.4917333126068115 [2023/08/14 13:04:47] ppocr DEBUG: rec_res num : 19, elapse : 0.0530390739440918 [[[704.0, 487.0], [752.0, 486.0], [775.0, 1661.0], [727.0, 1662.0]], ('DATA EXCHANGE COMPLIANCE OFFICER CERTIFICATE', 0.9702687859535217)] [[[192.0, 577.0], [232.0, 576.0], [247.0, 995.0], [207.0, 996.0]], ('五星级认证DEXCO(2023.6-2024.6)', 0.9567397236824036)] [[[170.0, 653.0], [204.0, 652.0], [211.0, 919.0], [177.0, 920.0]], ('学员编号:202304004', 0.9882038235664368)] [[[1038.0, 704.0], [1058.0, 704.0], [1062.0, 1026.0], [1042.0, 1026.0]], ('05205c05205c05c05205', 0.5611487030982971)] [[[641.0, 775.0], [689.0, 774.0], [703.0, 1385.0], [655.0, 1386.0]], ('数据交易合规师认证证书', 0.9952551126480103)] [[[325.0, 960.0], [404.0, 957.0], [414.0, 1210.0], [334.0, 1213.0]], ('王吴越', 0.9942548871040344)] [[[823.0, 997.0], [865.0, 995.0], [874.0, 1223.0], [832.0, 1225.0]], ('深圳数据交易所', 0.9977880120277405)] [[[927.0, 1004.0], [1007.0, 1004.0], [1007.0, 1136.0], [927.0, 1136.0]], ('O', 0.7073357701301575)] [[[117.0, 1024.0], [197.0, 1024.0], [197.0, 1156.0], [117.0, 1156.0]], ('CO5', 0.5484486222267151)] [[[222.0, 1252.0], [252.0, 1252.0], [252.0, 1310.0], [222.0, 1310.0]], ('深圳', 0.9764337539672852)] [[[307.0, 1331.0], [356.0, 1335.0], [348.0, 1445.0], [299.0, 1441.0]], ('交易所', 0.9822378754615784)] ## 3. 查看识别结果 ```python print(txts) ``` ['DATA EXCHANGE COMPLIANCE OFFICER CERTIFICATE', '五星级认证DEXCO(2023.6-2024.6)', '学员编号:202304004', '05205c05205c05c05205', '数据交易合规师认证证书', '王吴越', '深圳数据交易所', 'O', 'CO5', '深圳', '交易所'] ## 4. 构造Prompt (Prompt出处来自飞桨团队,针对ChatGLM2-6B进行了微调) ### 4.1 定义要抽取的Schema ```python ocr_result=txts key='{\'证书名称\',\'姓名\',\'学员编号\',\'认证星级\',\'认证期限\'}' ``` ### 4.2 查看构造好的Prompt ```python prompt = f"""你现在的任务是从OCR文字识别的结果中提取我指定的关键信息。OCR的文字识别结果使用```符号包围,包含所识别出来的文字,顺序在原始图片中从左至右、从上至下。我指定的关键信息使用[]符号包围。请注意OCR的文字识别结果可能存在长句子换行被切断、不合理的分词、对应错位等问题,你需要结合上下文语义进行综合判断,以抽取准确的关键信息。在返回结果时使用json格式,包含一个key-value对,key值为我指定的关键信息,value值为所抽取的结果。如果认为OCR识别结果中没有关键信息key,则将value赋值为“未找到相关信息”。请只输出json格式的结果,不要包含其它多余文字!下面正式开始:\n\nOCR文字:```{ocr_result}```\n\n要抽取的关键信息:[{key}]。\n\n请只输出JSON字典,不要输出额外内容!""" print(prompt) ``` 你现在的任务是从OCR文字识别的结果中提取我指定的关键信息。OCR的文字识别结果使用```符号包围,包含所识别出来的文字,顺序在原始图片中从左至右、从上至下。我指定的关键信息使用[]符号包围。请注意OCR的文字识别结果可能存在长句子换行被切断、不合理的分词、对应错位等问题,你需要结合上下文语义进行综合判断,以抽取准确的关键信息。在返回结果时使用json格式,包含一个key-value对,key值为我指定的关键信息,value值为所抽取的结果。如果认为OCR识别结果中没有关键信息key,则将value赋值为“未找到相关信息”。请只输出json格式的结果,不要包含其它多余文字!下面正式开始: OCR文字:```['DATA EXCHANGE COMPLIANCE OFFICER CERTIFICATE', '五星级认证DEXCO(2023.6-2024.6)', '学员编号:202304004', '05205c05205c05c05205', '数据交易合规师认证证书', '王吴越', '深圳数据交易所', 'O', 'CO5', '深圳', '交易所']``` 要抽取的关键信息:[{'证书名称','姓名','学员编号','认证星级','认证期限'}]。 请只输出JSON字典,不要输出额外内容! ## 5. 加载ChatGLM2-6B模型 ```python import torch from transformers import AutoTokenizer, AutoModel tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True) model = AutoModel.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True).half().cuda() model = model.eval() ``` ## 6. 使用ChatGLM2-6B模型进行推理 ```python response, history = model.chat(tokenizer, prompt, history=[]) print(response) ``` { "证书名称": "数据交易合规师认证证书", "姓名": "王吴越", "学员编号": "202304004", "认证星级": "五星级认证DEXCO(2023.6-2024.6)", "认证期限": "2023.6-2024.6" }