首先说明:下面的内容不一定对

类body:

变量:LayerParameter param_ :它里面放的是:body传进来的layerparameter的参数;

BlockingQueue<shared_ptr<QueuePair> > new_queue_pairs_:这是一个队列,它里面放的是一个队列对指针,

它的初始化:由传入的layerparameter参数赋值param_变量,并开启一个相应的进程;

它的析构函数:让进程停下来;

开启的这个进程它会干什么呢??用来读数据吧。

类data_reader:

变量:shared_ptr<QueuePair> queue_pair_:它是一个队列对的指针,并且用 prefetch*batch_size QueuePair 初始化了指向的queuePair 的实例 ,即里面的 free_ 队列的大小;

shared_ptr<Body> body_: 它是一个类body的指针,

map<const string, boost::weak_ptr<DataReader::Body> > bodies_: 它是一个map的容器,

其中的它键值:网络层的名字+源数据的路径表示,

而它对应的值:是一个指 针,指向了

在data_reader类的初始化时,它传入一个参数LayerParameter,下面是它做的事情:

1,把它的队列对指针queue_pair_ ,并且用 prefetch*batch_size QueuePair 初始化了指向的queuePair 的实例;

2,让body_的指针指向一个用LayerParameter初始化的body指针,并且向它指向的body里的变量阻塞队列new_queue_pairs_里压入一个值:为queue_pair_。

3. 初始化上面的参数bodies_, 它的键值为相关的网络层的名字+源数据的路径表示,而值为:与body_相对应的弱指针。

它的析构函数做的事:

1,把body_指向的空间释放掉,2,把 bodies_ 内的键-值 删除掉,因为里面的弱指针已经过期了。

类queuePair:

变量: BlockingQueue<Datum*> free_; 它是一个存放 datum指针的阻塞队列;

BlockingQueue<Datum*> full_;它也是一个存放 datum指针的阻塞队列;

它的初始化为:初始化一定大小size(传入的参数)的free_的空间;

它的析构函数做的事情:释放掉free里的指针所指向的内存空间,并且把free_的阻塞队列清空;

(它都没有管full_的事情啊,)

还有不懂的地方啊,先粘上吧;;;fuck.

data_reader.hpp

 #ifndef CAFFE_DATA_READER_HPP_
#define CAFFE_DATA_READER_HPP_ #include <map>
#include <string>
#include <vector> #include "caffe/common.hpp"
#include "caffe/internal_thread.hpp"
#include "caffe/util/blocking_queue.hpp"
#include "caffe/util/db.hpp" namespace caffe { /**
16 * @brief Reads data from a source to queues available to data layers.
17 * A single reading thread is created per source, even if multiple solvers
18 * are running in parallel, e.g. for multi-GPU training. This makes sure
19 * databases are read sequentially, and that each solver accesses a different
20 * subset of the database. Data is distributed to solvers in a round-robin
21 * way to keep parallel training deterministic.
22 */
class DataReader {
public:
explicit DataReader(const LayerParameter& param);
~DataReader(); inline BlockingQueue<Datum*>& free() const { //返回queue_pair_指向的queuepair里的free_阻塞队列;
return queue_pair_->free_;
}
inline BlockingQueue<Datum*>& full() const { //返回queue_pair_指向的queuepair里的full_阻塞队列;
return queue_pair_->full_;
} protected:
// Queue pairs are shared between a body and its readers
class QueuePair {
public:
explicit QueuePair(int size); //它初始化时,会为free_阻塞队列里push进去size个 Datum*;
~QueuePair(); //做的就是:把free_与full_里的指针指向的空间释放掉; BlockingQueue<Datum*> free_;
BlockingQueue<Datum*> full_; DISABLE_COPY_AND_ASSIGN(QueuePair);
}; // A single body is created per source
class Body : public InternalThread {
public:
explicit Body(const LayerParameter& param);
virtual ~Body(); protected:
void InternalThreadEntry(); //定义的入口函数,就是说对于body来说 ,这个线程是干什么的; ,它根据Layerparameter里的路径读取读据到new_queue_pairs_里的指针指向的queuepair中;
void read_one(db::Cursor* cursor, QueuePair* qp); const LayerParameter param_;
BlockingQueue<shared_ptr<QueuePair> > new_queue_pairs_; //这个阻塞队列里的不同的元素与solver_count有关系啊? ,初始化时,就把queue_pair_放进去了啊; friend class DataReader; DISABLE_COPY_AND_ASSIGN(Body);
}; // A source is uniquely identified by its layer name + path, in case
// the same database is read from two different locations in the net.
static inline string source_key(const LayerParameter& param) { //它做的就是形成一个字符串;
return param.name() + ":" + param.data_param().source();
} const shared_ptr<QueuePair> queue_pair_;
shared_ptr<Body> body_; static map<const string, boost::weak_ptr<DataReader::Body> > bodies_; DISABLE_COPY_AND_ASSIGN(DataReader);
}; } // namespace caffe #endif // CAFFE_DATA_READER_HPP_

