【云駐共創】探討文字識別中的語言模型
今天和大家一起學習文字識別中的語言模型。這是2018年發表在ACMMM的一篇論文,名為《Attention and Language Ensemble for Scene Text Recognition with Convolutional Sequence Modeling》。
本文將會根據三個部分進行解讀,分別是研究背景、算法模型的剖析、代碼復現。
一、研究背景
1.什么是場景文本識別
場景文本識別的任務是識別自然產品圖像中的一個文字信息。自然場景圖片中包含了豐富的語義信息,能夠用于基于內容的圖片修復、自動駕駛、圖片中的文字翻譯等。由于受自然場景中文本多樣性、背景的復雜性等影響因素影響,自然場景文本識別任務的難度遠大于掃描文檔的文字識別。并且具有重大的研究意義。
2.如何理解語言模型
首先舉個例子,如果不基于語言先驗去翻譯下面這串拼音,很可能被錯誤的翻譯成,你西安在趕什么。
所以語言模型的作用是根據當前語境的上下文推斷當前句子的意思。對于語言序列w1,w2,…wn,語言模型就是計算該序列的概率。
3.為什么我們需要語言模型呢?
文本圖像中包含兩層信息:視覺紋理信息和語言信息。
由于單純根據視覺紋理信息進行文字識別缺少了對上下文的字符語義信息的挖掘,時常會導致錯誤的文本識別結果。因此如何獲得魯棒的語言來提升識別性能,成為了近幾年場景文本識別任務中比較歡迎的一個思路。
4.了解傳統的語言模型
傳統使用的語言模型是N-Gram的語言模型,它的計算方法如下:
當n=1時,表示當前的識別結果,依靠當前信息,不需要通過之前的時間布的信息。
當n=2時,即當前的w1需要針對前一個字符信息進行考慮,來推斷當前的結果。
當n=3時,需要對前兩個信息進行考慮。
為了獲得更好的元件模型,通常我們n會取很大,但會導致一個缺點:設計復雜,計算量大。這就是為什么傳統的方法在目前很少去使用的主要的原因。
如何去替代這個傳統的語言模型呢
1.基于RNN的語言建模
比較經典的一個工作是發表在2016年CVPR的一篇基于RNN的一個語言模型的文章。首先通過CNN的視覺特征提取,對每個時間步引入注意力的操作,使得每個時間步關注一個區域的視覺信息。通過參考之前時間步的信息實現語言建模,從而預測當前時間步的字符。它的優勢就是省去了N-Gram語言建模的復雜方式。
2.基于Transformer的語言模型
通過雙向的語言模型建模,捕獲更加魯棒的語言信息。同時引用了迭代語言矯正的操作,進一步提升識別結果。
研究的主要貢獻
提出了一個全部基于CNN的文本識別模型,解決了RNN梯度消失的問題。
提出新的聯合考慮視覺信息和語言信息的方法,采用來自注意力模塊和語言模塊的多個loss同時監督,實現端到端訓練。
在沒有字典的情況下,該方法在SVT數據集上,詞準確率達到了9%。
二、基于CNN的文本識別模型的剖析
前面介紹了語言模型是怎么做的,接下來就是算法具體的實現。首先了解一下該模型。
該模型摒棄了RNN結構,僅僅使用CNN來完成。在解碼器中同時考慮了視覺信息和語言信息。
編解碼器的具體結構如下:
通過5種結構的編碼,得到Encorder信息,然后再輸入解碼器,也是Decorder這里面進行解碼。如下圖,通過語言解碼和視覺解碼,最后通過線性層來進行預測。
兩種算法的具體實現如下:
總結一下,該算法的創新點如下:
摒棄了RNN,整個模型僅使用CNN搭建而成。
在解碼器中同時考慮視覺信息和語言信息,通過對視覺和語言模型都加入監督實現視覺和語言的聯合學習。
下圖可以看出兩個方法之間的對比
實驗結果
最終實驗結果在STV上只用了一個合成數據集就取得了83.9的識別結果。
三、代碼復現
接下來按照實驗結果來進行代碼復現,復現思路分為三步,
原則是先實現,在調優已達到論文的要求
首先在GitHub上下載開源的代碼,在開源代碼基礎上進行調優。經過不斷試錯,最終選擇一個基于PyTorch框架的開源代碼。
和Modelarts環境適配之后,經過一些參數調整,在單卡和八卡訓練下達到精度要求。
首先了解Modelarts環境
Modelarts是一個即開即用的在線開發環境。Modelarts集成了Jupyter notebook,可為大家提供在線交互式開發調試工具。大家可以通過創建開發環境,自行開發調試訓練模型,在在線環境為大家安裝常用的機器學習引擎和軟件庫,實現即開即用。
然后模型部署的話,在Modelarts上訓練好的模型,通過模型管理和服務部署功能,可以快速發布在線推理服務,實現高吞吐、低延時支持多模型的灰度發布。同時支持批量的推理任務,處理大數大批量數據推理時,高效分布式計算Modelarts提供了模型優化能力,使模型更好的匹配邊緣設備與華為的HiLens結合,可將模型輕松部署到攝像頭等端測試設備快速進行應用開發。
代碼講解
接下來通過六個部分對代碼進行講解。
1.Model主體:conv-ensemble-str/model/model.py
首先經過Encoder通過對輸入圖片進行編碼處理之后,得到一個Encoder特征,再將Encoder特征和label輸入到解碼器中,然后就是loss的計算,train的設置。代碼如下:
class Model(object):
def __init__(self, params, mode):
self.encoder = EncoderResnet(params, mode)
self.decoder = DecoderConv(params, mode, self.charset.num_charset)
def __call__(self, features, labels):
with tf.variable_scope('model'):
features, labels = self._preprocess(features, labels) # tf.logging.info('Preprocess data.')
encoder_output = self.encoder(features) # tf.logging.info('Create encoder.')
decoder_output = self.decoder(encoder_output, labels) # tf.logging.info('Create decoder.')
if self.mode == ModeKeys.TRAIN:
loss = self._compute_loss(decoder_output, labels) # tf.logging.info('Compute loss.')
train_op = self._build_train_op(loss)
predictions = self._create_predictions(decoder_output, features, labels) ?tf.logging.info('Create predictions.')
return predictions, loss, train_op
2.Encoder部分:conv-ensemble-str/model/encoder_resnet.py
首先它包括了很多個resnet blocks,它通過對特征進行卷積操作,多個疊加提升它側身表達能力,這里用的是resnet_V2的結構。代碼如下:
class EncoderResnet(object):
def __call__(self, features):
# conv1
with arg_scope([layers_lib.conv2d], activation_fn=None, normalizer_fn=None):
net = resnet_utils.conv2d_same(inputs, 16, 5, stride=2, scope='conv1')
# resnet blocks
blocks = []
for i in range(len(self.encoder_params['block_name'])):
block = resnet_v2.resnet_v2_block(scope=self.encoder_params['block_name'][i],
base_depth=self.encoder_params['base_depth'][i],num_units=self.encoder_params['num_units'][i], stride=self.encoder_params['stride'][i])
blocks.append(block)
net, _ = resnet_v2.resnet_v2(net, blocks, is_training=(self.mode == ModeKeys.TRAIN), global_pool=False, output_stride=2, include_root_block=False, scope='resnet')
return net
3.Decoder部分:conv-ensemble-str/model/decoder_conv.py
如下是參考配置,下方是Decoder的訓練和Decoder測試的代碼:
class DecoderConv(object):
def __init__(self, params, mode, num_charset):
self.params = params
self.params.update(DECODER_DEFUALT_PARAM)
self.mode = mode
self.num_charset = num_charset
self.max_sequence_length = self.params['dataset']['max_sequence_length']
def __call__(self, encoder_output, labels):
if self.mode == ModeKeys.TRAIN:
with tf.variable_scope("decoder"):
outputs = self.conv_decoder_train(encoder_output, labels)
return outputs
else:
outputs, _, __ = self.conv_decoder_infer(encoder_output)
return outputs
4.Decoder部分,卷積語言模型:conv-ensemble-str/model/decoder_conv.py
此部分為Decoder的語言模型和attention模型的具體操作
class ConvBlock(object):
def __call__(self, encoder_output, input_embed):
# 1D convolution
for layer_idx in range(self.params['cnn_layers']):
with tf.variable_scope("conv" + str(layer_idx)):
# language module ......
# shortcut and layer norm ......
# attention module ......
# shortcut and layer norm ......
next_layer = language_layer + attention_layer
language_logit, scores = self.create_logit(language_layer,...)
attention_logit, scores = self.create_logit(attention_layer,...)
return language_logit, attention_logit, scores
5.基于CNN的Language模塊:conv-ensemble-str/model/decoder_conv.py
這是一維的卷積操作,具體實現是通過GLU進行語言的建模。
language_layer = self.conv1d_weightnorm(
inputs=language_layer,
out_dim=nout * 2,
kernel_size=kernal_width,
padding="VALID",
output_collection=output_collection)
# to avoid using future information
language_layer = language_layer[:, 0:-kernal_width + 1, :]
# add GLU
language_layer = self.gated_linear_units(language_layer, output_collection)
6.Attention模塊:conv-ensemble-str/model/decoder_conv.py
def attention_score(self, dec_rep, encoder_output):
N, H, W, C = encoder_output.get_shape().as_list()
N = N or tf.shape(dec_rep)[0]
M = dec_rep.get_shape().as_list()[1] or tf.shape(dec_rep)[1]
encoder_reshape = tf.reshape(encoder_output, [N, H * W, C])
# N*(H*W)*C # N*M*C ** N*(H*W)*C --> N*M*(H*W)
att_score = tf.matmul(dec_rep, encoder_reshape, transpose_b=True) * tf.sqrt(1.0 / C)
att_score = tf.nn.softmax(att_score)
# N*M*(H*W) # N*M*(H*W) ** N*(H*W)*C --> N*M*C
att_out = tf.matmul(att_score, encoder_reshape)
att_score = tf.reshape(att_score, [N, M, H, W])
return att_out, att_score
最后對語言模型進行一個總結
語言模型的優勢是語言模型能夠幫助在視覺信息不充足的情況下,提升識別結果。但同時有兩個問題:
第一個問題就是out of vocabulary問題,目前基于注意力的方法容易在訓練集中沒有出現過的詞匯中識別錯誤,且精度和在測試過程中使用訓練集中出現過的詞匯的效果之間gap遠大于基礎分割的識別方法,因此如何獲得一個魯棒的語言模型是一種挑戰。
第二個問題是,它的計算復雜度比較高。對于計算量問題,雖然目前Transformer應用于識別是一種趨勢,且能夠通過并行計算提升識別效率,但對于長文本的識別,其計算量增加明顯(RNN為線性增加,Transformer為平方增加)。
后續是否能根據這種分割和Attention結合的訓練思路,來提升識別結果,或許是一個解決思路。
Modelarts有近11G的數據集。有需要的可以掃碼獲取算法源代碼。
查看活動詳情:https://bbs.huaweicloud.com/blogs/293957
OCR 神經網絡
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。