表格结构识别 SPLERGE tf/keras 实现(上)

本文详细介绍了SPLERGE模型在表格结构识别中的应用,包括数据准备、模型搭建、训练和评估。作者实现了SFCN、RPN和CPN组件,并在ICDAR2013和2019表格数据集上进行训练。面对过拟合问题,提出了数据增强和模型正则化等改进措施。最后,分享了模型在split阶段的实际效果及性能提升策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


更新:非常抱歉,经过交流讨论,发现一处我的代码错误,Merge 模型中最前面应该加上对应的 SFCN,我写了 SFCN 但是却没加入到 Merge 模型中。

更新:我自己用 tf 实现的 SPLERGE 代码已开源在 githubgitee,因为数据很少,模型效果是 over-fitting 的,仅供学习。

SPLERGE

之前有写过 2019 年 ICDAR 表格结构识别最佳论文 Deep Splitting and Merging for Table Structure Decomposition 的介绍,也有一个野生 torch 版本的项目实现,我自己用 tf/keras 写过 split 阶段的复现,整理了一下。merge 部分的在下篇中写。

针对 split 阶段,整个过程不外乎可以分为数据准备、模型搭建、模型训练和模型评估,如果模型评估结果不尽人意或者希望能更上一层,就要复盘整个过程中哪里还有改进点。

数据准备

使用的数据就是 ICDAR 2013 年和 2019 年的表格数据(提取码: vwwf),其中的每份数据都包含对应的 pdf、csv、xls、reg.xml 和 str.xml 几个文件。
ICDAR表格数据

在结构识别任务中,以表格图片信息作为输入,输出预测的横纵分隔线,所以只需要用 pdf、reg 和 str 三个文件信息就可以了。每个 pdf 包含一页或多页,在其中一页或多页中存在一个或多个表格,首先将每个 pdf 文件的每一页都转为图片,再根据 reg 文件中的信息裁剪获得表格区域图片,str 文件中包含每个字块的信息,结合这几部分信息就可以得到 split 的训练数据。
在这里插入图片描述

数据量不是很多,一共 248 个表格, 这里是将表格图片和对应行列的分隔信息写进了 tfrecords 用来训练。

备注:
(1)原始表格数据中表格位置和字块位置的纵向坐标都是上下倒置的,需要转换一下。
(2)有一处错误,icdar2013-competition-dataset-with-gt/competition-dataset-us/us-018-reg.xml 文件中 26ß(经过查看,应该是260)。
(3)有关 str 文件中 merge 相关的信息(虽然现在重点在说 split 部分,但还是先记录下来),标注标准不太一致。对于不跨行或者不跨列的说明,部分写法只写 start 不写end,部分写法是 start 和 end 都指向一行/列,需要注意下。

问题:
(1)有关 pdf 转 png,安装 fitz 和 PyMuPDF,以往装包还真没遇到过 pip 版本问题的,这是第一次= =,升级 pip 就好了。
(2)一直以为 os.path.join(s1, s2) 可以解决所有的路径拼接问题,偶然发现 s2 必须不能以斜杠开头,否则并不会把两个路径拼接出来。

模型搭建

原论文介绍的很清楚,一共三个大组件分别是 SFCN、RPN 和 CPN,其中 RPN 和 CPN 某种意义上对称,都由 5 个大体相同的 Block 组成。

# SFCN
class SFCN(tf.keras.Model):
    def __init__(self):
        super().__init__()
        cnn = tf.keras.Sequential()
        dilation = [1, 1, 2]
        for i in range(3):
            cnn.add(tf.keras.layers.Conv2D(filters=18, kernel_size=7, padding='same', kernel_initializer=kernel_init, activation='relu', dilation_rate=dilation[i]))
        self.cnn = cnn

    def call(self, input):
        output = self.cnn(input)
        return output
# Block
class Block(tf.keras.Model):
    def __init__(self, block_num, mode=None):
        super().__init__()
        self.block_num = block_num # start from index 1
        self.mode = mode
        self.conv1 = tf.keras.layers.Conv2D(filters=6, kernel_size=3, padding='same', kernel_initializer=kernel_init, activation='relu', dilation_rate=2)
        self.conv2 = tf.keras.layers.Conv2D(filters=6, kernel_size=3, padding='same', kernel_initializer=kernel_init, activation='relu', dilation_rate=3)
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值