1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        從代碼角度分析高效文本檢測算法DBNet

        共 7199字,需瀏覽 15分鐘

         ·

        2021-07-18 22:17

        0 摘要


            論文題目:Real-time Scene Text Detection with Differentiable Binarization

            arxiv: https://arxiv.org/abs/1911.08947

            github: https://github.com/MhLiao/DB


            DBNet是華科白翔組AAAI2020新提出的高效文本檢測算法,速度極快,性能也是非常不錯的。整體思路非常簡單,是一個值得嘗試的優(yōu)異算法。


           其核心采用的是基于分割的做法進行文本檢測,即將每個文本塊都進行語義分割,然后對分割概率圖進行簡單二值化、最終轉(zhuǎn)化得為box或者poly格式的檢測結(jié)果。除去網(wǎng)絡(luò)設(shè)計方面的差異,本文最大特點是引入了Differentiable Binarization(DB)模塊來優(yōu)化分割預(yù)測結(jié)果。常規(guī)的基于語義分割的文本檢測算法都是直接輸出二值語義概率圖或者其他輔助信息,然后經(jīng)過閾值二值化得到最終結(jié)果,要想得到比較好的文本檢測效果,一般都需要復(fù)雜的后處理,例如PSENet和PANet,會導(dǎo)致速度很慢。本文嘗試將閾值二值化過程變得可微,這一小小改動不僅可以增加錯誤預(yù)測梯度,也可以聯(lián)合優(yōu)化各個分支,得到更好的語義概率圖。


           總而言之:通過引入輔助的DB可微模塊,促進語義概率圖分支的學(xué)習(xí),只要分割概率圖學(xué)好了,那么后處理自然也就簡單了,實驗結(jié)果表明,速度非常快,效果也是非常不錯的,如下所示。其實目前大部分算法速度慢的原因都是各種復(fù)雜后處理,一旦后處理可以簡單化,那么速度其實都可以很快。



        1 算法介紹

        算法核心流程如下: 

            和常規(guī)基于語義分割算法的區(qū)別是多了一條threshold map分支,該分支的主要目的是和分割圖聯(lián)合得到更接近二值化的二值圖,屬于輔助分支。其余操作就沒啥了。整個核心知識就這些了。

            下面結(jié)合代碼進行詳細分析。算法整體詳細流程如下: 


        1.1 骨架網(wǎng)絡(luò)和FPN

            骨架網(wǎng)絡(luò)采用的是resnet18或者resnet50,為了增加網(wǎng)絡(luò)特征提取能力,在layer2、layer3和layer4模塊內(nèi)部引入了變形卷積dcnv2模塊。在resnet輸出的4個特征圖后面采用標(biāo)準的FPN網(wǎng)絡(luò)結(jié)構(gòu),得到4個增強后輸出,然后cat進來,得到1/4的特征圖輸出fuse。

            其中,resnet骨架特征提取代碼在backbones/resnet.py里,具體是輸出x2, x3, x4, x5,分別是1/4~1/32尺寸。FPN部分代碼在decoders/seg_detector.py里面,具體是: 

        1.2 head部分

            輸出head在訓(xùn)練時候包括三個分支,分別是probability map、threshold map和經(jīng)過DB模塊計算得到的approximate binary map。

            首先對fuse特征圖經(jīng)過一系列卷積和反卷積,擴大到和原圖一樣大的輸出,然后經(jīng)過sigmod層得到0-1輸出概率圖probability map;同時對fuse特征圖采用類似上采樣操作,經(jīng)過sigmod層的0-1輸出閾值圖threshold map;將這兩個輸出圖經(jīng)過DB模塊得到approximate binary map。三個圖通道都是1,輸出和輸入是一樣大的(代碼注釋寫錯了,不是1/2,而是1)。要想分割精度高,高分辨率輸出是必要的。  

            這部分代碼也在decoders/seg_detector.py里面,主流程為: 

            由于本文重點是DB模塊,故有必要重點說明下。其實就是如下公式:

        本質(zhì)就是帶參數(shù)K的sigmod函數(shù),通過參數(shù)K=50來模擬hard截斷二值化函數(shù):

            SB是標(biāo)準二值化函數(shù)。為了說明DB模塊的引入對于聯(lián)合訓(xùn)練的優(yōu)勢,作者對該函數(shù)進行梯度分析,也就是對approximate binary map進行求導(dǎo)分析,由于是sigmod輸出,故假設(shè)Loss是bce,對于label為0或者1的位置,其Loss函數(shù)可以重寫為: 

        x表示probability map-threshold map,最后一層關(guān)于x的梯度很容易計算: 

        看上圖右邊,(b)圖是當(dāng)label=1,x預(yù)測值從-1到1的梯度,可以發(fā)現(xiàn),當(dāng)k=50時候梯度遠遠大于k=1,錯誤的區(qū)域梯度更大,對于label=0的情況分析也是一樣的。故: 


        (1) 通過增加參數(shù)K,就可以達到增大梯度的目的,加快收斂 
        (2) 在預(yù)測錯誤位置,梯度也是顯著增加


            總之通過引入DB模塊,通過參數(shù)K可以達到增加梯度幅值,更加有利優(yōu)化,可以使得三個輸出圖優(yōu)化更好,最終分割結(jié)果會優(yōu)異。而DB模塊本身就是帶參數(shù)的sigmod函數(shù),實現(xiàn)如下: 


        1.3 loss分析

            輸出是單個單通道圖,probability map和approximate binary map是典型的分割輸出,故其loss就是普通的bce,但是為了平衡正負樣本,還額外采用了難負樣本采樣策略,對背景區(qū)域和前景區(qū)域采用3:1的設(shè)置。對于threshold map,其輸出不一定是0-1之間,后面會介紹其值的范圍,當(dāng)前采用的是L1 loss,且僅僅計算擴展后的多邊形內(nèi)部區(qū)域,其余區(qū)域忽略。

        Ls是probability map,Lt是閾值圖,Lb是近似二值化圖,alpha=1,beta=10。其中平衡bce實現(xiàn)在decoders/balance_cross_entropy_loss.py,實現(xiàn)非常簡單: 

           本文整個論文Loss的實現(xiàn)在decoders/ seg_detector_loss.py的L1BalanceCELoss類,可以發(fā)現(xiàn)其實approximate binary map采用的并不是論文中的bce,而是可以克服正負樣本平衡的dice loss。一般在高度不平衡的二值分割任務(wù)中,dice loss效果會比純bce好,但是更好的策略是dice loss +bce loss。 


        1.4 label生成

            理解三個輸出圖label的生成過程,是本文的關(guān)鍵,下面結(jié)合代碼詳細講,具體會結(jié)合整個dataset的生成過程分析。

          首先分析配置文件,以icdar2015數(shù)據(jù)為例experiments/ seg_detector/ base_ic15.yaml 


            仔細看配置結(jié)構(gòu),可以發(fā)現(xiàn)整個項目框架結(jié)構(gòu)其實解耦度很高的,代碼質(zhì)量比較高,和mmdetection設(shè)計思想非常類似,只不過我覺得本文yaml配置沒有mmdetection那種采用py文件且注冊類的實現(xiàn)好。但是相比大部分開源代碼,本項目已經(jīng)是非常良心了??梢钥闯?,其是靠yaml配置來組裝各個類,每個子模塊都可以通過類名+類參數(shù)的方式替換。

            我們重點分析dataset數(shù)據(jù)生成過程,從配置可以看出,除了數(shù)據(jù)的前處理外,在數(shù)據(jù)處理部分一共經(jīng)過了7個處理函數(shù),分別是:


        (1) AugmentDetectionData數(shù)據(jù)增強類; 
        (2) RandomCropData 數(shù)據(jù)裁剪類,因為數(shù)據(jù)裁剪涉及到比較復(fù)雜的多變形標(biāo)注后處理,所以單獨列出來 
        (3) MakeICDARData 數(shù)據(jù)重新組織類 
        (4) MakeSegDetectionData 生成概率圖和對應(yīng)mask類 
        (5) MakeBorderMap 生成閾值圖和對應(yīng)Mask類 
        (6) NormalizeImage 圖片歸一化類 
        (7) FilterKeys 字典數(shù)據(jù)過濾類,具體是把superfluous里面的key和value刪掉,不輸入網(wǎng)絡(luò)中


        是不是和mmdetection的pipeline非常類似呀!

        下面開始對每個類重點分析。 


        (1) 數(shù)據(jù)預(yù)處理 
            在data/image_dataset.py,數(shù)據(jù)預(yù)處理邏輯非常簡單,就是讀取圖片和gt標(biāo)注,解析出每張圖片poly標(biāo)注,包括多邊形標(biāo)注、字符內(nèi)容以及是否是忽略文本,忽略文本一般是比較模糊和小的文本。在進行上述7個類的處理前,我們可以先對數(shù)據(jù)和標(biāo)注進行可視化,具體可以在getitem方法里面插入: 

        以icdar2015數(shù)據(jù)集為例,忽略文本顏色是白色顯示。 



        (2) AugmentDetectionData 

            該類在data/processes/augment_data.py,其目的就是對圖片和poly標(biāo)注進行數(shù)據(jù)增強,包括翻轉(zhuǎn)、旋轉(zhuǎn)和縮放三個,參數(shù)如配置所示。本文采用的增強庫是imgaug。可以看出本文訓(xùn)練階段對數(shù)據(jù)是不保存比例的resize,然后再進行三種增強。

            由于icdar數(shù)據(jù),文本區(qū)域占比都是非常小的,故不能用直接resize到指定輸入大小的數(shù)據(jù)增強操作,而是使用后續(xù)的randcrop操作比較科學(xué)。但是如果自己項目的數(shù)據(jù)文本區(qū)域比較大,則可能沒必要采用RandomCropData這么復(fù)雜的數(shù)據(jù)增強操作,直接resize算了。


        (3) RandomCropData 
            該類在data/ processes/ random_crop_data.py,其目的是對圖片進行裁剪到指定的[640, 640]。由于斜框的特點,裁剪增強沒那么容易做,本文采用的裁剪策略非常簡單: 遍歷每一個多邊形標(biāo)注,只要裁剪后有至少有一個poly還在裁剪框內(nèi),則認為該次裁剪有效。這個策略主要可以保證一張圖片中至少有一個gt,且實現(xiàn)比較簡單。

        其具體流程是:


        1 將每張圖片的所有poly數(shù)據(jù)進行水平和垂直方向投影,有標(biāo)注的地方是1,其余地方是0 
        2 找出沒有標(biāo)注即0值的水平和垂直坐標(biāo)h_axis和w_axis 
        3 如果全部是1,則表示poly橫跨了整圖,則直接返回,無法裁剪 
        4 對水平和垂直坐標(biāo)進行連續(xù)0區(qū)域分離,其實就是把所有連續(xù)0坐標(biāo)區(qū)域切割處理變成List輸出h_regions、w_regions 
        5 以w_regions為例,長度為n,先從n個區(qū)域隨機選擇2個區(qū)域,然后在這兩個區(qū)域內(nèi)部隨機選擇兩個點,構(gòu)成x方向最大最小坐標(biāo),h_regions也是一樣處理,此時就得到了xmin, ymin, xmax - xmin, ymax - ymin值 
        6 判斷裁剪區(qū)域是否過小;以及判斷是否裁剪框內(nèi)部是否至少有一個標(biāo)注在內(nèi)部,沒有被裁斷,如果條件滿足則返回上述值,否則重復(fù)max_tries次,直到成功


        代碼如下: 

            在得到裁剪區(qū)域后,就比較簡單了。先對裁剪區(qū)域圖片進行保存長寬比的resize,最長邊為網(wǎng)絡(luò)輸入,例如640x640, 然后從上到下pad,得到640x640的圖片 

        如果進行可視化,會顯示如下所示: 

        可以看出,這種裁剪策略雖然簡單暴力,但是為了拼接成640x640的輸出,會帶來大量無關(guān)全黑像素區(qū)域。


        (4) MakeICDARData 
            該類在data/ processes/ make_icdar_data.py,就是簡單的組織數(shù)據(jù)而已

        OrderedDict(image=data['image'],             polygons=polygons,             ignore_tags=ignore_tags,             shape=shape,             filename=filename,             is_training=data['is_training'])


        (5) MakeSegDetectionData 
            該類在data/ processes/ make_seg_detection_data.py,該類的功能是:將多邊形數(shù)據(jù)轉(zhuǎn)化為mask格式即概率圖gt,并且標(biāo)記哪些多邊形是忽略區(qū)域

            為了防止標(biāo)注間相互粘連,不好后處理,區(qū)分實例,目前做法都是會進行shrink即沿著多邊形標(biāo)注的每條邊進行向內(nèi)縮減一定像素,得到縮減的gt,然后才進行訓(xùn)練;在測試時候再采用相反的手動還原回來。


            縮減做法采用的也是常規(guī)的Vatti clipping algorithm,是通過pyclipper庫實現(xiàn)的,縮減比例是默認0.4,公式是 

        r=0.4,A是多邊形面積,L是多邊形周長,通過該公式就可以對每個不同大小的多邊形計算得到一個唯一的D,代表每條邊的向內(nèi)縮放像素個數(shù)。

        如果進行可視化,如下所示: 

            概率圖內(nèi)部全白區(qū)域就是概率圖的label,右圖是忽略區(qū)域mask,0為忽略區(qū)域,到時候該區(qū)域是不計算概率圖loss的。


        (6) MakeBorderMap 
            該類在data/make_border_map.py,目的是計算閾值圖和對應(yīng)mask。 

            仔細看閾值圖的標(biāo)注,首先紅線點是poly標(biāo)注;然后對該多邊形先進行shrink操作,得到藍線; 然后向外反向shrink同樣的距離,得到綠色;閾值圖就是綠線和藍色區(qū)域,以紅線為起點,計算在綠線和藍線區(qū)域內(nèi)的點距離紅線的距離,故為距離圖。


        其代碼的處理邏輯是: 


        1 對每個poly進行向外擴展,參數(shù)和向內(nèi)shrink一樣,然后對擴展后多邊形內(nèi)部填充1,得到對應(yīng)的mask
        2 為了加快計算速度,對每條poly計算最小包圍矩,然后在裁剪后的圖片內(nèi)部,計算每個點到poly上面每條邊的距離 
        3 只保留0-1值內(nèi)的距離值,其余位置不用 
        4 把距離圖貼到原圖大小的圖片上,如果和其余poly有重疊,則取最大值


        5 為了使得后續(xù)閾值圖和概率圖進行帶參數(shù)的sigmod操作,得到近似二值圖,需要對閾值圖的取值范圍進行變換,具體是將0-1范圍變換到0.3-0.6范圍


        可視化如下所示: 

        采用matpoltlib繪制距離圖會更好看


        (7) NormalizeImage和FilterKeys 
            這兩個類就沒啥說的了,就是歸一化圖片和刪除后續(xù)不用的字段而已。


            至此,就可以得到概率圖、概率圖對應(yīng)mask,閾值圖和閾值圖對于的mask,而近似二值化圖的label也是概率圖。


        1.5 推理邏輯


        配置如下: 

            如果不考慮label,則其處理邏輯和訓(xùn)練邏輯有一點不一樣,其把圖片統(tǒng)一resize到指定的長度進行預(yù)測。

            前面說過閾值圖分支其實可以相當(dāng)于輔助分支,可以聯(lián)合優(yōu)化各個分支性能。故在測試時候發(fā)現(xiàn)概率圖預(yù)測值已經(jīng)蠻好了,故在測試階段實際上把閾值圖分支移除了,只需要概率圖輸出即可。


            后處理邏輯在structure/ representers/ seg_detector_representer.py,本文特色就是后處理比較簡單,故流程為: 


        1 對概率圖進行固定閾值處理,得到分割圖 
        2 對分割圖計算輪廓,遍歷每個輪廓,去除太小的預(yù)測;對每個輪廓計算包圍矩形,然后計算該矩形的預(yù)測score
        3 對矩形進行反向shrink操作,得到真實矩形大?。蛔詈筮€原到原圖size就可以了


        采用作者提供的訓(xùn)練好的權(quán)重進行預(yù)測,可視化預(yù)測結(jié)果如下所示: 

        測試icdar2015數(shù)據(jù),可以得到如下輸出:

        [INFO] [2020-07-10 10:11:57,999] precision : 0.877384 (500)[INFO] [2020-07-10 10:11:57,999] recall : 0.775156 (500)[INFO] [2020-07-10 10:11:57,999] fmeasure : 0.823108 (1)

        符合論文里面的指標(biāo)。論文中指標(biāo)截圖:

        可以看出變形卷積和閾值圖對整個性能都有比較大的促進作用。 

        2 總結(jié)

            本文通過從原理和實現(xiàn)細節(jié)方面詳細講解了本算法。可以看出,本文思路還是非常清晰的,代碼質(zhì)量也比較高,效果也很不錯,推薦大家可以去看看。由于本人水平有限和碼子比較多,可能有些小錯誤,歡迎批評和指正。


        瀏覽 268
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            免费观看的黄色视频 | 妇女撒尿bbbb | 91靠逼视频 | 成人免费A级毛片无码片2022 | 国产成人无码a在线观看不卡 | 奶大灬舒服灬一进一出三区 | 国产午夜精品视频一区二区三区 | 国产亚洲色婷婷久久99 | 尽跟没入夹得好紧h | 色婷婷五月婷婷 |