Caffe版Faster R-CNN可視化——網絡模型,圖像特徵,Loss圖,PR曲線

可視化網絡模型

  Caffe目前有兩種經常使用的可視化模型方式:python

  • 使用Netscope在線可視化
  • Caffe代碼包內置的draw_net.py文件能夠可視化網絡模型

Netscope

  Netscope能可視化神經網絡體系結構(或技術上說,Netscope能可視化任何有向無環圖)。目前Netscope能可視化Caffe的prototxt 文件。網址爲: ethereon.github.io/netscope/#/…   Netscope的使用很是簡單,只須要將prototxt的文件複製到Netscope的編輯框,再按快捷鍵Shift+Enter便可獲得網絡模型的可視化結構。Netscope的優勢是顯示的網絡模型簡潔,並且將鼠標放在右側可視化的網絡模型的任意模塊上,會顯示該模塊的具體參數。圖1以Faster R-CNN中ZF模型的train.prototxt文件爲例git

圖1 Netscope可視化ZF網絡模

draw_net.py

  draw_net.py一樣是將prototxt繪製成網絡模型,在繪製以前,須要安裝兩個依賴庫:github

一、安裝GraphViz   # sudo apt-get install GraphViz   注意,這裏用的是apt-get來安裝,而不是pip.   2 、安裝pydot   # sudo pip install pydot   用的是pip來安裝,而不是apt-get網絡

  安裝完畢後,便可調用draw_net.py繪製網絡模型,如繪製caffe自帶的LeNet網絡模型:app

sudo python python/draw_net.py examples/mnist/lenet_train_test.prototxt netImage/lenet.png --rankdir=TB
複製代碼

  其中有三個參數,各自的含義爲:ide

第一個參數:網絡模型的prototxt文件 第二個參數:保存的圖片路徑及名字 第二個參數:–rankdir=x , x 有四種選項,分別是LR, RL, TB, BT 。用來表示網絡的方向,分別是從左到右,從右到左,從上到小,從下到上。默認爲LR。工具

  可視化結果以下圖所示:學習

圖2 draw_net.py可視化LeNet網絡模型

可視化圖像特徵

  關於圖像的可視化,我也使用過兩種兩種方式:測試

  • 修改demo.py代碼輸出中間層結果
  • 使用可視化工具deep-visualization-toolbox

修改demo.py

  該部分是參考薛開宇的《caffe學習筆記》中的逐層特徵可視化部分,仍是以ZFNet網絡訓練Pascal VOC爲例,修改demo.py文件後,代碼以下:fetch

#!/usr/bin/env python
#-*-coding:utf-8-*-


import matplotlib
matplotlib.use('Agg')
import _init_paths
from fast_rcnn.config import cfg
from fast_rcnn.test import im_detect
from fast_rcnn.nms_wrapper import nms
from utils.timer import Timer
import matplotlib.pyplot as plt
import numpy as np
import scipy.io as sio
import caffe, os, sys, cv2
import argparse

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',
                  'VGG16_faster_rcnn_final.caffemodel'),
        'zf': ('ZF',
                  'zf_faster_rcnn_iter_2000.caffemodel')}

def vis_detections(im, class_name, dets, thresh=0.5):
    """Draw detected bounding boxes."""
    inds = np.where(dets[:, -1] >= thresh)[0]
    if len(inds) == 0:
        return

    im = im[:, :, (2, 1, 0)]
    fig, ax = plt.subplots(figsize=(12, 12))
    ax.imshow(im, aspect='equal')
    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')

    ax.set_title(('{} detections with '
                  'p({} | box) >= {:.1f}').format(class_name, class_name,
                                                  thresh),
                  fontsize=14)
    plt.axis('off')
    plt.tight_layout()
    plt.draw()

