dataLayer作为整个网络的输入层,

数据从leveldb中取。

leveldb的数据是通过图片转换过来的。

网络建立的时候。

datalayer主要是负责设置一些參数,比方batchsize。channels,height。width等。

这次会通过读leveldb一个数据块来获取这些信息。

然后启动一个线程来预先从leveldb拉取一批数据。这些数据是图像数据和图像标签。

正向传播的时候,

datalayer就把预先拉取好数据复制到指定的cpu或者gpu的内存。

然后启动新线程再预先拉取数据,这些数据留到下一次正向传播使用。

// Copyright 2013 Yangqing Jia

#include <stdint.h>
#include <leveldb/db.h>
#include <pthread.h> #include <string>
#include <vector> #include "caffe/layer.hpp"
#include "caffe/util/io.hpp"
#include "caffe/vision_layers.hpp" using std::string; namespace caffe { template <typename Dtype>
void* DataLayerPrefetch(void* layer_pointer) {
CHECK(layer_pointer);
DataLayer<Dtype>* layer = reinterpret_cast<DataLayer<Dtype>*>(layer_pointer);
CHECK(layer);
Datum datum;
CHECK(layer->prefetch_data_);
Dtype* top_data = layer->prefetch_data_->mutable_cpu_data();//数据
Dtype* top_label = layer->prefetch_label_->mutable_cpu_data();//标签
const Dtype scale = layer->layer_param_.scale();
const int batchsize = layer->layer_param_.batchsize();
const int cropsize = layer->layer_param_.cropsize();
const bool mirror = layer->layer_param_.mirror(); if (mirror && cropsize == 0) {//当前实现须要同一时候设置mirror和cropsize
LOG(FATAL) << "Current implementation requires mirror and cropsize to be "
<< "set at the same time.";
}
// datum scales
const int channels = layer->datum_channels_;
const int height = layer->datum_height_;
const int width = layer->datum_width_;
const int size = layer->datum_size_;
const Dtype* mean = layer->data_mean_.cpu_data();
for (int itemid = 0; itemid < batchsize; ++itemid) {//每一批数据的数量是batchsize。一个循环拉取一张?
// get a blob
CHECK(layer->iter_);
CHECK(layer->iter_->Valid());
datum.ParseFromString(layer->iter_->value().ToString());//利用迭代器拉取下一批数据
const string& data = datum.data();
if (cropsize) {//假设须要裁剪
CHECK(data.size()) << "Image cropping only support uint8 data";
int h_off, w_off;
// We only do random crop when we do training.
//仅仅是在训练阶段做随机裁剪
if (Caffe::phase() == Caffe::TRAIN) {
// NOLINT_NEXT_LINE(runtime/threadsafe_fn)
h_off = rand() % (height - cropsize);
// NOLINT_NEXT_LINE(runtime/threadsafe_fn)
w_off = rand() % (width - cropsize);
} else {//測试阶段固定裁剪
h_off = (height - cropsize) / 2;
w_off = (width - cropsize) / 2;
}
// NOLINT_NEXT_LINE(runtime/threadsafe_fn)
//怎么感觉以下两种情况的代码是一样的?
if (mirror && rand() % 2) {
// Copy mirrored version
for (int c = 0; c < channels; ++c) {
for (int h = 0; h < cropsize; ++h) {
for (int w = 0; w < cropsize; ++w) {
top_data[((itemid * channels + c) * cropsize + h) * cropsize
+ cropsize - 1 - w] =
(static_cast<Dtype>(
(uint8_t)data[(c * height + h + h_off) * width
+ w + w_off])
- mean[(c * height + h + h_off) * width + w + w_off])
* scale;
}
}
}
} else {
// Normal copy
for (int c = 0; c < channels; ++c) {
for (int h = 0; h < cropsize; ++h) {
for (int w = 0; w < cropsize; ++w) {
top_data[((itemid * channels + c) * cropsize + h) * cropsize + w]
= (static_cast<Dtype>(
(uint8_t)data[(c * height + h + h_off) * width
+ w + w_off])
- mean[(c * height + h + h_off) * width + w + w_off])
* scale;
}
}
}
}
} else {//假设不须要裁剪
// we will prefer to use data() first, and then try float_data()
//我们优先考虑data(),然后float_data()
if (data.size()) {
for (int j = 0; j < size; ++j) {
top_data[itemid * size + j] =
(static_cast<Dtype>((uint8_t)data[j]) - mean[j]) * scale;
}
} else {
for (int j = 0; j < size; ++j) {
top_data[itemid * size + j] =
(datum.float_data(j) - mean[j]) * scale;
}
}
} top_label[itemid] = datum.label();
// go to the next iter
layer->iter_->Next();
if (!layer->iter_->Valid()) {
// We have reached the end. Restart from the first.
DLOG(INFO) << "Restarting data prefetching from start.";
layer->iter_->SeekToFirst();
}
} return reinterpret_cast<void*>(NULL);
} template <typename Dtype>
DataLayer<Dtype>::~DataLayer<Dtype>() {
// Finally, join the thread
CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed.";
} template <typename Dtype>
void DataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
CHECK_EQ(bottom.size(), 0) << "Data Layer takes no input blobs.";
CHECK_EQ(top->size(), 2) << "Data Layer takes two blobs as output.";
// Initialize the leveldb
leveldb::DB* db_temp;
leveldb::Options options;
options.create_if_missing = false;
options.max_open_files = 100;
LOG(INFO) << "Opening leveldb " << this->layer_param_.source();
leveldb::Status status = leveldb::DB::Open(
options, this->layer_param_.source(), &db_temp);
CHECK(status.ok()) << "Failed to open leveldb "
<< this->layer_param_.source() << std::endl << status.ToString();
db_.reset(db_temp);
iter_.reset(db_->NewIterator(leveldb::ReadOptions()));//通过迭代器来操纵leveldb
iter_->SeekToFirst();
// Check if we would need to randomly skip a few data points
//是否要随机跳过一些数据
if (this->layer_param_.rand_skip()) {
// NOLINT_NEXT_LINE(runtime/threadsafe_fn)
unsigned int skip = rand() % this->layer_param_.rand_skip();
LOG(INFO) << "Skipping first " << skip << " data points.";
while (skip-- > 0) {//循环次数
iter_->Next();
if (!iter_->Valid()) {
iter_->SeekToFirst();
}
}
}
// Read a data point, and use it to initialize the top blob.
//读取一个数据点。用来初始化topblob。所谓初始化,仅仅要是指reshape。
//能够观察到以下iter_调用调用next。所以这次读取仅仅是用来读取出来channels等參数的,不作处理。
Datum datum;
datum.ParseFromString(iter_->value().ToString());//利用迭代器读取第一个数据点
// image图像数据
int cropsize = this->layer_param_.cropsize();//裁剪大小
if (cropsize > 0) {//须要裁剪
(*top)[0]->Reshape(
this->layer_param_.batchsize(), datum.channels(), cropsize, cropsize);
prefetch_data_.reset(new Blob<Dtype>(
this->layer_param_.batchsize(), datum.channels(), cropsize, cropsize));
} else {//不须要裁剪
(*top)[0]->Reshape(
this->layer_param_.batchsize(), datum.channels(), datum.height(),
datum.width());
prefetch_data_.reset(new Blob<Dtype>(
this->layer_param_.batchsize(), datum.channels(), datum.height(),
datum.width()));
}
LOG(INFO) << "output data size: " << (*top)[0]->num() << ","
<< (*top)[0]->channels() << "," << (*top)[0]->height() << ","
<< (*top)[0]->width();
// label标签数据
(*top)[1]->Reshape(this->layer_param_.batchsize(), 1, 1, 1);
prefetch_label_.reset(
new Blob<Dtype>(this->layer_param_.batchsize(), 1, 1, 1));
// datum size
datum_channels_ = datum.channels();
datum_height_ = datum.height();
datum_width_ = datum.width();
datum_size_ = datum.channels() * datum.height() * datum.width();
CHECK_GT(datum_height_, cropsize);
CHECK_GT(datum_width_, cropsize);
// check if we want to have mean是否要减去均值
if (this->layer_param_.has_meanfile()) {
BlobProto blob_proto;
LOG(INFO) << "Loading mean file from" << this->layer_param_.meanfile();
ReadProtoFromBinaryFile(this->layer_param_.meanfile().c_str(), &blob_proto);
data_mean_.FromProto(blob_proto);
CHECK_EQ(data_mean_.num(), 1);
CHECK_EQ(data_mean_.channels(), datum_channels_);
CHECK_EQ(data_mean_.height(), datum_height_);
CHECK_EQ(data_mean_.width(), datum_width_);
} else {
// Simply initialize an all-empty mean.
data_mean_.Reshape(1, datum_channels_, datum_height_, datum_width_);
}
// Now, start the prefetch thread. Before calling prefetch, we make two
// cpu_data calls so that the prefetch thread does not accidentally make
// simultaneous cudaMalloc calls when the main thread is running. In some
// GPUs this seems to cause failures if we do not so.
prefetch_data_->mutable_cpu_data();
prefetch_label_->mutable_cpu_data();
data_mean_.cpu_data();
DLOG(INFO) << "Initializing prefetch";
CHECK(!pthread_create(&thread_, NULL, DataLayerPrefetch<Dtype>,
reinterpret_cast<void*>(this))) << "Pthread execution failed.";
DLOG(INFO) << "Prefetch initialized.";
} template <typename Dtype>
void DataLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
// First, join the thread 等待线程结束
CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed.";
// Copy the data拷贝数据到top,即该层的输出
memcpy((*top)[0]->mutable_cpu_data(), prefetch_data_->cpu_data(),
sizeof(Dtype) * prefetch_data_->count());
memcpy((*top)[1]->mutable_cpu_data(), prefetch_label_->cpu_data(),
sizeof(Dtype) * prefetch_label_->count());
// Start a new prefetch thread启动新线程拉取下一批数据
CHECK(!pthread_create(&thread_, NULL, DataLayerPrefetch<Dtype>,
reinterpret_cast<void*>(this))) << "Pthread execution failed.";
} // The backward operations are dummy - they do not carry any computation.
template <typename Dtype>
Dtype DataLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom) {
return Dtype(0.);
} INSTANTIATE_CLASS(DataLayer); } // namespace caffe

