跃迁引擎

空気を読んだ雨降らないでよ

iOS Research & Development


「端智能」基于自然语言处理 (NLP) 的光学字符识别 (OCR)

前言

本期将会向大家介绍人工智能领域的一大重要分支:自然语言处理(NLP),与由 卷积神经网络循环神经网络 以及《用于基于图像的序列识别的端到端可训练神经网络及其在场景文本识别中的应用》论文算法 等相关算法组成的光学字符识别(OCR)相结合在端智能领域的实践与应用,并展示客户端基于强大的机器学习能力来进行的实际效果的演示以及背后运行原理的分析。受限于篇幅,本文的客户端代码将全部由 iOS 平台 CoreML 机器学习框架Vision 图像识别框架 来构成和演示。

希望大家在本期分享之后能够对人工智能的发展以及端智能应用场景的落地,有一个更深一步的思考和认知,有助于更深层次的为我们今后的业务进行赋能。

参加本次分享你将收获

  • 人工智能端智能发展上的进一步深入了解。
  • 自然语言处理学科及其分支领域的基础概念、实现原理、区别差异以及相关的场景应用。
  • 光学字符识别的基本原理与实现过程,相关的场景应用。
  • 卷积神经网络的基本原理与相关知识结构。
  • 循环神经网络的基本原理与相关知识结构。
  • 如何在 iOS 平台上基于 CoreML & Vision 实现一套高性能的图像文字识别功能。

什么是自然语言处理 (NLP) ?

自然语言处理 (NLP) 是计算机科学的一个分支,更具体地说,是人工智能 (AI) 的分支,旨在让计算机能够以与人类大致相同的方式理解文本和语音。

自然语言处理 (NLP) 将计算语言学(基于规则的人类语言建模)与统计、机器学习和深度学习模型相结合。 这些技术共同让计算机能够以文本或语音数据的形式处理人类语言,“理解”语言的完整含义,感知书写者或说话者的情绪并满足他们的意图。

自然语言处理 (NLP) 驱动计算机程序将文本从一种语言翻译成另一种语言,响应语音命令,以及快速甚至实时总结大量文本。 在日常生活中,你有可能与多种形式的自然语言处理 (NLP) 互动,包括 GPS 语音系统、数字助手、语音到文本听写软件、客服聊天机器人以及其他为消费者提供便利的系统。 此外,自然语言处理 (NLP) 在企业解决方案中也发挥着越来越大的作用,有助于精简业务运营,提高员工生产力以及简化任务关键型业务流程。

自然语言处理 (NLP) 任务

人们说的话往往含混不清、模棱两可,因此要开发出能够准确确定文本或语音数据中预期含义的软件,是件非常困难的事情。 同音异形词、同音异议词、讽刺、习语、隐喻、语法与用法例外、句子结构的变化等等,这些只是人类语言中不规则现象的一些例子,我们需要很多年的时间才能掌握,但如果想让自然语言驱动的应用发挥作用,程序员必须让这些应用从一开始就能准确地识别和理解人类语言。

一些自然语言处理 (NLP) 任务通过分解人类文本语音数据,帮助计算机理解所采集的内容。 这些任务包括:

  • 语音识别,也称为语音转文本,用于将语音数据以可靠的方式转换为文本数据。 任何遵循语音命令或回答口述问题的应用都需要语音识别功能。 语音识别的挑战性在于人们的说话方式 — 语速快,含糊不清,各种重音、语调和口音,以及语法常常不正确。
  • 词性标注,也称语法标注,这个过程按照用法和上下文确定特定单词或文本片段的词性。 “I can make a paper plane” 中 “make” 的词性为动词,”What make of car do you own?” 中 “make” 为名词。
  • 词义消歧,用于对多义单词选择含义,通过语义分析过程确定单词在特定上下文中最准确的意思。 例如,词义消歧可帮助区分动词 “make” 在 “make the grade”(达到)和 “make a bet”(做出)中的含义。
  • 命名实体识别 ,简称 NEM,用于将单词或短语识别为有意义的实体。 NEM 将”Kentucky”识别为地点,将 “Fred” 识别为男性的名字。
  • 指代消解,用于确定两个单词是否以及何时指代同一实体。 最常见的例子是确定某个代词所指的人或物体(例如,”她”指玛丽),但也可能涉及识别文本中的隐喻或习语(例如,”熊”有时并不表示动物,而是指体型魁梧、体毛较多的人)。
  • 情绪分析,尝试从文本中提取主观特质,例如,态度、情绪、讽刺、困惑和怀疑。
  • 自然语言生成,有时被视为语音识别或语音转文本的逆操作;该任务用于将结构化信息转化为人类语言

NLP、NLU 与 NLG:三个自然语言处理概念之间的差异

虽然自然语言处理 (NLP)自然语言理解 (NLU)自然语言生成 (NLG) 都是相关主题,但它们是不同的主题。从较高的层面来看,NLU 和 NLG 只是 NLP 的组成部分。考虑到它们的交叉方式,它们在对话中通常会被混淆,但在这篇文章中,我们将单独定义每个术语并总结它们的差异以澄清任何歧义。

什么是自然语言处理?

自然语言处理****(NLP)从计算语言学发展而来,利用计算机科学、人工智能、语言学和数据科学等不同学科的方法,使计算机能够理解人类书面和口头形式的语言。虽然计算语言学更关注语言的各个方面,但自然语言处理强调使用机器学习和深度学习技术来完成任务,例如语言翻译或问答。自然语言处理的工作原理是获取非结构化数据并将其转换为结构化数据格式。它通过识别命名实体(称为命名实体识别的过程)和识别单词模式来实现这一点,使用标记化、词干提取和词形还原等方法来检查单词的词根形式。例如,单词上的后缀 -ed(如 Called)表示过去时态,但它与现在时态动词 Calling 具有相同的基本不定式(to call)。

虽然存在多种 NLP 算法,但不同的方法往往用于不同类型的语言任务。例如,隐马尔可夫链往往用于词性标记。循环神经网络有助于生成适当的文本序列。N 元语法是一种简单语言模型 (LM),它为句子或短语分配概率以预测响应的准确性。这些技术共同支持聊天机器人等流行技术,或亚马逊 Alexa 或苹果 Siri 等语音识别产品。然而,它的应用范围远不止于此,影响了教育和医疗保健等其他行业。

什么是自然语言理解?

