1. 如何调用caffe已经训练好的net
文件夹里面,然后写一个main函数调用这个类就可以了,比如:复制,保存到caffe/examples/myproject/net_operator.hpp,然后同目录下写一个main.cpp,在main函数里面#include "net_operator.hpp",就可以使用这个类了:const string net_prototxt = "..."; // 你的网络的prototxt文件,用绝对路径,下面同理const string pre_trained_file = "..."; // 你训练好的.caffemodel文件const string img_path = "..."; // 你要测试的图片路径// 创建NetOperator对象NetOperator net_operator(net_prototxt, pre_trained_file);Blob<float> *blob = net_operator.processImage(img_path);// blob就得到了最后一层的输出结果,至于blob里面是怎么存放数据的,你需要去看看官网对它的定义写完main.cpp之后,到caffe目录下,make,然后它会编译你写的文件,对应生成的可执行文件。比如按我上面写的那样,make之后就会在caffe/build/examples/myproject文件夹里面生成一个main.bin,执行这个文件就可以了。因为生成的可执行文件并不是直接在代码目录下,所以前面我建议你写的路径用绝对路径另外如果你要获取的不是最后一层的输出,你需要修改一下processImage函数的返回值,通过NetOperator的成员变量net_来获取你需要的blob,比如有个blob名称为"label",你想获取这个blob,可以通过net_->blob_by_name("label")来获取,当然获取到的是shared_ptr<Blob<float> >类型的,搜一下boost shared_ptr就知道跟普通指针有什么不同了好了,接下来是贴代码了:#include <caffe/caffe.hpp>#include <opencv2/core/core.hpp>#include <opencv2/highgui www.hbbz08.com /highgui.hpp>#include <opencv2/imgproc/imgproc.hpp>#include <iosfwd>#include <memory>#include <string>#include <utility>#include <vector>using namespace caffe; // NOLINT(build/namespaces)using std::string;class NetOperator{public: NetOperator(const string& net_prototxt); NetOperator(const string& net_prototxt, const string& trained_file); ~NetOperator() { } int batch_size() { return batch_size_; } Blob<float>* processImage(const string &img_path, bool is_color = true); Blob<float>* processImages(const vector<string> &img_paths, bool is_color = true);private: void createNet(const string& net_prototxt); // read the image and store it in the idx position of images in the blob void readImageToBlob(const string &img_path, int idx = 0, bool is_color = true); shared_ptr<Net<float> > net_; cv::Size input_geometry_; int batch_size_; int num_channels_; Blob<float>* input_blob_; TransformationParameter transform_param_; shared_ptr<DataTransformer<float> > data_transformer_; Blob<float> transformed_data_;};NetOperator::NetOperator(const string& net_prototxt) { createNet(net_prototxt);}NetOperator::NetOperator(const string& net_prototxt, const string& trained_file) { createNet(net_prototxt); net_->CopyTrainedLayersFrom(trained_file);}void NetOperator::createNet(const string& net_prototxt) {#ifdef CPU_ONLY Caffe::set_mode(Caffe::CPU);#else Caffe::set_mode(Caff www.hnne.com e::GPU);#endif net_.reset(new Net<float>(net_prototxt, TEST)); CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input."; CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output."; Blob<float>* input_layer = net_->input_blobs()[0]; batch_size_ = input_layer->num(); num_channels_ = input_layer->channels(); CHECK(num_channels_ == 3 || num_channels_ == 1) << "Input layer should have 1 or 3 channels."; input_geometry_ = cv::Size(input_layer->width(), input_layer->height()); // reshape the output shape of the DataTransformer vector<int> top_shape(4); top_shape[0] = 1; top_shape[1] = num_channels_; top_shape[2] = input_geometry_.height; top_shape[3] = input_geometry_.width; this->transformed_data_.Reshape(top_shape);}Blob<float>* NetOperator::processImage(const string &img_path, bool is_color) { // reshape the net for the input input_blob_ = net_->input_blobs()[0]; input_blob_->Reshape(1, num_channels_, input_geometry_.height, input_geometry_.width); net_->Reshape(); readImageToBlob(img_path, 0, is_color); net_->ForwardPrefilled(); return net_->output_blobs()[0];}Blob<float>* NetOperator::processImages(const vector<string> &img_paths, bool is_color) { int img_num = img_paths.size(); // reshape the net for the input input_blob_ = net_->input_blobs()[0]; input_blob_->Reshape(img_num, num_channels_, input_geometry_.height, input_geometry_.width); net_->Reshape(); for (int i=0; i<img_num; i++) { readImageToBlob(img_paths[i], i, is_color); } net_->ForwardPrefilled(); return net_->output_blobs()[0];}void NetOperator::readImageToBlob(const string &img_path, int idx, bool is_color) { // read the image and resize to the target size cv::Mat img; int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR : CV_LOAD_IMAGE_GRAYSCALE); cv::Mat cv_img_origin = cv::imread(img_path, cv_read_flag); if (!cv_img_origin.data) { LOG(ERROR) << "Could not open or find file " << img_path; return ; } if (input_geometry_.height > 0 && input_geometry_.width > 0) { cv::resize(cv_img_origin, img, input_geometry_); } else { img = cv_img_origin; } // transform the image to a blob using DataTransformer // create a DataTransformer using default TransformationParameter (no transformation) data_transformer_.reset( new DataTransformer<float>(transform_param_, TEST)); data_transformer_->InitRand(); // set the output of DataTransformer to the idx image of the input blob int offset = input_blob_->offset(idx); this->transformed_data_.set_cpu_data(input_blob_->mutable_cpu_data() + offset); // transform the input image data_transformer_->Transform(img, &(this->transformed_data_));
2. caffe中怎么固定前面的网络参数,训练后面层的参数
1、会更新,finetune的过程相当于继续训练,跟直接训练的区别是初始化的时候:
a. 直接训练是按照网络定义指定的方式初始化(如高斯随机初始化)
b. finetune是用你已经有的参数文件来初始化(就是之前训练好的caffemodel)
2、嗯,这个问题有两种情况:比如有4个全连接层A->B->C->D
a. 你希望C层的参数不会改变,C前面的AB层的参数也不会改变,这种情况也就是D层的梯度不往前反向传播到D层的输入blob(也就是C层的输出blob 没有得到梯度),你可以通过设置D层的propagate_down为false来做到。
propagate_down的数量与输入blob的数量相同,假如你某个层有2个输入blob,那么你应该在该layer的Param里面写上两行:
propagate_down : 0 # 第1个输入blob不会得到反向传播的梯度
propagate_down : 0 # 第2个输入blob不会得到反向传播的梯度
这样的话,你这个layer的梯度就不会反向传播啦,前面的所有layer的参数也就不会改变了
b. 你希望C层的参数不会改变,但是C前面的AB层的参数会改变,这种情况,只是固定了C层的参数,C层得到的梯度依然会反向传播给前面的B层。只需要将对应的参数blob的学习率调整为0:
你在layer里面加上param { lr_mult: 0 }就可以了,比如全连接层里面:
layer {
type: "InnerProct"
param { # 对应第1个参数blob的配置,也就是全连接层的参数矩阵的配置
lr_mult: 0 # 学习率为0,其他参数可以看caffe.proto里面的ParamSpec这个类型
}
param { # 对应第2个参数blob的配置,也就是全连接层的偏置项的配置
lr_mult: 0 # 学习率为0
}
}
不知道这样说你能不能理解
3. Caffe中权值是怎么更新的
1、会更新,finetune的过程相当于继续训练,跟直接训练的区别是初始化的时候内: a. 直接训练容是按照网络定义指定的方式初始化(如高斯随机初始化) b. finetune是用你已经有的参数文件来初始化(就是之前训练好的caffemodel)
4. 如何利用Caffe训练ImageNet分类网络
1.下载好来自ImageNet的training和validation数据集合;分别存放在如下的格式:
/path/to/imagenet/train/n01440764/n01440764_10026.JPEG
/path/to/imagenet/val/ILSVRC2012_val_00000001.JPEG
2. 进行一些预处理操作:
cd $CAFFE_ROOT/data/ilsvrc12/
./get_ilsvrc_aux.sh
3.训练数据和测试数据分别放在train.txt和val.txt中,里面有他们的文件和相对应的标签;
4. 最后作者把1000类的类名用0--999表示,他们相对应的类别名称则用synset_words.txt 来存储他们之间的映射。
5.作者提到怎么去是否应该先把图像都归一化到256*256中,作者提到用Maprece去加快这种过程;
也可以直接这么做:
for name in /path/to/imagenet/val/*.JPEG; do
convert -resize 256x256\! $name $name
Done
6.在 create_imagenet.sh中设置训练的参数,并在里面指定训练和测试的数据库路径,如果图像没有提前归一化到相同的大小,则需要加”RESIZE=true“,设置”GLOG_logtostderr=1 “表示了可以参考更多的信息,
在执行 ./create_imagenet.sh 之后会有新的数据文件生成:
ilsvrc12_train_leveldb 和 ilsvrc12_val_leveldb
7. 因为模型需要我们减去图像的均值,所以我们需要计算图像均值,在工具
tools/compute_image_mean.cpp 实现了这种操作,
或者可以直接用:
./make_imagenet_mean.sh 脚本来进行计算图像均值,并生成:
data/ilsvrc12/imagenet_mean.binaryproto 文件
8.定义网络的结构:imagenet_train_val.prototxt .
里面有两行指定了数据库和图像的路径
source: "ilvsrc12_train_leveldb"
mean_file:"../../data/ilsvrc12/imagenet_mean.binaryproto"
并且指定了 include { phase: TRAIN } or include { phase: TEST } .来区分训练和测试
9.关于输入层的不同:
训练数据中,,data项来自 ilsvrc12_train_leveldb 并且进行了随机镜像操作,测试数据中data项来自于ilsvrc12_val_leveldb 而没有进行随机镜像操作;
10.输出层的不同:
输出层都为 softmax_loss 层,在训练网络当中,用来计算损失函数,并且用来初始化BP过程,测试网络同样有一个第二个输出层,accuracy,它用来报告测试的精度,在训练的过程中,测试网络将实例化并且测试准确率,产成的命令行为:Test score #0: xxx and Test score #1: xxx 等。
11.运行网络,其中设置
每批batch为256个,运行450000次迭代,接近90次epoch;
每1000次迭代,就在用测试集进行测试;
设置初始的学习率为0.01,并且每100000次迭代中进行学习率下降,大概进行20次epoch;
每20次epoch就显示出一些数据信息;
网络训练的动量为0.9,权重衰减因子为0.0005,
每10000次迭代中,就生成当前状态的快照;
这些设置在 examples/imagenet/imagenet_solver.prototxt .中进行设置,并且同样我们需要指定文件的路径:
net: "imagenet_train_val.prototxt"
12.开始训练网络:
./train_imagenet.sh
13. 在K20中,每20个迭代花费36s,所以,一幅图像的一次前馈+反馈(FW+BW)大概需要7ms,前馈花费2.5ms,剩下的是反馈,
可以在 examples/net_speed_benchmark.cpp 中进行时间的查看;
14.因为我们有保存了快照,所以我们可以通过
./resume_training.sh 来进行resume恢复,脚本caffe_imagenet_train_1000.solverstate 保留了要恢复的所有信息,
15.总结,Caffe可以很方便进行通过设置文件的方式来进行设置不同的网络结构。
5. Caffe训练自己的imagenet,ubuntu提示killed
1、准备数据。
假设已经下载好数据集和验证集,存储路径为:
/path/to/imagenet/train/n01440764/n01440764_10026.JPEG
/path/to/imagenet/val/ILSVRC2012_val_00000001.JPEG
首选需要创建一个txt文件,列举出所有图像以及对应的lable,caffe包“Python/caffe/imagenet/ilsvrc_2012_train.txt”和“ilsvrc_2012_val.txt”两个文件分别是标好的训练集和验证集的文件,共分为1000类。
还需要注意的是,所有的图像都需要归一到同样的尺寸。
2、转化生成训练集。
运行下面的命令:
GLOG_logtostderr=1 examples/convert_imageset.bin /path/to/imagenet/train/ python/caffe/imagenet/ilsvrc_2012_train.txt /path/to/imagenet-train-leveldb
生成文件存储在“/path/to/imagenet-train_leveldb”路径下。
3、计算图像均值。
执行命令:
examples/demo_compute_image_mean.bin /path/to/imagenet-train-leveldb /path/to/mean.binaryproto
第一个参数是执行脚本代码,第二个参数是上一步生成的数据集,第三个参数是存储图像均值的目录路径。
4、定义网络。
ImageNet的网络定义在“examples/imagenet.prototxt”文件中,使用时需要修改里面source和meanfile变量的值,指向自己文件的路径。
仔细观察imagenet.prototxt和imagenet_val.prototxt文件可以发现,训练和验证的参数大部分都相同,不同之处在于初始层和最后一层。训练时,使用softmax_loss层来计算损失函数和初始化后向传播,验证时,使用accuracy层来预测精确度。
在文件“examples/imagenet_solver.prototxt”中定义solver协议,同样需要修改train_net和test_net的路径。
5、训练网络。
执行命令:
GLOG_logtostderr=1 examples/train_net.bin examples/imagenet_solver.prototxt
6、在python中使用已经训练好的模型。
Caffe只提供封装好的imagenet模型,给定一副图像,直接计算出图像的特征和进行预测。首先需要下载模型文件。
Python代码如下:
[python] view plain print?
from caffe import imagenet
from matplotlib import pyplot
# Set the right path to your model file, pretrained model
# and the image you would like to classify.
MODEL_FILE = 'examples/imagenet_deploy.prototxt'
PRETRAINED = '/home/jiayq/Downloads/caffe_reference_imagenet_model’
IMAGE_FILE = '/home/jiayq/lena.png'
net = imagenet.ImageNetClassifier(MODEL_FILE, PRETRAINED)
#预测
prediction = net.predict(IMAGE_FILE)
#绘制预测图像
print 'prediction shape:', prediction.shape
pyplot.plot(prediction)
prediction shape: (1000,)
[<matplotlib.lines.Line2D at 0x8faf4d0>] #结果如图所示
图上的横轴表示的label,纵轴表示在该类别上的概率,有图我们看到,lena.jpg被分到了”sombrero”这组,结果还算准确。
6. caffe ssd 里的resize是怎么实现的
环境为caffe下以imagenet为样本集训练resnset网络。
在初始化生成lmdb的create_imagenet.sh脚本中,resize参数分别设置为256*256和512*512。