def demo(net, image_name):
    """Detect object classes in an image using pre-computed object proposals."""

    # Load the demo image
    im_file = os.path.join(cfg.DATA_DIR, 'demo', image_name)
    im = cv2.imread(im_file)

    # Detect all object classes and regress object bounds
    timer = Timer()
    timer.tic()
    scores, boxes = im_detect(net, im)
    timer.toc()
    print ('Detection took {:.3f}s for '
           '{:d} object proposals').format(timer.total_time, boxes.shape[0])

    # Visualize detections for each class
    CONF_THRESH = 0.8
    NMS_THRESH = 0.3
    for cls_ind, cls in enumerate(CLASSES[1:]):
        cls_ind += 1 # because we skipped 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(dets, NMS_THRESH)
        dets = dets[keep, :]
        vis_detections(im, cls, dets, thresh=CONF_THRESH)

def parse_args():
    """Parse input arguments."""
    parser = argparse.ArgumentParser(description='Faster R-CNN demo')
    parser.add_argument('--gpu', dest='gpu_id', help='GPU device id to use [0]',
                        default=0, type=int)
    parser.add_argument('--cpu', dest='cpu_mode',
                        help='Use CPU mode (overrides --gpu)',
                        action='store_true')
    parser.add_argument('--net', dest='demo_net', help='Network to use [zf]',
                        choices=NETS.keys(), default='zf')

    args = parser.parse_args()

    return args





