http://ethereon.github.io/netscope/#/editor 在线可视化模型结构,shift+enterhtml
写模型结构代码的时候能够直接使用这个功能来所见即所得python
xx.prototxtlinux
除了第一行设置该模型的名字,其他全是layer的设置c++
layer应该时没有顺序的,由于layer中要设置bottom和top,分别表示输入端和输出端,可是编写代码按模型顺序写会更加易读git
layer中的不一样type须要不一样的参数github
http://caffe.berkeleyvision.org/tutorial/layers.html 能够看到全部不一样的type数组
type: Python 时须要增长网络
python_param {app
module: ''" python文件名ide
layer: '' python中class的名字
param_str: "{'xx':,..... }"
include {
phase: TRAIN/TEST
}
}
Caffe can be told to include or exclude a layer when running a network in a particular phase
通常也就是输入会有这个设定了,对于TRAIN或者TEST对应不一样的输入层
注意通常layer中param会定义两个用以定义lr和decay,不是覆盖的关系,虽然名字都同样,可是对应的表示不同,通常第一个描述filter,第二个描述bias,以下:
1 layer { 2 name: "conv1" 3 type: "Convolution" 4 bottom: "data" 5 top: "conv1" 6 # learning rate and decay multipliers for the filters 7 param { lr_mult: 1 decay_mult: 1 } 8 # learning rate and decay multipliers for the biases 9 param { lr_mult: 2 decay_mult: 0 } 10 convolution_param { 11 num_output: 96 # learn 96 filters 12 kernel_size: 11 # each filter is 11x11 13 stride: 4 # step 4 pixels between each filter application 14 weight_filler { 15 type: "gaussian" # initialize the filters from a Gaussian 16 std: 0.01 # distribution with stdev 0.01 (default mean: 0) 17 } 18 bias_filler { 19 type: "constant" # initialize the biases to zero (0) 20 value: 0 21 } 22 } 23 }
在可视化模型结构的过程当中,只有layer中的name表明的层可视化出来了,其余的top,bottom取的名字其实表明着数据流,也就是blob,具体指代的图中的边
若是输入输出的边相同,说明这两个结点能够合成
注意对于单个结点,通常都是top名和layer名同样
参考: http://blog.leanote.com/post/braveapple/Caffe-%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7
caffe的运行提供三种接口: C++接口(命令行), Python接口, 和Matlab接口
C++接口(命令行);
./build/tools/caffe train --solver=xx.prototxt
caffe <command> <args>
caffe中自带程序可对图像数据转换成db(leveldb/lmdb)文件
./build/tools/convert_imageset [FLAGS] ROOTFOLDER/LISTFILE DB_NAME
FLAGS: 图片参数组,后面详细介绍
ROOTFOLDER/: 图片存放的绝对路径,从linux系统根目录开始
LISTFILE: 图片文件列表清单,通常为一个txt文件,一行一张图片
DB_NAME: 最终生成的db文件存放目录
若是咱们本地有训练数据集,.jpg格式,那咱们须要本身建立一个图片列表清单,本身写脚本
python接口使用方法;
https://blog.csdn.net/l691899397/article/details/76202178
训练的方式
提取特征的方式
使用输入图片到deploy
怎么计算均值文件
1. 二进制格式的均值计算
caffe中使用的均值数据格式时binaryproto,caffe自带计算均值代码
./build/tools/compute_image_mean examples/mnist/mnist_train_lmdb examples/mnist/mean.binaryproto
第一个参数,是须要计算均值的数据,格式为lmdb的训练数据,第二个参数,计算出来的结果保存文件
2. python格式的均值计算
咱们先按1计算出二进制格式的均值,而后转换成python格式的均值。
1 #!/usr/bin/env python 2 import numpy as np 3 import sys,caffe 4 if len(sys.argv)!=3: 5 print "Usage: python convert_mean.py mean.binaryproto mean.npy" 6 sys.exit() 7 blob = caffe.proto.caffe_pb2.BlobProto() 8 bin_mean = open( sys.argv[1] , 'rb' ).read() 9 blob.ParseFromString(bin_mean) 10 arr = np.array( caffe.io.blobproto_to_array(blob) ) 11 npy_mean = arr[0] 12 np.save( sys.argv[2] , npy_mean )
保存为convert_mean.py
运行: Python convert_mean.py mean.binaryproto mean.npy
*.caffemodel文件里面存放的就是各层的参数,即net.params,里面没有数据net.blobs. *.solverstate时用来恢复训练的,防止意外终止而保存的快照
咱们能够提出caffemodel里面保存的参数进行可视化
参考连接: http://blog.leanote.com/post/braveapple/Caffe-%E4%BD%BF%E7%94%A8%E6%8A%80%E5%B7%A7
python/draw_net.py能够将网络模型由prototxt变成一张图片
sudo apt-get install GraphViz
sudo pip install pydot
采用的也是jupyter notebook进行曲线绘制
若是不须要绘制曲线,只须要训练出一个 caffemodel,直接调用 solver.solve()
就能够了。若是要绘制曲线,就须要把迭代过程当中的值保存下来,所以不能直接调用 solver.solve()
, 须要迭代。在迭代过程当中,每迭代200次测试一次
一样代码参考连接
下载caffemodel文件和均值文件
在测试阶段,须要把测试数据减去均值
synset_words.txt文件
分类方法:
c++方式
./build/examples/cpp_classification/classification.bin \ models/bvlc_reference_caffenet/deploy.prototxt \ models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel \ data/ilsvrc12/imagenet_mean.binaryproto \ data/ilsvrc12/synset_words.txt \ examples/images/cat.jpg
python接口
参考连接
使用别人训练好的参数,此处有一个大坑,那就是必须和别人用同一个 network ,由于参数是根据 network 而来的。固然,最后一层,咱们是能够修改的,由于咱们的数据可能并无1000类,而只有几类。咱们把最后一层的输出类别改一下,而后把层的名称改一下就能够了。最后用别人的参数、修改后的 network 和咱们本身的数据,再进行训练,使得参数适应咱们的数据,这样一个过程,一般称之为微调 (fine tuning)。
修改data层:
把均值文件(mean_file)、数据源文件 (source)、批次大小 (batch_size)和数据源格式 (backend) 这四项做相应的修改。
修改最后一个全链接层:
只须要修改两个地方,一个name,一个时num_output,看本身的分类任务时多少类
咱们能够看下模型的一些参数和一些中间输出
看下如何读取网络的结构:
对于每一层,其结构构成为:(batch_size, channel_dim, height, width)
# 对于每一层,显示输出类型。 for layer_name, blob in net.blobs.iteritems(): print layer_name + '\t' + str(blob.data.shape) data (50, 3, 227, 227) conv1 (50, 96, 55, 55) pool1 (50, 96, 27, 27) norm1 (50, 96, 27, 27) conv2 (50, 256, 27, 27) pool2 (50, 256, 13, 13) norm2 (50, 256, 13, 13) conv3 (50, 384, 13, 13) conv4 (50, 384, 13, 13) conv5 (50, 256, 13, 13) pool5 (50, 256, 6, 6) fc6 (50, 4096) fc7 (50, 4096) fc8 (50, 1000) prob (50, 1000)
看下参数的形状: net.params索引[0]表示weights, [1]表示为biases
参数形状为(output_channels, input_channels, filter_height,filter_width) 时weights
(output_channels,)为biases
for layer_name, param in net.params.iteritems(): print layer_name + '\t' + str(param[0].data.shape), str(param[1].data.shape) conv1 (96, 3, 11, 11) (96,) conv2 (256, 48, 5, 5) (256,) conv3 (384, 256, 3, 3) (384,) conv4 (384, 192, 3, 3) (384,) conv5 (256, 192, 3, 3) (256,) fc6 (4096, 9216) (4096,) fc7 (4096, 4096) (4096,) fc8 (1000, 4096) (1000,)
能够定义一个函数来帮助可视化特征
def vis_square(data): """输入一个形如:(n, height, width) or (n, height, width, 3)的数组,并对每个形如(height,width)的特征进行可视化sqrt(n) by sqrt(n)""" # 正则化数据 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) # 扩展一个像素(白色) # 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.imshow(data) plt.axis('off') plt.show()
看下第一个卷积层的输出特征
# 参数为一个[weights, biases]的列表 filters = net.params['conv1'][0].data vis_square(filters.transpose(0, 2, 3, 1))