自然语言理解****(NLU)是自然语言处理的一个子集,它使用文本和语音的句法和语义分析来确定句子的含义。句法是指句子的语法结构,而语义是指其预期含义。NLU 还建立了相关的本体:指定单词和短语之间关系的数据结构。虽然人类在对话中自然会这样做,但机器需要结合这些分析来理解不同文本的预期含义。 我们区分同音异义词和同音异义词的能力很好地说明了语言的细微差别。例如,我们来看以下两个句子:

  1. Alice is swimming against the current.(爱丽丝正在逆流游泳)
  2. The current version of the report is in the folder.(报告的当前版本位于该文件夹中)

在第一句中,”current”一词是一个名词。它前面的动词”swimming”为读者提供了额外的上下文,使我们能够得出结论:我们指的是海洋/河流中的水流。第二句话使用”current”一词,但作为形容词。它所描述的名词”version”表示报告的多次迭代,使我们能够确定我们所指的是文件的最新状态。

这些方法也常用于数据挖掘以了解消费者态度。特别是,情绪分析使品牌能够更密切地监控客户反馈,从而使他们能够聚集积极和消极的社交媒体评论并跟踪净推荐分数。通过审查负面情绪评论,公司能够更快地识别和解决其产品或服务中的潜在问题领域。

什么是自然语言生成?

自然语言生成(NLG)是自然语言处理的另一个子集。自然语言理解侧重于计算机阅读理解,而自然语言生成则使计算机能够写作。NLG 是根据某些数据输入生成人类语言文本响应的过程。该文本还可以通过文本转语音服务转换为语音格式。

NLG 还包括了文本摘要功能,该功能能够从输入文档生成摘要,同时保持信息的完整性。这种提取式摘要属于让人工智能的创新。

最初,NLG 系统使用模板来生成文本。基于一些数据或查询,NLG 系统会填补空白,就像 Mad Libs 游戏一样。但随着时间的推移,自然语言生成系统随着隐马尔可夫链、循环神经网络和变压器的应用而不断发展,从而能够实时生成更动态的文本。

与 NLU 一样,NLG 应用程序需要考虑基于词法、词典、语法和语义的语言规则,以选择如何适当地表达响应。他们分三个阶段解决这个问题:

  • 文本规划:在此阶段,以逻辑方式制定排序总体内容。
  • 句子规划:此阶段考虑标点符号文本流,将内容分解为段落和句子,并在适当的情况下合并代词或连词。
  • 实现:此阶段考虑语法准确性,确保遵循标点符号和词形变化的规则。例如,动词run的过去式是ran,而不是runned

NLP、NLU、NLG 总结

  • 自然语言处理 (NLP) 旨在将非结构化语言数据转换为结构化数据格式,使机器能够理解语音和文本并制定相关的上下文响应。其子主题包括自然语言处理和自然语言生成。
  • 自然语言理解(NLU)侧重于通过语法和上下文进行机器阅读理解,使其能够确定句子的预期含义。
  • 自然语言生成(NLG)专注于文本生成,或者由机器基于给定数据集构建英语或其他语言的文本。

什么是光学字符识别 (OCR) ?

光学字符识别Optical Character Recognition,缩写:OCR)是指对包含文本内容的图像或视频进行处理和识别,并提取其中所包含的文字及排版信息的过程。例如,一个常见的应用是将包含文档图像的不可编辑状态的 PDF 文档通过 OCR 技术识别后,转换为可编辑状态的 Word 格式文档。

通常来说,根据不同文本内容的特性而言,OCR 技术的应用场景大致可分为以下几类:

  • 印刷文本识别:印刷文本通常指报刊、杂志、文档、小票等使用现代计算机字体编排并印刷的文本内容。这类文本内容通常具有清晰一致的字体、间距等,因此识别技术相对成熟,并被广泛应用于纸质文件、报刊的数字化上。
  • 手写文本识别:相较于具有固定字体的印刷文本而言,手写文本往往根据不同的书写者以及书写工具会具有极大的变化,因此其识别难度相较于印刷文本而言要更高。手写体识别可以帮助用户快速将手写的笔记内容数字化输入到计算机中,也被用在一些电子备忘录中来对用户的手写笔记内容进行检索。此外,由手写文本识别进一步派生的一个应用则是签名笔迹认证,这类方法用于比对签名的真实性。
  • 公式文本识别:数学公式通常由大量符号及数字组成,由于根式,分式等规则的存在,数学公式往往存在二维结构,即并不能保证识别的顺序一定符合固定的阅读顺序。因此,数学公式的 OCR 模型往往显著有别于常规的自然语言文本 OCR 处理技术。通常来说,数学公式的 OCR 识别需要借助使用 LaTeX 等结构化的文档标记语言来实现,即,OCR 给出的输出是一组 LaTeX 标记符号。
  • 场景文本识别:场景文本识别,有时也被称作通用文本识别技术。这类识别技术能够对任意场景下的图片中包含的任意形式的文本进行识别,包括但不仅限于:街边商铺的招牌、超市内商品中的文本、合影中人物衣着上的文本、城市建筑上的商标名称等等。这类技术已经被应用到了许多应用中,例如智能手机中允许搜索或提取相册中带有文本内容的图像,聊天软件中允许直接复制对方发送图片中的文本内容等。
  • 古籍文本识别:古籍文档与现代印刷的排版和布局通常具有很大的差别,例如,阅读顺序可能自上而下,自右向左等。因此,使用基于现代文档数据开发的 OCR 技术和模型在包含这些内容的图像上的识别效果往往不够好。因此,在对大量古籍进行数字化保护的过程中,催生了专门针对该类型文档内容进行识别的 OCR 技术。

发展历史

OCR 的概念是在1929年由德国科学家Tausheck最先提出来,并申请了专利。后来美国科学家Handel也提出了利用技术对文字进行识别的想法。中国最早的 OCR商业应用是由科学家王庆人教授在南开大学开发出来的,并在美国市场投入商业使用。日本在20世纪60年代开始研究 OCR 理论,开发了邮政编码识别系统。

基本处理过程

OCR 的处理过程大体分为图像输入前期处理中期处理后期处理文本输出这 5 个步骤。具体流程如下:

图像输入

对于不同的图像格式,有着不同的存储格式、不同的压缩方式,目前有OpenCV、CxImage等。

前期处理

二值化

如今数字摄像头拍摄的图片,大多数是彩色图像,彩色图像所含信息量巨大,较为不适用于OCR技术。

对于图片的内容,我们可以简单的分为前景与背景,为了让计算机更快的、更好地进行OCR相关计算,我们需要先对彩色图进行处理,使图片只剩下前景信息与背景信息。二值化也可以简单地将其理解为“黑白化”。

