当前位置: 首页>Php>正文

人工智能公司,世界人工智能大賽OCR賽題方案!

人工智能公司,世界人工智能大賽OCR賽題方案!

?Datawhale干貨?

作者:阿水,北京航空航天大學,Datawhale成員

本文以世界人工智能創新大賽(AIWIN)手寫體 OCR 識別競賽為實踐背景,給出了OCR實踐的常見思路和流程。本項目使用PaddlePaddle 2.0動態圖實現的CRNN文字識別模型,全文代碼及思路如下。后臺回復 211112?可獲取完整代碼。

代碼地址:https://aistudio.baidu.com/aistudio/projectdetail/2612313

9fc2149a20ab7d0997fc5c48b9d538a6.png

賽題背景

銀行日常業務中涉及到各類憑證的識別錄入,例如身份證錄入、支票錄入、對賬單錄入等。以往的錄入方式主要是以人工錄入為主,效率較低,人力成本較高。近幾年來,OCR相關技術以其自動執行、人為干預較少等特點正逐步替代傳統的人工錄入方式。但OCR技術在實際應用中也存在一些問題,在各類憑證字段的識別中,手寫體由于其字體差異性大、字數不固定、語義關聯性較低、憑證背景干擾等原因,導致OCR識別率準確率不高,需要大量人工校正,對日常的銀行錄入業務造成了一定的影響。

比賽地址:http://ailab.aiwin.org.cn/competitions/65

賽題任務

本次賽題將提供手寫體圖像切片數據集,數據集從真實業務場景中,經過切片脫敏得到,參賽隊伍通過識別技術,獲得對應的識別結果。即:

  • 輸入:手寫體圖像切片數據集

  • 人工智能公司、輸出:對應的識別結果

83356cd54e226f93837b59d6aee2bed0.png

代碼說明

本項目是PaddlePaddle 2.0動態圖實現的CRNN文字識別模型,可支持長短不一的圖片輸入。CRNN是一種端到端的識別模式,不需要通過分割圖片即可完成圖片中全部的文字識別。CRNN的結構主要是CNN+RNN+CTC,它們分別的作用是:

  • 使用深度CNN,對輸入圖像提取特征,得到特征圖;

  • 使用雙向RNN(BLSTM)對特征序列進行預測,對序列中的每個特征向量進行學習,并輸出預測標簽(真實值)分布;

  • 人工智能7大應用領域,使用 CTC Loss,把從循環層獲取的一系列標簽分布轉換成最終的標簽序列。ff18c6f973d87feb0ad3183fb222af82.png

CRNN的結構如下,一張高為32的圖片,寬度隨意,一張圖片經過多層卷積之后,高度就變成了1,經過paddle.squeeze()就去掉了高度,也就說從輸入的圖片BCHW經過卷積之后就成了BCW。然后把特征順序從BCW改為WBC輸入到RNN中,經過兩次的RNN之后,模型的最終輸入為(W, B, Class_num)。這恰好是CTCLoss函數的輸入。85027c795e36c8d93ccb89d86cf7f9fc.png

代碼詳情

使用環境:

  • PaddlePaddle 2.0.1

  • Python 3.7

!\rm?-rf?__MACOSX/?測試集/?訓練集/?dataset/
!unzip?2021A_T1_Task1_數據集含訓練集和測試集.zip?>?out.log

步驟1:生成額外的數據集

這一步可以跳過,如果想要獲取更好的精度,可以自己添加。