data_reader.cpp

 #include <boost/thread.hpp>
#include <map>
#include <string>
#include <vector> #include "caffe/common.hpp"
#include "caffe/data_reader.hpp"
#include "caffe/layers/data_layer.hpp"
#include "caffe/proto/caffe.pb.h" namespace caffe { using boost::weak_ptr; map<const string, weak_ptr<DataReader::Body> > DataReader::bodies_;
static boost::mutex bodies_mutex_; DataReader::DataReader(const LayerParameter& param)
: queue_pair_(new QueuePair( //
param.data_param().prefetch() * param.data_param().batch_size())) {
// Get or create a body
boost::mutex::scoped_lock lock(bodies_mutex_);
string key = source_key(param);
weak_ptr<Body>& weak = bodies_[key];
//boost::weak_ptr 必定总是通过 boost::shared_ptr 来初始化的。一旦初始化之后,它基本上只提供一个有用的方法: lock()。
//此方法返回的boost::shared_ptr 与用来初始化弱指针的共享指针共享所有权。 如果这个共享指针不含有任何对象,返回的共享指针也将是空的。
//expired()用于检测所管理的对象是否已经释放;lock()用于获取所管理的对象的强引用指针。
body_ = weak.lock();
if (!body_) {
body_.reset(new Body(param));
bodies_[key] = weak_ptr<Body>(body_);
}
body_->new_queue_pairs_.push(queue_pair_);
} DataReader::~DataReader() {
string key = source_key(body_->param_);
body_.reset();
boost::mutex::scoped_lock lock(bodies_mutex_);
if (bodies_[key].expired()) {
bodies_.erase(key); //删除一个元素;
}
} // DataReader::QueuePair::QueuePair(int size) {
// Initialize the free queue with requested number of datums
for (int i = ; i < size; ++i) {
free_.push(new Datum());
}
} DataReader::QueuePair::~QueuePair() { //释放掉内存;
DataReader::QueuePair::~QueuePair() { //释放掉内存;
Datum* datum;
while (free_.try_pop(&datum)) {
delete datum;
}
while (full_.try_pop(&datum)) {
delete datum;
}
} // DataReader::Body::Body(const LayerParameter& param)
: param_(param),
new_queue_pairs_() {
StartInternalThread();
} DataReader::Body::~Body() {
StopInternalThread();
} void DataReader::Body::InternalThreadEntry() {
shared_ptr<db::DB> db(db::GetDB(param_.data_param().backend())); //我真没有看到db::DB的构造函数这样的初始化啊;
db->Open(param_.data_param().source(), db::READ); //创建环境并打开;
shared_ptr<db::Cursor> cursor(db->NewCursor()); //创建了一个cursor用于读取;
vector<shared_ptr<QueuePair> > qps; //从下面的代码可以看出里面装的是阻塞队列 new_queue_pqirs里的指针;
try {
int solver_count = param_.phase() == TRAIN ? Caffe::solver_count() : ; // To ensure deterministic runs, only start running once all solvers
// are ready. But solvers need to peek on one item during initialization,
// so read one item, then wait for the next solver.
for (int i = ; i < solver_count; ++i) { //这个第一个数据是不是特别呢?,还是为了让cursor移动到first position?
shared_ptr<QueuePair> qp(new_queue_pairs_.pop()); //初始化为new_queue_pairs_队列里的第一个元素(里面放的是queuepair的指针;
read_one(cursor.get(), qp.get()); //不同的solver对应的数据在database里是连续存储的??这个solver_count到底是什么东西?
qps.push_back(qp); //在vector的尾部追加一个数据;
}
// Main loop
while (!must_stop()) { // 有点不明白什么时候退出循环;
for (int i = ; i < solver_count; ++i) {
read_one(cursor.get(), qps[i].get());
}
// Check no additional readers have been created. This can happen if
// more than one net is trained at a time per process, whether single
// or multi solver. It might also happen if two data layers have same
// name and same source.
CHECK_EQ(new_queue_pairs_.size(), );
}
} catch (boost::thread_interrupted&) {
// Interrupted exception is expected on shutdown
}
} // void DataReader::Body::read_one(db::Cursor* cursor, QueuePair* qp) {
Datum* datum = qp->free_.pop(); //可以看出free_与full_共用一组地址;
// TODO deserialize in-place instead of copy?
datum->ParseFromString(cursor->value()); //cursor的value函数返回string形式的data值;
qp->full_.push(datum); // go to the next iter
cursor->Next();
if (!cursor->valid()) { //意思就是,当valid_值(valid()函数返回的)为false,说明没有找到,从数据开始,重新找)
DLOG(INFO) << "Restarting data prefetching from start.";
cursor->SeekToFirst(); //把curso移动到first位置;
}
} } // namespace caffe

