1. 程式人生 > >caffe cnn提取各層特徵並可視化結果(Python介面)

caffe cnn提取各層特徵並可視化結果(Python介面)

親測有用,之前參考的薛開宇的學習筆記,部分程式碼需要修改,自己修改後的版本如下:

</p>

#caffe特徵的視覺化
import numpy  as np
import matplotlib.pyplot as plt
import matplotlib.image as ima
import os
import pickle
import cv2

caffe_root='/home/falingling/caffe/'
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'
#'examples/imagenet/caffe_reference_imagenet_model'
model_file = caffe_root+'models/bvlc_reference_caffenet/deploy.prototxt'  
pretrained = caffe_root+ 'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel'
image_file = caffe_root+'examples/images/cat.jpg'  
#image_file = caffe_root+'examples/_temp/baby_74.jpg'
npload = caffe_root+ 'python/caffe/imagenet/ilsvrc_2012_mean.npy'  
#net=caffe.Classifier(caffe_root+'examples/imagenet/deploy.prototxt',caffe_root+'examples/imagenet/caffe_reference_imagenet_model')

net = caffe.Net(model_file,pretrained,caffe.TEST)
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))
transformer.set_raw_scale('data', 255)
transformer.set_channel_swap('data', (2,1,0))
im=caffe.io.load_image(image_file)
net.blobs['data'].reshape(1,3,227,227)
net.blobs['data'].data[...] = transformer.preprocess('data',im)
# 因為參考模型本來頻道是 BGR,所以要將 RGB 轉換
#參考模型執行在【0,255】的灰度,而不是【0,1】
#net = caffe.Classifier(model_file, pretrained,image_dims=(256,256),mean=np.load(npload).mean(1).mean(1),channel_swap=(2,1,0),input_scale=255)
#scores=net.predict([caffe.io.load_image(image_file)])
#print scores,,顯示圖片
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()]
#predictions=out[self.outputs[0]].squeeze(axis=None)
# our network takes BGR images, so we need to switch color channels
# 網路需要的是 BGR 格式圖片,所以轉換顏色頻道
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.axis('off') # 不顯示座標軸
    plt.show()    
out = net.forward()
#image=net.blobs['data'].data[4].copy()
#show_image(image.transpose(1,2,0))
#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,:40]
vis_square(feat,padval=1)
#第二個卷積層,我們只顯示前面 48 個濾波器,每一個濾波器為一行。
filters = net.params['conv2'][0].data
#vis_square(filters[:48].reshape(48**2, 5, 5))
#第二層輸出 256 張 feature,這裡顯示 20 張。
feat = net.blobs['conv2'].data[0, :20]
#vis_square(feat, padval=1)
#第三個卷積層:全部 384 個 feature map
feat = net.blobs['conv3'].data[0]
#vis_square(feat, padval=0.5)
#第四個卷積層:全部 384 個 feature map
feat = net.blobs['conv4'].data[0]
#vis_square(feat, padval=0.5)
#第五個卷積層:全部 256 個 feature map
feat = net.blobs['conv5'].data[0]
#vis_square(feat, padval=0.5)
#第五個 pooling 層
feat = net.blobs['pool5'].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()   
#第七層輸出後的直方分佈
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()
#對後輸出後的直方分佈
#feat=net.blobs['prob'].data[0]
#plt.subplot(2,1,1)
#plt.plot(feat.flat)
#plt.show()
#看標籤
#執行測試  
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]]

<p>

每次只能顯示一張特徵圖,可以去掉對應的圖片顯示的程式碼的註釋#,來顯示所需要的某層的影象。

顯示的網路結構資訊如圖:

引數資訊如圖:

卷積層1的過濾器視覺化為:

第一個卷積層過濾後的輸出,顯示96 張(程式碼中寫的是40,可自行修改) :


第二層輸出 256 張 feature,這裡顯示 20 張:

第三個卷積層:全部 384 個 feature map:


第四個卷積層:全部 384 個 feature map:

第五個卷積層:全部 256 個:

第五個 pooling 層:

第六層輸出後的直方分佈:

第七層輸出後的直方分佈:

對後輸出後的直方分佈:

最終的分類結果顯示:

結果可以看出確定是正確的分類。