一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

tensorflow LSTM CTC實現(xiàn)端到端OCR

 yespon 2017-11-19

最近在做OCR相關(guān)的東西,關(guān)于OCR真的是有悠久了歷史了,最開始用tesseract,然而效果總是不理想,其中字符分割真的是個博大精深的問題,那么多年那么多算法,然而應(yīng)用到實際總是有諸多問題。比如說非等間距字體的分割,漢字的分割,有光照陰影的圖片的字體分割等等,針對特定的問題,特定的算法能有不錯的效果,但也僅限于特定問題,很難有一些通用的結(jié)果。于是看了Xlvector的博客之后,發(fā)現(xiàn)可以端到端來實現(xiàn)OCR,他是基于mxnet的,于是我想把它轉(zhuǎn)到tensorflow這個框架來,順便還能熟悉一下這個框架。更加細節(jié)的實現(xiàn)方法見另一篇 http:///2017-04-23/tensorflow-lstm-ctc-input-output/


生成數(shù)據(jù)

利用captcha來生成驗證碼,具體生成驗證碼的代碼,

在公眾號 datadw 里 回復(fù) OCR   即可獲取。

共生成4-6位包含數(shù)字和英文大小寫的訓練圖片128000張和測試圖片400張。命名規(guī)則就是num_label.png,生成的圖片如下圖



關(guān)于生成數(shù)據(jù),再多說一點,可以像Xlvector那樣一邊生成一邊訓練,這樣樣本是無窮的,效果更好。但是實際應(yīng)用中有限樣本的情況還是更多的。

載入數(shù)據(jù)

兩種載入數(shù)據(jù)方式

pipeline

最開始想通過一個tf.train.string_input_producer來讀入所有的文件名,然后以pipline的方式讀入,但是由于標簽的是不定長的,想通過正則來生成label,一開始是想用py_func來實現(xiàn),后來發(fā)現(xiàn)傳入string會有問題,所以最后還是選擇生成tf.record文件,關(guān)于不定長問題,把比較短的標簽在后面補零(0是blank的便簽,就是說自己的類別中不能出現(xiàn)0這個類),然后讀出每個batch后,再把0去掉。

一次性載入

我這里給一個目錄,然后遍歷里面所有的文件,等到訓練的時候,每一個epoch循環(huán)把文件的index給手動shuffle一下,然后就可以每次截取出一個batch來用作輸入了

class DataIterator:
   def __init__(self, data_dir):
       self.image_names = []
self.image = []
self.labels=[]
for root, sub_folder, file_list in os.walk(data_dir):
           for file_path in file_list:
               image_name = os.path.join(root,file_path)
self.image_names.append(image_name)
im = cv2.imread(image_name,0).astype(np.float32)/255.
               im = cv2.resize(im,(image_width,image_height))
# transpose to (160*60) and the step shall be 160
               # in this way, each row is a feature vector
               im = im.swapaxes(0,1)
self.image.append(np.array(im))
#image is named as .//00000_abcd.png
               code = image_name.split('/')[2].split('_')[1].split('.')[0]
code = [SPACE_INDEX if code == SPACE_TOKEN else maps[c] for c in list(code)]
self.labels.append(code)
print(image_name,' ',code)
@property
   def size(self):
       return len(self.labels)
def input_index_generate_batch(self,index=None):
       if index:
           image_batch=[self.image[i] for i in index]
label_batch=[self.labels[i] for i in index]
else:
           # get the whole data as input
           image_batch=self.image
label_batch=self.labels
def get_input_lens(sequences):
           lengths = np.asarray([len(s) for s in sequences], dtype=np.int64)
return sequences,lengths
batch_inputs,batch_seq_len = get_input_lens(np.array(image_batch))
batch_labels = sparse_tuple_from_label(label_batch)
return batch_inputs,batch_seq_len,batch_labels


需要注意的是tensorflow lstm輸入格式的問題,其label tensor應(yīng)該是稀疏矩陣,所以讀取圖片和label之后,還要進行一些處理,具體可以看代碼

在公眾號 datadw 里 回復(fù) OCR   即可獲取。

關(guān)于載入圖片,發(fā)現(xiàn)12.8w張圖一次讀進內(nèi)存,內(nèi)存也就漲了5G,如果訓練數(shù)據(jù)加大,還是加一個pipeline來讀比較好。

網(wǎng)絡(luò)結(jié)構(gòu)

然后是網(wǎng)絡(luò)結(jié)構(gòu)

