在Notebook使用Pytorch實現物體檢測
首先,這里介紹一種two-stage算法(Faster R-CNN),將目標區域檢測和類別識別分為兩個任務進行物體檢測。這里采用pytorch引擎進行模型構建。

如果您已熟練使用notebook和Github,可以從Github下載樣例文件(Faster-R-CNN.ipynb),然后上傳至ModelArts notebook中直接使用。
創建并打開Notebook
名稱
用戶可自定義Notebook實例名稱。
自動停止
為避免資源浪費,啟用自動停止功能,并選擇1小時后自動停止。
工作環境
選擇“Multi-Engine 1.0 (python3 推薦)”。
資源池
選“公共資源池”。
類型
選擇“GPU”。
規格
選擇“GPU: 1*v100NV32 CPU: 8 核 64GiB”,您也可以選擇“免費規格”,如果使用“免費規格”,可能會由于使用人數較多導致排隊等待。
存儲類型
選擇“云硬盤(EVS)”,使用默認的5GB磁盤規格即可。
在ModelArts管理控制臺,進入“開發環境>Notebook”頁面,單擊左上角的“創建”。
在“創建Notebook”頁面,填寫相關信息,然后單擊“下一步”。
根據界面提示完成Notebook實例創建,單擊“返回Notebook列表”。
在“Notebook列表”中,等待Notebook實例創建完成,當狀態變為“運行中”時,表示Notebook實例已創建成功。
單擊操作列的“打開”,進入Notebook開發環境。
在Jupyter頁面,單擊“New>pytorch-1.0.0”,新建一個Pytorch工作環境。
單擊左上方的文件名“Untitled”,并輸入一個與本示例相關的名稱,例如“Faster R-CNN”。
執行如下代碼測試開發環境是否可用。在單元格中輸入,然后單擊“Run”,運行后回hello,ModelArts!,表示開發環境可正常使用。
print(“hello,ModelArts!”)
數據準備
首先,執行如下代碼將需要的代碼和數據下載到Notebook。
這里使用PASCAL VOC 2007數據集訓練模型,共20個類別的物體。
import os
from modelarts.session import Session
sess = Session()
if sess.region_name == ‘cn-north-1’:
bucket_path=“modelarts-labs/notebook/DL_object_detection_faster/fasterrcnn.tar.gz”
elif sess.region_name == ‘cn-north-4’:
bucket_path=“modelarts-labs-bj4/notebook/DL_object_detection_faster/fasterrcnn.tar.gz”
else:
print(“請更換地區到北京一或北京四”)
if not os.path.exists(’./experiments’):
sess.download_data(bucket_path=bucket_path, path="./fasterrcnn.tar.gz")
if os.path.exists(’./fasterrcnn.tar.gz’):
# 解壓壓縮包
os.system(“tar -xf ./fasterrcnn.tar.gz”)
# 清理壓縮包 os.system("rm -r ./fasterrcnn.tar.gz")
當回顯信息出現如下類似信息時,表示數據已導入成功。
Successfully download file modelarts-labs-bj4/notebook/DL_object_detection_faster/fasterrcnn.tar.gz from OBS to local ./fasterrcnn.tar.gz
安裝依賴并引用
執行如下命令,等待運行結束。
!pip install pycocotools==2.0.0
!pip install torchvision==0.4.0
!pip install protobuf==3.9.0
當出現“Successfully installed…”類似信息時,表示上述命令安裝成功。分兩個Cell,執行如下示例代碼,引用依賴。
import tools._init_paths
%matplotlib inline
from future import absolute_import
from future import division
from future import print_function
import tensorboardX as tb
from datasets.factory import get_imdb
from model.train_val import get_training_roidb, train_net
from model.config import cfg, cfg_from_file, cfg_from_list, get_output_dir, get_output_tb_dir
import roi_data_layer.roidb as rdl_roidb
from roi_data_layer.layer import RoIDataLayer
import utils.timer
import pickle
import torch
import torch.optim as optim
from nets.vgg16 import vgg16
import numpy as np
import os
import sys
import glob
import time
神經網絡搭建
模型訓練超參設置
為了減少訓練時間,我們在預訓練模型的基礎上進行訓練。這里,我們使用VGG16作為FasterRCNN的主干網絡。
imdb_name = “voc_2007_trainval”
imdbval_name = “voc_2007_test”
使用的預訓練模型位置
weight = “./data/imagenet_weights/vgg16.pth”
訓練迭代次數
max_iters = 100
cfg模型文件位置
cfg_file = ‘./experiments/cfgs/vgg16.yml’
set_cfgs = None
if cfg_file is not None:
cfg_from_file(cfg_file)
if set_cfgs is not None:
cfg_from_list(set_cfgs)
print(‘Using config:’)
print(cfg)
2.定義讀取數據集函數
數據集的標注格式是PASCAL VOC格式。
def combined_roidb(imdb_names):
def get_roidb(imdb_name): # 加載數據集 imdb = get_imdb(imdb_name) print('Loaded dataset `{:s}` for training'.format(imdb.name)) # 使用ground truth作為數據集策略 imdb.set_proposal_method(cfg.TRAIN.PROPOSAL_METHOD) print('Set proposal method: {:s}'.format(cfg.TRAIN.PROPOSAL_METHOD)) roidb = get_training_roidb(imdb) return roidb roidbs = [get_roidb(s) for s in imdb_names.split('+')] roidb = roidbs[0] if len(roidbs) > 1: for r in roidbs[1:]: roidb.extend(r) tmp = get_imdb(imdb_names.split('+')[1]) imdb = datasets.imdb.imdb(imdb_names, tmp.classes) else: imdb = get_imdb(imdb_names) return imdb, roidb
3.設置模型訓練參數
np.random.seed(cfg.RNG_SEED)
加載訓練數據集
imdb, roidb = combined_roidb(imdb_name)
print(’{:d} roidb entries’.format(len(roidb)))
設置輸出路徑
output_dir = get_output_dir(imdb,None)
print('Output will be saved to {:s}'.format(output_dir))
設置日志保存路徑
tb_dir = get_output_tb_dir(imdb, None)
print('TensorFlow summaries will be saved to {:s}'.format(tb_dir))
加載驗證數據集
orgflip = cfg.TRAIN.USE_FLIPPED
cfg.TRAIN.USE_FLIPPED = False
_, valroidb = combined_roidb(imdbval_name)
print(’{:d} validation roidb entries’.format(len(valroidb)))
cfg.TRAIN.USE_FLIPPED = orgflip
創建backbone網絡
在案例中使用的是VGG16模型,可以嘗試其他不同的模型結構,例如Resnet等
net = vgg16()
運行上述代碼后,界面將呈現回顯信息,當出現“done”信息時,表示運行結束,請執行下一段。
分3個Cell執行如下3段代碼。
from model.train_val import filter_roidb, SolverWrapper
對ROI進行篩選,將無效的ROI數據篩選掉
roidb = filter_roidb(roidb)
valroidb = filter_roidb(valroidb)
sw = SolverWrapper(
net,
imdb,
roidb,
valroidb,
output_dir,
tb_dir,
pretrained_model=weight)
print(‘Solving…’)
顯示所有模型屬性
sw.dict.keys()
sw.net為主干網絡
print(sw.net)
4.定義神經網絡結構
使用PyTorch搭建神經網絡。
部分實現細節可以去相應的文件夾查看源碼。
構建網絡結構,模型加入ROI數據層
sw.data_layer = RoIDataLayer(sw.roidb, sw.imdb.num_classes)
sw.data_layer_val = RoIDataLayer(sw.valroidb, sw.imdb.num_classes, random=True)
構建網絡結構,在VGG16基礎上加入ROI和Classifier部分
lr, train_op = sw.construct_graph()
加載之前的snapshot
lsf, nfiles, sfiles = sw.find_previous()
snapshot 為訓練提供了斷點訓練,如果有snapshot將加載進來,繼續訓練
if lsf == 0:
lr, last_snapshot_iter, stepsizes, np_paths, ss_paths = sw.initialize()
else:
lr, last_snapshot_iter, stepsizes, np_paths, ss_paths = sw.restore(str(sfiles[-1]), str(nfiles[-1]))
iter = last_snapshot_iter + 1
last_summary_time = time.time()
在之前的訓練基礎上繼續進行訓練
stepsizes.append(max_iters)
stepsizes.reverse()
next_stepsize = stepsizes.pop()
將net切換成訓練模式
print(“網絡結構:”)
sw.net.train()
sw.net.to(sw.net._device)
5.開始訓練
while iter < max_iters + 1:
if iter == next_stepsize + 1:
# 加入snapshot節點
sw.snapshot(iter)
lr *= cfg.TRAIN.GAMMA
scale_lr(sw.optimizer, cfg.TRAIN.GAMMA)
next_stepsize = stepsizes.pop()
utils.timer.timer.tic() # 數據通過ROI數據層,進行前向計算 blobs = sw.data_layer.forward() now = time.time() if iter == 1 or now - last_summary_time > cfg.TRAIN.SUMMARY_INTERVAL: # 計算loss函數 # 根據loss函數對模型進行訓練 rpn_loss_cls, rpn_loss_box, loss_cls, loss_box, total_loss, summary = \ sw.net.train_step_with_summary(blobs, sw.optimizer) for _sum in summary: sw.writer.add_summary(_sum, float(iter)) # 進行數據層驗證計算 blobs_val = sw.data_layer_val.forward() summary_val = sw.net.get_summary(blobs_val) for _sum in summary_val: sw.valwriter.add_summary(_sum, float(iter)) last_summary_time = now else: rpn_loss_cls, rpn_loss_box, loss_cls, loss_box, total_loss = \ sw.net.train_step(blobs, sw.optimizer) utils.timer.timer.toc() if iter % (cfg.TRAIN.DISPLAY) == 0: print('iter: %d / %d, total loss: %.6f\n >>> rpn_loss_cls: %.6f\n ' '>>> rpn_loss_box: %.6f\n >>> loss_cls: %.6f\n >>> loss_box: %.6f\n >>> lr: %f' % \ (iter, max_iters, total_loss, rpn_loss_cls, rpn_loss_box, loss_cls, loss_box, lr)) print('speed: {:.3f}s / iter'.format( utils.timer.timer.average_time())) # 進行snapshot存儲 if iter % cfg.TRAIN.SNAPSHOT_ITERS == 0: last_snapshot_iter = iter ss_path, np_path = sw.snapshot(iter) np_paths.append(np_path) ss_paths.append(ss_path) # 刪掉多余的snapshot if len(np_paths) > cfg.TRAIN.SNAPSHOT_KEPT: sw.remove_snapshot(np_paths, ss_paths) iter += 1
if last_snapshot_iter != iter - 1:
sw.snapshot(iter - 1)
sw.writer.close()
sw.valwriter.close()
測試部分
在這部分中,我們利用訓練得到的模型進行推理測試。
%matplotlib inline
from future import absolute_import
from future import division
from future import print_function
將路徑轉入lib
import tools._init_paths
from model.config import cfg
from model.test import im_detect
from torchvision.ops import nms
from utils.timer import Timer
import matplotlib.pyplot as plt
import numpy as np
import os, cv2
import argparse
from nets.vgg16 import vgg16
from nets.resnet_v1 import resnetv1
from model.bbox_transform import clip_boxes, bbox_transform_inv
import torch
參數定義
PASCAL VOC類別設置
CLASSES = (‘background’,
‘aeroplane’, ‘bicycle’, ‘bird’, ‘boat’,
‘bottle’, ‘bus’, ‘car’, ‘cat’, ‘chair’,
‘cow’, ‘diningtable’, ‘dog’, ‘horse’,
‘motorbike’, ‘person’, ‘pottedplant’,
‘sheep’, ‘sofa’, ‘train’, ‘tvmonitor’)
網絡模型文件名定義
NETS = {‘vgg16’: (‘vgg16_faster_rcnn_iter_%d.pth’,),‘res101’: (‘res101_faster_rcnn_iter_%d.pth’,)}
數據集文件名定義
DATASETS= {‘pascal_voc’: (‘voc_2007_trainval’,),‘pascal_voc_0712’: (‘voc_2007_trainval+voc_2012_trainval’,)}
結果繪制
將預測的標簽和邊界框繪制在原圖上。
def vis_detections(im, class_dets, thresh=0.5):
“”“Draw detected bounding boxes.”""
im = im[:, :, (2, 1, 0)]
fig, ax = plt.subplots(figsize=(12, 12))
ax.imshow(im, aspect=‘equal’)
for class_name in class_dets:
dets = class_dets[class_name]
inds = np.where(dets[:, -1] >= thresh)[0]
if len(inds) == 0:
continue
for i in inds: bbox = dets[i, :4] score = dets[i, -1] ax.add_patch( plt.Rectangle((bbox[0], bbox[1]), bbox[2] - bbox[0], bbox[3] - bbox[1], fill=False, edgecolor='red', linewidth=3.5) ) ax.text(bbox[0], bbox[1] - 2, '{:s} {:.3f}'.format(class_name, score), bbox=dict(facecolor='blue', alpha=0.5), fontsize=14, color='white') plt.axis('off') plt.tight_layout() plt.draw()
準備測試圖片
我們將測試圖片傳到test文件夾下,我們準備了兩張圖片進行測試,大家也可以通過notebook的upload按鈕上傳自己的測試數據。注意,測試數據需要是圖片,并且放在test文件夾下。
test_file = “./test”
模型推理
這里我們加載一個預先訓練好的模型,也可以選擇案例中訓練的模型。
import cv2
from utils.timer import Timer
from model.test import im_detect
from torchvision.ops import nms
cfg.TEST.HAS_RPN = True # Use RPN for proposals
模型存儲位置
這里我們加載一個已經訓練110000迭代之后的模型,可以選擇自己的訓練模型位置
saved_model = “./models/vgg16-voc0712/vgg16_faster_rcnn_iter_110000.pth”
print('trying to load weights from ', saved_model)
加載backbone
net = vgg16()
構建網絡
net.create_architecture(21, tag=‘default’, anchor_scales=[8, 16, 32])
加載權重文件
net.load_state_dict(torch.load(saved_model, map_location=lambda storage, loc: storage))
net.eval()
選擇推理設備
net.to(net._device)
print(‘Loaded network {:s}’.format(saved_model))
for file in os.listdir(test_file):
if file.startswith("._") == False:
file_path = os.path.join(test_file, file)
print(file_path)
# 打開測試圖片文件
im = cv2.imread(file_path)
# 定義計時器 timer = Timer() timer.tic() # 檢測得到圖片ROI scores, boxes = im_detect(net, im) print(scores.shape, boxes.shape) timer.toc() print('Detection took {:.3f}s for {:d} object proposals'.format(timer.total_time(), boxes.shape[0])) # 定義閾值 CONF_THRESH = 0.7 NMS_THRESH = 0.3 cls_dets = {} # NMS 非極大值抑制操作,過濾邊界框 for cls_ind, cls in enumerate(CLASSES[1:]): cls_ind += 1 # 跳過 background cls_boxes = boxes[:, 4*cls_ind:4*(cls_ind + 1)] cls_scores = scores[:, cls_ind] dets = np.hstack((cls_boxes, cls_scores[:, np.newaxis])).astype(np.float32) keep = nms(torch.from_numpy(cls_boxes), torch.from_numpy(cls_scores), NMS_THRESH) dets = dets[keep.numpy(), :] if len(dets) > 0: if cls in cls_dets: cls_dets[cls] = np.vstack([cls_dets[cls], dets]) else: cls_dets[cls] = dets vis_detections(im, cls_dets, thresh=CONF_THRESH) plt.show()
運行結束后,測試圖片的預測效果如下圖所示。
trying to load weights from ./models/vgg16-voc0712/vgg16_faster_rcnn_iter_110000.pth
Loaded network ./models/vgg16-voc0712/vgg16_faster_rcnn_iter_110000.pth
./test/test_image_1.jpg
(300, 21) (300, 84)
Detection took 0.055s for 300 object proposals
./test/test_image_0.jpg
(300, 21) (300, 84)
Detection took 0.058s for 300 object proposals
結語
到這里,整個實驗流程就結束了,這次實驗是將目標區域檢測和類別識別分為兩個任務進行物體檢測,歡迎大家動手去實踐。
pytorch 機器學習 網絡
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。