19.目標檢測


本課程來自深度之眼deepshare.net,部分截圖來自課程視頻。

圖像目標檢測是什麼?

目標檢測:判斷圖像中目標的位置
目標檢測兩要素
1.分類:分類向量[p0,,pn][p_0,…,p_n]
2.迴歸:迴歸邊界框[x1y1x2y2][x_1,y_1,x_2,y_2]
下圖實例中,紅色框是邊界框,每個框上面有分類信息,以及分類的概率
在這裏插入圖片描述
這裏有個識別錯誤的,把手識別爲飛盤了,不過概率也很低,可以設置閾值把這些過濾掉
在這裏插入圖片描述
從代碼上看到,模型接收的參數是一個list,和之前的不一樣。

input_list=[img_chw]

輸出也是一個list,然後存到dict裏面

output_list=model(input_list)
output_dict=output_list[e]

然後從dict裏面讀取邊界框,類別,概率

out _boxes=output_dict["boxes"].cpu()
out_scores=output_dict["scores"].cpu() 
out_labels=output_dict["labels"].cpu()

邊界框打印出來是這個樣子。
在這裏插入圖片描述
可以看到,和之前講的一樣,每個框由兩個座標組成。
分類標籤的數字和COCO數據集中的標籤一致,1是人。
在這裏插入圖片描述
分類概率是降序排列的,以便我們設置閾值,過濾不需要顯示的邊界框。
在這裏插入圖片描述
這裏的fasterCNN模型是用COCO數據集訓練的,該數據集的label如下:

# classes_coco
COCO_INSTANCE_CATEGORY_NAMES = [
    '__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
    'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
    'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
    'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
    'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
    'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
    'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
    'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table',
    'N/A', 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
    'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
    'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]

看到person,人是1

模型是如何完成目標檢測的?

將3D張量映射到兩個張量
1.分類張量:shape爲[N,c+1],這裏N代表檢測出來多少個目標
2.邊界框張量:shape爲[N,4]
文獻:《Recent Advances in Deep Learning for Object Detection》-2019
在這裏插入圖片描述

確定邊界框數量N

傳統方法——滑動窗策略
祭出NG的DL的視頻截圖:
在這裏插入圖片描述
檢測窗口中是否出現要檢測的目標,由於窗口大小對於檢測的結果有影響,因此,通常會使用不同大小(不同長寬比)的滑動窗口進行檢測。
在這裏插入圖片描述
以上方法缺點:
1.重複計算量大,下面陰影部分就是重複計算的部分
在這裏插入圖片描述
2.窗口大小難確定
利用卷積減少重複計算:特徵圖一個像素對應原圖一塊區域
在這裏插入圖片描述
上面的圖中,上半部分是傳統的CNN,做的是4分類任務,所以得到的是114的結果。下半部分中,從6616到22400這個地方,用的是55的卷積核進行FC操作,最後得到的22* 4的結果,裏面的每一個114都可以對應到原始16163圖像中的4個滑動窗口(藍色部分,每個滑動窗口大小爲14* 143,slide爲2.)
下面是一個實例,原始圖像是28
283的,滑動窗口大小爲1414,slide爲2,每行滑動窗口數量爲:28142+1=8\frac{28-14}{2}+1=8,所以最後得到的結果是8*8大小的,每個像素對應一個滑動窗口,每個像素的長度是4(4分類),最後那個檢測到小汽車的滑動窗口是最後一行第三個窗口。
在這裏插入圖片描述

深度學習目標檢測模型簡介

在這裏插入圖片描述
文獻:《Object Detection in 20 Years-A Survey》-2019
從2014年爲界,之前用的傳統方法,之後從RCNN開始用的TWO STAGE、YOLO開始用的是ONE STAGE。
按流程分爲:one-stage和two-stage
文獻:《A Survey of Deep Learning-based Object Detection》-2019
在這裏插入圖片描述
在這裏插入圖片描述
可以看到two-stage比one-stage多了一個Proposal region。
下面看兩者的典型模型
在這裏插入圖片描述
YOLO中是對特徵圖進行操作的,劃分爲19*19的網格,網格每個區域如圖所示是對應到原始圖片的,最後對每一個網格進行分類和迴歸操作。

PyTorch中的Faster RCNN訓練

Faster RCNN結構分析

在這裏插入圖片描述
Faster RCNN先通過全卷積(CNN)操作(這個操作在原文中叫backbone,骨幹網絡)得到特徵圖,然後經過stage 1, RPN的推薦,在RPN模塊中其實會生成數10萬個候選框,Faster RCNN會通過非最大值抑制(NMS,上圖中沒畫出來)算法,對這數十萬個候選框進行篩選,得到2000個候選框(超參數,自己設置,test階段是1000),用這2000個候選框對特徵圖進行摳取,得到在這裏插入圖片描述然後經過ROI 層操作得到一個固定大小的結果,這個ROI (這個是在maskRCNN中提出來的)層和上節課中提到的自適應卷積操作一樣,上一步摳取出來的結果大小是不一樣的。要把這些不一樣的結果轉化爲相同33大小(這個33的結果channel爲512,不是2000,Faster RCNN會把剛纔得到的2000個候選結果再次篩選得到512.),然後再經過FC操作,最後做分類和迴歸。
總體來看,Faster RCNN 數據流及其shape:

  1. Feature map:[256, h_f,w_f]
  2. 2 Softmax:[ num_anchors,h_f,w_f]
  3. Regressors:[ num_anchors*4,h_f,w_f]
  4. NMS OUT:[n_proposals=2000,4]
  5. ROI Layer:[512,256,7,7],512是從上面的2000選出來的。
  6. FC1FC2:[512,1024]
  7. c+1 Softmax:[512,c+1]
  8. Regressors:[512,(c+1)*4]

代碼分析

從代碼分析中進一步驗證上面數據流和shape。
代碼的整體框架如下:
1.torchvision.models.detection.fasterrcnn_resnet50_fpn()返回 FasterRCNN實例,FasterRCNN繼承自GeneralizedRCNN,GeneralizedRCNN繼承自Module,要看FasterRCNN的forward,這個是在GeneralizedRCNN中實現的。
2.class FasterRCNN(GeneralizedRCNN)
3.class GeneralizedRCNN(nn.Module),下面是GeneralizedRCNN的forward函數
forward():
1.features=self.backbone(images.tensors)
2.proposals邊界框(經過NMS的),proposal_losses=self.rpn(images,features,targets)
3.detections,detector_losses=self.roi_heads(features,proposals,images.image_sizes,targets)
注意輸入self.roi_heads的前面兩個輸入是features,proposals,分別代表特徵圖和候選區域。
代碼中num_anchors是指特徵圖上一個像素對應原圖多個錨框。
下面對每個模塊進行小結

1.features=self.backbone(images.tensors)

faster_rcnn.py332行:

backbone=resnet_fpn_backbone(resnet50,pretrained_backbone)

backbone_utils.py44行:

backbone=resnet.__dict__[backbone_name](pretrained=pretrained,norm_layer=misc_nn_ops.FrozenBatchNorm2d)

torchvision/models/resnet.py195行: forward()
在這裏插入圖片描述

2.proposals,proposal_losses=selfrpn(images,features,targets)

faster_rcnn.py194行:

rpn=RegionProposalNetwork(.……)

torchvision/models/detection/rpn.py 380行:

forward():
objectness, pred_bbox_deltas=self.head(features)#得到下圖虛線框部分

anchors=self. anchor_generator(images, features)
proposals=self. box_coder.decode(pred_bbox_deltas.detach), anchors)
proposals=proposals.view(num_images,-1,4)
boxes, scores=self.filter_proposals(proposals, objectness, images.image_sizes, num_anchors_per_level)# 179046->2000