本文作者:linger

本文链接:http://blog.csdn.net/lingerlanlan/article/details/27348265

caffe源代码分析--data_layer.cpp的更多相关文章

  1. caffe源代码分析--softmax_layer.cpp

    caffe源代码分析--softmax_layer.cpp // Copyright 2013 Yangqing Jia // #include <algorithm> #include ...

  2. caffe源代码分析--Blob类代码研究

    作者:linger 转自须注明转自:http://blog.csdn.net/lingerlanlan/article/details/24379689 数据成员 shared_ptr<Sync ...

  3. caffe源代码分析--math_functions.cu代码研究

    当中用到一个宏定义CUDA_KERNEL_LOOP 在common.hpp中有. #defineCUDA_KERNEL_LOOP(i,n) \ for(inti = blockIdx.x * bloc ...

  4. Caffe源代码中Solver文件分析

    Caffe源代码(caffe version commit: 09868ac , date: 2015.08.15)中有一些重要的头文件,这里介绍下include/caffe/solver.hpp文件 ...

  5. 转:SDL2源代码分析

    1:初始化(SDL_Init()) SDL简介 有关SDL的简介在<最简单的视音频播放示例7:SDL2播放RGB/YUV>以及<最简单的视音频播放示例9:SDL2播放PCM>中 ...

  6. 转:ffdshow 源代码分析

    ffdshow神奇的功能:视频播放时显示运动矢量和QP FFDShow可以称得上是全能的解码.编码器.最初FFDShow只是mpeg视频解码器,不过现在他能做到的远不止于此.它能够解码的视频格式已经远 ...

  7. Android系统进程Zygote启动过程的源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6768304 在Android系统中,所有的应用 ...

  8. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个 Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home ...

  9. Android应用程序安装过程源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6766010 Android系统在启动的过程中, ...

