Gmgge / TrOCR-Seal-Recognition

基于transformer的ocr识别,在公章(印章识别, seal recognition)拓展应用
121 stars 24 forks source link

感觉印章识别用这个方式,很容易识别出其他文字,结果完全不对的结果,有点鸡肋,这个缺点很难解决 #21

Closed cqray1990 closed 2 months ago

Gmgge commented 5 months ago

可以的话,贴一两个你这边的测试样例,我看看训练集中有没有覆盖类似场景

cqray1990 commented 5 months ago

可以的话,贴一两个你这边的测试样例,我看看训练集中有没有覆盖类似场景

53 44

之前试过两阶段的,但是还有文字方向的问题,定位文本拉直,还有弯曲文本的,楼主有头试过其他方式? 楼主哟试过合合的印章识别?他的很准,而且清晰的一般不会错,错的不离谱,感觉他不是用这个方式做的,难道他的海量数据很多?

Gmgge commented 5 months ago

企业微信截图_20240325162944 可以尝试我的在线识别模型,我看你这个圆形印章是可以识别的,椭圆印章我这边没做任何优化,可能效果不能保证。

由于我这个在线平台是先印章检测,检测模型正在优化中,训练的印章都是正常图标中的印章检测,直接裁剪出来的印章可能不太符合这个使用场景,后期会覆盖

Gmgge commented 5 months ago

目前主流的端到端和多阶段都有,具体你可以参考印章识别的一些比赛。

1.我这边先前是多阶段的,印章检测、文本定位、透视变换、ocr识别,当然了多阶段也区分各种,有的是弯曲文字直接识别,有的是变换成矩形。 2.数据很重要,尤其是字符识别这边需要的数据就更多了,从最基础的来说,你得覆盖常用字典里面的字吧?然后是不是得覆盖一些长短词?

wang-zhix commented 5 months ago

应该是数据集不足导致的,数据集太少,会导致模型有时候会胡说八道 你可以尝试搞一个假样本制作工具,多搞一些背景有字的样本

Gmgge commented 5 months ago

是的,有点类似asr里面,没做过噪音增强的训练容易把噪音识别出来一些乱七八糟的内容,不想重新训练就直接上阈值过滤掉

cqray1990 commented 5 months ago

目前主流的端到端和多阶段都有,具体你可以参考印章识别的一些比赛。

1.我这边先前是多阶段的,印章检测、文本定位、透视变换、ocr识别,当然了多阶段也区分各种,有的是弯曲文字直接识别,有的是变换成矩形。 2.数据很重要,尤其是字符识别这边需要的数据就更多了,从最基础的来说,你得覆盖常用字典里面的字吧?然后是不是得覆盖一些长短词?

多阶段效果好?,有分印章形状?而且都要做文字方向判断,不然文字定位之后,拉直或者直接切出来都有方向问题,可以推荐一些多阶段的方式?ABENet,TPS PGNet都有试过

Gmgge commented 5 months ago

1.多阶段效果好? 很难说好多少?相对来说端到端会更好,但是多阶段会更快 2.之前有想介绍下多阶段,但是怕你误入歧途。。。如果说文本180度翻转的方向问题,这个可以参考ocr的操作,训练个文本方向分类器。具体的话,你可以画图演示下相关方向问题吗?

cqray1990 commented 5 months ago

1.多阶段效果好? 很难说好多少?相对来说端到端会更好,但是多阶段会更快 2.之前有想介绍下多阶段,但是怕你误入歧途。。。如果说文本180度翻转的方向问题,这个可以参考ocr的操作,训练个文本方向分类器。具体的话,你可以画图演示下相关方向问题吗? 多阶段试过,就是模型太多了,文本检测之后,是否需要将弯曲的文本拉值呢,拉值之后再去分方向,还是直接弯曲的识别呢,用控制点拉直的,控制点找不准,导致拉值效果不太好 @Gmgge

Gmgge commented 5 months ago

看下ICDAR` 2023 Competition on Reading the Seal Title的排行榜技术方案可以了解更多。

个人觉得这个时候不要太担心拉直扭曲的问题,因为如果你的训练集都这样,且能训练收敛的话就没有问题,毕竟有人用深度学习来做扭曲纠正的。

如果你实在担心,或者说你不想再重新训练ocr,先前实验过针对圆印章是检测到位置与角度之后之后,会进行印章圆弧拟合,拟合到之后,再针对圆环切割拉直,该方案不再需要定位弧形文本区域,而且不需要重新训练ocr即可达到不错的精度。

cqray1990 commented 5 months ago

ICDAR` 2023 Competition on Reading the Seal Title

