在alexnet 训练最后,会有全连接转卷积过程。用来替代滑动窗口。下面函数可以实现这个功能。
emmmm...注意使用时候,根据你的层名字,修改对应代码。我懒得写成通用的了,实在是没啥意义~
然后一般别人都会提供两个网络,一个是全连接,一个是卷积的。 两个对应的层名字不同。我不推荐这个,那样你要去修改他的上下层名字。多麻烦的,直接不该名字,如下面,方便点。
以上~~~
/**
*将全连接网络,转换成为卷积网络
*/
int ChangeFCToConv(char *pszSrcSolver, char *pszDstSolver, char *pszSrcCaffeModel, char *pszDstCaffeModel)
{
caffe::NetParameter netparam;
string model = pszSrcCaffeModel;
ReadNetParamsFromBinaryFileOrDie(model, &netparam);
caffe::LayerParameter *srcFc6 = nullptr, *srcFc7 = nullptr, *srcFc8 = nullptr;
caffe::NetParameter srcNetParam;
ReadNetParamsFromTextFileOrDie(pszSrcSolver, &srcNetParam);
for (int i = 0; i < srcNetParam.layer_size(); i++)
{
caffe::LayerParameter *xxx = srcNetParam.mutable_layer(i);
const string &name = xxx->name();
if (name == "fc7-conv")
{
srcFc6 = srcNetParam.mutable_layer(i);
}
}
int layer_size = netparam.layer_size();
cout << "layer_size = " << layer_size << endl;
caffe::LayerParameter* layerparam = NULL;
caffe::Net<float> net(pszSrcSolver, caffe::TEST);
net.CopyTrainedLayersFrom(netparam);
auto netBlob = net.blob_by_name("fc6");
for (int i = 0; i < layer_size; i++) {
layerparam = netparam.mutable_layer(i);
const string& layername = layerparam->name();
const string& layertype = layerparam->type();
//cout << "layertype: " << layertype << endl;
if (layername == "conv2")
{
srcFc6 = layerparam;
}
if (layername == "fc6") {
const string& layername = layerparam->name();
cout << "layername: " << layername << endl;
const string& topname = layerparam->top(0);
cout << " " << topname << endl;
cout << " " << layerparam->type() << endl;
layerparam->release_inner_product_param();
caffe::BlobProto *blob0 = layerparam->mutable_blobs(0);
caffe::Blob<float> x_blob0;
x_blob0.FromProto(*blob0, true);
x_blob0.Reshape(4096, 256, 6, 6);
x_blob0.ToProto(blob0);
layerparam->set_type("Convolution");
caffe::ConvolutionParameter *conv = new caffe::ConvolutionParameter();
conv->add_kernel_size(1); //设置你需要的参数
conv->set_kernel_size(0, 6);
conv->set_num_output(4096);
layerparam->set_allocated_convolution_param(conv);
}
if (layername == "fc7")
{
const string& layername = layerparam->name();
cout << "layername: " << layername << endl;
const string& topname = layerparam->top(0);
cout << " " << topname << endl;
cout << " " << layerparam->type() << endl;
layerparam->release_inner_product_param();
caffe::BlobProto *blob0 = layerparam->mutable_blobs(0);
caffe::Blob<float> x_blob0;
x_blob0.FromProto(*blob0, true);
x_blob0.Reshape(4096, 4096, 1, 1);
x_blob0.ToProto(blob0);
layerparam->set_type("Convolution");
caffe::ConvolutionParameter *conv = new caffe::ConvolutionParameter();
conv->add_kernel_size(1);
conv->set_kernel_size(0, 1);
conv->set_num_output(4096);
layerparam->set_allocated_convolution_param(conv);
}
if (layername == "fc8")
{
const string& layername = layerparam->name();
cout << "layername: " << layername << endl;
const string& topname = layerparam->top(0);
cout << " " << topname << endl;
cout << " " << layerparam->type() << endl;
layerparam->release_inner_product_param();
caffe::BlobProto *blob0 = layerparam->mutable_blobs(0);
caffe::Blob<float> x_blob0;
x_blob0.FromProto(*blob0, true);
x_blob0.Reshape(2, 4096, 1, 1);
x_blob0.ToProto(blob0);
layerparam->set_type("Convolution");
caffe::ConvolutionParameter *conv = new caffe::ConvolutionParameter();
conv->add_kernel_size(1);
conv->set_kernel_size(0, 1);
conv->set_num_output(1000);
layerparam->set_allocated_convolution_param(conv);
}
if (layername == "data")
{
layerparam->release_data_param();
}
}
//fstream outcaffemodel(pszDstCaffeModel,ios_base::out|ios_base::trunc|ios_base::binary);
//netparam.SerializeToOstream(&outcaffemodel);
WriteProtoToBinaryFile(netparam, pszDstCaffeModel);
//outcaffemodel.close();
google::protobuf::ShutdownProtobufLibrary();
return 0;
}