1. 程式人生 > >使用caffe的python介面實現內部引數視覺化

使用caffe的python介面實現內部引數視覺化

1。這裡並不介紹如何訓練cnn及caffe配置,主要介紹如何實現cnn內部引數視覺化。

#這是我訓練時使用的train.prototxt檔案,在實現視覺化之前首先需要對這個檔案進行修改,
#trian.prototxt檔案的前2層及尾部需要修改,修改成train_deploy.prototxt檔案。
name: "face_train"
layer {
  name: "face"
  type: "Data"
  top: "data"
  top: "label"
  data_param {
    source: "train_lmdb"
    batch_size: 100
    backend:LMDB  
  
} transform_param { scale: 0.00390625 mirror: true } include: { phase: TRAIN } } layer { name: "face" type: "Data" top: "data" top: "label" include { phase: TEST } transform_param { scale: 0.00390625 } data_param { source: "val_lmdb" batch_size: 100
backend: LMDB
} } layer { name: "conv1" type: "Convolution" bottom: "data" ........... ........... ........... layer { name: "ip1" type: "InnerProduct" bottom: "contact_conv" top: "ip1" param { name: "fc6_w" lr_mult: 1 decay_mult: 1 } param { name: "fc6_b"
lr_mult: 2 decay_mult: 0
} inner_product_param { num_output: 160 weight_filler { type: "gaussian" std: 0.005 } bias_filler { type: "constant" value: 0.1 } } layer { name: "ip2" type: "InnerProduct" bottom: "ip1" top: "ip2" param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0 } inner_product_param { num_output: 200 weight_filler { type: "gaussian" std: 0.01 } bias_filler { type: "constant" value: 0 } } } layer { name: "accuracy" type: "Accuracy" bottom: "ip2" bottom: "label" top: "accuracy" include: { phase: TEST } } layer { name: "loss" type: "SoftmaxWithLoss" bottom: "ip2" bottom: "label" top: "loss" }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115

修改後的train_deploy.prototxt,我這裡只需要ip1輸出的資料,故刪除了ip2及後面所有的層,若需要輸出概率,可以先把ip2後的層刪除,再添加個softmax層

#train_deploy.prototxt
name: "face_train"
input: "data"
input_dim: 1 #影象個數
input_dim: 3 #通道數
input_dim: 128
input_dim: 128
layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  .......
  .......
  .......
 layer {
  name: "ip1"
  type:  "InnerProduct"
  bottom: "contact_conv"
  top: "ip1"
  param {
    name: "fc6_w"
    lr_mult: 1
    decay_mult: 1
  }
  param {
    name: "fc6_b"
    lr_mult: 2
    decay_mult: 0
  }
  inner_product_param {
    num_output: 160
    weight_filler {
      type: "gaussian"
      std: 0.005
    }
    bias_filler {
      type: "constant"
      value: 0.1
    }
  }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  1. train_deploy檔案已建立好,現在是python時間,這裡我是在jupyter notebook進行python程式設計,如果不是在jupyter notebook中運算的話,%matplotlib inline會報錯,請先配置好jupyter notebook,這個非常好用
import numpy as np
import matplotlib.pyplot as plt
import os,sys,caffe
%matplotlib inline
caffe_root='/home/chen/Downloads/caffe-master/'
os.chdir(caffe_root)
sys.path.insert(0,caffe_root+'python')

#載入測試圖片,並顯示
#caffe.io.load_image會把讀取的影象轉化為float32,並歸一化
im = caffe.io.load_image('examples/images/image/test_000000-000008.jpg')
print im.shape
plt.imshow(im)
plt.axis('off')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

這裡寫圖片描述

#im的shape是(128,128,3),我們要把它轉換成(1,3,128,128)
X=np.empty((1,3,128,128))
X[0,0,:,:]=im[:,:,0]
X[0,1,:,:]=im[:,:,1]
X[0,2,:,:]=im[:,:,2]
caffe.set_mode_gpu()
#載入網路模型和caffemodel
net = caffe.Net(caffe_root + 'examples/images/train2_deploy.prototxt',
                caffe_root + 'examples/images/face3_iter_40000.caffemodel',
                caffe.TEST)
#將影象資料載入到網路中
net.blobs['data'].data[...] = X 
#執行測試模型,並顯示各層資料資訊
net.forward()
[(k, v.data.shape) for k, v in net.blobs.items()]     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

上面載入資料到網路時並沒有減去均值,因為我這裡並沒有使用均值。 
這裡寫圖片描述

# 編寫一個函式,用於顯示各層資料
def show_data(Inputdata, padsize=1, padval=0):
    data=Inputdata
    for i in range(data.shape[1]):
        data[0,i] -= data[0,i].min()
        data[0,i]/= data[0,i].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))

    # tile the filters into an image
    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:])
    plt.figure()
    plt.imshow(data,cmap='gray')
    plt.axis('off')
plt.rcParams['figure.figsize'] = (8, 8)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
# 編寫一個函式,用於顯示各層資料
def show_data2(Inputdata, padsize=1, padval=0):
    data=Inputdata
    # 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))

    # tile the filters into an image
    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:])
    plt.figure()
    plt.imshow(data,cmap='gray')
    plt.axis('off')
plt.rcParams['figure.figsize'] = (8, 8)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'

#顯示conv1輸出影象
 show_data(net.blobs['conv1'].data[0])   

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

這裡寫圖片描述

#顯示conv2輸出影象
show_data(net.blobs['conv2'].data[0])
  • 1
  • 2
  • 1
  • 2

這裡寫圖片描述

##顯示各層的引數資訊
[(k, v[0].data.shape) for k, v in net.params.items()]
  • 1
  • 2
  • 1
  • 2

這裡寫圖片描述

#顯示conv1所用卷積核
show_data2(net.params['conv1'][0].data.reshape(20*3,3,3))
  • 1
  • 2
  • 1
  • 2

這裡寫圖片描述

#顯示conv2所用卷積核
show_data2(net.params['conv2'][0].data.reshape(40*20,4,4))
  • 1
  • 2
  • 1
  • 2

這裡寫圖片描述

#我這裡只是用CNN提取特徵,故只需要ip1輸出的160維向量,
#如果需要計算概率可以在後面加上一個softmax層
out=net.blobs['ip1'].data
out.shape
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

這裡寫圖片描述

3.總結 
訓練好網路,再提取出160維的特徵。至此完成內部引數視覺化和模型呼叫,那2個顯示函式是用的別人的,會使用OpenCV的朋友可以自己寫一個更好的函式來使用。我這裡就偷下懶了,後面會考慮自己寫個顯示的函式。 
有些朋友可能訓練時使用了均值檔案,請點這裡 http://www.cnblogs.com/denny402/p/5105911.html