看下ICDAR` 2023 Competition on Reading the Seal Title的排行榜技术方案可以了解更多。

个人觉得这个时候不要太担心拉直扭曲的问题,因为如果你的训练集都这样,且能训练收敛的话就没有问题,毕竟有人用深度学习来做扭曲纠正的。

如果你实在担心,或者说你不想再重新训练ocr,先前实验过针对圆印章是检测到位置与角度之后之后,会进行印章圆弧拟合,拟合到之后,再针对圆环切割拉直,该方案不再需要定位弧形文本区域,而且不需要重新训练ocr即可达到不错的精度。

@针对圆形的极坐标切割拉直?圆印章角度怎么检测?直接角度分类?

Gmgge commented 5 months ago

可以尝试下有角度的目标检测。

dc6273632 commented 4 months ago

大佬,我想使用旋转目标检测模型先检测出印章中的每一个字,然后再对单个字符做方向分类,再送到识别模型进行识别,你觉得这样可行么?

Gmgge commented 4 months ago

昨晚应该是写了一堆,有点忙结果忘了点comment。。。

大概解释下,单个文字的检测识别,算是传统方法思路,如果说非常关注单个孤立文字or数字的准确率,可以使用该逻辑来尝试。

在印章识别领域,可以尝试弯曲文本行识别,基于语义分割的文本行检测,目前很多都是可以做弯曲文本的检测的。识别阶段并非一定要做透视变换把文字扭曲正,因为基于transformer的网络从逻辑和实验上都是可以直接解决该问题的。但是这不表明显示的弯曲文本纠正是不可以接受的策略,如果你的弯曲策略很完善,后续识别可以使用更简单的网络结构,既可以保证准确率,也可以大大提升速度。

dc6273632 commented 2 months ago

昨晚应该是写了一堆,有点忙结果忘了点comment。。。

大概解释下,单个文字的检测识别,算是传统方法思路,如果说非常关注单个孤立文字or数字的准确率,可以使用该逻辑来尝试。

在印章识别领域,可以尝试弯曲文本行识别,基于语义分割的文本行检测,目前很多都是可以做弯曲文本的检测的。识别阶段并非一定要做透视变换把文字扭曲正,因为基于transformer的网络从逻辑和实验上都是可以直接解决该问题的。但是这不表明显示的弯曲文本纠正是不可以接受的策略,如果你的弯曲策略很完善,后续识别可以使用更简单的网络结构,既可以保证准确率,也可以大大提升速度。

试了一下单个字符的检测,对于一些印章文字有一定间隔的识别还是很准的,但是对于那些文字很多间隔很小的印章就不行了,不知道百度的印章识别接口是如何实现的,识别的好准。。有的字人都不太看得清,它都能给识别出来,还是对的

dc6273632 commented 2 months ago

昨晚应该是写了一堆,有点忙结果忘了点comment。。。

大概解释下,单个文字的检测识别,算是传统方法思路,如果说非常关注单个孤立文字or数字的准确率,可以使用该逻辑来尝试。

在印章识别领域,可以尝试弯曲文本行识别,基于语义分割的文本行检测,目前很多都是可以做弯曲文本的检测的。识别阶段并非一定要做透视变换把文字扭曲正,因为基于transformer的网络从逻辑和实验上都是可以直接解决该问题的。但是这不表明显示的弯曲文本纠正是不可以接受的策略,如果你的弯曲策略很完善,后续识别可以使用更简单的网络结构,既可以保证准确率,也可以大大提升速度。

还有大佬,您有联系方式吗?我这边有一些真实的人工标注的印章数据集可以提供,也想跟您探讨探讨技术方面的一些问题。

wang-zhix commented 2 months ago

你是需要每个字的坐标吗? 不需要坐标的话,这个模型就可以达到很高的识别率

dc6273632 commented 2 months ago

你是需要每个字的坐标吗? 不需要坐标的话,这个模型就可以达到很高的识别率

这个模型我试了,确实不错,但是百度接口是怎么做到,连人都看不清楚的字,还能识别正确的。。太奇怪了。 微信图片_20240627181659 这个百度识别出的是滦南县鸿涛门窗厂,关键人家确实是这个名字。。

dc6273632 commented 2 months ago

我用这个模型训练大概100个epoch,样本量12000,0.05的验证集,为什么到80个epoch的时候,loss就差不多是0了,但是精度还算正常,eval_cer大概0.0125,eval_acc大概90.8,这个算过拟合么?

wang-zhix commented 2 months ago

这个模型结构是可以支持到很高准确度的,给你一些我训练的方法 1.样本数量问题,你可以试着生成一些假样本(可以先用大量假样本训练一个base模型,然后用真样本强化微调) 2.更多的样本增强,我使用了 颜色变换、灰度化和二值化、对比度、仿射变换、高斯模糊、高斯噪声、亮度、分段仿射变换 3.模型参数量增大(欠拟合) 4.增大dropout参数(过拟合)

希望可以帮到你

dc6273632 commented 2 months ago

这个模型结构是可以支持到很高准确度的,给你一些我训练的方法 1.样本数量问题,你可以试着生成一些假样本(可以先用大量假样本训练一个base模型,然后用真样本强化微调) 2.更多的样本增强,我使用了 颜色变换、灰度化和二值化、对比度、仿射变换、高斯模糊、高斯噪声、亮度、分段仿射变换 3.模型参数量增大(欠拟合) 4.增大dropout参数(过拟合)

希望可以帮到你

如果我的印章中最大字符长度也就32左右,那设置模型参数的时候是不是不要设置的过长比较好一点? 还有如果要增大模型的参数量,是不是就不能用现有的这些预训练模型了?要用微软的trocr-base-printed预训练模型?我现在用的是TAL_OCR_CHN这个预训练模型,大概100多M,用微软的base得有1个多G,large模型得两个多G。。

wang-zhix commented 2 months ago

1.因为这是生成式的模型,只要设置的比你的最大字符长度大就可以了。我认为设置的长度并不会有影响。 2.修改了模型,肯定就要自己从头训练了,没法用现有的预训练

模型定义参考 你可以通过调整参数 来增大模型参数量


from transformers import (
    TrOCRConfig,
    TrOCRProcessor,
    TrOCRForCausalLM,
    ViTConfig,
    ViTModel,
    VisionEncoderDecoderModel,
    Seq2SeqTrainingArguments,
    Seq2SeqTrainer,
    ViTImageProcessor,
    RobertaTokenizer,
    default_data_collator,
)

vocab_file_path = 'cust-data/weights/vocab.json'
merges_file_path = 'cust-data/weights/merges.txt'

image_processor = ViTImageProcessor(size={"height": 384, "width": 384})
tokenizer = RobertaTokenizer(vocab_file=vocab_file_path, merges_file=merges_file_path)
processor = TrOCRProcessor(image_processor=image_processor, tokenizer=tokenizer)
vocab = tokenizer.get_vocab()
vocab_inp = {vocab[key]: key for key in vocab}

vit_config = ViTConfig(hidden_size=384,
        num_hidden_layers=12,
        num_attention_heads=6,
        intermediate_size=1536,
        hidden_act="gelu",
        hidden_dropout_prob=0.0,
        decoder_start_token_id=2,
        attention_probs_dropout_prob=0.0,
        initializer_range=0.02,
        layer_norm_eps=1e-12,
        image_size=384,
        patch_size=16,
        num_channels=3,
        qkv_bias=True,
        encoder_stride=16,)
encoder = ViTModel(vit_config)

trocr_config = TrOCRConfig(vocab_size=len(tokenizer),
                        cross_attention_hidden_size=384,
                        d_model=256,
                        decoder_layers=6,
                        decoder_attention_heads=8,
                        decoder_ffn_dim=1024,
                        activation_function="gelu",
                        max_position_embeddings=512,
                        dropout=0.1,
                        attention_dropout=0.0,
                        activation_dropout=0.0,
                        decoder_start_token_id=2,
                        init_std=0.02,
                        decoder_layerdrop=0.0,
                        use_cache=True,
                        scale_embedding=False,
                        use_learned_position_embeddings=True,
                        layernorm_embedding=True,
                        pad_token_id=1,
                        bos_token_id=0,
                        eos_token_id=2,
                           )
decoder = TrOCRForCausalLM(trocr_config)
model = VisionEncoderDecoderModel(encoder=encoder, decoder=decoder)
model.config.decoder_start_token_id = tokenizer.cls_token_id
model.config.pad_token_id = tokenizer.pad_token_id
model.config.eos_token_id = tokenizer.sep_token_id

model.save_pretrained("./test_model")
processor.save_pretrained('./test_model')
dc6273632 commented 2 months ago

1.因为这是生成式的模型,只要设置的比你的最大字符长度大就可以了。我认为设置的长度并不会有影响。 2.修改了模型,肯定就要自己从头训练了,没法用现有的预训练

模型定义参考 你可以通过调整参数 来增大模型参数量


from transformers import (
    TrOCRConfig,
    TrOCRProcessor,
    TrOCRForCausalLM,
    ViTConfig,
    ViTModel,
    VisionEncoderDecoderModel,
    Seq2SeqTrainingArguments,
    Seq2SeqTrainer,
    ViTImageProcessor,
    RobertaTokenizer,
    default_data_collator,
)

vocab_file_path = 'cust-data/weights/vocab.json'
merges_file_path = 'cust-data/weights/merges.txt'

image_processor = ViTImageProcessor(size={"height": 384, "width": 384})
tokenizer = RobertaTokenizer(vocab_file=vocab_file_path, merges_file=merges_file_path)
processor = TrOCRProcessor(image_processor=image_processor, tokenizer=tokenizer)
vocab = tokenizer.get_vocab()
vocab_inp = {vocab[key]: key for key in vocab}

vit_config = ViTConfig(hidden_size=384,
        num_hidden_layers=12,
        num_attention_heads=6,
        intermediate_size=1536,
        hidden_act="gelu",
        hidden_dropout_prob=0.0,
        decoder_start_token_id=2,
        attention_probs_dropout_prob=0.0,
        initializer_range=0.02,
        layer_norm_eps=1e-12,
        image_size=384,
        patch_size=16,
        num_channels=3,
        qkv_bias=True,
        encoder_stride=16,)
encoder = ViTModel(vit_config)

trocr_config = TrOCRConfig(vocab_size=len(tokenizer),
                        cross_attention_hidden_size=384,
                        d_model=256,
                        decoder_layers=6,
                        decoder_attention_heads=8,
                        decoder_ffn_dim=1024,
                        activation_function="gelu",
                        max_position_embeddings=512,
                        dropout=0.1,
                        attention_dropout=0.0,
                        activation_dropout=0.0,
                        decoder_start_token_id=2,
                        init_std=0.02,
                        decoder_layerdrop=0.0,
                        use_cache=True,
                        scale_embedding=False,
                        use_learned_position_embeddings=True,
                        layernorm_embedding=True,
                        pad_token_id=1,
                        bos_token_id=0,
                        eos_token_id=2,
                           )
decoder = TrOCRForCausalLM(trocr_config)
model = VisionEncoderDecoderModel(encoder=encoder, decoder=decoder)
model.config.decoder_start_token_id = tokenizer.cls_token_id
model.config.pad_token_id = tokenizer.pad_token_id
model.config.eos_token_id = tokenizer.sep_token_id

model.save_pretrained("./test_model")
processor.save_pretrained('./test_model')

根据你的这套配置的话模型的参数量大概有多少?我感觉small模型的参数拟合不太够,精度达不到要求,base模型的参数又有点大了,训练时间太久了,14000的数据集,两张12G的3060卡,要训练40个小时。。数据集是1万的合成印章+4000的人工标注,后面还会增加,这得搞多久。。

wang-zhix commented 2 months ago

这只是个参考代码,你需要自己调整参数(保存后只有114MB) 中文训练确实耗时,字太多了。这个我也没有好办法

dc6273632 commented 2 months ago

这只是个参考代码,你需要自己调整参数(保存后只有114MB) 中文训练确实耗时,字太多了。这个我也没有好办法

是哎,只要涉及到中文文字识别的都太蛋疼了,基本的至少要覆盖3-5千,还有一大堆生僻字,可能都有5-7千了。。你用你的这套配置大概能达到多少的精度?

wang-zhix commented 2 months ago

现在的训练不在我这了,所以这只是参考代码,具体参数我也没看。 线上版本应该有98左右

dc6273632 commented 2 months ago

现在的训练不在我这了,所以这只是参考代码,具体参数我也没看。 线上版本应该有98左右

98精度有点强了。。我用仓库作者的这套配置,在训练集上也就95左右。。看来参数还是要慢慢调的