图像降噪

对于不同的图像,噪点的定义可能不同,根据噪点的特征进行去噪的过程,称为降噪。

倾斜校正

由于一般用户,在拍照文档时,难以拍摄得完全符合水平平齐与竖直平齐,因此拍照出来的图片不可避免的产生倾斜,这就需要图像处理软件进行校正。

中期处理

版面分析

将文档图片分段落,分行的过程称为版面分析,由于实际文档的多样性、复杂性,此步骤目前仍待优化。

字符切割

由于拍照、书写条件的限制,经常造成字符粘连、断笔,直接使用此类图像进行OCR分析将会极大限制OCR性能。因此需要进行字符切割,即:将不同字符之间分割开。

字符识别

早期以模板匹配为主,后期以特征提取为主。由于文字的位移、笔画的粗细、断笔、粘连、旋转等因素的影响,极大地影响特征提取难度。

版面还原

人们希望识别后的文字,仍然像原始文档图片那样排列,段落、位置、顺序不变地输出到Word文档、PDF文档等,这一过程称为版面还原。

后期处理

根据特定的语言上下文的关系,对识别结果进行校正。

文本输出

将识别出的字符以某一格式的文本输出。

主流实现

CNN + RNN + CTC

  • 卷积神经网络(CNN)

卷积神经网络(convolutional neural network,缩写:CNN)是一种前馈神经网络****(FCNN),它的人工神经元可以响应一部分覆盖范围内的周围单元,对于大型图像处理有出色表现。

卷积神经网络由一个或多个卷积层和顶端的全连通层(对应经典的神经网络)组成,同时也包括关联权重池化层(pooling layer)。这一结构使得卷积神经网络能够利用输入数据的二维结构。与其他深度学习结构相比,卷积神经网络在图像语音识别方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比较其他深度、前馈神经网络,卷积神经网络需要考量的参数更少,使之成为一种颇具吸引力的深度学习结构。

卷积神经网络的灵感来自于动物视觉皮层组织的神经连接方式。单个神经元只对有限区域内的刺激作出反应,不同神经元的感知区域相互重叠从而覆盖整个视野。

卷积神经网络是人工神经网络的一种特殊类型,在其至少一层中使用称为卷积的数学运算代替通用矩阵乘法。它们专门设计用于处理像素数据,并用于图像识别和处理

CNN是根据生物的视觉处理过程来进行设计的。

大脑中视觉皮层接收视觉信号的过程

HubelWiesel在20世纪50年代到20世纪60年代的研究发现,猫和猴子的视觉皮层中包含着能分别对某一小块视觉区域进行回应的神经元。当眼睛不动的时候,在一定区域内的视觉刺激能使单个神经元兴奋,那这个区域就称为这个神经元的感受野。相邻的细胞具有相似且重叠的感受野。为了形成一张完整的视觉图像,整个视觉皮层上的神经元的感受野的大小和位置呈现系统性的变化。左脑和右脑分别对应其对侧的视野。他们在其1968年的一篇论文中确定了大脑中有两种不同的基本视觉细胞:

  • 简单细胞
  • 复杂细胞

Hubel和Wiesel还提出了这两种细胞用于模式识别任务的级联模型。

