wenmo8 发布的文章

通过对多样化基准的严格评估,论文展示了现有特定方法在实现跨领域推理以及其偏向于数据偏差拟合方面的缺陷。从两阶段的视角重新审视视觉推理:(
1
)符号化和(
2
)基于符号或其表示的逻辑推理,发现推理阶段比符号化更擅长泛化。因此,更高效的做法是通过为不同数据领域使用分离的编码器来实现符号化,同时使用共享的推理器。

来源:晓飞的算法工程笔记 公众号

论文: Take A Step Back: Rethinking the Two Stages in Visual Reasoning

Introduction


推理能力是人类智能的集中体现,它是概念形成、对世界的认知理解以及与环境交互的基础。具体而言,视觉推理作为人类获取信息和理解的主要方式之一,已经成为广泛研究的焦点。近年来,随着深度学习的进步,涌现出了许多关于视觉推理的研究工作。此外,也出现了各种数据集来评估推理模型。

然而,现有视觉推理工作的显著局限性在于它们直接依赖于通过端到端深度学习模型同时进行识别和推理阶段,例如,在回答逻辑问题时识别图像中的概念。然而,这种范式存在显而易见的局限性:
1
)推理注释(规则、关系)比符号注释(三角形、立方体、苹果)要昂贵且困难得多,当前严格的视觉推理数据集通常很小。因此,当前方法往往是在小数据集上的特定任务,阻碍了它们的泛化潜力。
2
)同时追求符号识别和逻辑推理的通用模型可能效率低下且具有挑战性,即使是最近的大型语言模型(
LLM
)也难以处理多样化的视觉推理任务。

论文认为视觉推理的重点在于先从视觉信号中获取符号化表示,随后是逻辑推理,如图
1
所示。因此,一个问题浮现出来:这两个阶段应该纠缠在一起还是解开?推理自然比符号化具有更好的泛化性。例如,可以使用类似的逻辑分析不同任务的规则(如下围棋、做数学题和发现异常),但对于识别字母和物体则需要完全不同的知识。因此,论文认为解开符号化和推理将是一个更明智的选择。最近大型语言模型(
LLM
)在基于文本的推理任务上的成功也验证了这一点,因为
LLM
直接利用从人类观察中得出的抽象符号(语言),并专注于高级语言任务。相对而言,多模态大型语言模型(
MLLM
)即使参数更多,仍在视觉推理中遇到困难。最近,另一个相关的研究趋势是神经符号方法,将原始输入转换为明确的符号,以便进行后续推理和分析。然而,神经符号方法通常局限于单一数据集,这使得在不同任务之间实现泛化变得具有挑战性。

论文在多个具有显著领域差距的基准任务上进行了全面的实验,以验证假设。将符号化阶段定义为利用深度神经网络(
DNN
)进行表示提取,采用多种架构(如
MLP

CNN

GNN

Transformer
、神经符号模型、
LLM
等)实现逻辑推理器。论文主要探讨两个关键问题:(
1
) 在训练过的
DNN
模型中,符号化阶段的结束在哪里?即确定适合推理的合适符号(表示),如模型的深度、特征特性等。(
2
) 针对抽象的符号,哪种类型的模型和训练策略最适合进行推理,并赋予泛化能力?

对于第一个问题,论文发现不同的任务和领域需要非常不同规模的参数或模型深度才能实现良好的符号化。因此,针对特定领域,一个小型的独立领域内编码器就足以从数据中提取符号,以供后续推理阶段使用。虽然像
CLIP
这样的通用大型基础模型在某些任务上表现不错,但在与其训练数据存在巨大领域差距的任务上仍然面临挑战。对于第二个问题,实验结果显示,现有方法在执行跨领域推理时往往困难重重,而更倾向于适应与训练数据一致的偏见。因此,也许只能通过训练它执行各种推理任务(如解谜、物理预测、视觉问答)和数据领域(
2D

3D
、文本)来实现可泛化的共享推理器,即“近似原则”。

基于实验的发现,论文构建了一个简洁的框架,采用分离的编码器来实现不同数据领域的最佳符号化,并遵循“近似原则”建立了一个共享的推理器。该方法在跨领域基准测试中表现出色,使用更少的参数即可达到优异的性能。

总体而言,论文的贡献如下:

  1. 总结了一种高效的视觉推理的两阶段方法,借鉴了先前的视觉推理网络的思路。
  2. 探讨了视觉推理中符号化和逻辑推理的最优设计原则。
  3. 引入了一个简洁的框架,在多个具有领域差距的数据集上表现良好。

Preliminary


Two Stages

如上所述,视觉推理可以分为两个阶段:符号化阶段提取基础数据的符号表示,推理阶段进行逻辑推理。

对于人类来说,从感觉器官收集到的视觉和听觉信息的不同模态,通过不同的通路转换成电信号,然后发送到小脑皮层进行逻辑推理。类比地,为了通用的视觉推理机器,分离的任务特定符号化器和共享的领域无关推理器是一个合理的选择。此外,推理器应能够对来自各种模态的输入信息进行统一推理。换句话说,推理的本质在于其泛化能力。

  • Symbolization Stage