import?os
import?time
from?random?import?choice,?randint,?randrangefrom?PIL?import?Image,?ImageDraw,?ImageFont#?驗證碼圖片文字的字符集
characters?=?'拾伍佰正仟萬捌貳整陸玖圓叁零角分肆柒億壹元'def?selectedCharacters(length):result?=?''.join(choice(characters)?for?_?in?range(length))return?resultdef?getColor():r?=?randint(0,?100)g?=?randint(0,?100)b?=?randint(0,?100)return?(r,?g,?b)def?main(size=(200,?100),?characterNumber=6,?bgcolor=(255,?255,?255)):#?創建空白圖像和繪圖對象imageTemp?=?Image.new('RGB',?size,?bgcolor)draw01?=?ImageDraw.Draw(imageTemp)#?生成并計算隨機字符串的寬度和高度text?=?selectedCharacters(characterNumber)print(text)font?=?ImageFont.truetype(font_path,?40)width,?height?=?draw01.textsize(text,?font)if?width?+?2?*?characterNumber?>?size[0]?or?height?>?size[1]:print('尺寸不合法')return#?繪制隨機字符串中的字符startX?=?0widthEachCharater?=?width?//?characterNumberfor?i?in?range(characterNumber):startX?+=?widthEachCharater?+?1position?=?(startX,?(size[1]?-?height)?//?2)draw01.text(xy=position,?text=text[i],?font=font,?fill=getColor())#?對像素位置進行微調,實現扭曲的效果imageFinal?=?Image.new('RGB',?size,?bgcolor)pixelsFinal?=?imageFinal.load()pixelsTemp?=?imageTemp.load()for?y?in?range(size[1]):offset?=?randint(-1,?0)for?x?in?range(size[0]):newx?=?x?+?offsetif?newx?>=?size[0]:newx?=?size[0]?-?1elif?newx?<?0:newx?=?0pixelsFinal[newx,?y]?=?pixelsTemp[x,?y]#?繪制隨機顏色隨機位置的干擾像素draw02?=?ImageDraw.Draw(imageFinal)for?i?in?range(int(size[0]?*?size[1]?*?0.07)):draw02.point((randrange(0,?size[0]),?randrange(0,?size[1])),?fill=getColor())#?保存并顯示圖片imageFinal.save("dataset/images/%d_%s.jpg"?%?(round(time.time()?*?1000),?text))def?create_list():images?=?os.listdir('dataset/images')f_train?=?open('dataset/train_list.txt',?'w',?encoding='utf-8')f_test?=?open('dataset/test_list.txt',?'w',?encoding='utf-8')for?i,?image?in?enumerate(images):image_path?=?os.path.join('dataset/images',?image).replace('\\',?'/')label?=?image.split('.')[0].split('_')[1]if?i?%?100?==?0:f_test.write('%s\t%s\n'?%?(image_path,?label))else:f_train.write('%s\t%s\n'?%?(image_path,?label))def?creat_vocabulary():#?生成詞匯表with?open('dataset/train_list.txt',?'r',?encoding='utf-8')?as?f:lines?=?f.readlines()v?=?set()for?line?in?lines:_,?label?=?line.replace('\n',?'').split('\t')for?c?in?label:v.add(c)vocabulary_path?=?'dataset/vocabulary.txt'with?open(vocabulary_path,?'w',?encoding='utf-8')?as?f:f.write('?\n')for?c?in?v:f.write(c?+?'\n')if?__name__?==?'__main__':if?not?os.path.exists('dataset/images'):os.makedirs('dataset/images')

步驟2:安裝依賴環境

!pip?install?Levenshtein
Looking?in?indexes:?https://pypi.tuna.tsinghua.edu.cn/simple
Requirement?already?satisfied:?Levenshtein?in?/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages?(0.16.0)
Requirement?already?satisfied:?rapidfuzz<1.9,>=1.8.2?in?/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages?(from?Levenshtein)?(1.8.2)

步驟3:讀取數據集

import?glob,?codecs,?json,?os
import?numpy?as?npdate_jpgs?=?glob.glob('./訓練集/date/images/*.jpg')
amount_jpgs?=?glob.glob('./訓練集/amount/images/*.jpg')lines?=?codecs.open('./訓練集/date/gt.json',?encoding='utf-8').readlines()
lines?=?''.join(lines)
date_gt?=?json.loads(lines.replace(',\n}',?'}'))lines?=?codecs.open('./訓練集/amount/gt.json',?encoding='utf-8').readlines()
lines?=?''.join(lines)
amount_gt?=?json.loads(lines.replace(',\n}',?'}'))
data_path?=?date_jpgs?+?amount_jpgs
date_gt.update(amount_gt)s?=?''
for?x?in?date_gt:s?+=?date_gt[x]char_list?=?list(set(list(s)))
char_list?=?char_list

步驟4:構造訓練集

