在 Caffe in Action 中我们已经介绍了如何编译pycaffe, 使用python来调用caffe的接口实现模型的定义和训练是十分方便的, 在权值和网络可视化方面也十分友好, 下面来学习一下pycaffe的使用
Build pyaffe
vim .bashrc
export PYTHONPATH="~/caffe_root_path/distribute/python:$PYTHONPATH"
export LD_LIBRARY_PATH="~/caffe_root_path/distribute/lib:$LD_LIBRARY_PATH"
ImportError: libcaffe.so.1.0.0: cannot open shared object file: No such file or directory
运行环境是我的caffe docker镜像, 见shang/caffe
生成网络 在开始之前要确保pycaffe编译成功, 并且将图片数据转化为LMDB文件.mdb
, 拥有图像的均值文件mean.binaryproto
我们拿cifar10
作为数据集进行实验
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 from caffe import layers as L, params as P, to_protopath = '/root/caffe/examples/cifar10/' train_lmdb = path + 'cifar10_train_lmdb' val_lmdb = path + 'cifar10_test_lmdb' mean_file = path + 'mean.binaryproto' train_proto = path + 'train_shang.prototxt' val_proto = path + 'val_shang.prototxt' def create_net (lmdb, batch_size, include_acc=False) : data, label = L.Data(source=lmdb, backend=P.Data.LMDB, batch_size=batch_size, ntop=2 , transform_param=dict(crop_size=40 , mean_file=mean_file, mirror=True )) conv1 = L.Convolution(data, kernel_size=5 , stride=1 , num_output=16 , pad=2 , weight_filler=dict(type='xavier' )) relu1 = L.ReLU(conv1, in_place=True ) pool1 = L.Pooling(relu1, pool=P.Pooling.MAX, kernel_size=3 , stride=2 ) conv2 = L.Convolution(pool1, kernel_size=3 , stride=1 , num_output=32 , pad=1 , weight_filler=dict(type='xavier' )) relu2 = L.ReLU(conv2, in_place=True ) pool2 = L.Pooling(relu2, pool=P.Pooling.MAX, kernel_size=3 , stride=2 ) fc3 = L.InnerProduct(pool2, num_output=1024 , weight_filler=dict(type='xavier' )) relu3 = L.ReLU(fc3, in_place=True ) drop3 = L.Dropout(relu3, in_place=True ) fc4 = L.InnerProduct(drop3, num_output=10 , weight_filler=dict(type='xavier' )) loss = L.SoftmaxWithLoss(fc4, label) if include_acc: acc = L.Accuracy(fc4, label) return to_proto(loss, acc) else : return to_proto(loss) def write_net () : with open(train_proto, 'w' ) as f: f.write(str(create_net(train_lmdb, batch_size=64 ))) with open(val_proto, 'w' ) as f: f.write(str(create_net(val_lmdb, batch_size=32 , include_acc=True ))) if __name__ == '__main__' : write_net()
在/root/caffe/examples/cifar10/
下面可以看到生成了配置文件train_shang.prototxt
和val_shang.prototxt
通过使用python这样就不用自己手动定义prototxt文件了否则将是一个很麻烦的事情
如果我们将原始图片不转化为lmdb文件, 那么可用ImageData作为数据源输入, 但是我们必须有原始图片的列表清单
, 就是一个txt文件,内容是一行一张图片
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 from caffe import layers as L,params as P,to_protopath='/home/xxx/data/' train_list=path+'train.txt' val_list=path+'val.txt' train_proto=path+'train.prototxt' val_proto=path+'val.prototxt' def create_net (img_list,batch_size,include_acc=False) : data,label=L.ImageData(source=img_list,batch_size=batch_size,new_width=48 ,new_height=48 ,ntop=2 , transform_param=dict(crop_size=40 ,mirror=True )) conv1=L.Convolution(data, kernel_size=5 , stride=1 ,num_output=16 , pad=2 ,weight_filler=dict(type='xavier' )) relu1=L.ReLU(conv1, in_place=True ) pool1=L.Pooling(relu1, pool=P.Pooling.MAX, kernel_size=3 , stride=2 ) conv2=L.Convolution(pool1, kernel_size=53 , stride=1 ,num_output=32 , pad=1 ,weight_filler=dict(type='xavier' )) relu2=L.ReLU(conv2, in_place=True ) pool2=L.Pooling(relu2, pool=P.Pooling.MAX, kernel_size=3 , stride=2 ) conv3=L.Convolution(pool2, kernel_size=53 , stride=1 ,num_output=32 , pad=1 ,weight_filler=dict(type='xavier' )) relu3=L.ReLU(conv3, in_place=True ) pool3=L.Pooling(relu3, pool=P.Pooling.MAX, kernel_size=3 , stride=2 ) fc4=L.InnerProduct(pool3, num_output=1024 ,weight_filler=dict(type='xavier' )) relu4=L.ReLU(fc4, in_place=True ) drop4 = L.Dropout(relu4, in_place=True ) fc5 = L.InnerProduct(drop4, num_output=7 ,weight_filler=dict(type='xavier' )) loss = L.SoftmaxWithLoss(fc5, label) if include_acc: acc = L.Accuracy(fc5, label) return to_proto(loss, acc) else : return to_proto(loss) def write_net () : with open(train_proto, 'w' ) as f: f.write(str(create_net(train_list,batch_size=64 ))) with open(val_proto, 'w' ) as f: f.write(str(create_net(val_list,batch_size=32 , include_acc=True ))) if __name__ == '__main__' : write_net()
即第一层由原来的Data类型,变成了ImageData类型,不需要LMDB文件和均值文件,只需要一个txt文件
生成solver Caffe在训练的时候,需要一些参数设置,我们一般将这些参数设置在一个叫solver.prototxt的文件里面
如果有50000个训练样本,batch_size为64,即每批次处理64个样本,那么需要迭代50000/64=782次才处理完一次全部的样本。我们把处理完一次所有的样本,称之为一代,即epoch。所以,这里的test_interval设置为782,即处理完一次所有的训练数据后,才去进行测试。如果我们想训练100代,则需要设置max_iter为78200
如果有10000个测试样本,batch_size设为32,那么需要迭代10000/32=313次才完整地测试完一次,所以设置test_iter为313
学习率变化规律我们设置为随着迭代次数的增加,慢慢变低。总共迭代78200次,我们将变化lr_rate三次,所以stepsize设置为78200/3=26067,即每迭代26067次,我们就降低一次学习率
那么我们的solver.prototxt如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 base_lr: 0.001 display: 782 gamma: 0.1 lr_policy: "step" max_iter: 78200 momentum: 0.9 snapshot: 7820 snapshot_prefix: "snapshot" solver_mode: GPU solver_type: SGD stepsize: 26067 test_interval: 782 test_iter: 313 test_net: "/root/caffe/examples/cifar10/val.prototxt" train_net: "/root/caffe/examples/cifar10/train.prototxt" weight_decay: 0.0005
代码如下:
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 path = '/root/caffe/examples/cifar10/' solver_file=path+'solver_shang.prototxt' sp={} sp['train_net' ]='"' +path+'train.prototxt"' sp['test_net' ]='"' +path+'val.prototxt"' sp['test_iter' ]='313' sp['test_interval' ]='782' sp['base_lr' ]='0.001' sp['display' ]='782' sp['max_iter' ]='78200' sp['lr_policy' ]='"step"' sp['gamma' ]='0.1' sp['momentum' ]='0.9' sp['weight_decay' ]='0.0005' sp['stepsize' ]='26067' sp['snapshot' ]='7820' sp['snapshot_prefix' ]='"snapshot"' sp['solver_mode' ]='GPU' sp['solver_type' ]='SGD' def write_solver () : with open(solver_file, 'w' ) as f: for key, value in sorted(sp.items()): if not (type(value) is str): raise TypeError('All solver parameters must be strings' ) f.write('%s: %s\n' % (key, value)) if __name__ == '__main__' : write_solver()
如果你觉得上面这种键值对的字典方式,写起来容易出错,我们也可以使用另外一种比较简便的方法
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 from caffe.proto import caffe_pb2s = caffe_pb2.SolverParameter() path='/home/xxx/data/' solver_file=path+'solver1.prototxt' s.train_net = path+'train.prototxt' s.test_net.append(path+'val.prototxt' ) s.test_interval = 782 s.test_iter.append(313 ) s.max_iter = 78200 s.base_lr = 0.001 s.momentum = 0.9 s.weight_decay = 5e-4 s.lr_policy = 'step' s.stepsize=26067 s.gamma = 0.1 s.display = 782 s.snapshot = 7820 s.snapshot_prefix = 'shapshot' s.type = “SGD” s.solver_mode = caffe_pb2.SolverParameter.GPU with open(solver_file, 'w' ) as f: f.write(str(s))
得到一个solver.prototxt文件,有了这个文件,我们下一步就可以进行训练了
模型训练 特别注意, 该文件要放在caffe根目录下, 我的是/root/caffe/
1 2 3 4 5 6 7 import caffepath = '/root/caffe/examples/cifar10/' caffe.set_mode_gpu() caffe.set_device(0 ) solver = caffe.SGDSolver(path + 'cifar10_quick_solver.prototxt' ) solver.solve()
Mnist实例
下载数据解压到/root/caffe/example/
下, 百度云
clone代码, 放在/root/caffe/example/mnist
下, python mnist.py
mnist.py
结果:
1 2 3 I1118 09:11:38.846159 671 solver.cpp:404] Test net output #0: Accuracy1 = 0.9918 I1118 09:11:38.846225 671 solver.cpp:404] Test net output #1: SoftmaxWithLoss1 = 0.0278273 (* 1 = 0.0278273 loss) I1118 09:11:38.846235 671 solver.cpp:322] Optimization Done.
生成deploy 如果要把训练好的模型拿来测试新的图片,那必须得要一个deploy.prototxt文件,这个文件实际上和test.prototxt文件差不多,只是头尾不相同而也。deploy文件没有第一层数据输入层,也没有最后的Accuracy层,但最后多了一个Softmax概率层。
这里我们采用代码的方式来自动生成该文件,以mnist为例:
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 from caffe import layers as L,params as P,to_protoroot = '/root/caffe/examples/' deploy=root+'mnist/deploy.prototxt' def create_deploy () : conv1=L.Convolution(bottom='data' , kernel_size=5 , stride=1 ,num_output=20 , pad=0 ,weight_filler=dict(type='xavier' )) pool1=L.Pooling(conv1, pool=P.Pooling.MAX, kernel_size=2 , stride=2 ) conv2=L.Convolution(pool1, kernel_size=5 , stride=1 ,num_output=50 , pad=0 ,weight_filler=dict(type='xavier' )) pool2=L.Pooling(conv2, pool=P.Pooling.MAX, kernel_size=2 , stride=2 ) fc3=L.InnerProduct(pool2, num_output=500 ,weight_filler=dict(type='xavier' )) relu3=L.ReLU(fc3, in_place=True ) fc4 = L.InnerProduct(relu3, num_output=10 ,weight_filler=dict(type='xavier' )) prob=L.Softmax(fc4) return to_proto(prob) def write_deploy () : with open(deploy, 'w' ) as f: f.write('name:"Lenet"\n' ) f.write('input:"data"\n' ) f.write('input_dim:1\n' ) f.write('input_dim:3\n' ) f.write('input_dim:28\n' ) f.write('input_dim:28\n' ) f.write(str(create_deploy())) if __name__ == '__main__' : write_deploy()
预测分类 到此为止, 我们已经训练好了一个mnist的caffemodel的模型, 并且生成了deploy.prototxt文件, 现在我们就利用这两个文件来对一个新的图片进行分类预测。
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 import caffeimport numpy as nproot = '/root/caffe/examples/' deploy=root + 'mnist/deploy.prototxt' caffe_model=root + 'mnist/lenet_iter_9380.caffemodel' img=root+'mnist/test/5/00008.png' labels_filename = root + 'mnist/test/labels.txt' net = caffe.Net(deploy,caffe_model,caffe.TEST) transformer = caffe.io.Transformer({'data' : net.blobs['data' ].data.shape}) transformer.set_transpose('data' , (2 ,0 ,1 )) transformer.set_raw_scale('data' , 255 ) transformer.set_channel_swap('data' , (2 ,1 ,0 )) im=caffe.io.load_image(img) net.blobs['data' ].data[...] = transformer.preprocess('data' ,im) out = net.forward() labels = np.loadtxt(labels_filename, str, delimiter='\t' ) prob= net.blobs['Softmax1' ].data[0 ].flatten() print proborder=prob.argsort()[-1 ] print 'the class is:' ,labels[order]
输出结果:1 2 [ 0. 0. 0. 0. 0. 1. 0. 0. 0. 0.] the class is: 5
网络可视化 $ python draw_net.py ../models/bvlc_reference_caffenet/train_val.prototxt caffenet.png
Drawing net to caffenet.png
draw_net.py执行的时候带三个参数:
第一个参数:网络模型的prototxt文件
第二个参数:保存的图片路径及名字
第三个参数:--rankdir=x
, x 有四种选项,分别是LR, RL, TB, BT 。用来表示网络的方向,分别是从左到右,从右到左,从上到下,从下到上。默认为LR
如下图所示:
pip install pydot==1.1.0
apt-get install graphviz
loss可视化 将训练过程中的loss和acc画出来
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 import numpyimport matplotlibmatplotlib.use('Agg' ) import matplotlib.pyplot as pltfrom matplotlib.pyplot import savefigimport caffecaffe.set_device(0 ) caffe.set_mode_gpu() path = '/root/caffe/examples/' solver = caffe.SGDSolver(path + 'mnist/solver.prototxt' ) niter = 9380 display = 100 test_iter = 100 test_interval = 938 train_loss = numpy.zeros(numpy.ceil(niter * 1.0 / display)) test_loss = numpy.zeros(numpy.ceil(niter * 1.0 / test_interval)) test_acc = numpy.zeros(numpy.ceil(niter * 1.0 / test_interval)) solver.step(1 ) _train_loss = 0 ; _test_loss = 0 ; _accuracy = 0 for it in range(niter): solver.step(1 ) _train_loss += solver.net.blobs['SoftmaxWithLoss1' ].data if it % display == 0 : train_loss[it // display] = _train_loss / display _train_loss = 0 if it % test_interval == 0 : for test_it in range(test_iter): solver.test_nets[0 ].forward() _test_loss += solver.test_nets[0 ].blobs['SoftmaxWithLoss1' ].data _accuracy += solver.test_nets[0 ].blobs['Accuracy1' ].data test_loss[it / test_interval] = _test_loss / test_iter test_acc[it / test_interval] = _accuracy / test_iter _test_loss = 0 _accuracy = 0 print '\nplot the train loss and test accuracy\n' _, ax1 = plt.subplots() ax2 = ax1.twinx() ax1.plot(display * numpy.arange(len(train_loss)), train_loss, 'g' ) ax1.plot(test_interval * numpy.arange(len(test_loss)), test_loss, 'y' ) ax2.plot(test_interval * numpy.arange(len(test_acc)), test_acc, 'r' ) ax1.set_xlabel('iteration' ) ax1.set_ylabel('loss' ) ax2.set_ylabel('accuracy' ) savefig('./loss.jpg' ) print "\nplot finish!!!\n"
由于在Linux终端下我们将结果保存为loss.jpg
, 保存路径为当前目录
特征可视化 在整个训练过程中, 模型的参数保存在caffemodel
文件里, 实际上就是各层的w和b值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import caffeimport numpy as nproot = '/root/caffe/examples/' deploy=root + 'mnist/deploy.prototxt' caffe_model=root + 'mnist/lenet_iter_9380.caffemodel' net = caffe.Net(deploy,caffe_model,caffe.TEST) [(k,v[0 ].data.shape) for k,v in net.params.items()] w1=net.params['Convolution1' ][0 ].data b1=net.params['Convolution1' ][1 ].data net.forward() [(k,v.data.shape) for k,v in net.blobs.items()] fea=net.blobs['InnerProduct1' ].data print fea
所有的参数和数据都加载到一个net变量里, 这是一个很复杂的对象, 其中net.params: 保存各层的参数值(w和b)
, net.blobs: 保存各层的数据值
1 2 3 [(k,v[0 ].data) for k,v in net.params.items()] [(k,v[0 ].data.shape) for k,v in net.params.items()]
查看各层的参数值,其中k表示层的名称,v[0].data就是各层的W值,而v[1].data是各层的b值。
注意:并不是所有的层都有参数,只有卷积层和全连接层才有
假设我们知道其中第一个卷积层的名字叫’Convolution1’, 则我们可以提取这个层的参数:1 2 w1=net.params['Convolution1' ][0 ].data b1=net.params['Convolution1' ][1 ].data
除了查看参数,我们还可以查看数据,但是要注意的是,net里面刚开始是没有数据的,需要运行net.forward()
1 2 3 4 5 net.forward() [(k,v.data) for k,v in net.blobs.items()] [(k,v.data.shape) for k,v in net.blobs.items()]
实际上数据刚输入的时候叫图片数据,卷积之后就叫特征, 只要知道某个层的名称,就可以抽取这个层的特征, 如果要抽取第一个全连接层的特征,则可用命令:1 2 fea=net.blobs['InnerProduct1' ].data print fea
模型可视化 在训练过程中可以把训练好的模型保存起来,如lenet_iter_10000.caffemodel, 训练多少次就自动保存一下,这个是通过snapshot进行设置的,保存文件的路径及文件名前缀是由snapshot_prefix来设定的。这个文件里面存放的就是各层的参数,即net.params,里面没有数据(net.blobs)。还生成了一个相应的solverstate文件,这个和caffemodel差不多,但它多了一些数据,如模型名称、当前迭代次数等。两者的功能不一样,训练完后保存起来的caffemodel,是在测试阶段用来分类的,而solverstate是用来恢复训练的,防止意外终止而保存的快照, 相当于一个实时备份
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 import numpy as npimport os,sys,caffeimport matplotlibmatplotlib.use('Agg' ) import matplotlib.pyplot as pltfrom matplotlib.pyplot import savefigcaffe_root='./' os.chdir(caffe_root) sys.path.insert(0 ,caffe_root+'python' ) plt.rcParams['figure.figsize' ] = (8 , 8 ) plt.rcParams['image.interpolation' ] = 'nearest' plt.rcParams['image.cmap' ] = 'gray' net = caffe.Net(caffe_root + 'cifar10_quick.prototxt' , caffe_root + 'cifar10_quick_iter_5000.caffemodel' , caffe.TEST) [(k, v[0 ].data.shape) for k, v in net.params.items()] def show_feature (data, padsize=1 , padval=0 ) : data -= data.min() data /= data.max() 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 :]) plt.imshow(data) plt.axis('off' ) weight = net.params["conv1" ][0 ].data print weight.shapeshow_feature(weight.transpose(0 , 2 , 3 , 1 )) weight = net.params["conv2" ][0 ].data print weight.shapeshow_feature(weight.reshape(32 *32 , 5 , 5 )) weight = net.params["conv3" ][0 ].data print weight.shapeshow_feature(weight.reshape(64 *32 ,5 ,5 ))
实验结果:
第一个卷积层:
第二个卷积层:
第三个卷积层:
数据可视化 在测试过程当中, 进行数据的可视化, 前提是得到caffemodel, 和一张测试图片, 我们在cifar10的dog类中选一张图片进行测试, 首先加载模型和测试图片代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import numpy as npimport matplotlib.pyplot as pltimport sys,os,caffecaffe_root = './' sys.path.insert(0 , caffe_root + 'python' ) os.chdir(caffe_root) if not os.path.isfile(caffe_root + 'cifar10_quick_iter_4000.caffemodel' ): print "caffemodel is not exist..." else : print "Ready to Go ..." caffe.set_mode_gpu() net = caffe.Net(caffe_root + 'cifar10_quick.prototxt' , caffe_root + 'cifar10_quick_iter_4000.caffemodel' , caffe.TEST) print str(net.blobs['data' ].data.shape)img = caffe.io.load_image('./dog4.png' ) print img.shapeplt.imshow(img) plt.axis('off' ) print img.shape
然后编写一个函数,将二进制的均值转换为python的均值:
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 def convert_mean (binMean,npyMean) : blob = caffe.proto.caffe_pb2.BlobProto() bin_mean = open(binMean, 'rb' ).read() blob.ParseFromString(bin_mean) arr = np.array( caffe.io.blobproto_to_array(blob) ) npy_mean = arr[0 ] np.save(npyMean, npy_mean ) binMean=caffe_root+'examples/cifar10/mean.binaryproto' npyMean=caffe_root+'examples/cifar10/mean.npy' convert_mean(binMean,npyMean) transformer = caffe.io.Transformer({'data' : net.blobs['data' ].data.shape}) transformer.set_transpose('data' , (2 ,0 ,1 )) transformer.set_mean('data' , np.load(npyMean).mean(1 ).mean(1 )) transformer.set_raw_scale('data' , 255 ) transformer.set_channel_swap('data' , (2 ,1 ,0 )) net.blobs['data' ].data[...] = transformer.preprocess('data' ,img) inputData=net.blobs['data' ].data plt.figure() plt.subplot(1 ,2 ,1 ),plt.title("origin" ) plt.imshow(img) plt.axis('off' ) plt.subplot(1 ,2 ,2 ),plt.title("subtract mean" ) plt.imshow(transformer.deprocess('data' , inputData[0 ])) plt.axis('off' ) print 'subtract mean finished.'
mean.binaryproto是由caffe本身自带的工具计算得来的, 上面的代码生成了mean.npy
文件, 将测试图片进行预处理, 减去均值:
显示网络中每层的数据信息和参数信息
1 2 3 4 5 6 7 8 9 10 11 12 net.forward() print 'Show data parameter:' data_shapes = [(k, v.data.shape) for k, v in net.blobs.items()] for data_shape in data_shapes: print data_shape print 'Show net parameter:' nets_shape = [(k, v[0 ].data.shape) for k, v in net.params.items()] for net_shape in nets_shape: print net_shape
下面编写一个函数,用于显示各层数据和参数, 并显示最后的分类概率:
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 def show_data (data, padsize=1 , padval=0 ) : data -= data.min() data /= data.max() 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 :]) plt.figure() plt.imshow(data, cmap='gray' ) plt.axis('off' ) print '-----Show finished.------' plt.rcParams['figure.figsize' ] = (8 , 8 ) plt.rcParams['image.interpolation' ] = 'nearest' plt.rcParams['image.cmap' ] = 'gray' show_data(net.blobs['conv1' ].data[0 ]) print net.blobs['conv1' ].data.shapeshow_data(net.params['conv1' ][0 ].data.reshape(32 *3 ,5 ,5 )) print net.params['conv1' ][0 ].data.shapeshow_data(net.blobs['pool1' ].data[0 ]) print net.blobs['pool1' ].data.shapeshow_data(net.blobs['conv2' ].data[0 ],padval=0.5 ) print net.blobs['conv2' ].data.shapeshow_data(net.params['conv2' ][0 ].data.reshape(32 **2 ,5 ,5 )) print net.params['conv2' ][0 ].data.shapeshow_data(net.blobs['conv3' ].data[0 ],padval=0.5 ) print net.blobs['conv3' ].data.shapeshow_data(net.params['conv3' ][0 ].data.reshape(64 *32 ,5 ,5 )[:1024 ]) print net.params['conv3' ][0 ].data.shapeshow_data(net.blobs['pool3' ].data[0 ],padval=0.2 ) print net.blobs['pool3' ].data.shapefeat = net.blobs['prob' ].data[0 ] print feat plt.figure() plt.plot(feat.flat) print 'Test finish.'
最终的分类结果:
1 2 3 [ 2.96744809e-04 1.60467534e-05 3.39228063e-05 3.95220798e-03 8.45546026e-07 9.95582640e-01 1.68944953e-05 6.99048323e-05 4.91492074e-07 3.02444241e-05 ]
从输入的结果和图示来看,最大的概率是9.95582640e-01,属于第5类(标号从0开始)。 与cifar10中的10种类型名称进行对比:
airplane[0]、automobile[1]、bird[2]、cat[3]、deer[4]、dog[5]、frog[6]、horse[7]、ship[8]、truck[9]
根据测试结果判断为dog
以上代码全部经过测试, 特别感谢: denny的学习专栏