在符号化阶段,实现了各种面向任务的特征提取网络。这些网络使用针对每个任务定制的符号编码器,将多模态输入(文本、图像、视频)转换为符号表示。具体而言,假设有
\(n\)
个任务。对于第
\(i\)
个任务,有输入数据
\(\mathbf{x}^{i}\)
和任务
\(t^{i}\)
,以及任务定向编码器
\(E^{i}\)
,通过以下方式得到符号表示集合
\(\mathbf{f}^{i}\)

\[\begin{equation}
\mathbf{f}^{i} = E_i(\mathbf{x}^{i} \mid t^{i}).
\end{equation}
\]

  • Reasoning Stage

推理器接收每个特定任务的符号表示,旨在捕捉数据中嵌入的更深入和更全面的模式和关系理解。对于所有任务的符号表示集合
\(\{\mathbf{f}^{(i)}\}_{i=1}^n\)
,将它们送入推理器
\(R\)
,在逻辑处理后得到其推理结果集合
\(\{\mathbf{c}^{i}\}_{i=1}^n\)
,以促进跨多模态问题解决:

\[\begin{equation}
\{\mathbf{c}^{i}\}^n_{i=1} = R(\{\mathbf{f}^{i}\}^n_{i=1}).
\label{eq:reasoning}
\end{equation}
\]

  • Task-specific Heads

框架的最后部分是任务特定头部,将推理器的推理结果作为输入,并生成任务特定的答案。针对不同的任务,我们需要构建任务特定的分类或回归头部
\(H_i\)
,以获得最终输出
\(s^i\)

\[\begin{equation}
s^i = H_i(\mathbf{c}^{i} \mid t^{i}).
\end{equation}
\]

Symbolization-Reasoning Framework


Entanglement v.s. Disentanglement

考虑到这两个阶段,一个自然的问题出现了:对于任务,符号编码器(符号化)和推理器(推理)应该共享还是分开?

为了验证共享推理器假设,进行了不同设计的比较(图
2
):

  1. Both-Separated
    :符号编码器和逻辑推理器均分离(每个任务的特定模型)。
  2. Both-Shared
    :符号编码器和推理器都是共享的。
  3. Shared-Encoder-Only
    :仅符号编码器是共享的。
  4. Shared-Reasoner-Only
    :仅推理器是共享的。

我们在几个多模态视觉推理基准上比较上述四种设计。对于共享的编码器/推理器,采用更多的参数来平衡它们与分离的编码器/推理器参数总和。在所有基准测试中,仅共享推理器(类型
4
)的表现远远优于仅共享编码器(类型
3
)和完全共享(类型
1

2
)。此外,仅共享推理器甚至在某些基准测试中超过了临时的完全分离模型,验证了其优越性和泛化能力。

Symbolization Depth

接下来,探讨符号编码器在不同任务中的合适深度。符号化阶段涉及处理来自不同领域的输入,并将它们映射到概念层次,即符号。尽管可以使用二进制或类似索引的表示(
one-hot
)来表示符号,但在深度学习的背景下,论文选择更具代表性的方式,即从深度神经网络中提取的高维特征。直观上,不同的任务可能需要不同程度的符号化。接下来的问题是如何确定每个任务的抽象层次。

为了回答这个问题,论文设计了实验来定量探究符号化过程中的程度。为了控制变量,在跨领域任务中采用相同的特征提取网络(
ResNet
),同时不断调整网络的深度。在不同深度下,将符号化网络的输出连接到相同的推理器,并以准确率作为符号化完成的指标进行测量。

假设当符号化完成时,网络深度-准确率曲线将显示出明显的拐点。通过监测这一拐点的出现,可以为不同任务选择合适的推理器深度,如图
3
所示。在实验中,结果与常识一致:过浅和过深的网络对推理任务都是有害的。一方面,如果编码器过浅,符号化可能无法在输入推理器之前完全完成,而推理器则需要完成部分符号化工作,从而影响推理性能。另一方面,过深的网络往往会过拟合于单一任务,从而削弱旨在泛化的共享推理器的性能。不同领域的任务也需要不同的符号化深度。设置深度不当会导致共享参数冲突,进而导致更深层次的性能不佳。

Reasoner Architecture

接下来,论文希望弄清楚哪种架构更适合于推理器,这是一个长期存在的问题。许多研究已经提出并在各种视觉推理基准上取得了改进。在这里,每个任务由其各自的编码器和任务头处理,这些设计旨在适应其数据的固有特性。论文为所有任务使用一个共享的推理器,并根据公式
2
中的符号表示进行处理。

论文选择了一系列在许多任务中取得了巨大成功的架构作为推理器的候选项:多层感知器(
MLP
)、卷积神经网络(
CNN
)和
Transformer
,还探索了将神经网络的表示能力与符号系统的可解释性结合的混合神经符号模型。此外,论文采用了流行的图形和自回归模型:图卷积网络(
GCN
)和
MiniGPT-4
。上述模型为论文提供了广泛且多样化的方法论。如果在各种领域多样化的数据集上观察到强大而一致的性能,这将导致假设存在某种类型的架构,特别擅长逻辑推理。

Generalization of Reasoner

最后但并非最不重要的是,论文的目标是验证其“近似原理”,即通过来自不同领域的多样化任务和数据的训练,得到一个接近能够提供通用逻辑推理能力的良好推理器。论文认为推理涵盖普适性和泛化能力,因此,首先在一个任务上训练完整的两阶段模型,然后直接将其推理器与另一个任务的另一个符号编码器配对。如果推理器具有泛化能力,则其应该能够很好地适应其他任务的编码器。然而,在论文的测试中,仅使用一个任务/领域训练的推理器通常泛化能力不佳。因此,接下来验证推理器在训练更多任务/领域后是否具有更好的泛化能力。

