基於OCR進行Bert獨立語義糾錯實踐

華為雲開發者聯盟發表於2023-04-07
摘要:本案例我們利用影片字幕識別中的文字檢測與識別模型,增加預訓練Bert進行糾錯

本文分享自華為雲社群《Bert特調OCR》,作者:杜甫蓋房子。

做這個專案的初衷是發現圖比較糊/檢測框比較長的時候,OCR會有一些錯誤識別,所以想對識別結果進行糾錯。一個很自然的想法是利用語義資訊進行糾錯,其實在OCR訓練時加入語義資訊也有不少工作,感興趣的朋友可以瞭解一下,為了更大程度複用已有的專案,我們決定保留現有OCR單元,在之後加入獨立語義糾錯模組進行糾錯。

本案例我們利用影片字幕識別中的文字檢測與識別模型,增加預訓練Bert進行糾錯,最終效果如下:

我們使用ModelBox Windows SDK進行開發,如果還沒有安裝SDK,可以參考ModelBox端雲協同AI開發套件(Windows)裝置註冊篇ModelBox端雲協同AI開發套件(Windows)SDK安裝篇完成裝置註冊與SDK安裝。

技能開發

這個應用對應的ModelBox版本已經做成模板放在華為雲OBS中,可以用sdk中的solution.bat工具下載,接下來我們給出該應用在ModelBox中的完整開發過程:

1)下載模板

執行.\solution.bat -l可看到當前公開的技能模板:

███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1
$ ./solution.bat -l
start download desc.json
 3942.12KB/S, percent=100.00%
Solutions name:
mask_det_yolo3
...
doc_ocr_db_crnn_bert

結果中的doc_ocr_db_crnn_bert即為文件識別應用模板,下載模板:

███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1
$ ./solution.bat -s doc_ocr_db_crnn_bert
...

solution.bat工具的引數中,-l 代表list,即列出當前已有的模板名稱;-s 代表solution-name,即下載對應名稱的模板。下載下來的模板資源,將存放在ModelBox核心庫的solution目錄下。

2)建立工程

ModelBox sdk目錄下使用create.bat建立doc_ocr工程

███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1
$ ./create.bat -t server -n doc_ocr -s doc_ocr_db_crnn_bert
sdk version is modelbox-win10-x64-1.5.1
success: create doc_ocr in D:\DEMO\modelbox-win10-x64-1.5.1\workspace

create.bat工具的引數中,-t 表示建立事務的類別,包括工程(server)、Python功能單元(Python)、推理功能單元(infer)等;-n 代表name,即建立事務的名稱;-s 代表solution-name,表示將使用後面引數值代表的模板建立工程,而不是建立空的工程。

workspace目錄下將建立出doc_ocr工程,工程內容如下所示:

doc_ocr
|--bin
│  |--main.bat:應用執行入口
│  |--mock_task.toml:應用在本地執行時的輸入輸出配置,此應用為http服務
|--CMake:存放一些自定義CMake函式
|--data:存放應用執行所需要的圖片、影片、文字、配置等資料
│  |--char_meta.txt:字形拆解檔案,用來計算字形相似度
│  |--character_keys.txt:OCR演算法的字符集合
│  |--GB2312.ttf:中文字型檔案
│  |--test_http.py:應用測試指令碼
│  |--text.jpg:應用測試圖片
│  |--vocab.txt:tokenizer配置檔案
|--dependence
│  |--modelbox_requirements.txt:應用執行依賴的外部庫在此檔案定義,本應用依賴pyclipper、Shapely、pillow等工具包
|--etc
│  |--flowunit:應用所需的功能單元存放在此目錄
│  │  |--cpp:存放C++功能單元編譯後的動態連結庫,此應用沒有C++功能單元
│  │  |--bert_preprocess:bert預處理功能單元,條件功能單元,判斷是否需要糾錯
│  │  |--collapse_position:歸攏單句糾錯結果
│  │  |--collapse_sentence:歸攏全文糾錯結果
│  │  |--det_post:文字檢測後處理功能單元
│  │  |--draw_ocr:ocr結果繪製功能單元
│  │  |--expand_img:展開功能單元,展開文字檢測結果
│  │  |--expand_position:展開功能單元,展開bert預處理結果
│  │  |--match_position:匹配糾錯結果
│  │  |--ocr_post:ocr後處理功能單元
|--flowunit_cpp:存放C++功能單元的原始碼,此應用沒有C++功能單元
|--graph:存放流程圖
│  |--doc_ocr.toml:預設流程圖,http服務
│  |--modelbox.conf:modelbox相關配置
|--hilens_data_dir:存放應用輸出的結果檔案、日誌、效能統計資訊
|--model:推理功能單元目錄
│  |--bert:Bert推理功能能單元
│  │  |--bert.toml:語義推理配置檔案
│  │  |--bert.onnx:語義推理模型
│  |--det:文字檢測推理功能單元
│  │  |--det.toml:文字檢測推理功能單元的配置檔案
│  │  |--det.onnx:文字檢測onnx模型
│  |--ocr:文字識別推理功能單元
│  │  |--ocr.toml:文字識別推理功能單元的配置檔案
│  │  |--ocr.onnx:文字識別onnx模型
|--build_project.sh:應用構建指令碼
|--CMakeLists.txt
|--rpm:打包rpm時生成的目錄,將存放rpm包所需資料
|--rpm_copyothers.sh:rpm打包時的輔助指令碼

3)檢視流程圖

doc_ocr工程graph目錄下存放流程圖,預設的流程圖doc_ocr.toml與工程同名,將流程圖視覺化:

