Layoutlm是一个视觉文档多任务通用的预训练模型。
本文是一个本科生对多模态浅薄理解的一个过程的学习和总结
目录结构
layoutlm在微软开源工作总仓库unilm下,将其全部clone。
layoutlm作为第一版本,如今已被弃用,微调样例和主模型代码,被额外一层 deprecated 目录包裹。
├── examples #微调示例 │ ├── classification #分类任务 │ │ └── run_classification.py │ └── seq_labeling #序列标记(信息抽取)任务 │ ├── preprocess.py │ ├── preprocess.sh │ └── run_seq_labeling.py ├── layoutlm #模型代码 │ ├── data #数据集代码,包含Dataset类 │ │ ├── funsd.py │ │ └── rvl_cdip.py │ └── modeling #模型主代码 │ ├── __init__.py │ └── layoutlm.py ├── mypy.ini ├── README.md └── setup.py
主要是有两个示例,代码里包含两个数据集和模型的主代码,init和layoutlm
Shell命令
在这种代码里,不会再以ipynb的形式一步一步的进行跑代码,实际上只需要跑.sh文件(在服务器linux环境)可以一步跑完
例如preprocess.sh
#!/bin/bash wget https://guillaumejaume.github.io/FUNSD/dataset.zip unzip dataset.zip && mv dataset data && rm -rf dataset.zip __MACOSX python preprocess.py --data_dir data/training_data/annotations \ --data_split train \ --output_dir data \ --model_name_or_path bert-base-uncased \ --max_len 510 python preprocess.py --data_dir data/testing_data/annotations \ --data_split test \ --output_dir data \ --model_name_or_path bert-base-uncased \ --max_len 510 cat data/train.txt | cut -d$'\t' -f 2 | grep -v "^$"| sort | uniq > data/labels.txt
简单的解释一下——先运行python的脚本 --data_dir data/training_data/annotations 制定了输入python文件的数据目录
--data_split train :这个参数指定了要处理的数据集的划分。在这个例子中,使用的是"train",表示训练集。 --output_dir data :这个参数指定了输出目录,即处理后的数据将保存在data
目录中。 --model_name_or_path bert-base-uncased :这个参数指定了模型的名称或路径。在这个例子中,使用的是bert-base-uncased
,表示使用了预训练的BERT模型,该模型是一个小写版本。 --max_len 510 :这个参数指定了文本序列的最大长度。在这个例子中,文本序列的最大长度被限制为510个标记。BERT模型在输入序列的长度上有限制,通常是512个标记,但会有一些保留给特殊标记。
实际上就是把一些参数放到py文件里,给它选定 测试训练集,输出路径 model name 最大长度限制。
再解释一下cat 操作
这是一个命令行操作序列,主要是针对文件data/train.txt
进行一系列文本处理。让我为你解释一下:
-
cat data/train.txt
: 读取data/train.txt
文件的内容并输出到标准输出(屏幕)。 -
cut -d$'\t' -f 2
: 使用制表符(\t
)作为分隔符,提取每一行的第二个字段。假设文件中的每一行都包含制表符分隔的字段,这个操作会提取第二个字段。 -
grep -v "^$"
: 从之前的操作结果中过滤掉空白行。grep -v "^$"
表示匹配不以开头是空白的行,即只保留非空行。 -
sort
: 对文本进行排序。 -
uniq
: 去除重复的行。 -
> data/labels.txt
: 将最终的结果保存到data/labels.txt
文件中。
综合起来,这个命令的目的是从data/train.txt
文件中提取第二个字段,过滤掉空白行,对结果进行排序并去除重复的行,最后将处理后的结果保存到data/labels.txt
文件中。这样,data/labels.txt
文件应该包含了data/train.txt
文件中第二个字段的非重复值。
实际上就是一个标签的提取
在最开始,只需要我们执行这个预加工的shell命令,就可以完成数据的加载
例如命令: chomd u+x hello.sh(添加x执行权限) ./hello.sh sh hello.sh
cd examples/seq_labeling ./preprocess.sh
执行微调脚本
python run_seq_labeling.py --data_dir data \ --model_type layoutlm \ --model_name_or_path path/to/pretrained/model/directory \ --do_lower_case \ --max_seq_length 512 \ --do_train \ --num_train_epochs 100.0 \ --logging_steps 10 \ --save_steps -1 \ --output_dir path/to/output/directory \ --labels data/labels.txt \ --per_gpu_train_batch_size 16 \ --per_gpu_eval_batch_size 16 \ --fp16
Funsd数据集内容
目录结构
data ├── testing_data # 50个样本 │ ├── annotations │ └── images └── training_data # 149个样本 ├── annotations └── images
data目录下,含有训练集和测试集,每个数据集拥有images和annotations两个目录
其中训练集中有149个样本,测试集中有50个样本。
Funsd数据集的标记比较仔细,以文本块为基本单位,包括文本框、文本、标签、词集合、关系,id,如下所示。
其中文本包含多个单词,词集合中又分别描述了子单词的文本和文本框位置信息。
标签表示该文本段的实体属性。关系则表示实体之间的关联关系,如问题和答案,以文本块之间的id双元组表示。
{ "box": [84,109,136,119], "text": "COMPOUND", "label": "question", "words": [ { "box": [84,109,136,119], "text": "COMPOUND" } ], "linking": [ [0,37] ], "id": 0 },
以上annotation信息,表示了一个扫描视觉文档具有的文本和布局信息,需要将其转换为模型可以学习的格式。
流程概览
由于本人能力有限,不能够完全的理解每一部分代码的含义并把它讲出来,我依据心哥@丘野对代码的注释,主要是提炼出一些必要的操作。
随机采样——set_Seed 因为要随机采样,先设计一个种子。接着get_labels是对原来label.txt的数据进行加工
train函数中,要设置batch size 其大小为每一个gpu的batch*gpu个数
设置dataloader 和 step步长 设置epoch=最大步长除以每个epoch的步长
设置优化器和半精训练
然后利用model.train()进入训练模式
-
train方法,加载模型、训练参数,执行训练流程,保存权重
-
evaluation 方法,在测试集上评估模型方法
main函数只要调用上面的操作
最后就是把输出的结果存到data里就可以了
主模型
模型里面定义了一些类
-
LayoutlmConfig
: 这是一个模型配置类,继承自BertConfig
,包含了一些关于模型的配置信息,例如词汇表大小、隐藏层大小等。 -
LayoutlmEmbeddings
: 这个类定义了模型的嵌入层,用于将输入转换为模型可接受的格式。该嵌入层包括词嵌入、位置嵌入、类型嵌入等。 -
LayoutlmModel
: 这是主要的Layoutlm模型类,继承自BertModel
。在这里,主要修改了模型的嵌入层为LayoutlmEmbeddings
。 -
LayoutlmForTokenClassification
: 这个类是用于标注任务的模型,继承自BertPreTrainedModel
。它包括了LayoutlmModel
以及一个线性分类器用于预测每个标记的类别。在训练时,可以计算损失值并进行反向传播。 -
LayoutlmForSequenceClassification
: 这个类是用于序列分类任务的模型,继承自BertPreTrainedModel
。类似于LayoutlmForTokenClassification
,它包含了LayoutlmModel
以及一个线性分类器用于预测整个序列的类别。