结构上,卷积神经网络由输入层隐藏层(卷积层、线性整流层(ReLU)、池化层输出层(完全连接层组成。

输入层

在卷积神经网络中,输入层是网络的第一层,负责接收原始数据。对于图像处理任务,输入层通常接收原始像素数据,例如一个图像的高度、宽度和颜色通道(对于彩色图像通常是RGB三个通道)。输入层不进行任何计算,只是将数据传递给后续的隐藏层进行处理

卷积层

卷积层可以产生一组平行的特征图(feature map),它通过在输入图像上滑动不同的卷积核并执行一定的运算而组成。此外,在每一个滑动的位置上,卷积核与输入图像之间会执行一个元素对应乘积并求和的运算以将感受野内的信息投影到特征图中的一个元素。这一滑动的过程可称为步幅 Z_s,步幅 Z_s 是控制输出特征图尺寸的一个因素。卷积核的尺寸要比输入图像小得多,且重叠或平行地作用于输入图像中,一张特征图中的所有元素都是通过一个卷积核计算得出的,也即一张特征图共享了相同的权重和偏置项。

线性整流层

线性整流层(Rectified Linear Units layer, ReLU layer)使用线性整流(Rectified Linear Units, ReLU

作为这一层神经的激励函数(Activation function)。它可以增强判定函数和整个神经网络的非线性特性,而本身并不会改变卷积层。

事实上,其他的一些函数也可以用于增强网络的非线性特性,如双曲正切函数

或者Sigmoid函数

相比其它函数来说,ReLU 函数更受青睐,这是因为它可以将神经网络的训练速度提升数倍,而并不会对模型的泛化准确度造成显著影响。

池化层

池化层是基于 Fast-RCNN 架构的卷积神经网络的一个重要组成部分。

池化(Pooling)是卷积神经网络中另一个重要的概念,它实际上是一种非线性形式的降采样。有多种不同形式的非线性池化函数,而其中“最大池化(Max pooling)”是最为常见的。它是将输入的图像划分为若干个矩形区域,对每个子区域输出最大值

直觉上,这种机制能够有效地原因在于,一个特征的精确位置远不及它相对于其他特征的粗略位置重要。池化层会不断地减小数据的空间大小,因此参数的数量和计算量也会下降,这在一定程度上也控制了过拟合。通常来说,CNN 的网络结构中的卷积层之间都会周期性地插入池化层。池化操作提供了另一种形式的平移不变性。因为卷积核是一种特征发现器,我们通过卷积层可以很容易地发现图像中的各种边缘。但是卷积层发现的特征往往过于精确,我们即使高速连拍拍摄一个物体,照片中的物体的边缘像素位置也不大可能完全一致,通过池化层我们可以降低卷积层对边缘的敏感性。

池化层每次在一个池化窗口(depth slice)上计算输出,然后根据步幅移动池化窗口。下图是目前最常用的池化层,步幅为2,池化窗口为 2x2 的二维最大池化层。每隔2个元素从图像划分出 2x2 的区块,然后对每个区块中的4个数取最大值。这将会减少75%的数据量。

除了最大池化之外,池化层也可以使用其他池化函数,例如“平均池化”甚至“L2-范数****池化”等。过去,平均池化的使用曾经较为广泛,但是最近由于最大池化在实践中的表现更好,平均池化已经不太常用。

RoI池化(Region of Interest)是最大池化的变体,其中输出大小是固定的,输入矩形是一个参数。

由于池化层过快地减少了数据的大小,目前文献中的趋势是使用较小的池化滤镜,甚至不再使用池化层。

完全连接层

最后,在经过几个卷积和最大池化层之后,神经网络中的高级推理通过完全连接层来完成。就和常规的非卷积人工神经网络中一样,完全连接层中的神经元与前一层中的所有激活都有联系。因此,它们的激活可以作为仿射变换来计算,也就是先乘以一个矩阵然后加上一个偏差(bias)偏移量(向量加上一个固定的或者学习来的偏差量)。

下图为一个使用仿射变换所制造有自相似****性(数学分支分形几何中,如果一个物体自我相似(Self-similarity),表示它和它本身的一部分完全或是几乎相似。若说一个曲线自我相似,即每部分的曲线有一小块和它相似。自然界中有很多东西有自我相似性质,例如海岸线。)的分形(又称碎形、残形,通常被定义为“一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状”,即具有自相似的性质。):

卷积神经网络的应用

影像识别

卷积神经网络通常在影像识别系统中使用。

视频分析

相比影像识别问题,视频分析要难许多。CNN也常被用于这类问题。

自然语言处理

卷积神经网络也常被用于自然语言处理。 CNN的模型被证明可以有效的处理各种自然语言处理的问题,如语义分析、搜索结果提取、句子建模 、分类、预测、和其他传统的NLP任务等。

药物发现

卷积神经网络已在药物发现中使用。卷积神经网络被用来预测的分子与蛋白质之间的相互作用,以此来寻找靶向位点,寻找出更可能安全和有效的潜在治疗方法。

围棋

卷积神经网络在计算机围棋领域也被使用。2016年3月,AlphaGo对战李世乭的比赛,展示了深度学习在围棋领域的重大突破。

微调(fine-tuning)

卷积神经网络(例如Alexnet、VGG网络)在网络的最后通常为softmax(在数学,尤其是概率论和相关领域中,Softmax函数,或称归一化指数函数,是逻辑斯谛函数的一种推广。它能将一个含任意实数的K维向量z “压缩”到另一个K维实向量σ(z)中,使得每一个元素的范围都在(0, 1)之间,并且所有元素的和为1)分类器。微调一般用来调整softmax分类器的分类数。例如原网络可以分类出2种图像,需要增加1个新的分类从而使网络可以分类出3种图像。微调(fine-tuning)可以留用之前训练的大多数参数,从而达到快速训练收敛的效果。例如保留各个卷积层,只重构卷积层后的全连接层与softmax层即可。

经典模型

  • LeNet

  • AlexNet

  • VGG

  • GoogLeNet

  • ResNet

  • DenseNet

  • 循环神经网络(RNN)

循环神经网络 (RNN) 是一种使用序列数据或时序数据的人工神经网络。 这些深度学习算法常用于顺序时间问题,如语言翻译、自然语言处理 (nlp)、语音识别、图像字幕等;它们包含在一些流行的应用中,比如 Siri、语音搜索和 Google Translate。 与前馈神经网络(Feedforward Neural Network,为人工智能领域中,最早发明的简单人工神经网络类型。在它内部,参数从输入层向输出层单向传播。有异于循环神经网络,它的内部不会构成有向环卷积神经网络 (CNN) 一样,循环神经网络利用训练数据进行学习。 区别在于“记忆”,因为它从先前的输入中获取信息,以影响当前的输入和输出。 虽然传统的深度神经网络假设输入和输出相互独立的,但循环神经网络的输出依赖于序列中先前的元素。 尽管未来的活动也可能有助于确定特定序列的输出,但是单向循环神经网络无法在预测中说明这些事件。

时间循环神经网络可以描述动态时间行为,因为和前馈神经网络(feedforward neural network)接受较特定结构的输入不同,RNN将状态在自身网络中循环传递,因此可以接受更广泛的时间序列结构输入。

手写识别是最早成功利用RNN的研究结果。

循环神经网络 (RNN) 的类型

前馈神经网络(FNN)将一个输入映射到一个输出,我们在上面的示意图中以这种方式展示了循环神经网络 (RNN) ,但实际上它们并没有这种约束。 相反,它们的输入和输出的长度可变,不同类型的循环神经网络 (RNN) 有着不同的用例,例如音乐生成、观点分类和机器翻译。

循环神经网络 (RNN) 常用激活函数

正如有关神经网络的学习文章中所讨论的那样,激活函数决定了神经元是否应该被激活。 这种非线性函数通常将特定神经元的输出转换为 0 到 1 或 -1 到 1 之间的值。

我们举个惯用语的例子来帮助解释循环神经网络 (RNN):

“you’ll never walk alone”(你永远不会独行),这通常是指表达鼓励与安慰。 为了体现出这个惯用语的意思,必须按这个特定顺序进行表达。 因此,循环神经网络需要考虑到该惯用语中每个单词的位置,并使用这些信息来预测序列中的下一个单词。

循环神经网络 (RNN) 的另一个显著特征是它们在每个网络层中共享参数。 虽然前馈网络的每个节点都有不同的权重,但循环神经网络在每个网络层都共享相同的权重参数。 尽管如此,这些权重仍可通过反向传播和梯度下降过程进行调整,以促进强化学习。

循环神经网络 (RNN) 利用随时间推移的反向传播 (BPTT) 算法来确定梯度,这与传统的反向传播略有不同,因为它特定于序列数据。 BPTT 的原理与传统的反向传播相同,模型通过计算输出层与输入层之间的误差来训练自身。 这些计算帮助我们适当地调整和拟合模型的参数。 BPTT 与传统方法的不同之处在于,BPTT 会在每个时间步长对误差求和,而前馈网络则不需要对误差求和,因为它们不会在每层共享参数。

通过这个过程,循环神经网络 (RNN) 往往会产生两个问题,即梯度爆炸梯度消失。 这些问题由梯度的大小定义,也就是损失函数沿着错误曲线的斜率。 如果梯度过小,它会更新权重参数,让梯度继续变小,直到变得可以忽略,即为 0。 发生这种情况时,算法就不再学习。 如果梯度过大,就会发生梯度爆炸,这会导致模型不稳定。 在这种情况下,模型权重会变得太大,并最终被表示为 NaN。 这些问题的一种解决方案就是减少神经网络中隐藏层的数量,以便消除循环神经网络 (RNN) 模型中的一些复杂性。

所以,单纯的RNN因为无法处理随着递归,权重指数级爆炸梯度消失问题,难以捕捉长期时间关联;而结合不同的 LSTM 可以很好解决这个问题。

循环神经网络 (RNN) 的架构变体

LSTM

长短期记忆(Long Short-Term Memory,LSTM)是一种时间循环神经网络(RNN),其本质上是循环神经网络架构上的一种变体。LSTM的表现通常比时间循环神经网络及隐马尔科夫模型(HMM)更好,比如用在不分段连续手写识别上。

Hochreiter和Schmidhuber于1997年提出了长短期记忆 (LSTM) 网络,并在多个应用领域创造了精确度记录。

  • 2007年,LSTM开始革新语音识别领域,在某些语音应用中胜过传统模型。
  • 2009年,一个由 CTC(Connectionist temporal classification,是一种常用在语音识别文本识别等领域的算法,用来解决输入和输出序列长度不一、无法对齐的问题。) 训练的LSTM 网络赢得了多项连笔手写识别竞赛,成为第一个赢得模式识别竞赛的RNN。
  • 2014年,百度在不使用任何传统语音处理方法的情况下,使用经过CTC训练的RNNs打破了Switchboard Hub5’00 语音识别基准。
  • LSTM还改进了大词汇量语音识别文本到语音合成并在谷歌 Android 系统中使用。据报道,2015年,谷歌语音识别通过接受过CTC训练的LSTM(谷歌语音搜索使用的)实现了49%的引用量的大幅提升。
  • LSTM打破了改进机器翻译语言建模多语言处理的记录。
  • LSTM 结合卷积神经网络改进了图像自动标注

BRNN

双向循环神经网络(BRNN):这是循环神经网络 (RNN) 的网络架构变体。 单向循环神经网络 (RNN) 只能从先前输入中抽取数据,做出有关当前状态的预测;而双向循环神经网络 (RNN) 还可以拉取未来的数据,从而提高预测的精度。 回到前面那个“you’ll never walk alone”的例子,如果模型知道该序列中的最后一个单词是”alone”,就更有可能预测该词组中的第二个单词是”walk”。

GRU

门控循环单元 (GRU):这种循环神经网络 (RNN) 变体类似于 LSTM,因为它也旨在解决 RNN 模型的短期记忆问题。 但它不使用”元胞状态 (是一种时间、空间、状态都离散,空间相互作用和时间因果关系为局部的网格动力学模型,具有模拟复杂系统时空演化过程的能力) “来调节信息,而是使用”隐藏状态”;它不使用三个门,而是两个:一个重置门和一个更新门。 类似于 LSTM 中的门,重置门和更新门控制要保留哪些信息以及保留多少信息。

如何快速理解 RNN?

结构上,与卷积神经网络(CNN)类似,首先看一个简单的循环神经网络,它由输入层、一个隐藏层和一个输出层组成,

我们可以这样来理解,如果把上面有$$W$$的那个带箭头的圈去掉,它就变成了最普通的 全连接神经网络(FCNN)。$$X$$是一个向量,它表示输入层的值(这里忽略了表示神经元节点的圆圈); $$S$$是一个向量,它表示隐藏层的值($$S$$外部的圆表示一个节点,通常情况下这一层会拥有多个节点,节点数与向量$$S$$的维度相同);

$$U$$ 是输入层隐藏层权重矩阵, $$O$$也是一个向量,它表示输出层的值;$$V$$是隐藏层输出层权重矩阵

那么,现在我们来看看$$W$$是什么。循环神经网络的隐藏层的值 $$S$$不仅仅取决于当前这次的输入$$X$$,还取决于上一次隐藏层的值$$S$$ 。权重矩阵$$W$$就是隐藏层上一次的值作为这一次的输入的权重。

我们给这个抽象对应的具体图:

我们从上图就能够很清楚的看到,上一时刻的隐藏层是如何影响当前时刻的隐藏层的。

如果我们把上面的图展开,循环神经网络也可以画成下面这个样子:

现在看上去就比较清楚了,这个网络在 $$t$$ 时刻接收到输入 $$X_t$$ 之后,隐藏层的值是 $$X_t$$,输出值是 $$O_t$$,关键一点是: $$S_t $$ 的值不仅仅取决于 $$X_t$$,还取决于 $$S_{t - 1}$$

最后给出 RNN 的总括图

  • 用于基于图像的序列识别的端到端可训练神经网络及其在场景文本识别中的应用(CTC)
    • 这是一种在计算机科学的计算机视觉与模式识别领域诞生的算法,最早发表于《用于基于图像的序列识别的端到端可训练神经网络及其在场景文本识别中的应用》这篇文论当中。
    • 基于图像的序列识别一直是计算机视觉领域的一个长期研究课题。在本文中,我们研究了场景文本识别问题,这是基于图像的序列识别中最重要和最具挑战性的任务之一。提出了一种新颖的神经网络架构,它将特征提取、序列建模和转录集成到一个统一的框架中。与之前的场景文本识别系统相比,所提出的架构具有四个独特的特性:(1)它是端到端可训练的,而大多数现有算法的组件是单独训练和调整的。(2) 它自然地处理任意长度的序列,不涉及字符分割或水平尺度标准化。(3)它不局限于任何预定义的词典,在无词典和基于词典的场景文本识别任务中都取得了显着的性能。(4)它生成了一个有效但小得多的模型,对于现实应用场景更实用。在标准基准(包括 IIIT-5K、街景文本和 ICDAR 数据集)上的实验证明了所提出的算法相对于现有技术的优越性。此外,所提出的算法在基于图像的乐谱识别任务中表现良好,这显然验证了其通用性。

CNN + RNN 基于 Attention 的方法

卷积神经网络(CNN)循环神经网络(RNN)前文已有介绍,这里不再赘述。

注意力机制(Attention)

注意力机制(Attention)是人工神经网络中一种模仿****认知注意力的技术。这种机制可以增强神经网络输入数据中某些部分的权重,同时减弱其他部分的权重,以此将网络的关注点聚焦于数据中最重要的一小部分。数据中哪些部分比其他部分更重要取决于上下文。可以通过梯度下降法对注意力机制进行训练。

类似于注意力机制的架构最早于1990年代提出,当时提出的名称包括乘法模块(multiplicative module)、sigma pi单元、超网络(hypernetwork)等。注意力机制的灵活性来自于它的“软权重”特性,即这种权重是可以在运行时改变的,而非像通常的权重一样必须在运行时保持固定

注意力机制用途包括 :

  • 神经图灵机中的记忆功能
  • 可微分神经计算机中的推理任务
  • Transformer 模型中的语言处理
  • Perceiver(感知器)模型中的多模态数据处理(声音、图像、视频和文本)。

假设我们有一个以索引 $$i$$ 排列的标记(token)序列。对于每一个标记 $$i$$,神经网络计算出一个相应的满足 $$\sum_{i} W_i = 1$$的非负软权重 $$Wi$$,每个标记都对应一个由词嵌入得到的向量 $$Vi$$,加权平均 $$\sum_{i} W_iV_i$$即是注意力机制的输出结果

可以使用查询-键机制(query-key mechanism)计算软权重。从每个标记的词嵌入,我们计算其对应的查询向量 $$Qi$$ 和键向量 $$Kj$$,再计算点积 $$QiKj$$的softmax函数便可以得到对应的权重,其中 $$i$$代表当前标记、 $$j$$表示与当前标记产生注意力关系的标记。

某些架构中会采用多头注意力机制(multi-head attention),其中每一部分都有独立的查询(query)、键(key)和值(value)。

语言翻译示例

下图展示了将英语翻译成法语的机器,其基本架构为编码器-解码器结构,另外再加上了一个注意力单元。在图示的简单情况下,注意力单元只是循环层状态的点积计算,并不需要训练。但在实践中,注意力单元由需要训练的三个完全连接的神经网络层组成。这三层分别被称为查询(query)、(key)和(value)。

上图为加入注意力机制的编码器-解码器架构。图中使用具体的数值表示向量的大小,使其更为直观。左侧黑色箭头表示的是编码器-解码器,中间橘色箭头表示的是注意力单元,右侧灰色与彩色方块表示的是计算的数据。矩阵$$H$$与向量$$w$$中的灰色区域表示零值。数值下标表示向量大小。字母下标 $$i$$与 $$i-1$$表示计算步

图例

标签 描述
100 语句最大长度
300 嵌入尺寸(词维度)
500 隐向量长度
9k, 10k 输入、输出语言的词典大小
x, Y 大小为9k与10k的独热词典向量。x → x以查找表实现。Y是解码器D线性输出的argmax值。
x 大小为300的词嵌入向量,通常使用GloVe或word2vec等模型预先计算得到的结果。
h 大小为500的编码器隐向量。对于每一计算步,该向量包含了之前所有出现过的词语的信息。最终得到的h可以被看作是一个“句”向量,杰弗里·辛顿则称之为“思维向量”(thought vector)。
s 大小为500的解码器隐向量。
E 500个神经元的循环神经网络编码器。输出大小为500。输入大小为800,其中300为词嵌入维度,500为循环连接。编码器仅在初始化时直接连接到解码器,故箭头以淡灰色表示。
D 两层解码器。循环层有500个神经元,线性全连接层则有10k个神经元(目标词典大小)。单线性层就包含500万(500×10k)个参数,约为循环层参数的10倍。
score 大小为100的对准分数
w 大小为100的注意力权重向量。这些权重为“软”权重,即可以在前向传播时改变,而非只在训练阶段改变的神经元权重。
A 注意力模块,可以是循环状态的点积,也可以是查询-键-值全连接层。输出是大小为100的向量w。
H 500×100的矩阵,即100个隐向量h连接而成的矩阵。
c 大小为500的上下文向量 = H * w,即以w对所有h向量取加权平均。

下表是每一步计算的示例。为清楚起见,表中使用了具体的数值图形而非字母表示向量与矩阵。嵌套的图形代表了每个 h 都包含之前所有单词的历史记录。在这里,我们引入注意力分数以得到所需的注意力权重

以矩阵展示的注意力权重表现了网络如何根据上下文调整其关注点

I love you
je 0.94 0.02 0.04
t’ 0.11 0.01 0.88
aime 0.03 0.95 0.02

注意力权重的这种展现方式回应了人们经常用来批评神经网络的可解释性****(Explainable AI,缩写为XAI,指的是让专家能够理解人工智能之成果的方法与技术。它相对于黑箱式的机器学习,因为黑箱式的机器学习的设计者本身也无法解释为什么人工智能能达到某些成果。可解释人工智能被认为是“要求解释的权利”(right to explanation)的一种实践。问题。对于一个只作逐字翻译而不考虑词序的网络,其注意力权重矩阵会是一个对角占优矩阵(指一矩阵的每一横行,对角线上元素的大小大于或等于同一横行其他元素大小的和。这里非对角占优的特性表明注意力机制能捕捉到更为细微的特征**。在第一次通过解码器时,94%的注意力权重在第一个英文单词“I”上,因此网络的输出为对应的法语单词“je”(我)。而在第二次通过解码器时,此时88%的注意力权重在第三个英文单词“you”上,因此网络输出了对应的法语“t’”(你)。最后一遍时,95%的注意力权重在第二个英文单词“love”上,所以网络最后输出的是法语单词“aime”(爱)。

客户端基于端智能对 NLP 和 OCR 的应用

Android

Android 基于 Google 生态拥有非常完善且丰富的机器学习使用路径,其中最著名的便是 Google 的 Firebase 所提供的 MLKit

MLKit

MLKit 是一个客户端机器学习套件 SDK,它通过一个强大且易用的软件包将 Google 的机器学习专业技术融入到 Android 和 iOS 应用中。无论你是刚开始接触机器学习,还是拥有丰富的相关经验,只需几行代码即可实现所需的功能。你无需具备丰富的神经网络或模型优化知识即可开始使用该套件。另一方面,如果你是一名经验丰富的机器学习开发者,机器学习套件提供了便捷的 API,可帮助您在移动应用中使用自定义 TensorFlow Lite 模型。

篇幅所限,这里不多做介绍,感兴趣的同学可以参照 Firebase 官方文档说明进行了解。

使用机器学习套件识别图片中的文本 (Android)

Apple

苹果的整体生态链从硬件到软件层面,都拥有着一套更为强大且高性能的机器学习支撑能力,其中最亮眼的便是 CoreMLVision 两大框架。

CoreML

上一期已经介绍过,这里不再赘述,详情见端智能 01 期 - 神经网络/机器学习在 iOS 端的应用与场景落地

Vision

Vision 是 Apple 基于机器学习所研发的一款强大的图像识别框架。它能够应用计算机视觉算法对输入图像视频执行各种任务。Vision 框架不仅能够执行人脸人脸标志检测文本检测条形码识别图像配准一般特征跟踪Vision 还允许使用自定义 Core ML 模型来执行分类对象检测等任务。

本期我们重点要介绍的是其中的识别图像文本能力,即使用 Vision 框架向应用程序添加文本识别功能。

识别图像中的文本

Vision 的众多强大功能之一是它能够检测和识别图像中的多语言文本。你可以在自己的应用程序中使用此功能来处理实时离线用例。在所有情况下,Vision 的所有处理都发生在用户的设备上,以增强性能和用户隐私。

Vision 的文本识别功能使用以下路径之一进行操作:

  • 快速路径
    • 快速路径使用框架的字符检测功能来查找单个字符,然后使用小型机器学习模型来识别单个字符单词。这种方法类似于传统的**光学字符识别 (OCR)**。
    • 有关使用快速路径的示例代码,请见从图像中的文本中提取电话号码 Demo 演示。
  • 准确路径
    • 准确路径使用神经网络字符串的形式查找文本,然后进行进一步分析以查找单个单词句子。这种方法更符合人类阅读文本的方式。
    • 有关使用准确路径的示例代码,请见在文档上构建已识别文本的结构 Demo 演示。

使用任一路径,您都可以选择应用基于自然语言处理 (NLP)语言校正阶段,以最大程度地减少误读的可能性。

使用 Vision & CoreML 实现对从图像中查找并突出显示关键字

目标

我们今天的目标是构建一个识别静态图像中文本的 iOS 应用程序。

就像你平时使用搜索关键字时一样,cmd + F 所有匹配的字符串都会在屏幕上突出显示,我们将突出显示图像中的一些选定的字符串。

涵盖的主题

在开始讨论实现之前,让我们先简单介绍一下我们将会涉及到的内容:

  • 使用相机或图库捕获图像
  • 使用 Vision 检测文本
  • 使用 Core ML 进行文本识别
  • 在某些关键字上绘制边界框

我们想要实现什么

我们希望在从相机/图库捕获的图像中识别出一些检测到的文本的名称后,突出显示这些文本,如下所示:

图像选择器控制器

它非常基本(只有一个 UIImage 和一个 Button)。我们需要的只是从照片库上传包含文本的图像或直接通过摄像头拍摄。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
presentPhotoPicker(sourceType: .photoLibrary)
return
}
let photoSourcePicker = UIAlertController()
let takePhoto = UIAlertAction(title: "Camera", style: .default) { [unowned self] _ in
self.presentPhotoPicker(sourceType: .camera)
}
let choosePhoto = UIAlertAction(title: "Photos Library", style: .default) { [unowned self] _ in
self.presentPhotoPicker(sourceType: .photoLibrary)
}
photoSourcePicker.addAction(takePhoto)
photoSourcePicker.addAction(choosePhoto)
photoSourcePicker.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))

present(photoSourcePicker, animated: true)

presentPhotoPicker 用于启动适当的应用程序(图库 / 摄像头)。单击图像后,我们启动 Vision Request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
picker.dismiss(animated: true)

guard let uiImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else {
fatalError("Error!")
}
imageView.image = uiImage
createVisionRequest(image: uiImage)
}

private func presentPhotoPicker(sourceType: UIImagePickerController.SourceType) {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = sourceType
present(picker, animated: true)
}
}

Vision 框架的使用

Vision 框架 是在 iOS 11 中推出的。它带来了图像识别和分析算法,根据 Apple 的说法,这些算法比 CoreImage Framework 更准确。对此的一个重要贡献是机器学习、深度学习和计算机视觉的底层使用。

该框架的实施包括三个重要的用例:

  • Request创建一个请求来检测对象的类型。你可以设置多种要检测的类型。
  • Request Handler这用于处理从请求获得的结果。
  • Observation结果以观察的形式存储。

Vision 框架中的一些重要类包括:

  • VNRequest它由一系列用于图像处理的请求组成。
  • VNObservation这给了我们结果的输出。
  • VNImageRequestHandler处理VNRequest给定图像上的一个或多个。

创建 Vision Image Request Handler

以下代码片段展示了如何创建 Vision Image Request Handler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func createVisionRequest(image: UIImage){

currentImage = image
guard let cgImage = image.cgImage else {
return
}
let requestHandler = VNImageRequestHandler(cgImage: cgImage, orientation: image.cgImageOrientation, options: [:])
let vnRequests = [vnTextDetectionRequest]

DispatchQueue.global(qos: .background).async {
do{
try requestHandler.perform(vnRequests)
}catch let error as NSError {
print("Error in performing Image request: \(error)")
}
}

}

我们可以传递多个请求,但本文的目标是文本检测识别

vnTextDetectionRequest 在下面的代码中定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
var vnTextDetectionRequest : VNDetectTextRectanglesRequest{
let request = VNDetectTextRectanglesRequest { (request,error) in
if let error = error as NSError? {
print("Error in detecting - \(error)")
return
}
else {
guard let observations = request.results as? [VNTextObservation]
else {
return
}

var numberOfWords = 0
for textObservation in observations {
var numberOfCharacters = 0
for rectangleObservation in textObservation.characterBoxes! {
let croppedImage = crop(image: self.currentImage, rectangle: rectangleObservation)
if let croppedImage = croppedImage {
let processedImage = preProcess(image: croppedImage)
self.imageClassifier(image: processedImage,
wordNumber: numberOfWords,
characterNumber: numberOfCharacters, currentObservation: textObservation)
numberOfCharacters += 1
}
}
numberOfWords += 1
}

DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
self.drawRectanglesOnObservations(observations: observations)
})

}
}

