Object Detection(1):R-CNN實踐

前段時間做的都是classification的工作。這周有時間,正好研究一下很感興趣的object detection。目前得出的結果都是基於RBG大神在13年所提出的開創性工作——R-CNN。這一結構可以看作是將CNN應用到Object Detection領域的開山之作。在ImageNet/VOC/MSCOCO上所有頂尖的方法都是基於這個結構或其變種,可見其影響之大。

今天我們就來學習一下這篇論文(arxiv.org/abs/1311.2524)

首先放幾張我實驗的結果圖:

另外,題圖也是識別的非常好,怎麼樣?是不是覺得非常有趣?如果你也想識別你自己的圖片的話,就繼續往下看吧!最後會提供識別的代碼供大家參考!

一.論文解讀

首先我們先分析一下這篇R-CNN論文.文章指出近幾年的Object Detection的performance遇到了一個瓶頸,在這篇文章提出了兩個很重要的觀點:

1.將CNN結構應用到提取出來的區域;

2.針對標記數據很少的問題,利用輔助訓練集如ImageNet的預訓練再進行fine-tuning

論文發表的2014年,DPM已經進入瓶頸期,即使使用複雜的特徵和結構得到的提升也十分有限。本文將深度學習引入檢測領域,一舉將PASCAL VOC上的檢測率從35.1%提升到53.7%。CNN的結構在2012的ImageNet大賽中取得了非常好的結果,於是,CNN的分類結果能多大程度的應用到object detection領域就成了大家關注的焦點問題。這篇文章就這個問題提出了一個解決方案:

1.首先基於原始圖像生成種類獨立的區域,這些區域構成了我們detector的候選檢測集

2.對第一步提取的所有區域應用CNN結構,得到一個固定長度的特徵向量

3.使用特定的SVM分類器對第二步的特徵向量進行分類

文中的這張圖非常形象的解釋了這一過程。

當然文中還有許多其他技術的使用,如對類別判定的分類器訓練以及位置精修,對這些技術這裡暫時不做分析,RGB大神的代碼是開源的,對這些部分感興趣的可以對應尋找:

GitHub - rbgirshick/rcnn: R-CNN: Regions with Convolutional Neural Network Features

二.識別過程

這部分我們分析上圖的細節實現部分:

1.首先是提取候選區域(大約2k個):論文中採用的是Selective Search方法,可以生成很多用於目標檢測的候選區域.github.com/sergeyk/sele代碼在這裡,主要是matlab代碼,不過裡面有python的介面。我們clone到本地,然後在matlab中打開整個項目,然後運行demo.m,等待編譯運行完畢後,在windows下可以看到這張圖:

類似的還有很多張,都是該演算法從圖像中提取出來的候選區域,下面我們測試一下其Python介面,打開selective_search.py,首先嘗試直接運行一下,果然得到了一個錯誤:

熟悉Linux的馬上就會發現,這個目錄是Linux下的,當然這個程序本來就是運行在LInux中的,我們只需要把/dev/null改成null就不會報這個錯了,改完之後再試著運行一下,T_T

又報了另一個錯,這下子必須的看程序了:

# Form the MATLAB script command that processes images and write ton# temporary results file.nf, output_filename = tempfile.mkstemp(suffix=.mat)nos.close(f)nfnames_cell = { + ,.join("{}".format(x) for x in image_fnames) + }ncommand = "{}({}, {})".format(cmd, fnames_cell, output_filename)nprint(command)nn# Execute command in MATLAB.nmc = "matlab -nojvm -r "try; {}; catch; exit; end; exit"".format(command)npid = subprocess.Popen(n shlex.split(mc), stdout=open(null, w), cwd=script_dirname)nretcode = pid.wait()nif retcode != 0:n raise Exception("Matlab script did not exit successfully!")n

我們看一下程序核心部分,首先程序生成一個臨時.mat文件,然後再python中調用matlab命令行,調用selective_search將生成的box保存到臨時生成的mat文件中,然後再讀入這個.mat文件讀取其中box的數據,這下上面的錯誤信息就明顯了:這個.mat文件是空的

retcode = pid.wait()n

後來才發現問題出現在這裡,windows下這一行貌似不起作用,程序並不會等待調用matlab的進程執行完畢,就直接執行下面的程序了,所以自然會出現上述錯誤了,後來又找了很多辦法都解決不了,最後只能採用一個笨方法,

time.sleep(5)n

在執行上述代碼行下面加一行,讓主程序在這裡停留5s等待命令行完成,這樣程序終於運行成功了 ^_^

然後我們把整個項目拷貝到PythonPath中,便於後面在程序中直接調用

2.計算CNN特徵:這裡直接使用了caffe model下RGB大神訓練出來的模型:caffe/models/bvlc_reference_rcnn_ilsvrc13 at master · BVLC/caffe · GitHub,配置文件也是caffe官方提供的deploy.prototxt,基本與CaffeNet一致,只是最後將fc8修改成了fc-rcnn:

caffe這裡使用全連接層替換了原文中使用的SVM作為探測器

