发布网友 发布时间:2022-04-25 13:14
共2个回答
热心网友 时间:2022-04-09 03:05
Caffe是目前深度学习比较优秀好用的一个开源库,采样c++和CUDA实现,具有速度快,模型定义方便等优点。学习了几天过后,发现也有一个不方便的地方,就是在我的程序中调用Caffe做图像分类没有直接的接口。Caffe的数据层可以从数据库(支持leveldb、lmdb、hdf5)、图片、和内存中读入。我们要在程序中使用,当然得从内存中读入,我们首先在模型定义文件中定义数据层:
1234567101112131415161718192021222324252627282930313233343536373839404142434445474849505152535455565758596061626365666768697071727374757677787980818283848586878890919293949596979910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216311651661671681691701711721731741751761771781791801811821831841851861871881190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250layers { 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 <string>#include <vector>#include "caffe/net.hpp"#include "caffe/data_layers.hpp"#include <opencv2/core.hpp>using cv::Mat; namespace caffe { template <typename Dtype>class Classifier {public: explicit Classifier(const string& param_file, const string& weights_file); Dtype test(vector<Mat> &images, vector<int> &labels, int iter_num); virtual ~Classifier() {} inline <a href="https://www.baidu.com/s?wd=shared_ptr&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YYPjc4mh7buWRYuW-hrjcd0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHf4PW6vPjf3P1bdrHRsnH0drf" target="_blank" class="-highlight">shared_ptr</a><Net<Dtype> > net() { return net_; } void predict(vector<Mat> &images, vector<int> *labels); void predict(vector<Dtype> &data, vector<int> *labels, int num); void extract_feature(vector<Mat> &images, vector<vector<Dtype>> *out); protected: <a href="https://www.baidu.com/s?wd=shared_ptr&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YYPjc4mh7buWRYuW-hrjcd0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHf4PW6vPjf3P1bdrHRsnH0drf" target="_blank" class="-highlight">shared_ptr</a><Net<Dtype> > net_; MemoryDataLayer<Dtype> *m_layer_; int batch_size_; int channels_; int height_; int width_; DISABLE_COPY_AND_ASSIGN(Classifier);};}//namespace #endif //CAFFE_CLASSIFIER_H <a href="https://www.baidu.com/s?wd=%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YYPjc4mh7buWRYuW-hrjcd0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHf4PW6vPjf3P1bdrHRsnH0drf" target="_blank" class="-highlight">构造函数</a>中我们通过模型定义文件(.prototxt)和训练好的模型(.caffemodel)文件构造一个Net对象,并用m_layer_指向Net中的memory data层,以便待会调用MemoryDataLayer中AddMatVector和Reset函数加入数据。#include <cstdio> #include <algorithm>#include <string>#include <vector> #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 <typename Dtype>Classifier<Dtype>::Classifier(const string& param_file, const string& weights_file) : net_(){ net_.reset(new Net<Dtype>(param_file, TEST)); net_->CopyTrainedLayersFrom(weights_file); //m_layer_ = (MemoryDataLayer<Dtype>*)net_->layer_by_name("mnist").get(); m_layer_ = (MemoryDataLayer<Dtype>*)net_->layers()[0].get(); batch_size_ = m_layer_->batch_size(); channels_ = m_layer_->channels(); height_ = m_layer_->height(); width_ = m_layer_->width();} template <typename Dtype>Dtype Classifier<Dtype>::test(vector<Mat> &images, vector<int> &labels, int iter_num){ m_layer_->AddMatVector(images, labels); // int iterations = iter_num; vector<Blob<Dtype>* > bottom_vec; vector<int> test_score_output_id; vector<Dtype> test_score; Dtype loss = 0; for (int i = 0; i < iterations; ++i) { Dtype iter_loss; const vector<Blob<Dtype>*>& 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.<a href="https://www.baidu.com/s?wd=push_back&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YYPjc4mh7buWRYuW-hrjcd0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHf4PW6vPjf3P1bdrHRsnH0drf" target="_blank" class="-highlight">push_back</a>(score); test_score_output_id.<a href="https://www.baidu.com/s?wd=push_back&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YYPjc4mh7buWRYuW-hrjcd0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHf4PW6vPjf3P1bdrHRsnH0drf" target="_blank" class="-highlight">push_back</a>(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 <typename Dtype>void Classifier<Dtype>::predict(vector<Mat> &images, vector<int> *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.<a href="https://www.baidu.com/s?wd=push_back&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YYPjc4mh7buWRYuW-hrjcd0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnHf4PW6vPjf3P1bdrHRsnH0drf" target="_blank" class="-highlight">push_back</a>(images[0].clone()); } } vector<int> valid_labels, predicted_labels; valid_labels.resize(valid_length, 0); m_layer_->AddMatVector(images, valid_labels); vector<Blob<Dtype>* > bottom_vec; for(int i = 0; i < valid_length / batch_size_; i++) { const vector<Blob<Dtype>*>& 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 <typename Dtype>void Classifier<Dtype>::predict(vector<Dtype> &data, vector<int> *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<int> predicted_labels; Dtype * label_ = new Dtype[valid_length]; memset(label_, 0, valid_length); m_layer_->Reset(data.data(), label_, valid_length); vector<Blob<Dtype>* > bottom_vec; for(int i = 0; i < valid_length / batch_size_; i++) { const vector<Blob<Dtype>*>& 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 <typename Dtype>void Classifier<Dtype>::extract_feature(vector<Mat> &images, vector<vector<Dtype>> *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<int> valid_labels; valid_labels.resize(valid_length, 0); m_layer_->AddMatVector(images, valid_labels); vector<Blob<Dtype>* > bottom_vec; out->clear(); for(int i = 0; i < valid_length / batch_size_; i++) { const vector<Blob<Dtype>*>& 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<Dtype> 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"}
热心网友 时间:2022-04-09 04:23
Caffe是目前深度学习比较优秀好用的一个开源库,采样c++和CUDA实现,具有速度快,模型定义方便等优点。学习了几天过后,发现也有一个不方便的地方,就是在我的程序中调用Caffe做图像分类没有直接的接口。Caffe的数据层可以从数据库(支持leveldb、lmdb、hdf5)、图片、和内存中读入。我们要在程序中使用,当然得从内存中读入,我们首先在模型定义文件中定义数据层:这里必须设置memory_data_param中的四个参数,对应这些参数可以参见源码中caffe.proto文件。现在,我们可以设计一个Classifier类来封装一下:构造函数中我们通过模型定义文件(.prototxt)和训练好的模型(.caffemodel)文件构造一个Net对象,并用m_layer_指向Net中的memory data层,以便待会调用MemoryDataLayer中AddMatVector和Reset函数加入数据。由于加入的数据个数必须是batch_size的整数倍,所以我们在加入数据时采用填充的方式。在模型文件的最后,我们把训练时的loss层改为argmax层:(变量分为定性和定量两类,比如1、2、3这样的自然数就是离散数据,因为它是特定的自然数值而比如[1,2]这个区间就是连续的,因为它可以取一到二之间的任意值分类变量里分为有序和无序。ordinal data (有序变量)(等级)有序分类变量是指各类别之间有程度的差别。如优良中差;±、+、++、+++nominal data(名义变量)(也叫名义)属性之间无程度和顺序的差别,例如二项分类,性别(男、女),药物反应(阴性、阳性)等。例如多项分类,血型( O、A、B、AB),职业(工、农、商、学、兵)等。统计学依据数据的计量尺度将数据划分为三类:定距型数据(Scale)、定序型数据(Ordinal)、定类型数据(Nominal)。··定距型数据(Scale)通常是指诸如身高、体重、血压等的连续型数据,也包括诸如人数、商品件数等离散型数据;··定序型数据(Ordinal)具有内在固有大小或高低顺序,但它又不同于定距型数据,一般可以数值或字符表示。如职称变量可以有低级、中级、高级三个取值,可以分别用1、2、3等表示,年龄段变量可以有老、中、青三个取值,分别用A B C表示等。这里,无论是数值型的1、2 、3 还是字符型的A B C ,都是有大小或高低顺序的,但数据之间却是不等距的。因为,低级和中级职称之间的差距与中级和高级职称之间的差距是不相等的;··定类型数据(Nominal)是指没有内在固有大小或高低顺序,一般以数值或字符表示的分类数据。如性别变量中的男、女取值,可以分别用1、 2表示,民族变量中的各个民族,可以用‘汉’‘回’‘满’等字符表示等。这里,无论是数值型的1、 2 还是字符型的‘汉’‘回’‘满’,都不存在内部固有的大小或高低顺序,而只是一种名义上的指代。