request.reportCharacterBoxes = true

return request
}

上面的代码片段中有很多内容。让我们来分析一下。

  • 观察结果是请求返回的结果
  • 我们的目标是用边界框突出显示检测到的文本,因此我们将观察结果类型转换为VNTextObservation.
  • 我们裁剪图像中检测到的文本部分。这些裁剪后的图像充当我们的 ML 模型的微输入(micro-inputs)。
  • 我们将这些图像调整到所需的输入大小后,将其输入 Core ML 模型进行分类

其中裁剪和预处理的代码可在 Demo 工程的ImageUtils.swift中找到。

绘制边界框

现在我们知道了 Vision 中检测到的文本VNTextObservations。每个观察都有一个边界框属性。每个观察结果的标签都将由 Core ML 的图像分类器进行预测处理。

所以我们可以简单地在文本上绘制矩形。下面的方法为我们实现了该实现,并突出显示了图像中的“Vision”和“Core ML”一词。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
func drawRectanglesOnObservations(observations : [VNDetectedObjectObservation]){
DispatchQueue.main.async {
guard let image = self.imageView.image
else{
print("Failure in retrieving image")
return
}
let imageSize = image.size
var imageTransform = CGAffineTransform.identity.scaledBy(x: 1, y: -1).translatedBy(x: 0, y: -imageSize.height)
imageTransform = imageTransform.scaledBy(x: imageSize.width, y: imageSize.height)
UIGraphicsBeginImageContextWithOptions(imageSize, true, 0)
let graphicsContext = UIGraphicsGetCurrentContext()
image.draw(in: CGRect(origin: .zero, size: imageSize))

graphicsContext?.saveGState()
graphicsContext?.setLineJoin(.round)
graphicsContext?.setLineWidth(8.0)

graphicsContext?.setFillColor(red: 0, green: 1, blue: 0, alpha: 0.3)
graphicsContext?.setStrokeColor(UIColor.green.cgColor)

var previousString = ""
let elements = ["VISION","COREML"]

observations.forEach { (observation) in
var string = observationStringLookup[observation as! VNTextObservation] ?? ""
let tempString = string
string = string.replacingOccurrences(of: previousString, with: "")
string = string.trim()
previousString = tempString

if elements.contains(where: string.contains){

let observationBounds = observation.boundingBox.applying(imageTransform)
graphicsContext?.addRect(observationBounds)
}
}
graphicsContext?.drawPath(using: CGPathDrawingMode.fillStroke)
graphicsContext?.restoreGState()

let drawnImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.imageView.image = drawnImage
}
}

