永发信息网

如何在程序中调用Caffe做图像分类

答案:2  悬赏:20  手机版
解决时间 2021-03-05 10:14
如何在程序中调用Caffe做图像分类
最佳答案
Caffe是目前深度学习比较优秀好用的一个开源库,采样c++和CUDA实现,具有速度快,模型定义方便等优点。学习了几天过后,发现也有一个不方便的地方,就是在我的程序中调用Caffe做图像分类没有直接的接口。Caffe的数据层可以从数据库(支持leveldb、lmdb、hdf5)、图片、和内存中读入。我们要在程序中使用,当然得从内存中读入,我们首先在模型定义文件中定义数据层:
layers {
name: "mydata"
type: MEMORY_DATA
top: "data"
top: "label"
transform_param {
scale: 0.00390625
}
memory_data_param {
batch_size: 10
channels: 1
height: 24
width: 24
}
}

这里必须设置memory_data_param中的四个参数,对应这些参数可以参见源码中caffe.proto文件。现在,我们可以设计一个Classifier类来封装一下:
#ifndef CAFFE_CLASSIFIER_H
#define CAFFE_CLASSIFIER_H

#include
#include
#include "caffe/net.hpp"
#include "caffe/data_layers.hpp"
#include
using cv::Mat;

namespace caffe {

template
class Classifier {
public:
explicit Classifier(const string& param_file, const string& weights_file);
Dtype test(vector &images, vector &labels, int iter_num);
virtual ~Classifier() {}
inline shared_ptr > net() { return net_; }
void predict(vector &images, vector *labels);
void predict(vector &data, vector *labels, int num);
void extract_feature(vector &images, vector> *out);

protected:
shared_ptr > net_;
MemoryDataLayer *m_layer_;
int batch_size_;
int channels_;
int height_;
int width_;

DISABLE_COPY_AND_ASSIGN(Classifier);
};
}//namespace
#endif //CAFFE_CLASSIFIER_H

构造函数中我们通过模型定义文件(.prototxt)和训练好的模型(.caffemodel)文件构造一个Net对象,并用m_layer_指向Net中的memory data层,以便待会调用MemoryDataLayer中AddMatVector和Reset函数加入数据。
#include

#include
#include
#include

#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/upgrade_proto.hpp"
#include "caffe_classifier.h"