圖示中,灰色部分為預置功能單元,其餘顏色為我們實現的功能單元,其中綠色為一般通用功能單元,紅色為推理功能單元,藍色為條件功能單元,黃色為展開歸攏功能單元。HTTP接收圖解碼後做預處理,接著是文字檢測,模型後處理得到檢測框,經過條件功能判斷,檢測到文字的圖送入展開功能單元,切圖進行文字識別,文字識別結果送入bert預處理單元判斷是否需要進行糾錯,如需糾錯則再展開並行進行語義推理,不需要糾錯的就直接進行結果繪製並返回。而未檢測到文字的幀則直接返回。

4)核心邏輯

本應用核心邏輯中的文字檢測與識別可以參考【ModelBox OCR實戰營】影片字幕識別中的相關介紹,本文重點介紹文字糾錯部分。

首先檢視糾錯預處理功能單元bert_preprocess

def process(self, data_context):
    in_feat = data_context.input("in_feat")
    out_feat = data_context.output("out_feat")
    out_bert = data_context.output("out_bert")

    for buffer_feat in in_feat:
        ocr_data = json.loads(buffer_feat.as_object())['ocr_result']
        score_data = json.loads(json.loads(buffer_feat.as_object())['result_score'])

        text_to_process = []
        text_to_pass = []
        err_positions = []
        for i, (sent, p) in enumerate(zip(ocr_data, score_data)):
            if not do_correct_filter(sent, self.max_seq_length):
                text_to_pass.append((i, sent))
            else:
                err_pos = find_err_pos_by_prob(p, self.prob_threshold)
                if not err_pos:
                    text_to_pass.append((i, sent))
                else:
                    text_to_process.append(sent)
                    err_positions.append(err_pos)
        if not text_to_process:
            out_feat.push_back(buffer_feat)
        else:
            out_dict = []
            texts_numfree = [self.number.sub(lambda m: self.rep[re.escape(m.group(0))], s) for s in text_to_process]
            err_positions = check_error_positions(texts_numfree, err_positions)
            if err_positions is None:
                err_positions = [range(len(d)) for d in texts_numfree]
            batch_data = BatchData(texts_numfree, err_positions, self.tokenizer, self.max_seq_length)
            input_ids, input_mask, segment_ids, masked_lm_positions = batch_data.data
            ...
    return modelbox.Status.StatusCode.STATUS_SUCCESS

預處理單元對透過do_correct_filter函式對OCR結果進行判斷,只對大於3個字的中文字元進行糾錯:

def do_correct_filter(text, max_seq_length):
    if re.search(re.compile(r'[a-zA-ZA-Za-z]'), text):
        return False
    if len(re.findall(re.compile(r'[\u4E00-\u9FA5]'), text)) < 3:
        return False
    if len(text) > max_seq_length - 2:
        return False
    return True

透過find_err_pos_by_prob函式定位需要糾錯的字元,只對OCR置信度小於閾值的字元進行糾錯:

def find_err_pos_by_prob(prob, prob_threshold):
    if not prob:
        return []
    err_pos = [i for i, p in enumerate(prob) if p < prob_threshold]
    return err_pos

如有需要糾錯的字元,則將該句編碼,進行語義推理。

語義推理後,透過collapse_position對推理結果進行解碼,在match_position功能單元中使用shape_similarity函式計算語義推理結果與OCR結果的字元相似度:

def shape_similarity(self, char1, char2):
    decomp1 = self.decompose_text(char1)
    decomp2 = self.decompose_text(char2)
    similarity = 0.0
    ed = edit_distance(safe_encode_string(decomp1), safe_encode_string(decomp2))
    normalized_ed = ed / max(len(decomp1), len(decomp2), 1)
    similarity = max(similarity, 1 - normalized_ed)
    return similarity

其中,decompose_text函式將單個漢字編碼為筆劃級別的IDS,如:

華: ⿱⿰⿰丿丨⿻乚丿⿻一丨

+----+
           | ⿱  |
           +----+
        化         十
      +----+     +----+
      | ⿰  |    | ⿻  |
      +----+     +----+
   亻       七  一      丨
 +----+    +----+
 | ⿰  |   | ⿻  |
 +----+    +----+
丿     丨  乚      丿

計算語義推理結果字元與原OCR結果字元相似度之後,綜合語義推理置信度與相似度判斷是否接收糾錯結果:

def accept_correct(self, confidence, similarity):
    if confidence + similarity >= self.all_conf \
        and confidence  >= self.confidence_conf \
            and similarity >= self.similarity_conf:
        return True
    return False

5)三方依賴庫

本應用依賴pyclipper、Shapely、pillow等工具包,ModelBox應用不需要手動安裝三方依賴庫,只需要配置在dependence\modelbox_requirements.txt,應用在編譯時會自動安裝。

技能執行

在專案目錄下執行.\bin\main.bat執行應用,為了方便觀察糾錯結果,我們將日誌切換為info:

███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1/workspace/doc_ocr
$ ./bin/main.bat default info
...
[2022-12-27 15:20:40,043][ INFO][httpserver_sync_receive.cc:188 ] Start server at http://0.0.0.0:8083/v1/ocr_bert

另起終端,進入專案data目錄下,執行test_http.py指令碼進行測試:

███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1/workspace/doc_ocr/data
$ python test_http.py

可以在技能執行日誌中觀察到接受的糾錯結果:

[2022-12-27 15:22:40,700][ INFO][match_position\match_position.py:51  ] confidence: 0.99831665, similarity: 0.6470588235294117, 櫃 -> 相

同時,在data目錄下可以看到應用返回的結果圖片:

 

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章