if __name__ == '__main__':

    cfg.TEST.HAS_RPN = True  # Use RPN for proposals

    args = parse_args()
    prototxt = os.path.join(cfg.MODELS_DIR, NETS[args.demo_net][0],
                            'faster_rcnn_alt_opt', 'faster_rcnn_test.pt')
    caffemodel = os.path.join(cfg.DATA_DIR, 'faster_rcnn_models',
                              NETS[args.demo_net][1])

    if not os.path.isfile(caffemodel):
        raise IOError(('{:s} not found.\nDid you run ./data/script/'
                       'fetch_faster_rcnn_models.sh?').format(caffemodel))

    if args.cpu_mode:
        caffe.set_mode_cpu()
    else:
        caffe.set_mode_gpu()
        caffe.set_device(args.gpu_id)
        cfg.GPU_ID = args.gpu_id
    net = caffe.Net(prototxt, caffemodel, caffe.TEST)
	#指定caffe路徑,如下是個人caffe路徑 
    caffe_root='/home/ouyang/GitRepository/py-faster-rcnn/caffe-fast-rcnn/'
    # import sys
    sys.path.insert(0, caffe_root+'python')
    # import caffe

    # #顯示的圖表大小爲 10,圖形的插值是以最近爲原則,圖像顏色是灰色
    plt.rcParams['figure.figsize'] = (10, 10)
    plt.rcParams['image.interpolation'] = 'nearest'
    plt.rcParams['image.cmap'] = 'gray'
    image_file = caffe_root+'examples/images/vehicle_0000015.jpg'  
    # 載入模型
    npload = caffe_root+ 'python/caffe/imagenet/ilsvrc_2012_mean.npy'  
    
    transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
    transformer.set_transpose('data', (2,0,1))
    transformer.set_mean('data', np.load(npload).mean(1).mean(1))
    # 參考模型的灰度爲0~255,而不是0~1
    transformer.set_raw_scale('data', 255) 
    # 因爲參考模型色彩是BGR,須要將其轉換爲RGB
    transformer.set_channel_swap('data', (2,1,0))
    im=caffe.io.load_image(image_file)
    net.blobs['data'].reshape(1,3,224,224)
    net.blobs['data'].data[...] = transformer.preprocess('data',im)
    # 顯示出各層的參數和形狀,第一個是批次,第二個是feature map數目,第三和第四是每一個神經元中圖片的長和寬
    print [(k,v.data.shape) for k,v in net.blobs.items()]
    #輸出網絡參數
    print [(k,v[0].data.shape) for k,v in net.params.items()]


   
    def show_image(im):
        if im.ndim==3:
            m=im[:,:,::-1]
        plt.imshow(im)
        #顯示圖片的方法
        plt.axis('off') # 不顯示座標軸
        plt.show()    

    # 每一個可視化的都是在一個由一個個網格組成
    def vis_square(data,padsize=1,padval=0):
        data-=data.min()
        data/=data.max()
        
        # force the number of filters to be square
        n=int(np.ceil(np.sqrt(data.shape[0])))
        padding=((0,n**2-data.shape[0]),(0,padsize),(0,padsize))+((0,0),)*(data.ndim-3)
        data=np.pad(data,padding,mode='constant',constant_values=(padval,padval))
        # 對圖像使用濾波器
        
        data=data.reshape((n,n)+data.shape[1:]).transpose((0,2,1,3)+tuple(range( 4,data.ndim+1)))
        data=data.reshape((n*data.shape[1],n*data.shape[3])+data.shape[4:])   
        
        #show_image(data)
        plt.imshow(data)
        plt.show()
        # 設置圖片的保存路徑,此處是個人路徑
        plt.savefig("./tools/Vehicle_2000/fc6.jpg")

    
    out = net.forward()
    image=net.blobs['data'].data[4].copy()
    image-=image.min()
    image/=image.max()
    # 顯示原始圖像
    show_image(image.transpose(1,2,0))
    #網絡提取conv1的卷積核
    filters = net.params['conv1'][0].data
    vis_square(filters.transpose(0, 2, 3, 1))
    #過濾後的輸出,96 張 featuremap
    feat =net.blobs['conv1'].data[0,:96]
    vis_square(feat,padval=1)
    #第二個卷積層,顯示所有的96個濾波器,每個濾波器爲一行。
    filters = net.params['conv2'][0].data
    vis_square(filters[:96].reshape(96**2, 5, 5))
    # #第二層輸出 256 張 featuremap
    feat = net.blobs['conv2'].data[0]
    vis_square(feat, padval=1)


    filters = net.params['conv3'][0].data
    vis_square(filters[:256].reshape(256**2, 3, 3))


    # 第三個卷積層:所有 384 個 feature map
    feat = net.blobs['conv3'].data[0]
    vis_square(feat, padval=0.5)


    #第四個卷積層,咱們只顯示前面 48 個濾波器,每個濾波器爲一行。
    filters = net.params['conv4'][0].data
    vis_square(filters[:384].reshape(384**2, 3, 3))

    # 第四個卷積層:所有 384 個 feature map
    feat = net.blobs['conv4'].data[0]
    vis_square(feat, padval=0.5)
    # 第五個卷積層:所有 256 個 feature map
    filters = net.params['conv5'][0].data
    vis_square(filters[:384].reshape(384**2, 3, 3))

    feat = net.blobs['conv5'].data[0]
    vis_square(feat, padval=0.5)
    #第五個 pooling 層
    feat = net.blobs['fc6'].data[0]
    vis_square(feat, padval=1)
    第六層輸出後的直方分佈
    feat=net.blobs['fc6'].data[0]
    plt.subplot(2,1,1)
    plt.plot(feat.flat)
    plt.subplot(2,1,2)
    _=plt.hist(feat.flat[feat.flat>0],bins=100)
    # #顯示圖片的方法
    #plt.axis('off') # 不顯示座標軸
    plt.show()  
    plt.savefig("fc6_zhifangtu.jpg") 
    # 第七層輸出後的直方分佈
    feat=net.blobs['fc7'].data[0]
    plt.subplot(2,1,1)
    plt.plot(feat.flat)
    plt.subplot(2,1,2)
    _=plt.hist(feat.flat[feat.flat>0],bins=100)
    plt.show()
    plt.savefig("fc7_zhifangtu.jpg") 
    #看標籤
    #執行測試  
    image_labels_filename=caffe_root+'data/ilsvrc12/synset_words.txt'
    #try:
    labels=np.loadtxt(image_labels_filename,str,delimiter='\t')
    top_k=net.blobs['prob'].data[0].flatten().argsort()[-1:-6:-1]
    #print labels[top_k]
    for i in np.arange(top_k.size):
        print top_k[i], labels[top_k[i]]
複製代碼

  下面貼幾張檢測結果

圖3 原始檢測圖片

圖4 conv1參數可視化

圖5 conv1特徵可視化

