一、转模型方法
NCNN编译完成后生成的工具中有一个caffe2ncnn,使用这个工具可以将caffe模型转成ncnn模型,该工具的命令参数格式为:./caffe2ncnn [caffeproto] [caffemodel] [ncnnparam] [ncnnbin],比如:
ncnn/build/tools/caffe/caffe2ncnn deploy.prototxt model.caffemodel model.param model.bin
二、NCNN模型文件说明
成功后会生成model.param和model.bin两个文件。model.param是ncnn网络结构文件,如:
7767517
19 19
Input data 0 1 data 0=64 1=64 2=3
Convolution conv1 1 1 data conv1 0=32 1=5 2=1 3=1 4=0 5=1 6=2400
ReLU relu1 1 1 conv1 conv1_relu1
Pooling pool1 1 1 conv1_relu1 pool1 0=0 1=2 2=2 3=0 4=0
Convolution conv2 1 1 pool1 conv2 0=64 1=3 2=1 3=1 4=0 5=1 6=18432
ReLU relu2 1 1 conv2 conv2_relu2
Pooling pool2 1 1 conv2_relu2 pool2 0=0 1=2 2=2 3=0 4=0
Convolution conv3 1 1 pool2 conv3 0=64 1=3 2=1 3=1 4=0 5=1 6=36864
ReLU relu3 1 1 conv3 conv3_relu3
Pooling pool3 1 1 conv3_relu3 pool3 0=0 1=2 2=2 3=0 4=0
Convolution conv4 1 1 pool3 conv4 0=128 1=2 2=1 3=1 4=0 5=1 6=32768
ReLU relu4 1 1 conv4 conv4_relu4
Pooling pool4 1 1 conv4_relu4 pool4 0=0 1=2 2=2 3=0 4=0
Convolution conv5 1 1 pool4 conv5 0=128 1=2 2=1 3=1 4=0 5=1 6=65536
ReLU relu5 1 1 conv5 conv5_relu5
InnerProduct ip1 1 1 conv5_relu5 ip1 0=512 1=1 2=262144
ReLU relu5 1 1 ip1 ip1_relu5
InnerProduct ip2 1 1 ip1_relu5 ip2 0=2 1=1 2=1024
Softmax softmax 1 1 ip2 softmax 0=0 1=1
第一行:7767517
param版本
第二行:[layer count] [blob count]
• layer count:后续的层line的数量,必须是所有层的准确数量
• blob count:所有blob的数量,一般情况下是大于等于层的数量的
第三行及之后:[layer type] [layer name] [input count] [output count] [input blobs] [output blobs] [layer specific params]
• layer type : 层类型的名字,例如Convolution、Softmax等
• layer name : 层的名字,在所有的层名字里面必须是唯一的
• input count : 本层输入的blob的数量
• output count : 本层输出的blob的数量
• input blobs : 所有输入blob的名字列表,由空格隔开,必须是在所有层的所有输入blob的名字里是唯一的
• output blobs : 所有输出blob的名字列表,由空格隔开,必须是在所有层的所有输出blob的名字里是唯一的
• layer specific params : key=value对的列表,由空格隔开
model.bin为与model.param中结构对应的模型参数。
需要注意的是,有时候转出来的model.param需要手动调整,比如caffe中的某些层在NCNN中不支持(如Tile)需要替换或删除,但不能影响model.param中定义的网络各层参数量,否则model.bin中的参数与model.param对应不上就会导致出错。
三、遇到过的问题
1.报find_blob_index_by_name blob1_splitncnn_3 failed的错误
deploy.prototxt格式问题,需要将
input: "blob1"
input_dim: N
input_dim: C
input_dim: H
input_dim: W
替换成如下格式
layer{
name: "blob1"
type: "Input"
top: "blob1"
input_param {
shape: {
dim: N
dim: C
dim: H
dim: W
}
}
}
2、caffe中的Tile层在ncnn中不支持,且ncnn中的expand层(ExpandDim)与pytorch中的expand_as功能不同,但ncnn中支持两个不同shape的blob相乘,如:N*C*1*1的blob与N*C*H*W的blob相加或相乘等等,这是通过BinaryOp来实现的,但两个blob的shape不相等时,不能用Eltwise层来实现相乘或相加,因为ncnn的Eltwise层中没有进行shape相同检查。
3、ncnn中支持Interp层,原生caffe中一般不支持,所以自定义caffe中的Interp层转到ncnn时,需要注意缩放参数的修改。
4、pytorch和ncnn中支持InstanceNorm层,但caffe中不支持,不过caffe中可以通过BatchNorm层来代替(前提是batch=1),在转ncnn时,需要先将.prototxt中的BatchNorm换成InstanceNorm,如果转换完成之后再在.param中修改,会把.caffemodel中替代InstanceNorm的BatchNorm的参数转到ncnn模型中,ncnn在加载.bin中的参数时会去按顺序获取层的参数(如BatchNorm的mean,var等),而ncnn中的InstanceNorm层的mean、var等是计算当前batch的,即会跳过从caffemodel中转过来的mean、var等参数,这就导致后面的所有层加载的参数发生顺序错乱,最终导致结果出错。比如:InstanceNorm层后面的BatchNorm层读取到的mean,var等参数都是错误的,甚至var为负数,导致sqrt(var)=nan的现象。
5、如果InstanceNorm中没有做线性变换(y=alpha*x+beta),那么caffe转ncnn时,.param中InstanceNorm的第三个参数affine要设置成0,即2=0。因为caffe中的BatchNorm中没有这个参数。
否则加载参数时会报模型参数不匹配的错误,如:"layer load_model 229 instance_norm1 failed"。
6、删减或增加层数之后,注意修改.param中的层数和blob数,否则会报错:
"load_model error at layer 355, parameter file has inconsistent content."