如图
4
所示,论文发现随着涉及不同任务和领域的数据越来越多,整体任务变得越来越具有挑战性。然而,推理器将会专注于“纯粹”的推理,而不是特定于任务/领域的解决方法,从而赋予更好的泛化能力。换句话说,论文的“近似原理”是合理的。因此,可以预测,随着训练数据和任务的增加,推理器在跨领域任务上的表现应该会更好。此外,一个共享并跨任务训练的推理器使整个视觉推理框架更轻便和更高效。

Experiments


Entanglement v.s. Disentanglement Analysis

为了比较图
2
中的三种类型,使用五个数据集对模型进行训练:
RAVEN

CVR

SVRT

Bongard-HOI

Bongard-LOGO
。为了控制变量并便于模型共享,对于上述所有类型,我们采用
ResNet-18
作为编码器,使用
MLP
作为推理器。

结果如表
1
所示,仅共享推理器的性能在所有五个数据集上与
ad-hoc
方案相当,在
RAVEN

SVRT
上甚至更高。此外,仅共享编码器和共享双方案在所有数据集上表现明显不及。这反映了在跨多个任务使用任务特定符号化器和共享推理器设计的有效性。

Optimal Symbolization Depth

接下来,通过探测符号编码器的深度来确定两个阶段之间的边界,如图
3
所示,使用的共享推理器是一个
MLP
。通过观察准确率的变化,希望找到明显的拐点和符号化基础阶段的终止点。为了确保公平性,在以下二维数据集(
RAVEN

CVR

SVRT

Bongard-LOGO

Bongard-HOI
)上采用
ResNet18
编码器。对于每个基准,训练各自的模型以达到最佳性能,然后在不同深度中断训练的网络,以探测符号化终止点。将分离的符号编码器的输出连接到一个共享推理器,并记录不同中断点处的准确率,这被视为符号化终止的证据。

如图
5
和表
2
所示,对于每个基准,网络深度表现出初期的增长,然后进入一个平稳期。不同任务的拐点位置因其难度水平和所需的符号抽象程度不同而异。例如,
Bongard-HOI
的拐点比
RAVEN
深得多,表明前者更难符号化,需要一个更深的符号化网络来获取复杂的高维特征。这些结果验证了在不同复杂度的数据集上使用深度不同的符号化网络的必要性,并说明了两个阶段之间的合理边界。

One-for-All Reasoner Architecture

接下来,找出适合的推理器架构,并测试其在仅共享推理器设计中的效果。选择了
9
个跨领域数据集(
RAVEN

CVR

SVRT

Bongard-HOI

Bongard-LOGO

Filtered-CoPhy

VQAv2
)来进行实验,因为用不同领域的数据解决各种推理问题可以更好地展示模型的推理能力。

根据不同任务的要求设计了任务特定的编码器和头部。至于推理器,测试了
CNN

MLP

Transformer

GCN
、混合神经符号模型和
MiniGPT-4
。首先单独训练每个数据集,以获得使用分离编码器和分离头部时的最佳结果,然后使用一个共享推理器对多个数据集进行联合训练。

如表
3
所示,在所有架构中,
MLP
在四个数据集上表现出乎意料的最佳性能,并且在其他五个数据集上表现相当。此外,
GCN
在三个数据集上表现良好,符合之前在推理工作中的经验。然而,通常被认为更先进的
Transformer
等其他架构并未显示明显优势。因此,选择
MLP
作为
One-for-All
中的轻量推理器。