deep-visualization-toolbox

  deep-visualization-toolbox是Jason Yosinsk出版在Computer Science上的一篇論文的源代碼,改論文主要講述的是卷積神經網絡的可視化,感興趣的朋友能夠看看這篇論文(論文地址)。B站上有個講怎麼使用該工具的視頻,這裏附上連接www.bilibili.com/video/av740…。   該工具的源碼在github:github.com/yosinski/de…。該github下有完整的安裝配置步驟,仍是以圖2中的馬爲例,貼幾張檢測結果圖。

圖6 ToolBox conv1特徵可視化

圖7 ToolBox conv2特徵可視化

  從檢測效果上看,仍是挺簡潔的。圖片左側的一列圖片左上角是輸入圖片,中間部分是圖片通過網絡前向傳播獲得的特徵圖可視化,左下角是其特徵可視化。

Loss可視化

  網絡訓練過程當中Loss值的可視化能夠幫助分析該網絡模型的參數是否合適。在使用Faster R-CNN網絡訓練模型時,訓練完成後的日誌文件中保存了網絡訓練各個階段的loss值,如圖8所示。只用寫簡單的python程序,讀取日誌文件中的迭代次數,以及須要的損失值,再畫圖便可完成Loss的可視化。

圖8 模型的訓練日誌
  在下面貼出Loss可視化的代碼:
#!/usr/bin/env python  
import os  
import sys  
import numpy as np  
import matplotlib.pyplot as plt  
import math  
import re  
import pylab  
from pylab import figure, show, legend  
from mpl_toolkits.axes_grid1 import host_subplot  
  
# 日誌文件名
fp = open('faster_rcnn_end2end_ZF_.txt.2018-04-13_19-46-23', 'r',encoding='UTF-8') 

  
train_iterations = []  
train_loss = []  
test_iterations = []  
#test_accuracy = []  
  
for ln in fp:  
  # get train_iterations and train_loss  
  if '] Iteration ' in ln and 'loss = ' in ln:  
    arr = re.findall(r'ion \b\d+\b,',ln)  
    train_iterations.append(int(arr[0].strip(',')[4:]))  
    train_loss.append(float(ln.strip().split(' = ')[-1]))  
      
fp.close()  
  
host = host_subplot(111)  
plt.subplots_adjust(right=0.8) # ajust the right boundary of the plot window  
#par1 = host.twinx()  
# set labels  
host.set_xlabel("iterations")  
host.set_ylabel("RPN loss")  
#par1.set_ylabel("validation accuracy")  
  
# plot curves  
p1, = host.plot(train_iterations, train_loss, label="train RPN loss")  
.  
host.legend(loc=1)  
  
# set label color  
host.axis["left"].label.set_color(p1.get_color())  
host.set_xlim([-1000, 60000])  
host.set_ylim([0., 3.5])  
  
plt.draw()  
plt.show()  
複製代碼

  可視化效果以下圖所示

圖9 Loss可視化

畫PR圖

  Faster R-CNN訓練網絡在輸出網絡模型的同級文件夾裏有每一類檢測目標每張圖片的準確率和召回率,能夠繪製準確率召回率(Precision-recall, PR)曲線,PR曲線的面積即準確率的值。   該文件存儲在==output\faster_rcnn_end2end\voc_2007_test\zf_faster_rcnn_iter==下的.pkl文件下,須要將其轉換爲.txt文件。代碼以下:

#-*-coding:utf-8-*-
import cPickle as pickle
import numpy as np 
np.set_printoptions(threshold=np.NaN) 
fr = open('./aeroplane_pr.pkl')    #open的參數是pkl文件的路徑
inf = pickle.load(fr)       #讀取pkl文件的內容
print inf
fo = open("aeroplane_pr.txt", "wb")
fo.write(str(inf))
fo.close()
fr.close()                       #關閉文件
複製代碼

  執行完這個程序後,會將.pkl文件轉換爲.txt文件保存。.txt文件能直觀看到每張圖片的檢測準確率與召回率。用與畫loss圖類似的方法,便可完成PR曲線的繪製。效果圖如圖10所示。

圖10 PR曲線

參考文獻

[1] 薛開宇,caffe學習筆記

[2] Yosinski J, Clune J, Nguyen A, et al. Understanding Neural Networks Through Deep Visualization[J]. Computer Science, 2015.

相關文章
相關標籤/搜索