graph = tf.Graph()
with graph.as_default():
   inputs = tf.placeholder(tf.float32, [None, None, num_features])
labels = tf.sparse_placeholder(tf.int32)
seq_len = tf.placeholder(tf.int32, [None])
# Stacking rnn cells
   stack = tf.contrib.rnn.MultiRNNCell([tf.contrib.rnn.LSTMCell(FLAGS.num_hidden,state_is_tuple=True) for i in range(FLAGS.num_layers)] , state_is_tuple=True)
# The second output is the last state and we will no use that
   outputs, _ = tf.nn.dynamic_rnn(stack, inputs, seq_len, dtype=tf.float32)
shape = tf.shape(inputs)
batch_s, max_timesteps = shape[0], shape[1]
# Reshaping to apply the same weights over the timesteps
   outputs = tf.reshape(outputs, [-1, FLAGS.num_hidden])
# Truncated normal with mean 0 and stdev=0.1
   W = tf.Variable(tf.truncated_normal([FLAGS.num_hidden,
num_classes],
stddev=0.1),name='W')
b = tf.Variable(tf.constant(0., shape=[num_classes],name='b'))
# Doing the affine projection
   logits = tf.matmul(outputs, W) + b
# Reshaping back to the original shape
   logits = tf.reshape(logits, [batch_s, -1, num_classes])
# Time major
   logits = tf.transpose(logits, (1, 0, 2))
global_step = tf.Variable(0,trainable=False)
loss = tf.nn.ctc_loss(labels=labels,inputs=logits, sequence_length=seq_len)
cost = tf.reduce_mean(loss)
#optimizer = tf.train.MomentumOptimizer(learning_rate=learning_rate,
   #        momentum=FLAGS.momentum).minimize(cost,global_step=global_step)
   optimizer = tf.train.AdamOptimizer(learning_rate=FLAGS.initial_learning_rate,
beta1=FLAGS.beta1,beta2=FLAGS.beta2).minimize(loss,global_step=global_step)
# Option 2: tf.contrib.ctc.ctc_beam_search_decoder
   # (it's slower but you'll get better results)
   #decoded, log_prob = tf.nn.ctc_greedy_decoder(logits, seq_len,merge_repeated=False)
   decoded, log_prob = tf.nn.ctc_beam_search_decoder(logits, seq_len,merge_repeated=False)
# Inaccuracy: label error rate
   lerr = tf.reduce_mean(tf.edit_distance(tf.cast(decoded[0], tf.int32), labels))


這里我參考了stackoverflow的一篇帖子寫的,

https:///questions/38059247/using-tensorflows-connectionist-temporal-classification-ctc-implementation

根據(jù)tensorflow 1.0.1的版本做了微調(diào),使用了Adam作為optimizer。

需要注意的是ctc_beam_search_decoder是非常耗時的.


轉(zhuǎn)自: 大數(shù)據(jù)挖掘DT數(shù)據(jù)分析


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    丰满人妻熟妇乱又乱精品古代| 欧美午夜色视频国产精品| 老司机这里只有精品视频| 黄色av尤物白丝在线播放网址 | 中文字幕一区二区熟女| 五月天综合网五月天综合网| 欧美一区二区不卡专区| 久久福利视频这里有精品| 国产免费人成视频尤物| 日韩欧美精品一区二区三区| 99久久精品一区二区国产| 国产精品欧美一区二区三区| 国产精品亚洲精品亚洲| 国产a天堂一区二区专区| 国产欧美另类激情久久久| 九九蜜桃视频香蕉视频| 亚洲欧美日韩国产自拍| 欧美熟妇一区二区在线| 亚洲中文字幕三区四区| 国产午夜精品亚洲精品国产| 欧美一本在线免费观看| 97人摸人人澡人人人超碰| 青青免费操手机在线视频| 国产中文另类天堂二区| 日本大学生精油按摩在线观看| 五月激情五月天综合网| 亚洲一区二区三区福利视频| 国产欧美日产中文一区| 男人大臿蕉香蕉大视频| 日本不卡一区视频欧美| 日韩中文字幕狠狠人妻| 在线观看免费无遮挡大尺度视频| 91精品日本在线视频| 国产一级内片内射免费看| 欧美不卡高清一区二区三区| 久久精品免费视看国产成人| 日本av在线不卡一区| 日本在线视频播放91| 成人精品一区二区三区在线| 亚洲国产成人一区二区在线观看| 成人欧美精品一区二区三区|