One-for-All
在大多数任务上表现出色,甚至与最先进技术(
SOTA

ad-hoc
相比也不遑多让。论文根据复杂性将
SOTA
分为轻量和重型,如表
4
所示,
One-for-All
与轻量
ad-hoc SOTA
表现可比,并且在一些数据集(如
RAVEN
)上甚至超越了轻量
ad-hoc SOTA
。这个实验表明,推理阶段与识别任务有着不同的性能参数关系。如果在多领域任务上进行训练,一个轻量级的推理器也可以在推理任务上表现出色。

由于推理能力不能仅通过准确性来衡量,论文还使用推理一致性评估推理能力。对于每个任务,使用相同的编码器和推理器参数,采用两种问答方法:“这个问题的答案是什么?”和“某个选项是否正确?”。一个具有良好推理能力的模型应该在这两种方法上产生一致的结果,而不像随机模型可能存在不一致性。论文使用
F1
分数来衡量这些方法之间的一致性,如表
5
所示。
One-for-All
在多个数据集上联合训练后,显示出比单独训练的模型更高的一致性,表明其在真正推理中的潜力。

为了进一步评估
LLM
的性能,采用
MiniGPT-4
作为共享推理器。
One-for-All
在相似的模型规模下也表现出优势。令人惊讶的是,轻量化的
One-for-All
在特定任务上超过了
MiniGPT-4
,例如
RAVEN

Bongard-HOI
,这提供了强有力的证据表明,模型参数数量与模型推理能力之间没有绝对的正相关关系。

为了分析基于
LLM
的模型性能,根据论文的两阶段框架设计探索任务,并分别进行检查:(
1
)符号化:
LLM-based
模型能否识别问题的要素。(
2
) 概念化:
LLM-based
模型能否学习任务背后的具体概念并进行推理。(
3
) 答案生成:
LLM-based
模型能否利用其学习到的概念来解决问题。以
MiniGPT-4
为代表,总结了
LLM-based
模型对
RAVEN

Bongard
中三级问题的典型响应,如图
6
所示。

论文发现
LLM
在解决视觉推理任务时可能会遇到某些幻觉情况。如图
6
所示,对于
RAVEN
问题,
MiniGPT-4
在第一阶段成功识别物体,但在第二阶段根据排列规则进行推理时失败。对于
Bongard
问题,
MiniGPT-4
在第一阶段成功识别人类活动,并在第二阶段逻辑推理中掌握了推理,但在答案生成阶段失败,并且在利用规则回答问题时迷失方向。基于以上案例,能够了解
LLM-based
模型在推理任务中的缺点,即其良好的概念理解能力,但在逻辑推理和答案生成方面表现不足。

Approximation Principle Verification

接下来,验证使用来自多个领域数据训练推理器可以确保推理器具有更好的泛化能力,在
SVRT

Bongard-HOI

Filtered-CoPhy

Balls
任务、
Filtered-CoPhy

Collision
任务以及
VQAv2
上进行了相关实验。这些数据集涵盖了
2D
谜题、
3D
视频和
VQA
任务,提供了多样化和多模态的数据,利用
Filtered-CoPhy

Collision
任务作为测试的基准。

论文引入越来越多跨领域数据集来训练推理器,并将其与目标测试数据集的分离编码器配对。鉴于各个数据集之间的固有差异,在推理器之前引入了基于
MLP
的高度轻量级适配器。为了均衡每个数据集对推理引擎的贡献,调整了用于跨数据集训练的样本大小。具体而言,使用了
1,000

3,000
的样本大小。

如表
6
所示,随着训练数据集数量的增加,推理器逐步改善。尽管处理来自多样化领域的更多数据集显著增加了复杂性,但经过训练的推理器在跨领域的
Filtered-CoPhy
上表现良好。这表明随着训练数据集领域的增加,推理器将专注于任务无关的纯推理,这验证了我们的“逼近原理”。

Additional Ablation Study

在表
7
中展示了在符号编码器是否使用预训练模型的消融实验,选择了
RAVEN

CVR

SVRT
数据集,并采用
ImageNet
作为预训练数据集。结果非常接近,可能的原因是
ImageNet
与这三个推理数据集之间存在明显的领域差异。

论文测试了
CLIP
作为通用和大型基础模型在充当通用符号编码器时的表现,将
CLIP
作为多模态数据集的视觉编码器,接着使用
MLP
作为推理器,并采用任务特定的头部网络。如表
8
所示,即使在微调后,使用
CLIP
得到的结果仍不及最佳的
One-for-All
方法。这验证了即使像
CLIP
这样的大型模型也无法完成不同数据集的符号化任务,从而确认了采用分离编码器和共享推理器框架设计的理论依据。



如果本文对你有帮助,麻烦点个赞或在看呗~
更多内容请关注 微信公众号【晓飞的算法工程笔记】

work-life balance.

论文提出了一个专门针对斯瓦希里语自然场景文本检测和识别的数据集,这在当前研究中是一个未充分开发的语言领域。数据集包括
976
张带标注的场景图像,可用于文本检测,以及
8284
张裁剪后的图像用于识别。

来源:晓飞的算法工程笔记 公众号

论文: The First Swahili Language Scene Text Detection and Recognition Dataset

Introduction


如今,沟通很大程度上依赖于文本内容。文本是一种极为优秀的沟通方式,其影响力也能持续非常长的时间。场景文本广泛存在且包含着相当丰富的语义和信息,有助于理解现实世界。各种服务如报纸、医院、金融服务、保险和法律机构日益将大多数文档数字化以便实际应用。应用场景如汽车辅助、工业自动化、机器人导航、实时场景翻译、欺诈检测、图像检索、产品搜索等,这些都依赖于场景文本识别,并且这些应用每天都在不断进化和发展。现在,理解和解释图像中包含的文本内容变得至关重要。此外,文本无处不在,出现在许多关键的自然场景中:道路标志、广告、海报、街道、餐馆、商店等。

近年来,研究人员在挑战性场景中检测和识别文本的模型方面取得了显著进展,这些场景包括模糊图像、非传统背景、变化的光照条件、曲线文字或在恶劣环境中捕获的图像等。然而,大多数研究集中在英语和汉语等广泛使用的语言上,对资源有限地区如印度乡村和非洲的其他语言的关注和资源较少。因此,许多世界语言缺乏适当的数据集和量身定制的模型,这使得在这些语言中有效解决场景图像中文本检测和识别的挑战变得困难。

斯瓦希里语,又称基斯瓦希里语,是非洲大陆上使用最广泛的语言之一。超过
1
亿人口在包括坦桑尼亚、乌干达、刚果民主共和国、布隆迪和肯尼亚在内的多个非洲国家使用斯瓦希里语。该语言是坦桑尼亚和肯尼亚的官方语言,并广泛用于公共管理、教育和媒体领域。斯瓦希里语从阿拉伯语(约占
40%
)、波斯语、葡萄牙语、英语和德语等外语中借用了许多词汇。尽管如此,斯瓦希里语仍被归类为资源匮乏的语言之一,自然语言处理任务受到了注释数据稀缺的限制。

虽然斯瓦希里语使用拉丁字母表,但大多数涉及拉丁字母表的大型数据集主要集中在拥有不同语言特征的语言,比如英语。缺乏关注导致了斯瓦希里语,这种被数百万人使用的语言,没有专门的资源来优化和微调文本检测和识别模型以适应其独特的特征。表
1
列出了该语言与英语相比的一些特征。

本文的主要目标是为斯瓦希里语开发一个全面的场景文本数据集:
Swahili-text
。这个图像集合旨在满足专门数据集的需求,为评估现有模型提供基准,并帮助研究社区开发斯瓦希里语场景文本检测和识别的新的最先进方法。
Swahili-text
包含
976
张图片,大部分来自坦桑尼亚的城市,其他来自社交媒体。这些图片包括商店标签、广告横幅、海报和街道名称。每张图片在单词级别上都进行了手动注释。据作者所知,
Swahili-Text
是第一个专为斯瓦希里语场景文本检测和识别开发的全面数据集。

Related work


Swahili Language Datasets for Natural Language Processing

斯瓦希里语仍然被归类为资源匮乏的语言。由于注释数据稀缺,自然语言处理任务受到了限制。然而,随着深度学习和语言模型的发展,许多数据集开始对语言建模任务提供越来越多的支持。其中,
Helsinki
数据集是最常用的数据集之一,专门用于斯瓦希里语的语言研究。该数据集提供了未注释和已注释版本的斯瓦希里语文本集合。该数据集旨在支持语言分析、语料库语言学以及与斯瓦希里语自然语言处理任务相关的各种研究工作。

Gelas
等人开发了一个用于语言建模任务的注释数据集。该数据集包含来自不同斯瓦希里语在线媒体平台的句子,涵盖了体育、一般新闻、家庭、政治和宗教等多个领域的句子。总共有
512,000
个独特单词。
Shikali
等人将该数据集与斯瓦希里语音节字母表结合,并改编了
Mikolov
等人提出的英语词类比数据集。
Barack W
等人开发了
Kencorpus
斯瓦希里语问答数据集(
KenSwQuAD
),旨在应对低资源语言,特别是斯瓦希里语中问答数据集的稀缺性,增强机器对自然语言的理解能力,应用于斯瓦希里语言者的互联网搜索和对话系统等任务。
Alexander R
等人则关注低资源语言(如斯瓦希里语)中语音数据集的缺乏,特别是口语数字识别领域。该研究开发了一个斯瓦希里语口语数字数据集,并研究了跨语言和多语言预训练方法对口头数字识别的影响。

这些数据集旨在促进斯瓦希里语言建模和自然语言处理任务的研究,然而在场景文本检测和识别任务中,目前还不存在一个全面的用于斯瓦希里语注释场景文本图像的数据集。

Latin Script Scene Text Datasets

场景文本识别领域受到标准数据集的影响,这些数据集使研究人员能够节省大量时间和精力来收集和注释数据。与拉丁字母场景文本识别相关的流行数据集有以下:

  1. ICDAR
    数据集在文档分析和识别领域非常流行。
    ICDAR 2013
    数据集包含
    462
    张高分辨率的自然场景图像,如户外场景、标志和海报。该数据集引入了多方向文本、不同光照条件以及混合字体和文字大小的挑战,以促进强大的文本识别算法的发展。
    ICDAR 2015
    偶发场景文本数据集包含通过
    Google Glass
    捕捉的
    1,670
    张图像。该数据集包括具有非传统文本形状、曲线文本和不同语言文本的偶发场景文本。
  2. Total-text
    数据集针对多方向和曲线文本问题提出。它包含具有不同方向文本的图像,主要是曲线文本。
  3. MSRA-TD500
    数据集结合了英文和中文词汇,也非常受欢迎。它包含来自实际场景的
    500
    张任意方向的图像,并以句子级别进行了注释。除了拉丁字母脚本的数据集外,还提出了多语言场景文本识别的几个多语言数据集。

然而,大多数这些数据集并不包括斯瓦希里语。据知,目前尚未创建用于斯瓦希里语场景文本检测和识别的公共数据集。虽然一些用于英语的数据集可以用来,因为它们使用相同的字母表,但它们并不像一个专门针对斯瓦希里语的数据集那样有效。

Scene Text Detection and Recognition Methods

深度学习技术的爆炸性发展显著影响了场景文本检测和识别领域,为场景文本检测和识别打开了全新的可能性,能够从文本图像中提取更强大和具有区分性的特征。

文本检测和文本识别可以看作是两个独立的任务。在文本检测阶段,其目标是识别并标记输入图像中存在文本的区域。存在三种主要的方法:基于回归、基于部分和基于分割的方法。基于回归的方法直接回归边界框。通过将文本检测转化为回归问题,模型学习估计文本实例的空间分布,这使其非常适合需要精确定位文本区域的场景。基于部分的方法识别并将文本部分与单词边界框关联起来。基于分割的方法结合像素级预测和后处理技术,利用语义分割和基于
MSER
的算法等技术检测文本实例。

文本识别涉及将检测到的文本区域转换为字符实例,主要有两种方法:
connectionist temporal classification

CTC
)模型和注意力机制模型。
CTC
模型使用递归神经网络计算基于单帧预测的标签序列的条件概率,该过程包括三个重要步骤:使用卷积网络从文本区域提取特征、使用递归神经网络在每帧预测标签分布以及后处理步骤将每帧的预测转换为最终的标签序列。