3.區域分類:這裡參考了caffe官方的RCNN-detection教程和pycaffe下的detect.py:

import numpy as npnimport pandas as pdnimport timenimport matplotlib.pyplot as pltnimport osnnimport caffennCROP_MODES = [list, selective_search]nCOORD_COLS = [ymin, xmin, ymax, xmax]nnndef detect(pretrained_model,model_def,mean_file,input_file,gpu=True):n mean=Nonen if mean_file:n mean = np.load(mean_file)nif mean.shape[1:] != (1, 1):n mean = mean.mean(1).mean(1)n channel_swap = [2,1,0]nnif gpu:n caffe.set_mode_gpu()nprint("GPU mode")nelse:n caffe.set_mode_cpu()nprint("CPU mode")nn# Make detector.n detector = caffe.Detector(model_def, pretrained_model, mean=mean,nraw_scale=255.0,channel_swap=channel_swap,context_pad=16)nn# Load input.n t = time.time()nprint("Loading input...")nif input_file.lower().endswith(txt):nwith open(input_file) as f:n inputs = [_.strip() for _ in f.readlines()]nelif input_file.lower().endswith(csv):n inputs = pd.read_csv(input_file, sep=,, dtype={filename: str})n inputs.set_index(filename, inplace=True)nelse:nraise Exception("Unknown input file type: not in txt or csv.")nn# Detect.n detections = detector.detect_selective_search(inputs)nprint("Processed {} windows in {:.3f} s.".format(len(detections),n time.time() - t))nn# Collect into dataframe with labeled fields.n df = pd.DataFrame(detections)n df.set_index(filename, inplace=True)n df[COORD_COLS] = pd.DataFrame(ndata=np.vstack(df[window]), index=df.index, columns=COORD_COLS)ndel(df[window])nnwith open(det_synset_words.txt, r) as f:n labels_df = pd.DataFrame([{synset_id: l.strip().split( )[0],nname: .join(l.strip().split( )[1:]).split(,)[0]}nfor l in f.readlines()])nnfor filename in inputs:n spec_df=df.loc[os.path.abspath(filename)]n predictions_df = pd.DataFrame(np.vstack(spec_df.prediction.values), columns=labels_df[name])n max_s=predictions_df.max(0)n max_s.sort_values(ascending=False,inplace=True)nprint(max_s[:10])nn i = predictions_df[max_s.index[0]].argmax()n j = predictions_df[max_s.index[1]].argmax()nn im = plt.imread(filename)n currentAxis = plt.gca()nn det = spec_df.iloc[i]n coords = (det[xmin], det[ymin]), det[xmax] - det[xmin], det[ymax] - det[ymin]n currentAxis.add_patch(plt.Rectangle(*coords, fill=False, edgecolor=r, linewidth=3))n currentAxis.text(det[xmin], det[ymin], max_s.index[0],nbbox=dict(facecolor=blue, alpha=0.5),nfontsize=10, color=white)nn det = spec_df.iloc[j]n coords = (det[xmin], det[ymin]), det[xmax] - det[xmin], det[ymax] - det[ymin]n currentAxis.add_patch(plt.Rectangle(*coords, fill=False, edgecolor=b, linewidth=3))n currentAxis.text(det[xmin], det[ymin], max_s.index[1],nbbox=dict(facecolor=blue, alpha=0.5),nfontsize=10, color=white)nn plt.axis(off)n plt.imshow(im)n plt.show()nnnif __name__==__main__:n pretrained_model=../../models/bvlc_reference_rcnn_ilsvrc13/bvlc_reference_rcnn_ilsvrc13.caffemodeln model_def=../../models/bvlc_reference_rcnn_ilsvrc13/deploy.prototxtn mean_file=../../models/ilsvrc_2012_mean.npyn detect(pretrained_model,model_def,mean_file,det_input.txt)n

總體思路就是用selective_search提取出接近2k個候選區域,然後將這些候選區域輸入caffe的CNN中,進行一遍forward操作後,然後將最優的幾個結果在圖像中畫出來

三.實驗

我們用上述代碼進行一些測試,跑出結果只需要對應修改最後幾行,修改文件路徑即可,detect函數的最後一個參數是輸入文件:

裡面存放要處理的文件路徑名,程序支持一次處理大量圖片,但由於前述第二部分windows下的那個bug,圖片數量很多時可能需要你手動調整sleep的時長

實驗結果圖在文章開頭部分已經放過了,感興趣的也可以自己進行測試,我這裡只是將可能性最高的兩種結果框出來了。

四.總結

RCNN開啟了CNN應用於目標檢測的大門,後面這一領域快速發展,SPPNet ,Fast RCNN還有近期的Faster RCNN,不僅大大提高了準確率,而且處理速度也飛快提升,Faster RCNN已經可以做到實時處理了。後面有時間會繼續分析這一系列論文!


推薦閱讀:

透過認知智能剖析商業本質(iPIN CEO楊洋)丨硬創公開課
綜藝節目也玩人工智慧?假噱頭還是真科普?

TAG:目标检测 | 深度学习DeepLearning | 人工智能 |