!mkdir?dataset
!mkdir?dataset/images
!cp?訓練集/date/images/*.jpg?dataset/images
!cp?訓練集/amount/images/*.jpg?dataset/images
mkdir:?cannot?create?directory?‘dataset’:?File?exists
mkdir:?cannot?create?directory?‘dataset/images’:?File?exists
with?open('dataset/vocabulary.txt',?'w')?as?up:for?x?in?char_list:up.write(x?+?'\n')data_path?=?glob.glob('dataset/images/*.jpg')
np.random.shuffle(data_path)
with?open('dataset/train_list.txt',?'w')?as?up:for?x?in?data_path[:-100]:up.write(f'{x}\t{date_gt[os.path.basename(x)]}\n')with?open('dataset/test_list.txt',?'w')?as?up:for?x?in?data_path[-100:]:up.write(f'{x}\t{date_gt[os.path.basename(x)]}\n')

執行上面程序生成的圖片會放在dataset/images目錄下,生成的訓練數據列表和測試數據列表分別放在dataset/train_list.txtdataset/test_list.txt,最后還有個數據詞匯表dataset/vocabulary.txt

數據列表的格式如下,左邊是圖片的路徑,右邊是文字標簽。

dataset/images/1617420021182_c1dw.jpg?c1dw
dataset/images/1617420021204_uvht.jpg?uvht
dataset/images/1617420021227_hb30.jpg?hb30
dataset/images/1617420021266_4nkx.jpg?4nkx
dataset/images/1617420021296_80nv.jpg?80nv

以下是數據集詞匯表的格式,一行一個字符,第一行是空格,不代表任何字符。

f
s
2
7
3
n
d
w

訓練自定義數據,參考上面的格式即可。

步驟5:訓練模型

不管你是自定義數據集還是使用上面生成的數據,只要文件路徑正確,即可開始進行訓練。該訓練支持長度不一的圖片輸入,但是每一個batch的數據的數據長度還是要一樣的,這種情況下,筆者就用了collate_fn()函數,該函數可以把數據最長的找出來,然后把其他的數據補0,加到相同的長度。同時該函數還要輸出它其中每條數據標簽的實際長度,因為損失函數需要輸入標簽的實際長度。

  • 國際青年人工智能大賽官網,在訓練過程中,程序會使用VisualDL記錄訓練結果

import?paddle
import?numpy?as?np
import?os
from?datetime?import?datetime
from?utils.model?import?Model
from?utils.decoder?import?ctc_greedy_decoder,?label_to_string,?cer
from?paddle.io?import?DataLoader
from?utils.data?import?collate_fn
from?utils.data?import?CustomDataset
from?visualdl?import?LogWriter#?訓練數據列表路徑
train_data_list_path?=?'dataset/train_list.txt'
#?測試數據列表路徑
test_data_list_path?=?'dataset/test_list.txt'
#?詞匯表路徑
voc_path?=?'dataset/vocabulary.txt'
#?模型保存的路徑
save_model?=?'models/'
#?每一批數據大小
batch_size?=?32
#?預訓練模型路徑
pretrained_model?=?None
#?訓練輪數
num_epoch?=?100
#?初始學習率大小
learning_rate?=?1e-3
#?日志記錄噐
writer?=?LogWriter(logdir='log')def?train():#?獲取訓練數據train_dataset?=?CustomDataset(train_data_list_path,?voc_path,?img_height=32)train_loader?=?DataLoader(dataset=train_dataset,?batch_size=batch_size,?collate_fn=collate_fn,?shuffle=True)#?獲取測試數據test_dataset?=?CustomDataset(test_data_list_path,?voc_path,?img_height=32,?is_data_enhance=False)test_loader?=?DataLoader(dataset=test_dataset,?batch_size=batch_size,?collate_fn=collate_fn)#?獲取模型model?=?Model(train_dataset.vocabulary,?image_height=train_dataset.img_height,?channel=1)paddle.summary(model,?input_size=(batch_size,?1,?train_dataset.img_height,?500))#?設置優化方法boundaries?=?[30,?100,?200]lr?=?[0.1?**?l?*?learning_rate?for?l?in?range(len(boundaries)?+?1)]scheduler?=?paddle.optimizer.lr.PiecewiseDecay(boundaries=boundaries,?values=lr,?verbose=False)optimizer?=?paddle.optimizer.Adam(parameters=model.parameters(),learning_rate=scheduler,weight_decay=paddle.regularizer.L2Decay(1e-4))#?獲取損失函數ctc_loss?=?paddle.nn.CTCLoss()#?加載預訓練模型if?pretrained_model?is?not?None:model.set_state_dict(paddle.load(os.path.join(pretrained_model,?'model.pdparams')))optimizer.set_state_dict(paddle.load(os.path.join(pretrained_model,?'optimizer.pdopt')))train_step?=?0test_step?=?0#?開始訓練for?epoch?in?range(num_epoch):for?batch_id,?(inputs,?labels,?input_lengths,?label_lengths)?in?enumerate(train_loader()):out?=?model(inputs)#?計算損失input_lengths?=?paddle.full(shape=[batch_size],?fill_value=out.shape[0],?dtype='int64')loss?=?ctc_loss(out,?labels,?input_lengths,?label_lengths)loss.backward()optimizer.step()optimizer.clear_grad()#?多卡訓練只使用一個進程打印if?batch_id?%?100?==?0:print('[%s]?Train?epoch?%d,?batch?%d,?loss:?%f'?%?(datetime.now(),?epoch,?batch_id,?loss))writer.add_scalar('Train?loss',?loss,?train_step)train_step?+=?1#?執行評估if?epoch?%?10?==?0:model.eval()cer?=?evaluate(model,?test_loader,?train_dataset.vocabulary)print('[%s]?Test?epoch?%d,?cer:?%f'?%?(datetime.now(),?epoch,?cer))writer.add_scalar('Test?cer',?cer,?test_step)test_step?+=?1model.train()#?記錄學習率writer.add_scalar('Learning?rate',?scheduler.last_lr,?epoch)scheduler.step()#?保存模型paddle.save(model.state_dict(),?os.path.join(save_model,?'model.pdparams'))paddle.save(optimizer.state_dict(),?os.path.join(save_model,?'optimizer.pdopt'))#?評估模型
def?evaluate(model,?test_loader,?vocabulary):cer_result?=?[]for?batch_id,?(inputs,?labels,?_,?_)?in?enumerate(test_loader()):#?執行識別outs?=?model(inputs)outs?=?paddle.transpose(outs,?perm=[1,?0,?2])outs?=?paddle.nn.functional.softmax(outs)#?解碼獲取識別結果labelss?=?[]out_strings?=?[]for?out?in?outs:out_string?=?ctc_greedy_decoder(out,?vocabulary)out_strings.append(out_string)for?i,?label?in?enumerate(labels):label_str?=?label_to_string(label,?vocabulary)labelss.append(label_str)for?out_string,?label?in?zip(*(out_strings,?labelss)):#?計算字錯率c?=?cer(out_string,?label)?/?float(len(label))cer_result.append(c)cer_result?=?float(np.mean(cer_result))return?cer_resultif?__name__?==?'__main__':train()

步驟6:模型預測

訓練結束之后,使用保存的模型進行預測。通過修改image_path指定需要預測的圖片路徑,解碼方法,筆者使用了一個最簡單的貪心策略。

import?os
from?PIL?import?Image
import?numpy?as?np
import?paddlefrom?utils.model?import?Model
from?utils.data?import?process
from?utils.decoder?import?ctc_greedy_decoderwith?open('dataset/vocabulary.txt',?'r',?encoding='utf-8')?as?f:vocabulary?=?f.readlines()vocabulary?=?[v.replace('\n',?'')?for?v?in?vocabulary]save_model?=?'models/'
model?=?Model(vocabulary,?image_height=32)
model.set_state_dict(paddle.load(os.path.join(save_model,?'model.pdparams')))
model.eval()def?infer(path):data?=?process(path,?img_height=32)data?=?data[np.newaxis,?:]data?=?paddle.to_tensor(data,?dtype='float32')#?執行識別out?=?model(data)out?=?paddle.transpose(out,?perm=[1,?0,?2])out?=?paddle.nn.functional.softmax(out)[0]#?解碼獲取識別結果out_string?=?ctc_greedy_decoder(out,?vocabulary)# print('預測結果:%s'?% out_string)return?out_stringif?__name__?==?'__main__':image_path?=?'dataset/images/0_8bb194207a248698017a854d62c96104.jpg'display(Image.open(image_path))print(infer(image_path))
71c08bed05494f6cd915a5b0e73deb47.png
<PIL.JpegImagePlugin.JpegImageFile?image?mode=RGB?size=123x33?at?0x7F4D525F08D0>
貳零貳零貳壹
from?tqdm?import?tqdm,?tqdm_notebookresult_dict?=?{}
for?path?in?tqdm(glob.glob('./測試集/date/images/*.jpg')):text?=?infer(path)result_dict[os.path.basename(path)]?=?{'result':?text,'confidence':?0.9}for?path?in?tqdm(glob.glob('./測試集/amount/images/*.jpg')):text?=?infer(path)result_dict[os.path.basename(path)]?=?{'result':?text,'confidence':?0.9}
with?open('answer.json',?'w',?encoding='utf-8')?as?up:json.dump(result_dict,?up,?ensure_ascii=False,?indent=4)!zip?answer.json.zip?answer.jsonadding:?answer.json?(deflated?85%)

ff05b337e2d24c7697cd68774955a046.png

整理不易,三連

https://www.nshth.com/php/338884.html
>

相关文章:

  • 人工智能公司
  • 人工智能7大應用領域
  • 國際青年人工智能大賽官網
  • 人工智能的弊端
  • ICPC計算機大賽
  • 人工智能教學方案
  • 2023全國人工智能大賽
  • 世界人工智能大賽
  • 人工智能公司,世界人工智能大賽OCR賽題方案!
  • leetcode最長無重復字符串,Leetcode PHP題解--D62 976. Largest Perimeter Triangle
  • ubuntu grub>命令修復方法,Ubutnu18.04解決:Starting Wait until snapd is fully seeded...
  • 什么是終端,烏邦圖如何進入終端界面
  • 論文去重的方法,j簡單去重心得
  • 尚硅谷springboot學習課程筆記
  • 匯編語言指令大全及實例解析,【匯編語言】簡記
  • Spring認證,spring security oauth2 基于 RBAC 的自定義認證
  • 一點點門店管理系統,一點點對WebResource.axd的配置及使用[原創]
  • Jupyter安裝,jupyter安裝php,如何安裝jupyter
  • yzl工具箱最新版本,10yum工具使用
  • 唯一nft藝術品交易平臺官網,【Beeple同款】NFT 電子藝術畫框上架鏈作
  • 七種基本的css選擇器,CSS的背景屬性
  • php論壇,Yac - PHP擴展
  • apache配置php環境,Ubuntu 16.04 安裝php的拓展yac
  • mysql試題及答案,mysql獲取id最大的一條記錄_sql查詢表中ID最大的一條數據腫么寫?
  • c語言程序設計第二版,求兩個整數的較大值(C語言)
  • 煙火人間歌曲DJ版,計算機音樂煙火人間,煙火人間在線試聽_陸虎_高音質歌曲_九酷音樂
  • 梯形的立方公式,用梯形算定積分
  • 鴻蒙系統又不發布了,華為微博回應鴻蒙,果不其然,華為放出終極大招!鴻蒙操作系統下月正式推送。就在剛剛,華為開通了鴻蒙操作系統的官方微博,關注人數已接近八萬。?.
  • 驗證集loss變正確率不變,測試ResNet在ImageNet驗證集上的準確率
  • hydraforce,Hydra – Brute Force HTTP(S)
  • 機器人仿真軟件哪個好,ROS導航仿真和多點導航3——實現機器人巡檢功能
  • 無線寬帶移動路由器原理,路由器的原理和作用
  • 1134: 小青蛙,跳跳跳
  • ac2018kod決賽,2019HDU多校第十場
  • BUUCTF筆記之Web系列部分WriteUp(四)
  • 中國元宇宙平臺,元界快訊|首個物聯網元宇宙平臺“物聯森友會”即將上線
  • 可視化數據庫軟件,優锘科技:可視化加速“歷史數據庫”運轉
  • 網絡中url的含義是什么,常用網絡圖片url地址