相关文章推荐
淡定的登山鞋  ·  Redis zSet命令_redis ...·  6 月前    · 
飘逸的企鹅  ·  Android ...·  11 月前    · 
安静的土豆  ·  sudo pip install ...·  1 年前    · 

0 项目背景

信息抽取任务旨在从非结构化的自然语言文本中提取结构化信息。在本系列项目中,将讨论如何又好又快地实现一个简历信息提取任务。

在前置项目 简历信息提取(五):用VI-LayoutXLM提升关键信息抽取效果 中,我们发现用PaddleOCR提供的VI-LayoutXLM模型能够有效做好图片格式简历文本的提取,从而提升关键信息抽取效果。

接下来,我们对这些提取的文本用PaddleNLP进行微调训练,从而能够对【图片-简历关键信息】和【word文档-简历关键信息】两条路径的结果准确性进行有效比较。

本项目还将完成图片格式简历信息抽取应用的在线部署。

0.1 参考资料

1 环境准备

# 解压缩数据集
!unzip data/data40148/train_20200121.zip
# 安装依赖库
!pip install python-docx
!pip install pypinyin
!pip install LAC
!pip install --upgrade paddlenlp
!pip install --upgrade paddleocr
!pip install pymupdf
# 首次更新完以后,重启后方能生效
import datetime
import os
import fitz  # fitz就是pip install PyMuPDF
import cv2
import shutil
import numpy as np
import pandas as pd
from tqdm import tqdm
import json
!git clone https://gitee.com/paddlepaddle/PaddleOCR.git
!wget https://paddleocr.bj.bcebos.com/ppstructure/models/vi_layoutxlm/ser_vi_layoutxlm_xfund_infer.tar
!tar -xvf ser_vi_layoutxlm_xfund_infer.tar -C ./PaddleOCR/
# 准备XFUND数据集,这里主要是为了获得字典文件class_list_xfun.txt
!mkdir ./PaddleOCR/train_data
!wget https://paddleocr.bj.bcebos.com/ppstructure/dataset/XFUND.tar
!tar -xf XFUND.tar -C ./PaddleOCR/train_data/

2 数据集准备

2.1 简历图片准备

首先是将简历数据集批量转换为图片格式。

def get_pic_info(path):
    # 将整理后的抽取结果返回为字典
    if os.path.splitext(path)[-1]=='.pdf':
        pdfDoc = fitz.open(path)
        for pg in range(pdfDoc.page_count):
            page = pdfDoc[pg]
            rotate = int(0)
            zoom_x = 4  # (1.33333333-->1056x816)   (2-->1584x1224)
            zoom_y = 4
            mat = fitz.Matrix(zoom_x, zoom_y).prerotate(rotate)
            pix = page.get_pixmap(matrix=mat, alpha=False)
            # 保存过渡图片
            pix.save(path[:-4] + '_%s.jpeg' % pg)
def get_pics(path):
    filenames = os.listdir(path)
    result = []
    for filename in tqdm(filenames):
        get_pic_info(os.path.join(path,filename))
