『森林火灾检测』基于PaddleX实现森林火灾检测
效果預(yù)覽
B站鏈接
AIStudio鏈接
項(xiàng)目背景
??2019年3月30日17時(shí) ,涼山州木里縣境內(nèi)發(fā)生森林火災(zāi),30名撲火人員犧牲。
??2020年3月30日15時(shí)35分,涼山州西昌市經(jīng)久鄉(xiāng)和安哈鎮(zhèn)交界的皮家山山脊處發(fā)生森林火災(zāi),參與火災(zāi)撲救的19人犧牲、3人受傷。這起森林火災(zāi)造成各類土地過(guò)火總面積3047.7805公頃,綜合計(jì)算受害森林面積791.6公頃,直接經(jīng)濟(jì)損失9731.12萬(wàn)元。
??2020年4月14日17時(shí)35分,西藏自治區(qū)林芝市巴宜區(qū)尼西村附近發(fā)生森林火災(zāi),3000余人歷時(shí)4晝夜持續(xù)撲救,明火于4月18日17時(shí)全部撲滅。此次撲救,共撲打火線13公里,清理煙點(diǎn)4200余處、站桿倒木3900余根,開(kāi)設(shè)防火隔離帶3.5公里,實(shí)施了兩次人工增雨。
??2021年3月13日12時(shí)許,寧夏固原市原州區(qū)張易鎮(zhèn)馬場(chǎng)村二林溝荒山起火,撲火過(guò)程中造成2人死亡,6人受傷。火場(chǎng)共有3處著火點(diǎn),在3個(gè)不同山頭,過(guò)火面積500余畝。
??2021年3月14日13時(shí)許,云南省昆明市盤(pán)龍區(qū)茨壩街道與龍泉街道交界處三丘田附近發(fā)生森林火災(zāi)。火情發(fā)生后,昆明市森林消防支隊(duì)249名指戰(zhàn)員迅速趕往現(xiàn)場(chǎng)處置,地方撲救力量(地方專業(yè)撲火隊(duì)員256人、半專業(yè)撲火隊(duì)員160人、干部群眾155人)緊密配合撲救。
??1950年以來(lái),中國(guó)年均發(fā)生森林火災(zāi)13067起,受害林地面積653019公頃,因?yàn)?zāi)傷亡580人。其中1988年以前,全國(guó)年均發(fā)生森林火災(zāi)15932起,受害林地面積947238公頃,因?yàn)?zāi)傷亡788人(其中受傷678人,死亡110人)。1988年以后,全國(guó)年均發(fā)生森林火災(zāi)7623起,受害林地面積94002公頃,因?yàn)?zāi)傷亡196人(其中受傷142人,死亡54人),分別下降52.2%、90.1%和75.3%。
??森林火災(zāi)由于在野外,人煙稀少,故而難以在初始階段就發(fā)現(xiàn)并及時(shí)撲滅,更大程度上只有當(dāng)火情演變?yōu)檩^大規(guī)模后,才能夠被發(fā)現(xiàn)并撲救,而這時(shí),撲救難度及損失程度已呈指數(shù)級(jí)上升。而如何在野外這樣的惡劣環(huán)境下及時(shí)捕捉火情并通報(bào)是人工智能時(shí)代下防火滅火的新命題。
??本項(xiàng)目基于PaddleX,選取PPYOLO進(jìn)行項(xiàng)目開(kāi)發(fā),并實(shí)現(xiàn)了windows端的部署,后期將結(jié)合PaddleSlim裁剪模型大小以及PaddleLite部署于樹(shù)莓派上。
實(shí)地操作
1. 數(shù)據(jù)處理
2. 模型訓(xùn)練
3. 模型導(dǎo)出
數(shù)據(jù)處理
#解壓數(shù)據(jù)集并將其移動(dòng)至dataset中 !tar -xf /home/aistudio/data/data90352/fire_detection.tar !mv VOC2020 dataset數(shù)據(jù)處理
??在本數(shù)據(jù)集中,由于文件名及文件內(nèi)容不符合PaddleX所提供的數(shù)據(jù)集讀取API,故需要對(duì)其進(jìn)行處理。觀察數(shù)據(jù)集可知,有兩個(gè)問(wèn)題:一為標(biāo)注文件的文件名中存在空格,這極大地影響了PaddleX數(shù)據(jù)集讀取;二為標(biāo)注文件中的內(nèi)容需要進(jìn)行對(duì)應(yīng)性修改。
# 修改.xml文件名,去掉文件名中的空格 # -*- coding: utf-8 -*- import os #設(shè)定文件路徑 jpg_path='dataset/JPEGImages/' anno_path = 'dataset/Annotations/' i=1 #對(duì)目錄下的文件進(jìn)行遍歷 for file in os.listdir(jpg_path): #判斷是否是文件if os.path.isfile(os.path.join(jpg_path,file))==True: #設(shè)置新文件名main = file.split('.')[0]if " " in main:new_main = main.replace(' ','')new_main_jpg = new_main + '.jpg'new_main_anno = new_main + '.xml'print(os.path.join(jpg_path,new_main_jpg))print(os.path.join(anno_path,new_main_anno))# new_name=file.replace(file,"rgb_%d.jpg"%i) # #重命名os.rename(os.path.join(jpg_path,main+'.jpg'),os.path.join(jpg_path,new_main_jpg))os.rename(os.path.join(anno_path,main+'.xml'),os.path.join(anno_path,new_main_anno))i+=1 #結(jié)束 print ("End") # 這里修改.xml文件中的<path>元素 !mkdir dataset/Annotations1 import xml.dom.minidom import ospath = r'dataset/Annotations' # xml文件存放路徑 sv_path = r'dataset/Annotations1' # 修改后的xml文件存放路徑 files = os.listdir(path) cnt = 1for xmlFile in files:dom = xml.dom.minidom.parse(os.path.join(path, xmlFile)) # 打開(kāi)xml文件,送到dom解析root = dom.documentElement # 得到文檔元素對(duì)象item = root.getElementsByTagName('path') # 獲取path這一node名字及相關(guān)屬性值for i in item:i.firstChild.data = '/home/aistudio/dataset/JPEGImages/' + str(cnt).zfill(6) + '.jpg' # xml文件對(duì)應(yīng)的圖片路徑with open(os.path.join(sv_path, xmlFile), 'w') as fh:dom.writexml(fh)cnt += 1 # 這里修改.xml文件中的<failname>元素 !mkdir dataset/Annotations2 import xml.dom.minidom import ospath = r'dataset/Annotations1' # xml文件存放路徑 sv_path = r'dataset/Annotations2' # 修改后的xml文件存放路徑 files = os.listdir(path)for xmlFile in files:dom = xml.dom.minidom.parse(os.path.join(path, xmlFile)) # 打開(kāi)xml文件,送到dom解析root = dom.documentElement # 得到文檔元素對(duì)象names = root.getElementsByTagName('filename')a, b = os.path.splitext(xmlFile) # 分離出文件名afor n in names:n.firstChild.data = a + '.jpg'with open(os.path.join(sv_path, xmlFile), 'w') as fh:dom.writexml(fh)下面刪除在數(shù)據(jù)集處理過(guò)程中所生成的冗余文件,并將其更改為適合PaddleX的數(shù)據(jù)集格式。
!rm -rf dataset/Annotations !rm -rf dataset/Annotations1 !mv dataset/Annotations2 dataset/Annotations??PaddleX非常貼心地為開(kāi)發(fā)者準(zhǔn)備了數(shù)據(jù)集劃分工具,免去了開(kāi)發(fā)者多寫(xiě)幾行代碼的需求。這里我們?cè)O(shè)置訓(xùn)練集、驗(yàn)證集、測(cè)試集劃分比例為7:2:1。
!paddlex --split_dataset --format VOC --dataset_dir /home/aistudio/dataset/ --val_value 0.2 --test_value 0.1模型訓(xùn)練
??在使用PaddleX進(jìn)行模型訓(xùn)練的過(guò)程中,我們使用目前PaddleX適配精度最高的PPYolo模型進(jìn)行訓(xùn)練。其模型較大,預(yù)測(cè)速度比YOLOv3-DarkNet53更快,適用于服務(wù)端。大家也可以更改其他模型嘗試一下。這里我訓(xùn)練了大概200個(gè)epoch(別問(wèn),問(wèn)就是沒(méi)算力了也懶得續(xù)點(diǎn)了……)當(dāng)然看趨勢(shì)還能漲!(有算力的童鞋可以試著調(diào)參或者繼續(xù)往下面去試試)
import os os.environ['CUDA_VISIBLE_DEVICES'] = '0'from paddlex.det import transforms import paddlex as pdx# 定義訓(xùn)練和驗(yàn)證時(shí)的transforms # API說(shuō)明 https://paddlex.readthedocs.io/zh_CN/develop/apis/transforms/det_transforms.html train_transforms = transforms.Compose([transforms.MixupImage(mixup_epoch=250), transforms.RandomDistort(),transforms.RandomExpand(), transforms.RandomCrop(), transforms.Resize(target_size=608, interp='RANDOM'), transforms.RandomHorizontalFlip(),transforms.Normalize() ])eval_transforms = transforms.Compose([transforms.Resize(target_size=608, interp='CUBIC'), transforms.Normalize() ])# 定義訓(xùn)練和驗(yàn)證所用的數(shù)據(jù)集 # API說(shuō)明:https://paddlex.readthedocs.io/zh_CN/develop/apis/datasets.html#paddlex-datasets-vocdetection train_dataset = pdx.datasets.VOCDetection(data_dir='/home/aistudio/dataset',file_list='/home/aistudio/dataset/train_list.txt',label_list='/home/aistudio/dataset/labels.txt',transforms=train_transforms,parallel_method='thread',shuffle=True) eval_dataset = pdx.datasets.VOCDetection(data_dir='/home/aistudio/dataset',file_list='/home/aistudio/dataset/val_list.txt',label_list='/home/aistudio/dataset/labels.txt',parallel_method='thread',transforms=eval_transforms)# 初始化模型,并進(jìn)行訓(xùn)練 # 可使用VisualDL查看訓(xùn)練指標(biāo),參考https://paddlex.readthedocs.io/zh_CN/develop/train/visualdl.html num_classes = len(train_dataset.labels)# API說(shuō)明: https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#paddlex-det-ppyolo model = pdx.det.PPYOLO(num_classes=num_classes)# API說(shuō)明: https://paddlex.readthedocs.io/zh_CN/develop/apis/models/detection.html#train # 各參數(shù)介紹與調(diào)整說(shuō)明:https://paddlex.readthedocs.io/zh_CN/develop/appendix/parameters.html model.train(num_epochs=540,train_dataset=train_dataset,train_batch_size=8,eval_dataset=eval_dataset,learning_rate=0.000125,save_interval_epochs=1,lr_decay_epochs=[270,320, 480],save_dir='output/ppyolo',resume_checkpoint='/home/aistudio/output/ppyolo/epoch_197',use_vdl=True)模型導(dǎo)出
??這里我們將訓(xùn)練過(guò)程中保存的模型導(dǎo)出為inference格式模型,其原因在于:PaddlePaddle框架保存的權(quán)重文件分為兩種:支持前向推理和反向梯度的訓(xùn)練模型 和 只支持前向推理的推理模型。二者的區(qū)別是推理模型針對(duì)推理速度和顯存做了優(yōu)化,裁剪了一些只在訓(xùn)練過(guò)程中才需要的tensor,降低顯存占用,并進(jìn)行了一些類似層融合,kernel選擇的速度優(yōu)化。而導(dǎo)出的inference格式模型包括__model__、__params__和model.yml三個(gè)文件,分別表示模型的網(wǎng)絡(luò)結(jié)構(gòu)、模型權(quán)重和模型的配置文件(包括數(shù)據(jù)預(yù)處理參數(shù)等)。
!paddlex --export_inference --model_dir=output/ppyolo/best_model --save_dir=./inference_model模型部署
模型導(dǎo)出后我們可以采用Python端以視頻流的形式部署。
import cv2 import paddlex as pdx from playsound import playsound# 修改模型所在位置 predictor = pdx.deploy.Predictor('D:\\project\\python\\fire\\inference_model') cap = cv2.VideoCapture('D:\\project\\python\\fire\\mda-kcwgejj7mfckc19e.mp4')while cap.isOpened():ret, frame = cap.read()if ret:result = predictor.predict(frame)score = result[0]['score']if score >= 0.3:print("*"*100)# 修改音頻所在位置# playsound('D:\\project\\python\\cigarette\\cigarette.mp3')# print(result)vis_img = pdx.det.visualize(frame, result, threshold=0.3, save_dir=None)cv2.imshow('cigarette', vis_img)if cv2.waitKey(1) & 0xFF == ord('q'):breakelse:break cap.release()請(qǐng)點(diǎn)擊此處查看本環(huán)境基本用法.
Please click here for more detailed instructions.
總結(jié)
以上是生活随笔為你收集整理的『森林火灾检测』基于PaddleX实现森林火灾检测的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 『PPYOLO tiny尝鲜』基于Pad
- 下一篇: 百度AI达人创造营之创意的起源