注意力机制在计算机视觉领域,包括场景文本识别中,取得了显著的成果。注意力机制专注于输入的相关部分,从而在复杂或变化的环境中实现更精确的字符识别。这种方法利用编码结构从文本区域提取特征向量,并利用解码结构生成字符实例。肖等人解决了注意力机制产生无关信息的问题,并提出了一种评估注意力结果与查询之间相关性的方法。通过将
Attention on Attention

AoA
)机制整合到文本识别框架中,可以消除无关的注意力,从而提高文本识别的准确性。

尽管在场景文本检测和识别方面取得了显著进展,但标注训练数据的不足仍然是一个障碍。深度学习算法在泛化到现实世界场景时受到大规模数据集稀缺的限制,尤其是对于低资源语言或尚未研究的语言,包括带有标注的场景文本图像的数据集。

Swahili Text Dataset


Dataset Description

斯瓦希里语场景文本检测和识别数据集包含
976
张自然场景图像,数据来源多样。这些数据由专注于计算机视觉和自然语言处理的研究人员以及斯瓦希里语母语者收集。图像来源广泛,包括互联网资源和在坦桑尼亚城市使用手机相机直接拍摄的图像。这确保了从斯瓦希里语使用地区获得了具有代表性的场景集合。

为确保收集到的图像准确性和相关性,实施了严格的质量控制措施,并特别注意消除光照不均和模糊的图像。该数据集经历了预处理步骤,以移除具有不良质量属性的图像,并对具有不完整数据的实例进行了修正或排除,以维护数据的完整性。数据集中的每个图像都以
JPEG
格式存储。