caffe的data_reader.cpp分析一下干了点什么的更多相关文章

  1. Recovery启动流程(3)--recovery.cpp分析

    转载请注明来源:cuixiaolei的技术博客 这篇文章主要通过分析高通recovery目录下的recovery.cpp源码,对recovery启动流程有一个宏观的了解.MTK和高通的recovery ...

  2. Recovery启动流程--recovery.cpp分析

    这篇文章主要通过分析高通recovery目录下的recovery.cpp源码,对recovery启动流程有一个宏观的了解. 当开机以后,在lk阶段,如果是recovery,会设置boot_into_r ...

  3. caffe layer层cpp、cu调试经验和相互关系

    对于layer层的cpp文件,你可以用LOG和printf.cout进行调试,cu文件不能使用LOG,可以使用cout,printf. 对于softmaxloss的layer层,既有cpp文件又有cu ...

  4. Caffe 激励层(Activation)分析

    Caffe_Activation 一般来说,激励层的输入输出尺寸一致,为非线性函数,完成非线性映射,从而能够拟合更为复杂的函数表达式激励层都派生于NeuronLayer: class XXXlayer ...

  5. Caffe 源碼閱讀(三) caffe.cpp

    补:主要函数运行顺序: main>>GetBrewFunction>>train>>Solve 從main函數說起: 1.gflags庫中爲main函數設置usag ...

  6. 从零开始山寨Caffe·捌:IO系统(二)

    生产者 双缓冲组与信号量机制 在第陆章中提到了,如何模拟,以及取代根本不存的Q.full()函数. 其本质是:除了为生产者提供一个成品缓冲队列,还提供一个零件缓冲队列. 当我们从外部给定了固定容量的零 ...

  7. caffe: fuck compile error again : error: a value of type "const float *" cannot be used to initialize an entity of type "float *"

    wangxiao@wangxiao-GTX980:~/Downloads/caffe-master$ make -j8find: `wangxiao/bvlc_alexnet/spl': No suc ...

  8. caffe︱深度学习参数调优杂记+caffe训练时的问题+dropout/batch Normalization

    一.深度学习中常用的调节参数 本节为笔者上课笔记(CDA深度学习实战课程第一期) 1.学习率 步长的选择:你走的距离长短,越短当然不会错过,但是耗时间.步长的选择比较麻烦.步长越小,越容易得到局部最优 ...

  9. ubuntu16.04 caffe(GPU模式)安装

    历时5天终于完成了,配置中出现了各种各样的Error,这里记录一下,希望能为正在安装的人提供一点帮助. 配置中主要参考博客:http://blog.csdn.net/yhaolpz/article/d ...

随机推荐

  1. Android动画的使用总结

    1.补间动画(透明渐变.平移.旋转.缩放.组合) 方法一:通过xml文件设置 1-1:创建:res/anim 1-2:java代码写调用 Animation a = AnimationUtils.lo ...

  2. Oracle字符集设置

    客户端与服务端字符集不一致会造成乱码问题. 在服务端: sql>SELECT * FROM NLS_DATABASE_PARAMETERS; 在查询结果中关注如下参数: nls_language ...

  3. SDUT 2603:Rescue The Princess

    Rescue The Princess Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Several days ago, a b ...

  4. StringComparison枚举

    public enum StringComparison { CurrentCulture, CurrentCultureIgnoreCase, InvariantCulture, Invariant ...

  5. python-haproxy作业讲解视频总结

    刚看完瞎驴的haproxy配置文件的作业讲解视频: 总结: 1.用户输入的字符串数据类型转换其他数据类型 1.1 eval('用户输入的数据') 1.2 json.loads('用户输入的数据') 2 ...

  6. servlet中Java连接数据库后的基本操作

    servlet中Java连接数据库后的基本操作 在eclipse中新建一个工程:login 在Server中新建一个服务器,基本的操作不用说了,在前两天的笔记中可以找到; 需要知道数据库的用户名和密码 ...

  7. 将具有关联关系的两个表从hibernate查询出来转成json对象时报错

    第一篇文章: 相信大家做过JSON相关的东西对这个异常并不陌生,这个异常是由于JSONObject插件内部会无限拆解你传入的对象,直到没有可拆解为止,问题就在这,如果你传入的对象有外键关系,或者相互引 ...

  8. zoj 3557 How Many Sets II

    How Many Sets II Time Limit: 2 Seconds      Memory Limit: 65536 KB Given a set S = {1, 2, ..., n}, n ...

  9. ie兼容整理

    那里面有东西要长研究 ie bug集合关于如何给各种浏览器打bug,可查询:browser hacks 几篇处理ie问题的帖子,帖子1

  10. 优化Linux生产服务器的经验之谈

    [51CTO独家特稿]如何优化自己的Linux生产服务器?本文结合实际的工作经验,总结了优化Linux生产服务器的九大要点.如果有些方法您尚未采用,不妨一试. 一.时间同步 生产环境下的服务器对时间的 ...