DataReader
作为DataLayer
的数据成员变量,以多线程的方式从数据库(如lmdb, hdf5)读取数据:
class DataReader {
public:
explicit DataReader(const LayerParameter& param);
~DataReader();
inline BlockingQueue& free() const {
return queue_pair_->free_;
}
inline BlockingQueue& full() const {
return queue_pair_->full_;
}
protected:
// Queue pairs are shared between a body and its readers
class QueuePair {
public:
explicit QueuePair(int size);
~QueuePair();
BlockingQueue free_;
BlockingQueue 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();
void read_one(db::Cursor* cursor, QueuePair* qp);
const LayerParameter param_;
BlockingQueue > new_queue_pairs_;
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();
}
protected:
const shared_ptr queue_pair_;
shared_ptr body_;
static map > bodies_;
DISABLE_COPY_AND_ASSIGN(DataReader);
};
下面看构造函数, 预读取的总的数据长度为prefetch*batch_size, weak_ptr结合shared_ptr保证线程安全:
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& weak = bodies_[key];
body_ = weak.lock();
if (!body_) {
body_.reset(new Body(param));
bodies_[key] = weak_ptr(body_);
}
body_->new_queue_pairs_.push(queue_pair_);
}
线程的核心函数:
void DataReader::Body::InternalThreadEntry() {
shared_ptr db(db::GetDB(param_.data_param().backend()));
db->Open(param_.data_param().source(), db::READ);
shared_ptr cursor(db->NewCursor());
vector > qps;
// Main loop
while (!must_stop()) {
for (int i = 0; i < solver_count; ++i) {
read_one(cursor.get(), qps[i].get());
}
CHECK_EQ(new_queue_pairs_.size(), 0);
}
}
void DataReader::Body::read_one(db::Cursor* cursor, QueuePair* qp) {
Datum* datum = qp->free_.pop();
datum->ParseFromString(cursor->value());
qp->full_.push(datum);
// go to the next iter
cursor->Next();
}
caffe
系列源码分析介绍本系列深度学习框架caffe
源码分析主要内容如下:
caffe源码分析-cmake 工程构建主要内容:
自己从头构建一遍工程,这样能让我更好的了解大型的项目的构建。当然原始的caffe的构建感觉还是比较复杂(主要是cmake),我这里仅仅使用cmake构建,而且简化点,当然最重要的是支持CLion直接运行调试(如果需要这个工程可以评论留下你的邮箱,我给你发送过去)。
SyncedMemory
, 以及类Blob
数据传输的媒介.主要内容:
caffe源码分析-SyncedMemory
caffe源码分析-Blob
其中Blob
分析给出了其直接与opencv的图片相互转化以及操作,可以使得我们更好的理解Blob
.
layer
的源码分析,包括从整体上说明了layer
类别以及其proto定义与核心函数.内容如下:
caffe源码分析-layer
caffe源码分析-ReLULayer
caffe源码分析-inner_product_layer
caffe源码分析-layer_factory
首先分析了最简单的layer
Relu
,然后在是inner_product_layer全连接层
, 最后是layer_factory
caffe中 以此工厂模式create各种Layer.
内容如下:
caffe源码分析-BlockingQueue
caffe源码分析-InternalThread
caffe源码分析-DataReader
内容如下:
caffe源码分析-DataTransformer
caffe源码分析-db, io
内容如下:
caffe c++示例(mnist 多层感知机c++训练,测试)
类似与caffe
一样按照layer、solver、loss、net
等模块构建的神经网络实现可以见下面这篇blog,相信看懂了这个python的代码理解caffe框架会更简单点.
神经网络python实现
最后如果需要cmake
+ CLion
直接运行调试caffe
的代码工程,可以评论留下你的邮箱,我给你发送过去.