接下来,让我们看看如何与 CoreML 框架结合起来,完成我们最终的功能。

CoreML 框架的使用

Core ML 框架可以让开发人员在其应用程序中轻松使用 ML 模型。借助该框架,可以处理输入数据以返回所需的输出。

在本文中,我们使用alphanum_28X28机器学习模型。该模型需要输入尺寸为28*28的图像并返回检测到的文本。

其中,调整图像大小的时机,发生在我们之前看到的预处理函数中。observationStringLookup是一个查找字典,它将每个观察结果绑定到 Core ML 模型中来预测文本。

为了判定文本内容,我们构建了一个名为 imageClassifier(image: wordNumber: characterNumber: currentObservation :) 的图像分类器函数,该函数对调整尺寸后的图片输入进行处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
func imageClassifier(image: UIImage, wordNumber: Int, characterNumber: Int, currentObservation : VNTextObservation){
let request = VNCoreMLRequest(model: model) { [weak self] request, error in
guard let results = request.results as? [VNClassificationObservation],
let topResult = results.first else {
fatalError("Unexpected result type from VNCoreMLRequest")
}
let result = topResult.identifier
let classificationInfo: [String: Any] = ["wordNumber" : wordNumber,
"characterNumber" : characterNumber,
"class" : result]
self?.handleResult(classificationInfo, currentObservation: currentObservation)
}
guard let ciImage = CIImage(image: image) else {
fatalError("Could not convert UIImage to CIImage :(")
}
let handler = VNImageRequestHandler(ciImage: ciImage)
DispatchQueue.global(qos: .userInteractive).async {
do {
try handler.perform([request])
}
catch {
print(error)
}
}
}