namespace caffe {

template
Classifier::Classifier(const string& param_file, const string& weights_file) : net_()
{
net_.reset(new Net(param_file, TEST));
net_->CopyTrainedLayersFrom(weights_file);
//m_layer_ = (MemoryDataLayer*)net_->layer_by_name("mnist").get();
m_layer_ = (MemoryDataLayer*)net_->layers()[0].get();
batch_size_ = m_layer_->batch_size();
channels_ = m_layer_->channels();
height_ = m_layer_->height();
width_ = m_layer_->width();
}

template
Dtype Classifier::test(vector &images, vector &labels, int iter_num)
{
m_layer_->AddMatVector(images, labels);
//
int iterations = iter_num;
vector* > bottom_vec;

vector test_score_output_id;
vector test_score;
Dtype loss = 0;
for (int i = 0; i < iterations; ++i) {
Dtype iter_loss;
const vector*>& result =
net_->Forward(bottom_vec, &iter_loss);
loss += iter_loss;
int idx = 0;
for (int j = 0; j < result.size(); ++j) {
const Dtype* result_vec = result[j]->cpu_data();
for (int k = 0; k < result[j]->count(); ++k, ++idx) {
const Dtype score = result_vec[k];
if (i == 0) {
test_score.push_back(score);
test_score_output_id.push_back(j);
} else {
test_score[idx] += score;
}
const std::string& output_name = net_->blob_names()[
net_->output_blob_indices()[j]];
LOG(INFO) << "Batch " << i << ", " << output_name << " = " << score;
}
}
}
loss /= iterations;
LOG(INFO) << "Loss: " << loss;
return loss;
}

template
void Classifier::predict(vector &images, vector *labels)
{
int original_length = images.size();
if(original_length == 0)
return;
int valid_length = original_length / batch_size_ * batch_size_;
if(original_length != valid_length)
{
valid_length += batch_size_;
for(int i = original_length; i < valid_length; i++)
{
images.push_back(images[0].clone());
}
}
vector valid_labels, predicted_labels;
valid_labels.resize(valid_length, 0);
m_layer_->AddMatVector(images, valid_labels);
vector* > bottom_vec;
for(int i = 0; i < valid_length / batch_size_; i++)
{
const vector*>& result = net_->Forward(bottom_vec);
const Dtype * result_vec = result[1]->cpu_data();
for(int j = 0; j < result[1]->count(); j++)
{
predicted_labels.push_back(result_vec[j]);
}
}
if(original_length != valid_length)
{
images.erase(images.begin()+original_length, images.end());
}
labels->resize(original_length, 0);
std::copy(predicted_labels.begin(), predicted_labels.begin() + original_length, labels->begin());
}

template
void Classifier::predict(vector &data, vector *labels, int num)
{
int size = channels_*height_*width_;
CHECK_EQ(data.size(), num*size);
int original_length = num;
if(original_length == 0)
return;
int valid_length = original_length / batch_size_ * batch_size_;
if(original_length != valid_length)
{
valid_length += batch_size_;
for(int i = original_length; i < valid_length; i++)
{
for(int j = 0; j < size; j++)
data.push_back(0);
}
}
vector predicted_labels;
Dtype * label_ = new Dtype[valid_length];
memset(label_, 0, valid_length);
m_layer_->Reset(data.data(), label_, valid_length);
vector* > bottom_vec;
for(int i = 0; i < valid_length / batch_size_; i++)
{
const vector*>& result = net_->Forward(bottom_vec);
const Dtype * result_vec = result[1]->cpu_data();
for(int j = 0; j < result[1]->count(); j++)
{
predicted_labels.push_back(result_vec[j]);
}
}
if(original_length != valid_length)
{
data.erase(data.begin()+original_length*size, data.end());
}
delete [] label_;
labels->resize(original_length, 0);
std::copy(predicted_labels.begin(), predicted_labels.begin() + original_length, labels->begin());
}
template
void Classifier::extract_feature(vector &images, vector> *out)
{
int original_length = images.size();
if(original_length == 0)
return;
int valid_length = original_length / batch_size_ * batch_size_;
if(original_length != valid_length)
{
valid_length += batch_size_;
for(int i = original_length; i < valid_length; i++)
{
images.push_back(images[0].clone());
}
}
vector valid_labels;
valid_labels.resize(valid_length, 0);
m_layer_->AddMatVector(images, valid_labels);
vector* > bottom_vec;
out->clear();
for(int i = 0; i < valid_length / batch_size_; i++)
{
const vector*>& result = net_->Forward(bottom_vec);
const Dtype * result_vec = result[0]->cpu_data();
const int dim = result[0]->count(1);
for(int j = 0; j < result[0]->num(); j++)
{
const Dtype * ptr = result_vec + j * dim;
vector one_;
for(int k = 0; k < dim; ++k)
one_.push_back(ptr[k]);
out->push_back(one_);
}
}
if(original_length != valid_length)
{
images.erase(images.begin()+original_length, images.end());
out->erase(out->begin()+original_length, out->end());
}
}
INSTANTIATE_CLASS(Classifier);
} // namespace caffe

由于加入的数据个数必须是batch_size的整数倍,所以我们在加入数据时采用填充的方式。
CHECK_EQ(num % batch_size_, 0) <<
"The added data must be a multiple of the batch size."; //AddMatVector