随机推荐

  1. 【leetcode❤python】 204. Count Primes

    #-*- coding: UTF-8 -*- #Hint1:#数字i,i的倍数一定不是质数,因此去掉i的倍数,例如5,5*1,5*2,5*3,5*4,5*5都不是质数,应该去掉#5*1,5*2,5*3 ...

  2. 教你21天学会C++ (有图有真相)

    这张图,是在一位有十多年开发经验的资深前辈博客里看到的,觉得很有趣,分享之~ 这位大神的博客是:http://coolshell.cn 理论是可行的,当你刚开始学习C++,到第21天的时候出门千万要小 ...

  3. 关于Linux的总结(三)

    1.man_page.txt 1.内部命令:echo 查看内部命令帮助:help echo 或者 man echo 2.外部命令:ls 查看外部命令帮助:ls --help 或者 man ls 或者 ...

  4. C++ socket programming in Linux

    Server.c #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #includ ...

  5. JAVA在win10上的安装环境配置

    [TOC] 第一步: 打开右击电脑选择属性 第二步: 选择高级系统设置 第三部: 选择环境变量 第四部: 选择在系统变量中新建:JAVA_HOME 属性值为你的java的jdk的位置比如我的:E:\J ...

  6. python并发编程之多进程

    一同步与异步 同步执行:一个进程在执行任务时,另一个进程必须等待执行完毕,才能继续执行 异步执行:一个进程在执行任务时,另一个进程无需等待其执行完毕就可以执行,当有消息返回时,系统会提醒后者进行处理, ...

  7. Spring框架源码阅读之Springs-beans(一)容器的基本实现概述(待续)

    去年通过实际框架代码的阅读,以及结合<Spring源码深度解析>和<Spring技术内幕>的阅读,对Spring框架内Bean模块有了一个整体性的认识.对此进行的总结性整理和回 ...

  8. TestFlight 的使用记载

    TestFlight:     TestFlight内测网上很多资料.大概是先打包,然后在App Store Connect 里添加测试员的邮箱地址. Testflight.top:公测要用到test ...

  9. 谷歌浏览器内核Cef js代码整理(二) 滚动条

    1.隐藏滚动条 document.documentElement.style.overflow = 'hidden';隐藏竖向滚动条:document.documentElement.style.ov ...

  10. 三种实现Android主界面Tab的方式

    在平时的Android开发中,我们经常会使用Tab来进行主界面的布局.由于手机屏幕尺寸的限制,合理使用Tab可以极大的利用屏幕资源,给用户带来良好的体验.学会Tab的使用方法已经成为学习Android ...