# 将简历文档转换为图片格式
result = get_pics('resume_train_20200121/pdf')
!mkdir 'resume_train_20200121/imgs'
!mv resume_train_20200121/pdf/*.jpeg resume_train_20200121/imgs/

2.2 标注文件准备

将对简历数据集的原始标注转换为与Label Studio标注匹配的格式。

%cd ~/PaddleOCR/ppstructure
/home/aistudio/PaddleOCR/ppstructure

为提高标注数据转换效率,我们针对简历数据集的实际情况进行了定制优化。原数据集中,每份简历最多(正反)两页,这也比较好理解,因为通常来说,投递的简历不会超过一张纸。

这样,我们得到的同一份简历图片后缀,也就至多是0和1了。

转换文件的核心代码如下:

    label_list = []
    # 设置实体抽取信息
    schema = ['姓名', '出生年月', '电话', '性别', '项目名称', '项目责任', '项目时间', '籍贯', '政治面貌', '落户市县', '毕业院校', '学位', '毕业时间', '工作时间', '工作内容', '职务', '工作单位']
    os.makedirs(args.output, exist_ok=True)
    with open('/home/aistudio/resume_train_20200121/unlabeled_data.txt', mode='w', encoding='utf-8') as f_w, open('/home/aistudio/resume_train_20200121/train_data.json', "r", encoding="utf-8") as f1:
        raw_examples = json.loads(f1.read())
        line_num = 1
        text_content = ''
        for line in tqdm(raw_examples): 
            res = []
            result_list = []
            img = cv2.imread('/home/aistudio/resume_train_20200121/imgs/' + line + '_0.jpeg')
            if img is not None:
                img = img[:, :, ::-1]
                ser_res, _, elapse = ser_predictor(img)
                ser_res = ser_res[0]
                for item in ser_res:
                    res.append(item['transcription'])
            # text_content = ''.join(res)                
            # res_str = '\n{}'.format(
            # text_content, ensure_ascii=False)
            if os.path.exists('/home/aistudio/resume_train_20200121/imgs/' + line + '_1.jpeg'):
                img2 = cv2.imread('/home/aistudio/resume_train_20200121/imgs/' + line + '_1.jpeg')
                if img2 is not None:
                    img2 = img2[:, :, ::-1]
                    ser_res, _, elapse = ser_predictor(img2)
                    ser_res = ser_res[0]
                    for item in ser_res:
                        res.append(item['transcription'])
            text_content = ''.join(res)
            res_str = '{}\n'.format(
                    text_content, ensure_ascii=False)
            f_w.write(res_str)
            for item in schema:
                schema_dict = {} 
                if item in raw_examples[line] and text_content.find(raw_examples[line][item]) > 0:
                    # 找到要抽取的文本内容
                    schema_dict["text"] = raw_examples[line][item]
                    # 遍历字符串,找到首个符合匹配的字符位置
                    schema_dict["start"] = text_content.find(raw_examples[line][item])
                    # 计算文本内容结束位置
                    schema_dict["end"] = len(raw_examples[line][item]) + text_content.find(raw_examples[line][item])
                    # 保存标签信息
                    schema_dict["labels"] = [item]
                if '项目经历' in raw_examples[line]:
                        for i in range(len(raw_examples[line]['项目经历'])):
                            if item in raw_examples[line]['项目经历'][i] and text_content.find(raw_examples[line]['项目经历'][i][item]) > 0:
                                schema_dict["text"] = raw_examples[line]['项目经历'][i][item]
                                schema_dict["start"] = text_content.find(raw_examples[line]['项目经历'][i][item])
                                schema_dict["end"] = len(raw_examples[line]['项目经历'][i][item]) + text_content.find(raw_examples[line]['项目经历'][i][item])
                                schema_dict["labels"] = [item]
                if '工作经历' in raw_examples[line]:
                    for i in range(len(raw_examples[line]['工作经历'])):
                        if item in raw_examples[line]['工作经历'][i] and text_content.find(raw_examples[line]['工作经历'][i][item]) > 0:
                            schema_dict["text"] = raw_examples[line]['工作经历'][i][item]
                            schema_dict["start"] = text_content.find(raw_examples[line]['工作经历'][i][item])
                            schema_dict["end"] = len(raw_examples[line]['工作经历'][i][item]) + text_content.find(raw_examples[line]['工作经历'][i][item]) - 1
                            schema_dict["labels"] = [item]                                             
                if '教育经历' in raw_examples[line]:
                    for i in range(len(raw_examples[line]['教育经历'])):
                        if item in raw_examples[line]['教育经历'][i] and text_content.find(raw_examples[line]['教育经历'][i][item]) > 0:
                            schema_dict["text"] = raw_examples[line]['教育经历'][i][item]
                            schema_dict["start"] = text_content.find(raw_examples[line]['教育经历'][i][item])
                            schema_dict["end"] = len(raw_examples[line]['教育经历'][i][item]) + text_content.find(raw_examples[line]['教育经历'][i][item])
                            schema_dict["labels"] = [item]
                if len(schema_dict) > 0:
                    result_dict = {"value":schema_dict,
                    "id": "",
                    "from_name": "label",
                    "to_name": "text",
                    "type": "labels",
                    "origin": "manual"}
                    result_list.append(result_dict)
            line_dict = {"id": line_num,
            "annotations":[{"id":line_num,"result":result_list}],
            "data": {"text":text_content}
            label_list.append(line_dict)
            line_num += 1
        json.dump(label_list, open('/home/aistudio/resume_train_20200121/label_studio.json', mode='w'), ensure_ascii=False, indent=4) 
# 用根据简历数据集定制处理的转换脚本替换原有的VI-LayoutXLM批量图片识别脚本
!cp ~/predict_kie_token_ser_2.py kie/predict_kie_token_ser.py
# 生成转换后的标注文件
!python kie/predict_kie_token_ser.py \
  --kie_algorithm=LayoutXLM \
  --ser_model_dir=../ser_vi_layoutxlm_xfund_infer \
  --use_visual_backbone=False \
  --image_dir=/home/aistudio/resume_train_20200121/imgs/ \
  --ser_dict_path=../train_data/XFUND/class_list_xfun.txt \
  --vis_font_path=../doc/fonts/simfang.ttf \
  --ocr_order_method="tb-yx"

3 模型训练

%cd ~
# 拉取PaddleNLP项目程序包
!git clone https://gitee.com/paddlepaddle/PaddleNLP.git
/home/aistudio
%cd ~/PaddleNLP/applications/information_extraction/text/
/home/aistudio/PaddleNLP/applications/information_extraction/text

3.1 切分训练数据集

本项目我们按照7:2:1转换并划分训练集、验证集和测试集。

!python ../label_studio.py \
    --label_studio_file /home/aistudio/resume_train_20200121/label_studio.json \
    --save_dir ./data \
    --splits 0.7 0.2 0.1 \
    --negative_ratio 3 \
    --task_type ext
[32m[2023-02-02 01:08:00,222] [    INFO][0m - Converting annotation data...[0m
100%|█████████████████████████████████████| 1400/1400 [00:00<00:00, 1503.12it/s]
[32m[2023-02-02 01:08:01,156] [    INFO][0m - Adding negative samples for first stage prompt...[0m
100%|████████████████████████████████████| 1400/1400 [00:00<00:00, 91362.11it/s]
[32m[2023-02-02 01:08:01,177] [    INFO][0m - Converting annotation data...[0m
100%|███████████████████████████████████████| 399/399 [00:00<00:00, 4349.45it/s]
[32m[2023-02-02 01:08:01,270] [    INFO][0m - Adding negative samples for first stage prompt...[0m
100%|██████████████████████████████████████| 399/399 [00:00<00:00, 76072.88it/s]
[32m[2023-02-02 01:08:01,277] [    INFO][0m - Converting annotation data...[0m
100%|███████████████████████████████████████| 201/201 [00:00<00:00, 5933.00it/s]
[32m[2023-02-02 01:08:01,311] [    INFO][0m - Adding negative samples for first stage prompt...[0m
100%|██████████████████████████████████████| 201/201 [00:00<00:00, 97553.24it/s]
[32m[2023-02-02 01:08:01,729] [    INFO][0m - Save 23800 examples to ./data/train.txt.[0m
[32m[2023-02-02 01:08:01,852] [    INFO][0m - Save 6783 examples to ./data/dev.txt.[0m
[32m[2023-02-02 01:08:01,915] [    INFO][0m - Save 3417 examples to ./data/test.txt.[0m
[32m[2023-02-02 01:08:01,916] [    INFO][0m - Finished! It takes 2.09 seconds[0m

3.2 微调训练

!python finetune.py  \
    --device gpu \
    --logging_steps 100 \
    --save_steps 1000 \
    --eval_steps 1000 \
    --seed 1000 \
    --model_name_or_path uie-base \
    --output_dir ./checkpoint/model_best \
    --train_path data/train.txt \
    --dev_path data/dev.txt  \
    --max_seq_len 512  \
    --per_device_train_batch_size  16 \
    --per_device_eval_batch_size 16 \
    --num_train_epochs 5 \
    --learning_rate 1e-5 \
    --do_train \
    --do_eval \
    --do_export \
    --export_model_dir ./checkpoint/model_best \
    --overwrite_output_dir \
    --disable_tqdm True \
    --metric_for_best_model eval_f1 \
    --load_best_model_at_end  True \
    --save_total_limit 1

这里我们会发现,微调模型训练效果相比于从纯文档抽取的前置项目简历信息提取(三):文本抽取的UIE格式转换与微调训练效果还有一定距离,接下来,我们就对这个情况进行分析。

3.3 模型评估

在模型评估中,我们针对测试集开启debug模式对每个正例类别分别进行评估。

!python evaluate.py \
    --model_path ./checkpoint/model_best \
    --test_path ./data/test.txt \
    --debug
[32m[2023-02-02 21:47:12,853] [    INFO][0m - We are using <class 'paddlenlp.transformers.ernie.tokenizer.ErnieTokenizer'> to load './checkpoint/model_best'.[0m
[32m[2023-02-02 21:47:12,878] [    INFO][0m - loading configuration file ./checkpoint/model_best/config.json[0m
[32m[2023-02-02 21:47:12,879] [    INFO][0m - Model config ErnieConfig {
  "architectures": [
    "UIE"
  "attention_probs_dropout_prob": 0.1,
  "dtype": "float32",
  "enable_recompute": false,
  "fuse": false,
  "hidden_act": "gelu",
  "hidden_dropout_prob": 0.1,
  "hidden_size": 768,
  "initializer_range": 0.02,
  "intermediate_size": 3072,
  "layer_norm_eps": 1e-12,
  "max_position_embeddings": 2048,
  "model_type": "ernie",
  "num_attention_heads": 12,
  "num_hidden_layers": 12,
  "pad_token_id": 0,
  "paddlenlp_version": null,
  "pool_act": "tanh",
  "task_id": 0,
  "task_type_vocab_size": 3,
  "type_vocab_size": 4,
  "use_task_id": true,
  "vocab_size": 40000
W0202 21:47:14.519857  4892 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 11.2
W0202 21:47:14.527417  4892 gpu_resources.cc:91] device: 0, cuDNN Version: 8.2.
[32m[2023-02-02 21:47:15,566] [    INFO][0m - All model checkpoint weights were used when initializing UIE.
[32m[2023-02-02 21:47:15,566] [    INFO][0m - All the weights of UIE were initialized from the model checkpoint at ./checkpoint/model_best.
If your task is similar to the task the model of the checkpoint was trained on, you can already use UIE for predictions without further training.[0m
[33m[2023-02-02 21:47:15,573] [ WARNING][0m - result['end'] - result ['start'] exceeds max_content_len, which will result in no valid instance being returned[0m
[33m[2023-02-02 21:47:15,574] [ WARNING][0m - result['end'] - result ['start'] exceeds max_content_len, which will result in no valid instance being returned[0m
[32m[2023-02-02 21:47:19,817] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:19,817] [    INFO][0m - Class Name: 姓名[0m
[32m[2023-02-02 21:47:19,817] [    INFO][0m - Evaluation Precision: 0.99265 | Recall: 0.99265 | F1: 0.99265[0m
[32m[2023-02-02 21:47:22,916] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:22,917] [    INFO][0m - Class Name: 出生年月[0m
[32m[2023-02-02 21:47:22,917] [    INFO][0m - Evaluation Precision: 1.00000 | Recall: 0.94690 | F1: 0.97273[0m
[32m[2023-02-02 21:47:28,373] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:28,373] [    INFO][0m - Class Name: 电话[0m
[32m[2023-02-02 21:47:28,373] [    INFO][0m - Evaluation Precision: 1.00000 | Recall: 1.00000 | F1: 1.00000[0m
[32m[2023-02-02 21:47:32,402] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:32,402] [    INFO][0m - Class Name: 项目名称[0m
[32m[2023-02-02 21:47:32,402] [    INFO][0m - Evaluation Precision: 0.99242 | Recall: 0.84516 | F1: 0.91289[0m
[32m[2023-02-02 21:47:35,720] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:35,720] [    INFO][0m - Class Name: 项目责任[0m
[32m[2023-02-02 21:47:35,720] [    INFO][0m - Evaluation Precision: 0.89189 | Recall: 0.74436 | F1: 0.81148[0m
[32m[2023-02-02 21:47:39,731] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:39,731] [    INFO][0m - Class Name: 项目时间[0m
[32m[2023-02-02 21:47:39,731] [    INFO][0m - Evaluation Precision: 0.99180 | Recall: 0.80132 | F1: 0.88645[0m
[32m[2023-02-02 21:47:43,577] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:43,578] [    INFO][0m - Class Name: 籍贯[0m
[32m[2023-02-02 21:47:43,578] [    INFO][0m - Evaluation Precision: 0.99306 | Recall: 1.00000 | F1: 0.99652[0m
[32m[2023-02-02 21:47:48,689] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:48,689] [    INFO][0m - Class Name: 毕业院校[0m
[32m[2023-02-02 21:47:48,689] [    INFO][0m - Evaluation Precision: 0.99425 | Recall: 0.87374 | F1: 0.93011[0m
[32m[2023-02-02 21:47:53,470] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:53,470] [    INFO][0m - Class Name: 毕业时间[0m
[32m[2023-02-02 21:47:53,470] [    INFO][0m - Evaluation Precision: 0.99415 | Recall: 0.92391 | F1: 0.95775[0m
[32m[2023-02-02 21:47:58,434] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:47:58,434] [    INFO][0m - Class Name: 工作时间[0m
[32m[2023-02-02 21:47:58,434] [    INFO][0m - Evaluation Precision: 1.00000 | Recall: 0.78261 | F1: 0.87805[0m
[32m[2023-02-02 21:48:02,322] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:48:02,323] [    INFO][0m - Class Name: 工作内容[0m
[32m[2023-02-02 21:48:02,323] [    INFO][0m - Evaluation Precision: 0.93496 | Recall: 0.77181 | F1: 0.84559[0m
[32m[2023-02-02 21:48:06,706] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:48:06,706] [    INFO][0m - Class Name: 职务[0m
[32m[2023-02-02 21:48:06,706] [    INFO][0m - Evaluation Precision: 0.96581 | Recall: 0.68902 | F1: 0.80427[0m
[32m[2023-02-02 21:48:12,174] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:48:12,174] [    INFO][0m - Class Name: 工作单位[0m
[32m[2023-02-02 21:48:12,174] [    INFO][0m - Evaluation Precision: 0.98052 | Recall: 0.75500 | F1: 0.85311[0m
[32m[2023-02-02 21:48:14,388] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:48:14,388] [    INFO][0m - Class Name: 性别[0m
[32m[2023-02-02 21:48:14,388] [    INFO][0m - Evaluation Precision: 1.00000 | Recall: 1.00000 | F1: 1.00000[0m
[32m[2023-02-02 21:48:17,908] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:48:17,908] [    INFO][0m - Class Name: 学位[0m
[32m[2023-02-02 21:48:17,908] [    INFO][0m - Evaluation Precision: 0.99254 | Recall: 0.98519 | F1: 0.98885[0m
[32m[2023-02-02 21:48:19,506] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:48:19,506] [    INFO][0m - Class Name: 政治面貌[0m
[32m[2023-02-02 21:48:19,506] [    INFO][0m - Evaluation Precision: 1.00000 | Recall: 1.00000 | F1: 1.00000[0m
[32m[2023-02-02 21:48:21,264] [    INFO][0m - -----------------------------[0m
[32m[2023-02-02 21:48:21,265] [    INFO][0m - Class Name: 落户市县[0m
[32m[2023-02-02 21:48:21,265] [    INFO][0m - Evaluation Precision: 1.00000 | Recall: 0.98462 | F1: 0.99225[0m

很显然,模型对于姓名、性别、电话这些特征明显的信息抽取效果良好,但是在长句识别的表现上不太乐观,项目责任、职务、工作内容这些信息抽取的f1 score都只在0.8左右,严重拖了后腿。

我们在回到输入数据上看,从unlabeled_data.txt中随便找一份图片简历的文本提取结果:

简历教育背景2001.06-2005.06北京师范大学生物工程硕士学位2008.05-2012.05北京林业大学历史学学士学位工作经历1992.09-2017.10深圳大运置业有限公司.net 后端开发工程师个人信息工作内容:姓名幕墙系统的概念设计及深化设计,并对建筑幕墙提出建设性的意见。与李冠光建筑师和业主进行沟通,了解建筑师和业主的建筑构想,并将他们的构思融入幕墙的系统设计。对幕墙系统的设计、系统规格及材料技术规格出生年月进行分析并提供指导。1933年10月籍贯新疆省阿克苏市项目经验政治面貌港澳同胞2002.08-2010.08和谐劳动”视野下的劳动关系协调机制研究户籍澳门省澳门市项目职责:电话1、带领和指导技术研发团队进行体外诊断试剂的研发、设计开发;2、13405045281负责总体技术规划,不断快速提升核心技术,构建稳定、高效的业务;Email3、负责团队目标和工作计划的制定和高效执行,保证诊断试剂研发部工作目标的达成;4、负责与其他部门之间的沟通与协作,满足和协调公司91jfa@sohu. com各相关部门提出的技术更新、新产品等技术需求;5、负责技术团队的管理,包括团队建设,人员激励、考评和培养;6、有效提升团队的工作热情、工作效率和质量;7、指导技术团队学习、交流,并不断提升整体团队技术水平。个人技能吃饭喝茶

很大一个原因,在于排版未能处理好。因为投递简历时,绝大多数人会使用格式各样的模板,如果遇到这类的简历,个人信息被独立在侧边栏。这种情况下,使用PaddleOCR的KIE提取,固然能够单独识别到内容,但由于OCR是逐行识别的,合并文本时简单的个人信息会混杂在其它内容中,就像我们上面看到的这段话,乍看还行,但是细看整个段落有几处非常不通顺,姓名手机号等信息已经混杂在文本中了。

也就是说,对于如果是逐行信息按部就班的表单,直接用PaddleOCR的KIE提取结果拼接,不失为一种快速有效的办法。但是对于简历这类“花样百出”的表单场景,如果要引入OCR技术,我们可能还是需要回溯到上游的版面识别任务中或者微调VI-LayoutXLM模型,寻找更加精确的解决方法。

4. 模型部署

尽管在长句识别上模型有待进一步优化,但是从测试集评估效果看,VI-LayoutXLM + PaddleNLP Taskflow微调得到的模型,在姓名、性别、出生年月、籍贯这类基本信息提取上,效果还是不错的,不失为实现图片简历信息抽取的一个比较好的办法。

下面,我们就通过应用创建工具实现这个模型的部署。由于VI-LayoutXLM模型还不支持whl安装,且抽取结果还有待进一步优化,这里,我们直接使用Taskflow后端调用OCR解析图片文档的能力。只对微调后的Taskflow文本抽取模型进行部署。

在使用测试图片部署效果时,使用streamlit部署有一个非常重要的注意事项,那就是streamlit默认读取的上传文件是字节流,虽然可以用st.image()直接显示图片,但是我们在使用Taskflow的文本抽取能力时,是无法解析的。

本项目中,我们使用PIL进行中转,解决办法如下:

per_image = st.file_uploader("上传图片", type=['png', 'jpg'], label_visibility='hidden')
if per_image:
    from io import BytesIO
    from PIL import Image
    st.image(per_image)
    # To read file as bytes:
    bytes_data = per_image.getvalue()
    #将字节数据转化成字节流
    bytes_data = BytesIO(bytes_data)
    #Image.open()可以读字节流
    capture_img = Image.open(bytes_data)
    capture_img = capture_img.convert('RGB')
    capture_img.save('temp.jpeg', quality=95)

在本项目中,我们将VI-LayoutXLM提取的图片格式简历处理后,结合原有数据标注进行了PaddleNLP的文本抽取模型微调训练,结果显示,虽然整体f1 socre>0.9+,但是因为缺失了关键的排版顺序信息,模型在长本文的抽取效果上还有较大提升空间。后续,我们将结合针对这个问题,结合文档抽取模型的微调训练等工作,进一步研究引入OCR后,如何提升简历信息的抽取效果。

cd Your_Local_Path git clone https://github.com/jiunting/MLARGE.git 将M-LARGE添加到PYTHONPATH 转到您的环境变量文件(.base_profile或.bashrc) vi ~/.bashrc vi ~/.bash_profile 并在文件中添加以下行 # set MLARGE export PYTHONPATH= $PYTHONPATH :YOUR_PATH_MARGE/MLARGE/src 2.生成破裂和地震波形数据 地震场景和合成地震波基于以下方法 Melgar,D.,LeVeque,RJ,Dreger,DS,&Allen,RM(2016年)。 运动破裂场景和合成位移 var schema = { string : { type : 'string' } , array : { type : 'array' , elemType : 'string' } ,
0. 摘要 参加了天池的一个pdf简历信息提取的比赛,这里进行回顾、整理和分享 赛题要求从pdf简历中提取出信息,比如说名字,籍贯等。这里搭建了一个BiLSTM-CRF模型,能够从PDF简历中提取出所需的信息。 模型的线上得分是0.727,排名 21/1200+ 1. 赛题相关 赛题和数据:https://tianchi.aliyun.com/competition/entrance/231771...
联合建模文档的layout信息和text信息,预训练文档理解模型。 使用BERT作为backbone,加入2-D绝对位置信息,图像信息,分别捕获token在文档中的相对位置以及字体、文字方向、颜色等视觉信息。 2-D Position Embedding. 将文档页面视为坐标系统(左上为原点), 使用2张embedding table构造4种位置嵌入,横纵轴各使用1张嵌入表; Image Embedding. 将文档页面图像分割成小图片序列,基于Faster R-CNN建
### 回答1: 我可以给你一些有关使用Docker Compose部署MySQL的指引:1.首先,在你的机器上安装Docker和Docker Compose;2.然后,创建一个docker-compose.yml文件,用来定义你的MySQL容器;3.在docker-compose.yml文件中添加MySQL配置;4.最后,使用docker-compose up命令来启动mysql容器。要使用Docker Compose部署MySQL,可以按照以下步骤进行操作: 1. 首先,在本地计算机上安装Docker和Docker Compose。 2. 创建一个新的目录,并在该目录下创建一个docker-compose.yml文件。 3. 在docker-compose.yml文件中添加以下内容: version: '3.7' services: image: mysql:latest restart: always environment: MYSQL_ROOT_PASSWORD: your_root_password MYSQL_DATABASE: your_database_name MYSQL_USER: your_username MYSQL_PASSWORD: your_password ports: - "3306:3306" volumes: - db_data:/var/lib/mysql volumes: db_data: 4. 保存并关闭docker-compose.yml文件。 5. 在终端中,导航到新创建的目录并运行以下命令:`docker-compose up -d`。这将启动MySQL容器并将其运行在后台。 6. 在MySQL客户端中连接到MySQL服务器。使用以下命令连接到MySQL: mysql -h 127.0.0.1 -P 3306 -u your_username -p 7. 在提示符下输入密码,即可连接到MySQL服务器。 这样,你就可以使用Docker Compose轻松地部署MySQL了。记得将上述步骤中的“your_root_password”、“your_database_name”、“your_username”和“your_password”替换为自己的值。好的,下面是docker-compose部署MySQL的步骤: 1. 首先,创建一个目录来存放docker-compose文件和MySQL数据文件: mkdir mysql cd mysql 2. 创建一个docker-compose.yml文件并打开它: touch docker-compose.yml vi docker-compose.yml 3. 将以下内容复制并粘贴到docker-compose.yml文件中: version: '3.7' services: image: mysql:5.7 container_name: mysql restart: always environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: example MYSQL_USER: example MYSQL_PASSWORD: example volumes: - ./data:/var/lib/mysql ports: - "3306:3306" 这将定义一个名为“db”的MySQL容器,并指定MySQL的版本为5.7。它将使用名为“mysql”的容器名称,并将始终在失败时重新启动。它还指定了MySQL的根密码、数据库名称、用户名和密码。数据文件将存储在名为“data”的目录中,并将端口3306映射到主机上的3306端口。 4. 保存并关闭docker-compose.yml文件。 5. 运行以下命令以启动MySQL容器: docker-compose up -d 这将启动容器并在后台运行。 6. 您可以使用以下命令检查容器是否正在运行: docker ps 这将显示正在运行的容器列表。 现在,您已经成功地使用docker-compose部署了一个MySQL容器。 ### 回答2: 在docker中运行MySQL可以使用docker-compose来进行部署,docker-compose是一个工具,可以帮助管理docker容器和服务,使得部署MySQL变得简单和可扩展。 下面是使用docker-compose部署MySQL的步骤: 1.准备docker-compose文件 在项目根目录中创建一个docker-compose.yml文件,文件中包含MySQL服务的配置信息。 version: '3' services: image: mysql:8 command: --default-authentication-plugin=mysql_native_password ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: mysql MYSQL_USER: user MYSQL_PASSWORD: password volumes: - dbdata:/var/lib/mysql volumes: dbdata: 在上面的docker-compose配置中,我们定义了一个MySQL服务,并命名为db。我们使用了官方MySQL 8镜像,MySQL_ROOT_PASSWORD是我们的root密码。我们还定义了MYSQL_DATABASE,MYSQL_USER和MYSQL_PASSWORD,以存储我们的数据库。同时我们定义了映射端口3306到主机上。 2.启动MySQL服务 在终端中进入项目目录,运行以下命令来启动MySQL服务: docker-compose up -d -d标志允许在后台运行。容器启动后,我们可以使用以下命令来查看正在运行的容器: docker ps 3.连接MySQL 要连接MySQL服务器,我们需要在主机上安装MySQL客户端软件,例如MySQL Workbench。使用以下命令运行MySQL客户端: mysql -h 127.0.0.1 -u user -p 在此命令中,我们指定了服务器的IP地址,用户名和密码。如果MySQL服务器可以正常运行,则应该可以在MySQL客户端中连接到MySQL服务。 4.使用MySQL 现在我们已经成功地部署了MySQL,并使用docker-compose创建了服务。现在可以使用该服务来创建数据库和表,插入数据等。 我们可以使用以下命令重新启动服务: docker-compose restart 如果我们想要停止服务,则可以运行以下命令: docker-compose down 综上所述,使用docker-compose来部署MySQL使得部署变得容易和可扩展。 它可以帮助我们节省大量的时间和资源,同时也可以在不同的开发环境中工作,这是非常有利的。 ### 回答3: Docker是一种容器化技术,在使用Docker容器部署MySQL服务时,Docker Compose可以帮助我们自动化管理Docker容器。Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。 首先,需要创建一个docker-compose.yml文件,用于定义MySQL容器的配置信息。以下是一个基本的docker-compose.yml文件示例: version: '3' services: image: mysql:latest container_name: mysql environment: MYSQL_ROOT_PASSWORD: mysql_password MYSQL_DATABASE: db_name MYSQL_USER: db_user MYSQL_PASSWORD: db_password ports: - "3306:3306" volumes: - /docker/mysql-data:/var/lib/mysql 在上述文件中,我们给MySQL容器命名为"mysql",使用MySQL镜像库中的最新版本,设置了MySQL的登录密码、用户名、数据库名和密码,指定了MySQL服务端口为"3306",定义了一个数据卷,将主机中的/docker/mysql-data目录映射到容器中的/var/lib/mysql目录中,以持久化存储数据。 接下来,执行以下命令来启动MySQL容器: $ docker-compose up -d 此命令会自动创建并启动MySQL容器,"db"服务名为docker-compose配置文件里的名字。"-d"参数表示容器以后台运行。 运行成功后,可以通过以下命令进入MySQL容器: $ docker exec -it mysql bash 然后,用以下命令登录MySQL: $ mysql -u <用户名> -p 输入MySQL管理员设置的密码即可成功登录。此时,我们使用的是互联网IP进行连接。如果要在本地连接,则需要添加docker-compose.yml文件中定义的端口,即3306。 以上是关于使用Docker Compose部署MySQL的流程。使用Docker Compose简单快捷地构建MySQL环境,可以使MySQL服务便于部署和维护,提高工作效率。