如何做免費(fèi)域名網(wǎng)站高級(jí)搜索引擎
前言
目標(biāo)識(shí)別如今以及迭代了這么多年,普遍受大家認(rèn)可和歡迎的目標(biāo)識(shí)別框架就是YOLO了。按照官方描述,YOLOv8 是一個(gè) SOTA 模型,它建立在以前 YOLO 版本的成功基礎(chǔ)上,并引入了新的功能和改進(jìn),以進(jìn)一步提升性能和靈活性。從基本的YOLOv1版本到如今v8版本,完成了多次蛻變,現(xiàn)在已經(jīng)相當(dāng)成熟并且十分的親民。我見(jiàn)過(guò)很多初學(xué)目標(biāo)識(shí)別的同學(xué)基本上只花一周時(shí)間就可以參照案例實(shí)現(xiàn)一個(gè)目標(biāo)檢測(cè)的項(xiàng)目,這全靠YOLO強(qiáng)大的解耦性和部署簡(jiǎn)易性。初學(xué)者甚至只需要修改部分超參數(shù)接口,調(diào)整數(shù)據(jù)集就可以實(shí)現(xiàn)目標(biāo)檢測(cè)了。但是我想表達(dá)的并不是YOLO的原理有多么難理解,原理有多難推理。一般工作中要求我們能夠運(yùn)行并且能夠完成目標(biāo)檢測(cè)出來(lái)就可以了,更重要的是數(shù)據(jù)集的標(biāo)注。我們不需要完成幾乎難以單人完成的造目標(biāo)檢測(cè)算法輪子的過(guò)程,我們需要理解YOLO算法中每個(gè)超參數(shù)的作用以及影響。就算我們能夠訓(xùn)練出一定準(zhǔn)確度的目標(biāo)檢測(cè)模型,我們還需要根據(jù)實(shí)際情況對(duì)生成結(jié)果進(jìn)行一定的改寫:例如對(duì)于圖片來(lái)說(shuō)一共出現(xiàn)了幾種目標(biāo);對(duì)于一個(gè)視頻來(lái)說(shuō),定位到具體時(shí)間出現(xiàn)了識(shí)別的目標(biāo)。這都是需要我們反復(fù)學(xué)習(xí)再練習(xí)的本領(lǐng)。
完成目標(biāo)檢測(cè)后,我們應(yīng)該輸出定位出來(lái)的信息,YOLO是提供輸出設(shè)定的超參數(shù)的,我們需要根據(jù)輸出的信息對(duì)目標(biāo)進(jìn)行裁剪得到我們想要的目標(biāo)之后再做上層處理。如果是車牌目標(biāo)識(shí)別的項(xiàng)目,我們裁剪出來(lái)的車牌就可以進(jìn)行OCR技術(shù)識(shí)別出車牌字符了,如果是安全帽識(shí)別項(xiàng)目,那么我們可以統(tǒng)計(jì)一張圖片或者一幀中出現(xiàn)檢測(cè)目標(biāo)的個(gè)數(shù)做出判斷,一切都需要根據(jù)實(shí)際業(yè)務(wù)需求為主。本篇文章主要是OCR模型對(duì)車牌進(jìn)行字符識(shí)別,結(jié)合YOLO算法直接定位目標(biāo)進(jìn)行裁剪,裁剪后生成OCR訓(xùn)練數(shù)據(jù)集即可。開(kāi)源項(xiàng)目地址如下,如果有幫助希望不吝點(diǎn)亮star~:
基于Yolov7-LPRNet的動(dòng)態(tài)車牌目標(biāo)識(shí)別算法模型https://github.com/Fanstuck/Yolov7-LPRNet其中數(shù)據(jù)集的質(zhì)量是尤為重要的,決定了模型的上限,因此想要搭建一個(gè)效果較好的目標(biāo)識(shí)別算法模型,就需要處理流程較為完善的開(kāi)源數(shù)據(jù)集。本篇文章采用的是CCPD數(shù)據(jù)集,上篇文章已經(jīng)詳細(xì)描述了整個(gè)項(xiàng)目的初步搭建過(guò)程,包括數(shù)據(jù)集準(zhǔn)備和數(shù)據(jù)預(yù)處理,大體系統(tǒng)框架和數(shù)據(jù)標(biāo)簽聚合,以及利用Yolov7進(jìn)行模型訓(xùn)練和推理,能夠得到圖片或者視頻幀中車牌的定位數(shù)據(jù),現(xiàn)在我們需要搭建LPRNet網(wǎng)絡(luò)來(lái)實(shí)現(xiàn)OCR車牌字符識(shí)別輸出。
一、車牌字符識(shí)別
一般來(lái)說(shuō)此類技術(shù)都成為OCR,OCR(Optical Character Recognition)技術(shù)是一種將圖像中的文字轉(zhuǎn)化為可編輯文本的技術(shù)。它可以通過(guò)計(jì)算機(jī)視覺(jué)和模式識(shí)別的方法來(lái)識(shí)別和提取圖像中的文字信息。根據(jù)調(diào)研使用的常用網(wǎng)絡(luò)框架有三種都可以作為車牌識(shí)別:
CRNN:最經(jīng)典的OCR模型了,采用CNN+RNN的網(wǎng)絡(luò)結(jié)構(gòu),提出CTC-Loss對(duì)齊算法解決不定長(zhǎng)序列對(duì)齊問(wèn)題;原始源碼是用于文字識(shí)別的,稍微改成車牌數(shù)據(jù)集,即可用于車牌識(shí)別了
LPRNet*:*相比經(jīng)典的CRNN模型,LPRNet 沒(méi)有采用RNN結(jié)構(gòu);是專門設(shè)計(jì)用于車牌識(shí)別的輕量級(jí)的模型,整個(gè)網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計(jì)高度輕量化,參數(shù)量?jī)H有0.48M
PlateNet:LPRNet網(wǎng)絡(luò)結(jié)構(gòu)中存在MaxPool3d等算子,在端上部署時(shí),會(huì)存在OP不支持等問(wèn)題,PlateNet模型去除MaxPool3d,改成使用MaxPool2d,保證模型可端上部署成功。
模型 | input-size | params(M) | GFLOPs |
---|---|---|---|
LPRNet | 94×24 | 0.48M | 0.147GFlops |
CRNN | 160×32 | 8.35M | 1.06GFlops |
PlateNet | 168×48 | 1.92M | 1.25GFlops |
?本項(xiàng)目采取的是LPRNet,這里簡(jiǎn)述一下LPRNet。
二、LPRNet
"LPRNet"是用于車牌識(shí)別(License Plate Recognition,LPR)的神經(jīng)網(wǎng)絡(luò)模型。主要設(shè)計(jì)出目標(biāo)就是針對(duì)檢測(cè)和識(shí)別車牌字符。 論文由Intel于2018年發(fā)表: LPRNet: License Plate Recognition via Deep Neural Networks,網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計(jì)追求高度輕量化,為了能夠方便在嵌入式設(shè)備使用,且識(shí)別率還不低完全夠用。LPRNet的特點(diǎn)有:
- End-to-End設(shè)計(jì):LPRNet是一個(gè)端到端的網(wǎng)絡(luò),可以直接從原始圖像中提取車牌信息,而無(wú)需手動(dòng)設(shè)計(jì)特征提取器。
- 針對(duì)性強(qiáng):LPRNet專門設(shè)計(jì)用于車牌識(shí)別任務(wù),因此在車牌識(shí)別任務(wù)上具有很強(qiáng)的性能。
- 多任務(wù)學(xué)習(xí):LPRNet通常包括字符分類任務(wù)和位置回歸任務(wù)。字符分類任務(wù)用于識(shí)別車牌上的每個(gè)字符,位置回歸任務(wù)用于定位車牌的位置。
- 卷積神經(jīng)網(wǎng)絡(luò):LPRNet通常使用卷積神經(jīng)網(wǎng)絡(luò)來(lái)提取特征,這使得它對(duì)圖像的空間信息進(jìn)行了很好的利用。
- 采用了特定的損失函數(shù):LPRNet通常會(huì)使用CTC(Connectionist Temporal Classification)損失函數(shù)來(lái)處理字符級(jí)別的識(shí)別,這是一種適用于序列標(biāo)注任務(wù)的損失函數(shù)。
Intel論文中設(shè)計(jì)了一個(gè)圖像預(yù)處理網(wǎng)絡(luò),將車牌圖像進(jìn)行變換(如偏移、旋轉(zhuǎn)車牌圖片),得到合適的車牌圖片輸入到CNN中,論文使用的是LocNet網(wǎng)絡(luò)自動(dòng)學(xué)習(xí)最佳的轉(zhuǎn)換參數(shù)。LocNet模型結(jié)構(gòu)如下:
?其中LPRNet的backbone模塊是自行設(shè)計(jì)的一個(gè)輕量化的backbone,其中設(shè)計(jì)的一個(gè)Small basic block其實(shí)就是一個(gè)瓶頸型的結(jié)構(gòu)。
Small basic block結(jié)構(gòu)如下:
先經(jīng)過(guò)第一個(gè)1x1卷積進(jìn)行降維,再用一個(gè)3x1和一個(gè)1x3卷積進(jìn)行特征提取,最后再用1個(gè)1x1卷積進(jìn)行升維。不對(duì)稱卷積可以代替對(duì)稱矩陣,3x1+1x3產(chǎn)生和3x3一樣的效果,參數(shù)量還更少了,而且還多了一個(gè)ReLU激活函數(shù),增加了非線性。
class small_basic_block(nn.Module):def __init__(self, ch_in, ch_out):super(small_basic_block, self).__init__()self.block = nn.Sequential(nn.Conv2d(ch_in, ch_out // 4, kernel_size=1),nn.ReLU(),nn.Conv2d(ch_out // 4, ch_out // 4, kernel_size=(3, 1), padding=(1, 0)),nn.ReLU(),nn.Conv2d(ch_out // 4, ch_out // 4, kernel_size=(1, 3), padding=(0, 1)),nn.ReLU(),nn.Conv2d(ch_out // 4, ch_out, kernel_size=1),)def forward(self, x):return self.block(x)
?backbone的整體架構(gòu):
self.backbone = nn.Sequential(nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1), # 0nn.BatchNorm2d(num_features=64),nn.ReLU(), # 2nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(1, 1, 1)),small_basic_block(ch_in=64, ch_out=128), # *** 4 ***nn.BatchNorm2d(num_features=128),nn.ReLU(), # 6nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(2, 1, 2)),small_basic_block(ch_in=64, ch_out=256), # 8nn.BatchNorm2d(num_features=256),nn.ReLU(), # 10small_basic_block(ch_in=256, ch_out=256), # *** 11 ***nn.BatchNorm2d(num_features=256), # 12nn.ReLU(),nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(4, 1, 2)), # 14nn.Dropout(dropout_rate),nn.Conv2d(in_channels=64, out_channels=256, kernel_size=(1, 4), stride=1), # 16nn.BatchNorm2d(num_features=256),nn.ReLU(), # 18nn.Dropout(dropout_rate),nn.Conv2d(in_channels=256, out_channels=class_num, kernel_size=(13, 1), stride=1), # 20nn.BatchNorm2d(num_features=class_num),nn.ReLU(), # *** 22 ***)
唯一需要注意的是:最后一層conv用的是一個(gè)13x1的卷積代替了原先的BiLSTM來(lái)結(jié)合序列方向(W方向)的上下文信息。全局上下文嵌入,這部分論文是使用一個(gè)全連接層提取上下文信息的,只融合了兩層,而這里是使用的avg pool層,而且還在4個(gè)尺度上進(jìn)行了融合:
global_context = list()for i, f in enumerate(keep_features):if i in [0, 1]:f = nn.AvgPool2d(kernel_size=5, stride=5)(f)if i in [2]:f = nn.AvgPool2d(kernel_size=(4, 10), stride=(4, 2))(f)f_pow = torch.pow(f, 2)f_mean = torch.mean(f_pow)f = torch.div(f, f_mean)global_context.append(f)x = torch.cat(global_context, 1)
不用再自己從新搭一遍神經(jīng)網(wǎng)絡(luò),比較麻煩, 我這里利用大佬的開(kāi)源網(wǎng)絡(luò)模型:GitHub - Fanstuck/LPRNet_Pytorch: Pytorch Implementation For LPRNet, A High Performance And Lightweight License Plate Recognition Framework.
作者:完全適用于中國(guó)車牌識(shí)別(Chinese License Plate Recognition)及國(guó)外車牌識(shí)別!
目前僅支持同時(shí)識(shí)別藍(lán)牌和綠牌即新能源車牌等中國(guó)車牌,但可通過(guò)擴(kuò)展訓(xùn)練數(shù)據(jù)或微調(diào)支持其他類型車牌及提高識(shí)別準(zhǔn)確率!
將該模型集成到我們項(xiàng)目,
那么接下來(lái)我們需要對(duì)裁剪的數(shù)據(jù)集進(jìn)行訓(xùn)練得到模型權(quán)重即可。有幾點(diǎn)需要注意:
-
準(zhǔn)備數(shù)據(jù)集,圖像大小必須為94x24。
-
若要顯示測(cè)試結(jié)果,請(qǐng)?zhí)砑印?-show true”或“--show 1”以運(yùn)行命令。
其他都挺好看清楚的,看作者提供的主要參數(shù)說(shuō)明:
-
-max_epoch:如果想要精度更高一點(diǎn),epoch可以設(shè)定更高一點(diǎn)。
-
-dropout_rate:假設(shè) Dropout rate 為 0.5,即隱藏層中 50% 的神經(jīng)元將在每次訓(xùn)練迭中被隨機(jī)關(guān)閉。防止過(guò)擬合,如果圖片量過(guò)少的情況下需要高一點(diǎn)更好。
-
-learning_rate:要是算力充足可以調(diào)小一點(diǎn)更加精確。
-
train_batch_size和test_batch_size的默認(rèn)就行,如果數(shù)據(jù)集較小不用太大。
-
resume_epoch重復(fù)訓(xùn)練,數(shù)據(jù)集小的可以,數(shù)據(jù)量大的沒(méi)有必要。
訓(xùn)練模型
根據(jù)自己的數(shù)據(jù)集以及硬件條件設(shè)置train_LPRNet.py的超參數(shù),這里得注意我們需要利用YOLOv7檢測(cè)出來(lái)的定位信息去裁剪原圖像的車牌坐標(biāo),裁剪到的圖片需要轉(zhuǎn)換為94,24的img_size的圖片才能訓(xùn)練。之前我們有過(guò)準(zhǔn)備數(shù)據(jù)集,直接使用即可。
數(shù)據(jù)集足夠大,訓(xùn)練時(shí)長(zhǎng)給的足夠多可以達(dá)到比較高的精度,我根據(jù)自己制作的數(shù)據(jù)集訓(xùn)練可以達(dá)到93.1%的正確率,該模型權(quán)重已經(jīng)上傳github大家不用再次訓(xùn)練了直接使用模型即可。
推理
開(kāi)源的模型權(quán)重能夠在我分割的數(shù)據(jù)集上面跑到73.2%準(zhǔn)確率,我們可以使用預(yù)訓(xùn)練模型在此基礎(chǔ)之上訓(xùn)練得到準(zhǔn)確度更高的模型,利用上述模型我們可以進(jìn)行車牌檢測(cè)看看效果:
測(cè)試了20張圖片達(dá)到50%,測(cè)試1000張圖片達(dá)到92.3%,測(cè)試6000張圖片達(dá)到了93.5%準(zhǔn)確率,效果還是可以的。
?
備注
有問(wèn)題的私信博主或者直接評(píng)論就可以了博主會(huì)長(zhǎng)期維護(hù)此開(kāi)源項(xiàng)目,目前此項(xiàng)目運(yùn)行需要多部操作比較繁瑣,我將不斷更新版本優(yōu)化,下一版本將加入U(xiǎn)I以及一鍵部署環(huán)境和添加sh指令一鍵運(yùn)行項(xiàng)目代碼。下篇文章將詳細(xì)解讀LPRNet模型如何進(jìn)行OCR識(shí)別, 再次希望對(duì)大家有幫助不吝點(diǎn)亮star~:
https://github.com/Fanstuck/Yolov7-LPRNethttps://github.com/Fanstuck/Yolov7-LPRNet