func handleResult(_ result: [String: Any], currentObservation : VNTextObservation) {
objc_sync_enter(self)
guard let wordNumber = result["wordNumber"] as? Int else {
return
}
guard let characterNumber = result["characterNumber"] as? Int else {
return
}
guard let characterClass = result["class"] as? String else {
return
}
if (textMetadata[wordNumber] == nil) {
let tmp: [Int: String] = [characterNumber: characterClass]
textMetadata[wordNumber] = tmp
} else {
var tmp = textMetadata[wordNumber]!
tmp[characterNumber] = characterClass
textMetadata[wordNumber] = tmp
}
objc_sync_exit(self)
DispatchQueue.main.async {
self.doTextDetection(currentObservation: currentObservation)
}
}

func doTextDetection(currentObservation : VNTextObservation) {
var result: String = ""
if (textMetadata.isEmpty) {
print("The image does not contain any text.")
return
}
let sortedKeys = textMetadata.keys.sorted()
for sortedKey in sortedKeys {
result += word(fromDictionary: textMetadata[sortedKey]!) + " "
}

observationStringLookup[currentObservation] = result
}

func word(fromDictionary dictionary: [Int : String]) -> String {
let sortedKeys = dictionary.keys.sorted()
var word: String = ""
for sortedKey in sortedKeys {
let char: String = dictionary[sortedKey]!
word += char
}
return word
}