斯瓦希里语文本数据集包含描绘自然场景的图像,其中包含斯瓦希里语文本元素,如街道标志、街道名称、广告、商店名称、横幅和其他常见于斯瓦希里语使用地区的标识物。为了便于场景文本检测和识别任务,数据集已进行标注,标注过程由领域专家进行,以确保对文本区域的准确注释。


1
展示了数据集中包含的部分图像。用于识别任务,数据集中的图像已裁剪为
8284
张图像。图
2
展示了斯瓦希里语文本裁剪图像的统计数据,包括按文本长度分组的图像数量和字符出现的分布情况。

Annotation

为确保文本检测和识别的准确性,并评估系统的性能,准确的文本实例注释至关重要。因此,斯瓦希里语文本数据集采用了细致的手动注释方法。每个图像中的每个文本区域都用单个边界框进行注释,以确保在处理斯瓦希里语文本的各种形状和位置时能够准确地标注。

每个图像的文本实例注释被收集到一个单独的文件中。该文件包含单词的边界框坐标和相应的文本转录。边界框是一个具有
n
个点的多边形,每个点都有水平位置
x1
和垂直位置
y1
的坐标。不可读的文本实例仅用边界框标记,以便于检测但不参与文本的识别。图
3
展示了一个带有注释的示例图像。

Experiments


Text Detection Experiment

Text Recognition Experiment



如果本文对你有帮助,麻烦点个赞或在看呗~
更多内容请关注 微信公众号【晓飞的算法工程笔记】

work-life balance.

前言

一个摄像头视野不大的时候,我们希望进行两个视野合并,这样让正视的视野增大,从而可以看到更广阔的标准视野。拼接的方法分为两条路,第一条路是stitcher类,第二条思路是特征点匹配。
本篇使用stitcher匹配,进行两张图来视野合并拼接。


Demo

在这里插入图片描述


两张图拼接过程


步骤一:打开图片

在这里插入图片描述

cv::Mat mat = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/29.jpg");
cv::Mat mat2 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/30.jpg");


步骤二:加入图片进入队列

在这里插入图片描述

std::vector<cv::Mat> vectorMat;
vectorMat.push_back(mat);
vectorMat.push_back(mat2);


步骤三:创建拼接类

在这里插入图片描述

cv::Ptr<cv::Stitcher> pStitcher = cv::Stitcher::create(cv::Stitcher::PANORAMA, false);
//cv::Ptr<cv::Stitcher> pStitcher = cv::Stitcher::create(cv::Stitcher::SCANS, false);


步骤四:拼接

在这里插入图片描述

cv::Ptr<cv::Stitcher> pStitcher = cv::Stitcher::create(cv::Stitcher::SCANS, false);
LOG;
cv::Stitcher::Status status = pStitcher->stitch(vectorMat, resultMat);
LOG;
if(status != cv::Stitcher::OK)
{
std::cout << "Failed to stitch, status =" << status << std::endl;
return;
}

对拼接后显示所有:
在这里插入图片描述

cv::namedWindow("mat", cv::WINDOW_NORMAL);
cv::imshow("mat", mat);
cv::resizeWindow("mat", cv::Size(400, 300));

cv::namedWindow("mat2", cv::WINDOW_NORMAL);
cv::imshow("mat2", mat2);
cv::resizeWindow("mat2", cv::Size(400, 300));

