【用训练好的模型,测试自己的一张图片并实现参数可视化——以MNIST数据集为例】
1.数据准备
1.1获取mnist数据集中的某一张图片(自己照的图片也可),将其转换为单通道格式,图片大小28*28,这里已经给大家准备了制作好的10张图片。点击链接,下载图片集
如下图所示:
tips:通过“位深度”的值可以判断是否为单通道,单通道的位深度为“8”,三通道的位深度为“24”。(R,G,B)
1.2 新建标签文档label.txt,内容为:标签值与标签名称的对应(中间用一个空格隔开),如下图所示:
1.3 将准备好的图片9.jpg和新建的label.txt放到caffe-master/data/mnist/的目录下,如下图所示:
1.4 在caffe-master/examples/mnist/文件目录下新建deploy.prototxt文件,其内容如下所示:
name: "LeNet"
layer {
name: "data"
type: "Input"
top: "data"
input_param { shape: { dim: 1 dim: 1 dim: 28 dim: 28 } }
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "conv2"
type: "Convolution"
bottom: "pool1"
top: "conv2"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 50
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "ip1"
type: "InnerProduct"
bottom: "pool2"
top: "ip1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 500
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "ip1"
top: "ip1"
}
layer {
name: "ip2"
type: "InnerProduct"
bottom: "ip1"
top: "ip2"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 10
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "prob"
type: "Softmax"
bottom: "ip2"
top: "prob"
}
1.5 在python开发环境下,进行基本设置
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import os
import caffe
import numpy as np
#设置显示面板的显示样式
plt.rcParams['figure.figsize'] = (8, 8) #宽幅图像
plt.rcParams['image.interpolation'] = 'nearest' #最邻近内插算法
plt.rcParams['image.cmap'] = 'gray' #显示为灰度图像,否则将以“热力图”的彩图显示
2.Caffe模型配置
#定义caffe的根目录
caffe_root='E:/DL/caffe-master/'
#加载caffe的根目录
os.chdir(caffe_root)
#设置caffe为cpu配置
caffe.set_mode_cpu()
#网络模型架构文件
model_def='examples/mnist/deploy.prototxt'
#网络模型参数文件
model_weights='examples/mnist/lenet_iter_1000.caffemodel'
#根据两个配置文件加载网络,并使用“测试”模式
net=caffe.Net(model_def,model_weights,caffe.TEST)
其中lenet._iter_1000.caffemodel就是之前已经训练好并保存下来的网络模型
3.图片维度配置
#数据初始化
#新建caffe数据转换器
trainsformer=caffe.io.Transformer({'data':net.blobs['data'].data.shape})
#python读取图片格式为H*W*K, 需转化为K*H*W
trainsformer.set_transpose('data',(2,0,1))
#加载图片,自动转换为3通道的灰度图,这三个通道完全一样
image=caffe.io.load_image('data/mnist/9.jpg')
#将图片放入数据转换器,变换维度
transformed_image=trainsformer.preprocess('data',image)
#将(3,28,28)转换成(1,1,28,28),若n>1,则网络会自动增广到设置的数量n
net.blobs['data'].data[...]=transformed_image.reshape(1,3,28,28)[:,0].reshape(1,1,28,28)
#驱动图片在网络中前向传播
output=net.forward()
注意:caffe.io.load_image()函数会自动将任何输入的图片转换为3通道的图片(28,28,3),只不过对于单通道的图片而言,这三个通道的图片是完全一样的。首先通过transformer数据转换器转换为(3,28,28),再用reshape函数最终转换为与deploy.prototxt的输入格式一致的(1,1,28,28)
4.输出预测值与网络内的张量形态
#此时网络中只有一张图片,获得该图片的概率值
output_prob=output['prob'][0]
#将最大的概率值输出到控制台
print output_prob.argmax()
#加载标签文件目录
label_file=caffe_root+'data/mnist/label.txt'
#加载标签
labels=np.loadtxt(label_file,str,delimiter=' ')
#获取标签值实际对应的标签名称
print 'output label:',labels[output_prob.argmax()][1]
#输出测试图片经过各层时的张量形态
for layer_name,blob in net.blobs.iteritems():
print layer_name+' '+str(blob.data.shape)
#输出各层参数的张量形态
for layer_name,param in net.params.iteritems():
print layer_name+'\t'+str(param[0].data.shape)+str(param[1].data.shape)
其结果如下图所示:
5.网络中的测试图片可视化
#定义python中的可视化面板
def vis_square(data):
#获得shape为(n,height,width)或(n,height,width,3)的序列,并将每一个图片均匀地显示在网格界面中
#正则化数据
data=(data-data.min())/(data.max()-data.min())
#根据图片的数量绘制正方形的布局网格
n=int(np.ceil(np.sqrt(data.shape[0])))
#为每一个小的显示窗口绘制边框
padding=(((0,n**2-data.shape[0]),(0,1),(0,1))+((0,0),)*(data.ndim-3))
#边框的颜色为白色
data=np.pad(data,padding,mode='constant',constant_values=1)
#将图片用小的窗口显示
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.imshow(data)
plt.axis('off')
plt.show()
#参数可视化
#由于通道数是1,所以只能用(n,height,width)这样的参数形式,只有3通道才可以用(n,height,width,3)的参数形式
#data的shape是(n,c,h,w),通过[:,0]取所有行(第一维度下)的第0个(第二个维度下的,即第0个通道)的数据,
#之后shape变为(n,h,w)
#获取第一层卷积核的数据
filters=net.params['conv1'][0].data[:,0]
#这里的data[n],中的n表示batch中的某一幅图
feat=net.blobs['con1'].data[0]
#可视化卷积核参数
vis_square(filters)
显示结果如下图所示:
将vis_square中的参数filters改为feat后,即可显示测试图片在经过第一个卷积层之后的效果:
不难想出,将“conv1”改为“conv2“、“pool1”后,将会获得对应的层的数据值,这里不再赘述。
注意:[:,0]的方法,是python对张量处理比较常用的降维处理技巧,应该熟练掌握!
reshape、transpose同样也是python中对张量处理常用的变维技巧,应熟练掌握!
6.Softmax概率输出图表可视化
feat=net.blobs['prob'].data[0]
plt.figure(figsize=(10,5))
plt.plot(feat.flat)
plt.show()
其结果如下图所示:
可以直观地看出,根据我们输入的这张测试图片(如下图所示),模型网络作出了较为准确的识别,识别为“9”的概率最大,而且也存在着识别成“4”的偏向,符合我们人眼的直观视觉!
实战经验总结:
1.要学会对张量维度的处理技巧,这在深度学习网络模型中至关重要!