其中的 textMetadata用于存储所有预测的单词(在 iOS13 及以上系统版本的 Vision 框架中,Vision 将识别的文本存储在 Observation 实例本身当中),并且observationStringLookup也是提前创建好的,现在,我们就可以突出显示选定的观察结果了(如同我们在本文开头看到的那样,最终输出中突出显示了“vision”、“core ml”等词)。

需要注意的是:取决于训练数据样本模型精度的因素,Core ML 模型可能无法对不同字体的文本给出正确的预测结果。

总结

感谢各位认真聆听到了这里,我们不妨对今天学习和了解的内容做一个总结

  • 自然语言处理(NLP)是计算机科学或者说是人工智能的一个分支,它是由自然语言理解(NLU)自然语言生成(NLG)组成的,它们之间的关系既关联又相互课题独立。
  • 光学字符识别(OCR) 的处理过程大体分为图像输入前期处理中期处理后期处理文本输出这 5 个步骤。
  • 卷积神经网络(CNN)循环神经网络(RNN)是当今实现光学字符识别(OCR)的核心主流方案。
  • AndroidiOS 客户端均拥有强大的机器学习能力与硬件支持,可以将诸如图像文本识别等在内的端智能轻松实现。
最近的文章

「端智能」移动端当前的应用与发展现状

前言在国内,阿里、腾讯等企业也先后进行了端智能的尝试。 阿里在手淘中宝贝列表重排、智能刷新、跳失点预测、智能 Push、拍立淘(以图搜图)等多个场景实现了端智能的落地,并推出了 MNN 神经网络深度学习框架。 腾讯则推出自研的 NCNN 框架,并在医疗、翻译、游戏、智能音箱等领域广泛应用端智能技 …

, , 开始阅读
更早的文章

iOS 短视频播放列表优化策略

基于洋葱学院短视频播放器进行优化改造,以下是优化策略图 三播放器加载策略 业务流程优化 …

, , 开始阅读
comments powered by Disqus