python不同曲线设置标签_【图像分类】基于Pascal VOC2012增强数据的多标签图像分类实战...
接著上一次的多標簽分類綜述,本文主要以Pascal VOC2012增強數(shù)據(jù)集進行多標簽圖像分類訓(xùn)練,詳細介紹增強數(shù)據(jù)集制作、訓(xùn)練以及指標計算過程,并通過代碼進行詳細闡述,希望能為大家提供一定的幫助!
作者&編輯 | 郭冰洋
上一期多標簽圖像分類文章,也是本文的基礎(chǔ),點擊可以閱讀:【技術(shù)綜述】多標簽圖像分類綜述
1 簡介
基于image-level的弱監(jiān)督圖像語義分割大多數(shù)以傳統(tǒng)分類網(wǎng)絡(luò)作為基礎(chǔ),從分類網(wǎng)絡(luò)中提取物體的位置信息,作為初始標注。
Pascal VOC2012的原始分割數(shù)據(jù)集僅包含1464個train圖片和1449張val圖片(共2913張),對于分類網(wǎng)絡(luò)來說其數(shù)據(jù)量過小。而benchmark_RELEASE分割數(shù)據(jù)集包括8498張train圖片和2857張val圖片(共11355張)。因此,許多論文中均選擇使用二者融合后的增強數(shù)據(jù)集。
近期在復(fù)現(xiàn)論文過程中發(fā)現(xiàn),使用增強數(shù)據(jù)集進行多標簽分類時,某些圖片缺少對應(yīng)的標記,需要對照原始Pascal VOC2012數(shù)據(jù)集的標注方法,重新獲取各類物體的標注信息,并完成多標簽分類任務(wù)以及相應(yīng)的指標評價。現(xiàn)將相關(guān)細節(jié)和部分代碼進行解讀,以幫助大家理解多標簽分類的流程和相關(guān)注意事項。
2 Pascal VOC2012數(shù)據(jù)集介紹
Pascal VOC2012數(shù)據(jù)集包括五個文件夾:
1、Annotation:存放xml格式的標注信息
2、JPEGImages:存放所有圖片,包括訓(xùn)練圖片和測試圖片
3、SegmentationClass:語義分割任務(wù)中用到的label圖片
4、SegmentationObject:實例分割任務(wù)用到的label圖片
5、ImageSets:存放每一種任務(wù)對應(yīng)的數(shù)據(jù),其又劃分為四個文件夾
(1) Action:存放人體動作的txt文件
(2) Layout:存放人體部位的txt文件
(3) Main:存放類別信息的txt文件
(4) Segmentation:存放分割訓(xùn)練的txt文件
本次實戰(zhàn)是關(guān)于圖片多標簽分類任務(wù)的介紹,因此主要關(guān)注的為Annotation文件夾和ImageSets下的Main文件夾。
Main文件夾中包含了20類物體的訓(xùn)練、驗證標簽文件,其命名格式為class_train.txt、class_trainval.txt或class_val.txt。其中,每個txt文件中均包含對應(yīng)的標記信息,若圖中存在對應(yīng)標簽,則為1,反之則為-1
3 benchmark_RELEAS數(shù)據(jù)集介紹
benchmark_RELEASE數(shù)據(jù)集包括兩個文件夾:
1、benchmark_code_RELEASE:相關(guān)評價指標的matlab文件
2、dataset:包括cls、img、inst三個文件夾和train.txt、val.txt兩個文件
(1) cls:語義分割的mat標注文件
(2) img:分割圖像
(3) inst:實例分割的mat標注文件
mat格式為matlab文件的一種,其中文件中主要包含了物體的類別、邊界、分割標注三類信息。
4 增強數(shù)據(jù)集介紹
所謂增強數(shù)據(jù)集,共包含兩個步驟:
1、將上述兩個數(shù)據(jù)集中的語義分割訓(xùn)練數(shù)據(jù)進行融合并剔除重復(fù)部分。即將"/benchmark_RELEASE/dataset/"路徑下的train和val文件與"/ImageSets/Segmentation/"路徑下的train和val文件進行融合,獲取最終的train.txt和val.txt文件,共12031個數(shù)據(jù)(8829+3202)。代碼及注釋如下(為了清晰展示步驟,將函數(shù)拆分,直接進行了書寫):
import os
from os.path import join as pjoin
import collectionsimport numpy as np
# PascalVOC2012路徑
voc_path = '/VOC/VOCdevkit/VOC2012/'
# benchmark_RELEASE路徑
sbd_path = '/VOC/benchmark_RELEASE/'
# 構(gòu)建內(nèi)置字典,用于存放train、val、trainval數(shù)據(jù)
files = collections.defaultdict(list)
# 填充files
for split in ["train", "val", "trainval"]: ? ?
# 獲取原始txt文件 ? ?
????? path = pjoin(voc_path,?
? ? ? "ImageSets/Segmentation", split + ".txt")?
? ? # 以元組形式打開文件? ? ?
? ? ? file_list = tuple(open(path, "r")) ? ?
? ? # rstrip清除換行符號/n,并構(gòu)成列表 ? ?
????? file_list = [id_.rstrip() for id_ in file_list] ? ?
? ? # 不同階段對應(yīng)不同列表 ? ?
? ? ? files[split] = file_list
# benchmark_RELEASE的train文件獲取
path = pjoin(sbd_path, "dataset/train.txt")
sbd_train_list = tuple(open(path, "r"))
sbd_train_list = [id_.rstrip() for id_ in sbd_train_list]
# benchmark_RELEASE與Pascal VOC2012訓(xùn)練數(shù)據(jù)融合
train_aug = files["train"] + sbd_train_list
# 清除重復(fù)數(shù)據(jù)
train_aug = [train_aug[i]?
for i in sorted(np.unique(train_aug,
return_index=True)[1])]
# 獲取最終train數(shù)據(jù)files["train_aug"] = train_aug
# benchmark_RELEASE的val文件獲取
path = pjoin(sbd_path, "dataset/val.txt")
sbd_val_list = tuple(open(path, "r"))
sbd_val_list = [id_.rstrip() for id_ in sbd_val_list]
# benchmark_RELEASE與Pascal VOC2012訓(xùn)練數(shù)據(jù)融合
val_aug = files["val"] + sbd_val_list
# 清除重復(fù)數(shù)據(jù)
val_aug = [val_aug[i]?
for i in sorted(np.unique(val_aug, return_index=True)[1])]
# 清除val中與train數(shù)據(jù)重復(fù)的內(nèi)容
set_diff = set(val_aug) - set(train_aug)
files["train_aug_val"] = list(set_diff)
2、將"/benchmark_RELEASE/dataset/cls"下mat格式的語義標簽解析成圖片,并與SegmentationClass文件夾下的圖片進行融合。此部分代碼可參考下述網(wǎng)址中的setup_annotation模塊。
https://github.com/meetshah1995/pytorchsemseg/blob/master/ptsemseg/loader/pascal_voc_loader.py
至此,增強數(shù)據(jù)集的train.txt、val.txt以及分割標注圖片均已獲得,可以愉快地用更大容量的數(shù)據(jù)集進行訓(xùn)練啦!
5 標簽文件制作
前一小節(jié)主要介紹了Pascal VOC2012數(shù)據(jù)集的文件夾構(gòu)成,在ImageSets/Main文件夾下包含了20類物體的標注文檔,包括train、val和trainval三種劃分。我們打開aeroplane_train.txt文檔可以看到,共有5717個訓(xùn)練數(shù)據(jù),每個圖像名稱后面均對應(yīng)了1或者-1,其中1表示圖片中存在該類別的物體,-1則表示圖片中不存在該類別的物體。增強數(shù)據(jù)集的train.txt和val.txt文件并沒有各類別的標注信息,因此,我們需要仿照原有的格式,構(gòu)建每個類別的標注文檔。
Annotation文件夾下包含了所有圖片標注信息的xml格式文件,其中子項目下代表途中的類別信息。打開其中的一個xml文件我們可以看到,一個圖中包含了多個類別信息,其中還有重復(fù)項,即圖中存在相同類別的物體。我的思路是遍歷train.txt和val.txt文檔中每個圖片對應(yīng)的xml文件,獲取其中的類別信息,然后判定類別信息是否包含當前類別,若包含則賦值1,反之賦值-1。對20個類別進行循環(huán)后,即可獲得相應(yīng)的標注文檔。
接下來我將以訓(xùn)練標注文檔的制作為展示,拆分步驟并結(jié)合代碼進行詳細的描述。
步驟1:讀取train.txt文件獲取訓(xùn)練圖片
# 獲取訓(xùn)練txt文件
def _GetImageSet(): ? ?
????????# txt路徑 ??
????????image_set_path = '/train.txt' ? ?
????????with open(image_set_path, 'r') as f: ? ? ? ?
? ? ? ? ? ? return [line.split()[0]?for line in f.readlines()]
# 訓(xùn)練圖片合集
img_set = _GetImageSet()
步驟2:讀取對應(yīng)的xml文件
# xml標注文件路徑?
annotation='/VOC/VOCdevkit/VOC2012/Annotations'?
# 構(gòu)建xml列表?
xml = []?
for img in img_set: ? ?
????????xml_path = os.path.join(annotation,img + '.xml') ??
????????xml.append(xml_path)
步驟3:根據(jù)xml中的項,判定圖片中是否存在該類別。讀取項之后,一定通過set()函數(shù),清除其中的重復(fù)類別名稱,否則會出現(xiàn)標簽重復(fù)的情況
# 類別?
VOC_CLASSES = ['aeroplane', 'bicycle', 'bird', 'boat','bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse','motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']?
for x in xml: ? ?
? ? # 獲取每個name的地址? ? ?
? ? elem_list = minidom.parse(x).
??????????????????????getElementsByTagName('name')
? ? name = []? ??
? ? # 讀取每個地址的內(nèi)容 ? ?
? ? ?for elem in elem_list: ? ? ? ??
????????????????cat_name = elem.firstChild.data ? ? ? ??
????????????????# 獲取name ? ? ? ??
????????????????name.append(cat_name) ? ?
????????# 刪除重復(fù)標記 ? ?
????????name = list(set(name)) ? ?
????????# 根據(jù)類別寫入標簽文件 ? ?
????????for cls in VOC_CLASSES: ? ? ? ?
????????????????txt = '/gt/%s_train.txt' % cls ? ? ? ?
????????????????if cls in name: ? ? ? ? ? ?
????????????????????????file_write_obj = open(txt, 'a') ? ? ? ? ? ?
????????????????????????gt = x[-15:-4] + ' ' +' '+ '1' ? ? ? ? ? ?
????????????????????????file_write_obj.writelines(gt) ? ? ? ? ? ?
????????????????????????file_write_obj.write('\n') ? ? ? ?
????????????????else: ? ? ? ? ? ?
????????????????????????file_write_obj = open(txt, 'a') ? ? ? ? ? ?
????????????????????????gt = x[-15:-4] + ' ' ?+ '-1' ? ? ? ? ? ?
????????????????????????file_write_obj.writelines(gt) ? ? ? ? ??
????????????????????????file_write_obj.write('\n')
通過以上三個步驟,就可以生成train.txt在20個類別下的標注文檔。標簽文件的制作是為了后續(xù)計算相應(yīng)的評價指標,以更好的評價分類網(wǎng)絡(luò)的性能。
6 增強數(shù)據(jù)集多標簽文件制作
根據(jù)標簽文件的制作,我們已經(jīng)獲取圖片在每個類別下對應(yīng)標簽,如何將其轉(zhuǎn)化成對應(yīng)的矩陣形式,是我們的下一步工作。
在多標簽分類任務(wù)中,我們可以構(gòu)建一個1x20的矩陣作為圖片的標簽,其中對應(yīng)的類別若存在,則置1,反之則置0。例如,如果圖片中含有aeroplane和bicycle兩個類別,其對應(yīng)的標簽矩陣應(yīng)該為[1,1,......,0,0]。同樣的,我們?nèi)匀豢梢愿鶕?jù)xml文件信息,進行矩陣的搭建。
在本節(jié)中,我仍將通過步驟拆分,結(jié)合代碼展示這一過程。
準備工作:設(shè)置文件夾名稱,類別信息名稱及其對應(yīng)的數(shù)字
# 圖片文件夾?
IMG_FOLDER_NAME = "JPEGImages"?
# 標簽文件夾?
ANNOT_FOLDER_NAME = "Annotations"?
# 標簽名稱(不含背景)?
CAT_LIST = ['aeroplane', 'bicycle', 'bird', 'boat','bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse','motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']?
# 標簽轉(zhuǎn)換為數(shù)字?
CAT_NAME_TO_NUM = /
????dict(zip(CAT_LIST,range(len(CAT_LIST))))
步驟1:構(gòu)建單張圖片對應(yīng)的標簽矩陣
# 從xml文件中讀取圖片標簽?
def load_image_label_from_xml(img, voc12_root): ? ?
????????# 獲取xml中的name項? ? ??
????????el_list=minidom.parse(os.path.join(voc12_root,
? ? ? ? ANNOT_FOLDER_NAME,img + '.xml'))
????? ? .getElementsByTagName('name')? ??
????????# 構(gòu)建標簽空矩陣 ? ?
????????multi_cls_lab = np.zeros((20), np.float32) ??
????????# 對xml中的name項進行操作 ? ?
????????for el in el_list: ? ? ? ?
????????????????# 讀取name ? ? ? ?
????????????????cat_name = el.firstChild.data ? ? ? ?
????????????????if cat_name in CAT_LIST: ? ? ? ? ??
????????????????# 轉(zhuǎn)換為數(shù)字標簽 ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? cat_num =/
????????????????????????CAT_NAME_TO_NUM[cat_name] ? ? ? ? ? ?
????????????????????????# 將標簽矩陣中對應(yīng)的位置賦1 ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? multi_cls_lab[cat_num] = 1.0 ? ?
????????# 返回標簽矩陣 ? ?
????????return multi_cls_lab
步驟2:遍歷所有的圖片,生成對應(yīng)的標簽矩陣
# 從.txt文件中載入所有xml文件對應(yīng)的標簽?
def load_image_label_list_from_xml(img_name_list, voc12_root): ? ?
? ? ? ? # 返回所有標簽矩陣 ? ?
? ? ? ?return [load_image_label_from_xml(img_name, voc12_root) for img_name in img_name_list]
步驟3:生成含有所有標簽矩陣的npy文件
# 加載圖片list?
def load_img_name_list(dataset_path): ? ?
????????# 獲取.txt文件中的圖片(含png和jpg,以及路徑文件)??
????????img_gt_name_list = /
????????????open(dataset_path).read().splitlines() ? ?
????????# 讀取圖片名字 ? ?
????????img_name_list = /
??????? [img_gt_name.split(' ')[0][-15:-4]?
????????for img_gt_name in img_gt_name_list]? ? ?
????????# 返回值 ??
????????return img_name_list?
# 獲取訓(xùn)練圖片列表?
img_name_list = load_img_name_list(args.train_list)?
# 獲取標簽列表?
label_list=load_image_label_list_from_xml(img_name_list,args.voc12_root)?
# 通過字典保存圖片及其對應(yīng)的標簽?
d = dict()?
for img, lbl in zip(img_name_list, label_list):? ??
????d[img_name] = label?
# 保存文件?
np.save(args.out, d)
至此,所有的標簽矩陣便構(gòu)建完成了。
7 評價指標計算
多標簽圖像分類網(wǎng)絡(luò)的性能需要根據(jù)平均準確率精度(mAP)來進行分析,而平均精度準確率均值需要先對每個類別的平均準確率進行計算。
根據(jù)分類網(wǎng)絡(luò)我們可以得到圖像在每個類別下對應(yīng)的預(yù)測得分,其具體形式如下:
results =?
{‘a(chǎn)eroplane’:{‘2007_000032’:[0.7,0.8,......0.9],
????????????????????????......
????????????????????????'2011_003276':[1.2,0.8,......0.3]}
????......
? 'tvmonitor':{‘2007_000032’:[0.1,-0.8,......0.2],
????????????????????????......
????????????????????????'2011_003276':[1.1,0.4,......0.8]}}
隨后我們載入每個圖像對應(yīng)的類別標簽,具體形式如下:
ground_truth =?
{‘a(chǎn)eroplane’:{‘2007_000032’:[0,1,......0],
????????????????????????......
????????????????????????'2011_003276':[1,0,......1]}
????......
? 'tvmonitor':{‘2007_000032’:[1,0,......0],
????????????????????????......
????????????????????????'2011_003276':[1,0,......1]}}
通過上述兩個集合,我們可以分別計算每個類別的平均準確率,計算平均準確率的方法Pascal VOC官方已經(jīng)給出,可以參照具體標準進行計算。具體代碼如下:
# 每個類別的計算
def EvaluateClass(self, cls, cls_results):
? ?# 獲取訓(xùn)練總數(shù)
? ?num_examples = len(self.image_set)
? ?# 構(gòu)建gts
? ?gts = np.ones(num_examples) * (-np.inf)
? ?# 構(gòu)建gts矩陣
? ?for i, image_id in enumerate(self.image_set):
? ? ? ?gts[i] = self.ground_truths[cls][image_id]
? ?# 構(gòu)建對應(yīng)的confidences矩陣
? ?confidences = np.ones(len(gts)) * (-np.inf)
? ?for i, image_id in enumerate(self.image_set):
? ? ? ?confidences[i] = cls_results[image_id]
? ?# 序號選擇
? ?sorted_index = np.argsort(confidences)[::-1]
? ?# 相應(yīng)評價指標獲取
? ?true_positives = gts[sorted_index] > 0
? ?false_positives = gts[sorted_index] < 0
? ?true_positives = np.cumsum(true_positives)
? ?false_positives = np.cumsum(false_positives)
? ?recalls = true_positives / np.sum(gts > 0)
? ?eps = 1e-10
? ?positives = false_positives + true_positives
? ?precisions = true_positives / (positives + (positives == 0.0) * eps)
? ?# 計算平均準確率
? ?average_precision = 0
? ?# 根據(jù)Pascal VOC官方計算方法計算
? ?for threshold in np.arange(0, 1.1, 0.1):
? ? ? ?precisions_at_recall_threshold = precisions[recalls >= threshold]
? ? ? ?if precisions_at_recall_threshold.size > 0:
? ? ? ? ? ?max_precision = np.max(precisions_at_recall_threshold)
? ? ? ?else:
? ? ? ? ? ?max_precision = 0
? ? ? ?average_precision = average_precision + max_precision / 11;
? ?return average_precision, list(precisions), list(recalls)
計算出每個類別的平均準確率后,則對所有類別的平均準確率求均值即可求得mAP值,在python代碼中可以直接使用mean函數(shù)實現(xiàn)。
8 訓(xùn)練細節(jié)
在進行訓(xùn)練前需要注意一點,數(shù)據(jù)讀取時我們需要同時獲取圖片名字、圖片、標簽三個信息,也是為了后續(xù)的評價指標計算做基礎(chǔ),這一點與傳統(tǒng)單標簽分類只讀取圖片和標簽的方法不同,需要格外注意。讀取數(shù)據(jù)集的代碼在此不再拆分詳細解釋。
本文以Pytorch框架進行編寫,進行了兩種策略的訓(xùn)練方式。
1、選擇ModelA1作為訓(xùn)練網(wǎng)絡(luò)(即resnet38),并使用對應(yīng)的預(yù)訓(xùn)練數(shù)據(jù),同時將全連接層轉(zhuǎn)換為卷積層,學(xué)習(xí)率設(shè)置為0.01,batch_size為4,損失函數(shù)選用hanming loss,采用SGD優(yōu)化,在AMD 2600X + GTX 1070Ti搭建的平臺,訓(xùn)練了約30個小時。
2、選擇Resnet50作為訓(xùn)練網(wǎng)絡(luò),同時將全連接層轉(zhuǎn)換為卷積層,學(xué)習(xí)率設(shè)置為0.01,batch_size為16,損失函數(shù)選用hanming loss,采用SGD優(yōu)化,在AMD 2600X + GTX 1070Ti搭建的平臺,訓(xùn)練了約2個小時。
9 結(jié)果分析
通過訓(xùn)練我們發(fā)現(xiàn),ModelA1取得的最優(yōu)準確率為91.8%,Resnet50取得的最優(yōu)準確率為90.3%,故此次結(jié)果分析暫時以ModelA1為準。
1、平均準確率均值(mAP)
2、各類別平均準確率曲線
3、每個類別的最高準確率
總結(jié)
以上就是整個多標簽圖像分類實戰(zhàn)的過程,由于時間限制,本次實戰(zhàn)并沒有進行詳細的調(diào)參工作,因此準確率還有一定的提升空間。
有三AI夏季劃
有三AI夏季劃進行中,歡迎了解并加入,系統(tǒng)性成長為中級CV算法工程師。
轉(zhuǎn)載文章請后臺聯(lián)系
侵權(quán)必究
往期精選
【技術(shù)綜述】多標簽圖像分類綜述
【技術(shù)綜述】你真的了解圖像分類嗎?
【AI-1000問】為什么深度學(xué)習(xí)圖像分類的輸入多是224*224
總結(jié)
以上是生活随笔為你收集整理的python不同曲线设置标签_【图像分类】基于Pascal VOC2012增强数据的多标签图像分类实战...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: InCDsrv.exe是什么进程 作用是
- 下一篇: IncMail.exe进程是什么文件 作