在模型文件的最后,我们把训练时的loss层改为argmax层:
layers {
name: "predicted"
type: ARGMAX
bottom: "prob"
top: "predicted"
}
全部回答
caffe是目前深度学习比较优秀好用的一个开源库,采样c++和cuda实现,具有速度快,模型定义方便等优点。学习了几天过后,发现也有一个不方便的地方,就是在我的程序中调用caffe做图像分类没有直接的接口。caffe的数据层可以从数据库(支持leveldb、lmdb、hdf5)、图片、和内存中读入。我们要在程序中使用,当然得从内存中读入,我们首先在模型定义文件中定义数据层: layers {  name: "mydata"  type: memory_data  top: "data"  top: "label"  transform_param {    scale: 0.00390625  }  memory_data_param {    batch_size: 10    channels: 1    height: 24    width: 24  } } 这里必须设置memory_data_param中的四个参数,对应这些参数可以参见源码中caffe.proto文件。现在,我们可以设计一个classifier类来封装一下: #ifndef caffe_classifier_h #define caffe_classifier_h #include  #include  #include "caffe/net.hpp" #include "caffe/data_layers.hpp" #include  using cv::mat; namespace caffe { template  class classifier { public:  explicit classifier(const string& param_file, const string& weights_file);  dtype test(vector &images, vector &labels, int iter_num);  virtual ~classifier() {}  inline shared_ptr > net() { return net_; }  void predict(vector &images, vector *labels);  void predict(vector &data, vector *labels, int num);  void extract_feature(vector &images, vector> *out); protected:  shared_ptr > net_;  memorydatalayer *m_layer_;  int batch_size_;  int channels_;  int height_;  int width_;  disable_copy_and_assign(classifier); }; }//namespace  #endif //caffe_classifier_h 构造函数中我们通过模型定义文件(.prototxt)和训练好的模型(.caffemodel)文件构造一个net对象,并用m_layer_指向net中的memory data层,以便待会调用memorydatalayer中addmatvector和reset函数加入数据。 #include  #include  #include  #include  #include "caffe/net.hpp" #include "caffe/proto/caffe.pb.h" #include "caffe/util/io.hpp" #include "caffe/util/math_functions.hpp" #include "caffe/util/upgrade_proto.hpp" #include "caffe_classifier.h" namespace caffe { template  classifier::classifier(const string& param_file, const string& weights_file) : net_() {  net_.reset(new net(param_file, test));  net_->copytrainedlayersfrom(weights_file);  //m_layer_ = (memorydatalayer*)net_->layer_by_name("mnist").get();  m_layer_ = (memorydatalayer*)net_->layers()[0].get();  batch_size_ = m_layer_->batch_size();  channels_ = m_layer_->channels();  height_ = m_layer_->height();  width_ = m_layer_->width(); } template  dtype classifier::test(vector &images, vector &labels, int iter_num) {    m_layer_->addmatvector(images, labels);    //    int iterations = iter_num;    vector* > bottom_vec;  vector test_score_output_id;  vector test_score;  dtype loss = 0;  for (int i = 0; i < iterations; ++i) {    dtype iter_loss;    const vector*>& result =        net_->forward(bottom_vec, &iter_loss);    loss += iter_loss;    int idx = 0;    for (int j = 0; j < result.size(); ++j) {      const dtype* result_vec = result[j]->cpu_data();      for (int k = 0; k < result[j]->count(); ++k, ++idx) {        const dtype score = result_vec[k];        if (i == 0) {          test_score.push_back(score);          test_score_output_id.push_back(j);        } else {          test_score[idx] += score;        }        const std::string& output_name = net_->blob_names()[            net_->output_blob_indices()[j]];        log(info) << "batch " << i << ", " << output_name << " = " << score;      }    }  }  loss /= iterations;  log(info) << "loss: " << loss;  return loss; } template  void classifier::predict(vector &images, vector *labels) {    int original_length = images.size();    if(original_length == 0)        return;    int valid_length = original_length / batch_size_ * batch_size_;    if(original_length != valid_length)    {        valid_length += batch_size_;        for(int i = original_length; i < valid_length; i++)        {            images.push_back(images[0].clone());        }    }    vector valid_labels, predicted_labels;    valid_labels.resize(valid_length, 0);    m_layer_->addmatvector(images, valid_labels);    vector* > bottom_vec;    for(int i = 0; i < valid_length / batch_size_; i++)    {        const vector*>& result = net_->forward(bottom_vec);        const dtype * result_vec = result[1]->cpu_data();        for(int j = 0; j < result[1]->count(); j++)        {            predicted_labels.push_back(result_vec[j]);        }    }    if(original_length != valid_length)    {        images.erase(images.begin()+original_length, images.end());    }    labels->resize(original_length, 0);    std::copy(predicted_labels.begin(), predicted_labels.begin() + original_length, labels->begin()); } template  void classifier::predict(vector &data, vector *labels, int num) {    int size = channels_*height_*width_;    check_eq(data.size(), num*size);    int original_length = num;    if(original_length == 0)        return;    int valid_length = original_length / batch_size_ * batch_size_;    if(original_length != valid_length)    {        valid_length += batch_size_;        for(int i = original_length; i < valid_length; i++)        {            for(int j = 0; j < size; j++)                data.push_back(0);        }    }    vector predicted_labels;    dtype * label_ = new dtype[valid_length];    memset(label_, 0, valid_length);    m_layer_->reset(data.data(), label_, valid_length);    vector* > bottom_vec;    for(int i = 0; i < valid_length / batch_size_; i++)    {        const vector*>& result = net_->forward(bottom_vec);        const dtype * result_vec = result[1]->cpu_data();        for(int j = 0; j < result[1]->count(); j++)        {            predicted_labels.push_back(result_vec[j]);        }    }    if(original_length != valid_length)    {        data.erase(data.begin()+original_length*size, data.end());    }    delete [] label_;    labels->resize(original_length, 0);    std::copy(predicted_labels.begin(), predicted_labels.begin() + original_length, labels->begin()); } template  void classifier::extract_feature(vector &images, vector> *out) {    int original_length = images.size();    if(original_length == 0)        return;    int valid_length = original_length / batch_size_ * batch_size_;    if(original_length != valid_length)    {        valid_length += batch_size_;        for(int i = original_length; i < valid_length; i++)        {            images.push_back(images[0].clone());        }    }    vector valid_labels;    valid_labels.resize(valid_length, 0);    m_layer_->addmatvector(images, valid_labels);    vector* > bottom_vec;    out->clear();    for(int i = 0; i < valid_length / batch_size_; i++)    {        const vector*>& result = net_->forward(bottom_vec);        const dtype * result_vec = result[0]->cpu_data();        const int dim = result[0]->count(1);        for(int j = 0; j < result[0]->num(); j++)        {            const dtype * ptr = result_vec + j * dim;            vector one_;            for(int k = 0; k < dim; ++k)                one_.push_back(ptr[k]);            out->push_back(one_);        }    }    if(original_length != valid_length)    {        images.erase(images.begin()+original_length, images.end());        out->erase(out->begin()+original_length, out->end());    } } instantiate_class(classifier); }  // namespace caffe 由于加入的数据个数必须是batch_size的整数倍,所以我们在加入数据时采用填充的方式。 check_eq(num % batch_size_, 0) <<      "the added data must be a multiple of the batch size.";  //addmatvector 在模型文件的最后,我们把训练时的loss层改为argmax层: layers {  name: "predicted"  type: argmax  bottom: "prob"  top: "predicted" }
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
求分享 韩国电影 谎言 的资源,谢谢
明朝时期南京的皇帝来北京的是哪个皇帝?是哪
6.27-2又2/5 2.3减2.6简便计算
国家赔偿责任的():职务侵权行为、损害事实、
馨丽洁化妆品超市这个地址在什么地方,我要处
哈勒盖图塔拉在哪里啊,我有事要去这个地方
旗长是什么级别
火罐风湿穴位图
下列变化属于化学变化的是CA. 冰雪融化B. 酒
一个男人总是跟着你 但是你回头看他时 他就给
顺达旅馆这个地址在什么地方,我要处理点事
用1.suit2.very well造句,并加中文.
dataWithContentsOfURL有替代的方法吗
hr是什么意思
《怪物大师》中,布布路一行人分别来自哪个大
推荐资讯
顺平县蒲阳镇西魏村村民委员会我想知道这个在
个人述职是什么意思
超级会员在洛克王国有什么用
如图,三角形ABC的面积为1平方分米,F是CD的中
Miss somebody I lost.Forget somebody I mis
尚好大药房包公井店怎么去啊,有知道地址的么
求孔子各弟子姓、名、字
深圳市道路违法第18条第2款第2项是什么意思呀
龙之谷国服声优
找古剑锋系列的小说,要txt完整精校版的《星
香港的大学里内地学生多不多啊 ?
dnf的公会红包点卷能不能一直存在
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?