cv::namedWindow("resultMat", cv::WINDOW_NORMAL);
cv::imshow("resultMat", resultMat);
cv::resizeWindow("resultMat", cv::Size(400, 300));


步骤五:对图像进行宽高黑边裁剪(略)

直接写个算法对周边黑色区域进行矩形探测,然后裁剪即可,方法很多,一般我们拍照的图片都不是全黑的,而黑边是全黑的,这个算法写起来有明显的特征。


耗时测试


原始图像1701x1280像素,耗时477ms左右

在这里插入图片描述

在这里插入图片描述

原始图片1701x1280像素,拼接消耗的时间约477ms:


图像缩小至400x300像素,耗时390ms左右

然后对其图片进行缩放后测试其耗时:
在这里插入图片描述

在这里插入图片描述

将图片统一缩放为800x600分辨率,其拼接耗时在390ms左右。


图像放大至1920x1080像素,耗时530ms左右

在这里插入图片描述

在这里插入图片描述

将图片放大至1920x1080分辨率,其拼接耗时在530ms左右


注意

本次测试并不严谨,基于同样图的缩放,单纯控制像素缩放来比较,但是得出的结论可以反应图像大小的影响,最终的耗时是受多方因素影响,包括但不限于检测特征电的数量、重叠区域的大小、像素分辨率、多图。


结论

这种方式适合对照片进行拼接,对黑边处理之后,效果很不错,但是,调用stitcher类实现时对图片的特征匹配有要求,一些特征点不够的图片无法拼接,并且,当图片较大或多张图片拼接时,速度慢。所以,倘若放到视频上,一秒钟25-60fps,那就肯定不行了。
SIFT算法拼接,SIFT算法可以提供较高的准确率,得到的图片需要经过再次处理,才能得到相对较好的图片,
ORB算法拼接,算法的速度非常快,但是最容易出现问题,且得到的图片需要经过再次处理,才能得到相对较好的图片,


函数原型


函数cv::Stitcher::create

static Ptr<Stitcher> create(Mode mode = PANORAMA, bool try_use_gpu = false);
  • 参数一:拼接模式枚举,只有2个值PANORAMA和SCANS
    PANORAMA:创建照片全景的模式,期望图像处于透视状态;
    SCANS:合成扫描的模式。期望仿射变换下的图像,默认情况下不补偿曝光。(由于咱们一般总归有角度偏移,所以这个方式对拼接图像有较高要求)
  • 参数二:是否使用gpu,这种方式编译opencv得带上gpu编译,编译opencv的时候开启支持gpu,在arm上的话,需要先确认芯片是否支持GPU,然后安装GPU驱动,然后编译opencv支持GPU选项,才可以。


函数cv::Stitcher:: stitch

CV_WRAP Status stitch(InputArrayOfArrays images, OutputArray pano);
  • 参数一:输入图像列表
  • 参数二:输出拼接结果
Status stitch(InputArrayOfArrays images, const std::vector<std::vector<Rect> > &rois, OutputArray pano);
  • 参数一:输入图像列表
  • 参数二:输入图像列表依次需要拼接的区域
  • 参数三:输出拼接结果


Demo源码

void OpenCVManager::testStitchImages()
{
cv::Mat mat = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/29.jpg");
cv::Mat mat2 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/30.jpg");

#if 0
// 拼接环视全景,特征点是完全不够,无法使用该方法,同时就算能拼也无法达到新能要求
cv::Mat mat = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/front_2024-08-22_17-15-08_result.png");
cv::Mat mat2 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/left_2024-08-22_17-15-10_result.png");
cv::Mat mat2 = cv::imread("D:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/right_2024-08-22_17-15-11_result.png");
#endif

#if 1
// 对图片进行缩放,测试其拼接耗时
cv::resize(mat, mat, cv::Size(1920, 1080));
cv::resize(mat2, mat2, cv::Size(1920, 1080));
#endif

std::vector<cv::Mat> vectorMat;
vectorMat.push_back(mat);
vectorMat.push_back(mat2);


cv::Mat resultMat;

cv::Ptr<cv::Stitcher> pStitcher = cv::Stitcher::create(cv::Stitcher::PANORAMA, false);
// cv::Ptr<cv::Stitcher> pStitcher = cv::Stitcher::create(cv::Stitcher::SCANS, false);
LOG;
cv::Stitcher::Status status = pStitcher->stitch(vectorMat, resultMat);
LOG;
if(status != cv::Stitcher::OK)
{
std::cout << "Failed to stitch, status =" << status << std::endl;
return;
}


cv::namedWindow("mat", cv::WINDOW_NORMAL);
cv::imshow("mat", mat);
cv::resizeWindow("mat", cv::Size(400, 300));

cv::namedWindow("mat2", cv::WINDOW_NORMAL);
cv::imshow("mat2", mat2);
cv::resizeWindow("mat2", cv::Size(400, 300));

cv::namedWindow("resultMat", cv::WINDOW_NORMAL);
cv::imshow("resultMat", resultMat);
cv::resizeWindow("resultMat", cv::Size(400, 300));

cv::waitKey(0);
}


对应工程模板v1.69.0

在这里插入图片描述

在上周五 12:24-14:05 遭遇
大规模 DDoS 攻击
后,今天11:40左右开始遭遇疑似大规模 CC 攻击,明显的特征是有很多来自海外各个国家IP的异常高频次访问请求。