在這裏插入圖片描述

3.detections,detector_losses=self.roi heads(features,proposals,images.image_sizes,targets)

faster_rcnn.py219行:

roi heads=RolHeads(……)

torchvision/models/detection/roi heads.py 522行:

forward():
	if self.training:
		proposals,matched_idxs,labels,regression targets=self.select_training_samples(proposals,targets)#2000-->512
	box_features=self.box_roi_pool(features, proposals, image shapes)
	box_features=self.box_head(box features)
	class logits, box_regression =self.box_predictor(box features)

小結

Faster RCNN主要組件
1.backbone
2.rpn
3.filter_proposals(NMS)
4.roi_heads

Faster RCNN——行人檢測

數據:PennFudanPed數據集,70張行人照片共345行人標籤。官方地址
模型:fasterrcnn_resnet50_fpn 進行finetune
在這裏插入圖片描述
在這裏插入圖片描述
數據集下載下來後解壓縮有三個文件夾
PNGImages70張行人圖片
Annotation標註,其中用文本的方式告訴我們邊界框座標是什麼。
在這裏插入圖片描述

self.names=[ name[:-4] for name in list(filter(lambda x:x.endswith(".png"), os.listdir(self. img_dir)))]#把png類型文件名保存下來,然後去標註文件夾下面找對應的邊界框結果。
f=open(path_txt,"r")
import re 
points=[re.findall(r"\d+",1ine) for line in f.readlines() if"Xmin"in line]#利用正則表達式來獲取座標的位置
boxes_list=list()
for point in points: 
	box=[int(p) for p in point]
	boxes _list.append(box[-4:])
boxes=torch.tensor(boxes_list, dtype=torch.float)
labels=torch.ones((boxes. shape[0],), dtype=torch.long)

然後把boxes和labels放到字典中。


 # 收集batch data的函數,由於目標檢測中的邊界框大小不一樣,不能像其他任務直接對數據進行拼接。
    def collate_fn(batch):
        return tuple(zip(*batch))

loss是模型自動設置,代碼中不用寫。

	# step 3: loss
    # in lib/python3.6/site-packages/torchvision/models/detection/roi_heads.py
    # def fastrcnn_loss(class_logits, box_regression, labels, regression_targets)

注意模型參數的類型:

loss_dict = model(images, targets)  # images is list; targets is [ dict["boxes":**, "labels":**], dict[] ],targets也是list,不過裏面是兩個dict

目標檢測推薦github(awesome系列):
https://github.com/amusi/awesome-obiect-detection

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章