虽然我们针对海外访问临时采取了躲避措施,但攻击请求不仅限于海外,我们躲不过去。

非常抱歉,这次攻击给大家带来了麻烦,请大家谅解。

这次遇到的攻击与去年遇到的攻击类似,攻击者用心良苦。

去年攻击时,手下留情,在十一假期加班一次采用 DDoS + CC 联合攻击,因为是节假日,影响很小,我们没有缴保护费。

今年攻击时,特地选择在工作日,周五 DDoS 攻击,周末双休,周一改用 CC 攻击,影响很大,逼着我们缴保护费。

但是,用心良苦的攻击者们,不是我们不想缴保护费,实在是园子太困难,困难到
向开发者求救
,缴不起保护费啊,你们再怎么用心良苦地攻击,我们还是缴不起保护费啊,请放手吧。

公众号同步发布
https://mp.weixin.qq.com/s/0HecUB8MM1l4ZyvLd1RAkg

注:如果发现发现不能访问园子,可以在上面这篇公众号文章的评论中查看当前攻击情况

关于攻击的一些情况:

1)在 CC 攻击期间,有一台负载均衡的 QPS 高达近2.4w

1)

在TS开发中,经常会遇到后台数据字段比较多的情况,这时候需要一个个复制字段然后给他手动配置数据类型来完成我们的TS类型定义,相当麻烦。有什么快速的方法呢,我就目前遇到的两种情况分别写了JS脚本来处理后台数据,直接生成我们需要的数据格式。

脚本编写

1. 处理数据字典中的数据

一般数据字典表里的数据可能在excel文件里,也可能是在在线网页中,但它一般都是一个表格的形式,比如以下这种:
image

我们只需要复制前两列的内容,字段和字段类型。
明白我们的需求后,开始编写js脚本:

// 定义一个方法
const dealDictionaryKey = (string) => {
  // 复制出来的数据是多行的形式,所以我们以'\n'去分开每一行数据
  const strArr = string.split('\n');
  let newString = '';
  // 遍历每行数据
  for (let item of strArr) {
    // 空白行跳过
    if (item.trim() === '') continue;
    // 替换常用的后台数据类型为js类型,如果有遗漏请自行添加 /t是单元格字段和单元格类型之间的隔离符号
    item = item.replace(/\t/, ': ').replace('INTEGER', 'number').replace(/TIMESTAMP|DATE/, 'Date')
        .replace(/TEXT|VARCHAR\(\d*\)|CHAR\(\d*\)/, 'string');
    // 递归是因为可能一个字段里有多个下划线
    item = toUppercase(item);
    newString += item + ';\n';
  }
  console.log(newString)
}
// 递归字符串,替换字符串中每一个 下划线+小写字母 为 大写字母 的形式
const toUppercase = (str) => {
    const idx = str.indexOf('_');
    // 替换到没有下划线为止
    if(idx === -1) return str;
    // 下划线+小写字母
    const oldStr = str.substr(idx, 2);
    // 生成的大写字母
    const initial = str.substr(idx + 1, 1).toUpperCase();
    // 替换
    str = str.replace(oldStr, initial);
    str = toUppercase(str);
    return str;
}
// 赋值测试
const str =
`
department_id	INTEGER
department_name	VARCHAR(125)
department_type	CHAR(1)
	
	
create_user	VARCHAR(25)
create_time	TIMESTAMP
update_user	VARCHAR(20)
update_time	TIMESTAMP

`
// 执行
dealDictionaryKey(str);

执行结果

departmentId: number;
departmentName: string;
departmentType: string;
createUser: string;
createTime: Date;
updateUser: string;
updateTime: Date;

2. 处理后台代码中复制的数据

我们直接查看后台代码,然后复制出来进行处理。后台代码一般形式如下:
image

我们直接复制花括号中的内容,进行处理。js脚本编写如下:

// 定义一个方法
const dealServerKey = (str) => {
  // 复制出来的数据是多行的形式,所以我们以'\n'去分开每一行数据
  const strArr = str.split('\n')
  let newString = ''
  // 遍历每行数据
  for (let item of strArr) {
    // 空行跳过
    if (item.trim() === '' || item.indexOf('private') === -1) continue;
    // 删除无用的private字段
    item = item.replace('private', '').replace(';', '').trim();
    // 先将字段和类型分开
    const keys = item.split(' ');
    const type = keys[0].replace(/Integer|BigDecimal/, 'number').replace('String', 'string')
    // 处理后调换位置
    newString += keys[1] + ': ' + type + ';\n';
  }
  console.log(newString)
}
// 输入测试
const str =  `
    private Integer departmentId;

    private String departmentName;

    private String departmentType;

    private String departmentTypeName;

    private Date createTime;
`
// 执行
dealServerKey(str);

执行结果

departmentId: number;
departmentName: string;
departmentType: string;
departmentTypeName: string;
createTime: Date;

使用

脚本编写后,当然可以在浏览器控制台直接使用,每次的输入内容和调用执行需要手动替换。不过这样使用不太直观方便,我这边一般都会使用
在线的执行js工具
,百度谷歌一搜很多。
以下以我使用的
run-js
为例:
image

将脚本复制到左侧代码框内,然后每次去替换
str
的赋值,点击中间的
执行
按钮,结果即可在右侧展示。
最后复制右侧内容到代码里即可。