Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/caffe/util/math_functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ void caffe_powx(const int n, const Dtype* a, const Dtype b, Dtype* y);
template <typename Dtype>
void caffe_gpu_powx(const int n, const Dtype* a, const Dtype b, Dtype* y);

unsigned int caffe_rng_rand();

template <typename Dtype>
Dtype caffe_nextafter(const Dtype b);

Expand Down
17 changes: 17 additions & 0 deletions include/caffe/vision_layers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ class DataLayer : public Layer<Dtype> {
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }

virtual void CreatePrefetchThread();
virtual void JoinPrefetchThread();
virtual unsigned int PrefetchRand();

shared_ptr<Caffe::RNG> prefetch_rng_;
shared_ptr<leveldb::DB> db_;
shared_ptr<leveldb::Iterator> iter_;
int datum_channels_;
Expand Down Expand Up @@ -467,6 +472,13 @@ class ImageDataLayer : public Layer<Dtype> {
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }

virtual void ShuffleImages();

virtual void CreatePrefetchThread();
virtual void JoinPrefetchThread();
virtual unsigned int PrefetchRand();

shared_ptr<Caffe::RNG> prefetch_rng_;
vector<std::pair<std::string, int> > lines_;
int lines_id_;
int datum_channels_;
Expand Down Expand Up @@ -743,6 +755,11 @@ class WindowDataLayer : public Layer<Dtype> {
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
const bool propagate_down, vector<Blob<Dtype>*>* bottom) { return; }

virtual void CreatePrefetchThread();
virtual void JoinPrefetchThread();
virtual unsigned int PrefetchRand();

shared_ptr<Caffe::RNG> prefetch_rng_;
pthread_t thread_;
shared_ptr<Blob<Dtype> > prefetch_data_;
shared_ptr<Blob<Dtype> > prefetch_label_;
Expand Down
2 changes: 1 addition & 1 deletion matlab/caffe/matcaffe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ static void init(MEX_ARGS) {
mxFree(param_file);
mxFree(model_file);

init_key = random();
init_key = random(); // NOLINT(caffe/random_fn)

if (nlhs == 1) {
plhs[0] = mxCreateDoubleScalar(init_key);
Expand Down
35 changes: 34 additions & 1 deletion scripts/cpp_lint.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
'build/namespaces',
'build/printf_format',
'build/storage_class',
'caffe/random_fn',
'legal/copyright',
'readability/alt_tokens',
'readability/braces',
Expand Down Expand Up @@ -1560,6 +1561,38 @@ def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
'Use C++11 raw strings or concatenation instead.')


c_random_function_list = (
'rand(',
'rand_r(',
'random(',
)

def CheckCaffeRandom(filename, clean_lines, linenum, error):
"""Checks for calls to C random functions (rand, rand_r, random, ...).

Caffe code should (almost) always use the caffe_rng_* functions rather
than these, as the internal state of these C functions is independent of the
native Caffe RNG system which should produce deterministic results for a
fixed Caffe seed set using Caffe::set_random_seed(...).

Args:
filename: The name of the current file.
clean_lines: A CleansedLines instance containing the file.
linenum: The number of the line to check.
error: The function to call with any errors found.
"""
line = clean_lines.elided[linenum]
for function in c_random_function_list:
ix = line.find(function)
# Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison
if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and
line[ix - 1] not in ('_', '.', '>'))):
error(filename, linenum, 'caffe/random_fn', 2,
'Use caffe_rng_rand() (or other caffe_rng_* function) instead of '
+ function +
') to ensure results are deterministic for a fixed Caffe seed.')


threading_list = (
('asctime(', 'asctime_r('),
('ctime(', 'ctime_r('),
Expand All @@ -1570,7 +1603,6 @@ def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error):
('getpwuid(', 'getpwuid_r('),
('gmtime(', 'gmtime_r('),
('localtime(', 'localtime_r('),
('rand(', 'rand_r('),
('strtok(', 'strtok_r('),
('ttyname(', 'ttyname_r('),
)
Expand Down Expand Up @@ -4530,6 +4562,7 @@ def ProcessLine(filename, file_extension, clean_lines, line,
CheckForNonStandardConstructs(filename, clean_lines, line,
nesting_state, error)
CheckVlogArguments(filename, clean_lines, line, error)
CheckCaffeRandom(filename, clean_lines, line, error)
CheckPosixThreading(filename, clean_lines, line, error)
CheckInvalidIncrement(filename, clean_lines, line, error)
CheckMakePairUsesDeduction(filename, clean_lines, line, error)
Expand Down
90 changes: 56 additions & 34 deletions src/caffe/layers/data_layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "caffe/layer.hpp"
#include "caffe/util/io.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/rng.hpp"
#include "caffe/vision_layers.hpp"

using std::string;
Expand All @@ -19,7 +20,7 @@ namespace caffe {
template <typename Dtype>
void* DataLayerPrefetch(void* layer_pointer) {
CHECK(layer_pointer);
DataLayer<Dtype>* layer = reinterpret_cast<DataLayer<Dtype>*>(layer_pointer);
DataLayer<Dtype>* layer = static_cast<DataLayer<Dtype>*>(layer_pointer);
CHECK(layer);
Datum datum;
CHECK(layer->prefetch_data_);
Expand Down Expand Up @@ -54,27 +55,23 @@ void* DataLayerPrefetch(void* layer_pointer) {
int h_off, w_off;
// We only do random crop when we do training.
if (layer->phase_ == Caffe::TRAIN) {
// NOLINT_NEXT_LINE(runtime/threadsafe_fn)
h_off = rand() % (height - crop_size);
// NOLINT_NEXT_LINE(runtime/threadsafe_fn)
w_off = rand() % (width - crop_size);
h_off = layer->PrefetchRand() % (height - crop_size);
w_off = layer->PrefetchRand() % (width - crop_size);
} else {
h_off = (height - crop_size) / 2;
w_off = (width - crop_size) / 2;
}
// NOLINT_NEXT_LINE(runtime/threadsafe_fn)
if (mirror && rand() % 2) {
if (mirror && layer->PrefetchRand() % 2) {
// Copy mirrored version
for (int c = 0; c < channels; ++c) {
for (int h = 0; h < crop_size; ++h) {
for (int w = 0; w < crop_size; ++w) {
top_data[((item_id * channels + c) * crop_size + h) * crop_size
+ crop_size - 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;
int top_index = ((item_id * channels + c) * crop_size + h)
* crop_size + (crop_size - 1 - w);
int data_index = (c * height + h + h_off) * width + w + w_off;
Dtype datum_element =
static_cast<Dtype>(static_cast<uint8_t>(data[data_index]));
top_data[top_index] = (datum_element - mean[data_index]) * scale;
}
}
}
Expand All @@ -83,13 +80,12 @@ void* DataLayerPrefetch(void* layer_pointer) {
for (int c = 0; c < channels; ++c) {
for (int h = 0; h < crop_size; ++h) {
for (int w = 0; w < crop_size; ++w) {
top_data[((item_id * channels + c) * crop_size + h) * crop_size
+ 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;
int top_index = ((item_id * channels + c) * crop_size + h)
* crop_size + w;
int data_index = (c * height + h + h_off) * width + w + w_off;
Dtype datum_element =
static_cast<Dtype>(static_cast<uint8_t>(data[data_index]));
top_data[top_index] = (datum_element - mean[data_index]) * scale;
}
}
}
Expand All @@ -98,8 +94,9 @@ void* DataLayerPrefetch(void* layer_pointer) {
// we will prefer to use data() first, and then try float_data()
if (data.size()) {
for (int j = 0; j < size; ++j) {
top_data[item_id * size + j] =
(static_cast<Dtype>((uint8_t)data[j]) - mean[j]) * scale;
Dtype datum_element =
static_cast<Dtype>(static_cast<uint8_t>(data[j]));
top_data[item_id * size + j] = (datum_element - mean[j]) * scale;
}
} else {
for (int j = 0; j < size; ++j) {
Expand All @@ -121,13 +118,12 @@ void* DataLayerPrefetch(void* layer_pointer) {
}
}

return reinterpret_cast<void*>(NULL);
return static_cast<void*>(NULL);
}

template <typename Dtype>
DataLayer<Dtype>::~DataLayer<Dtype>() {
// Finally, join the thread
CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed.";
JoinPrefetchThread();
}

template <typename Dtype>
Expand Down Expand Up @@ -157,8 +153,8 @@ void DataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
iter_->SeekToFirst();
// Check if we would need to randomly skip a few data points
if (this->layer_param_.data_param().rand_skip()) {
// NOLINT_NEXT_LINE(runtime/threadsafe_fn)
unsigned int skip = rand() % this->layer_param_.data_param().rand_skip();
unsigned int skip = caffe_rng_rand() %
this->layer_param_.data_param().rand_skip();
LOG(INFO) << "Skipping first " << skip << " data points.";
while (skip-- > 0) {
iter_->Next();
Expand Down Expand Up @@ -227,17 +223,45 @@ void DataLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,
}
data_mean_.cpu_data();
DLOG(INFO) << "Initializing prefetch";
CreatePrefetchThread();
DLOG(INFO) << "Prefetch initialized.";
}

template <typename Dtype>
void DataLayer<Dtype>::CreatePrefetchThread() {
phase_ = Caffe::phase();
const bool prefetch_needs_rand = (phase_ == Caffe::TRAIN) &&
(this->layer_param_.data_param().mirror() ||
this->layer_param_.data_param().crop_size());
if (prefetch_needs_rand) {
const unsigned int prefetch_rng_seed = caffe_rng_rand();
prefetch_rng_.reset(new Caffe::RNG(prefetch_rng_seed));
} else {
prefetch_rng_.reset();
}
// Create the thread.
CHECK(!pthread_create(&thread_, NULL, DataLayerPrefetch<Dtype>,
reinterpret_cast<void*>(this))) << "Pthread execution failed.";
DLOG(INFO) << "Prefetch initialized.";
static_cast<void*>(this))) << "Pthread execution failed.";
}

template <typename Dtype>
void DataLayer<Dtype>::JoinPrefetchThread() {
CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed.";
}

template <typename Dtype>
unsigned int DataLayer<Dtype>::PrefetchRand() {
CHECK(prefetch_rng_);
caffe::rng_t* prefetch_rng =
static_cast<caffe::rng_t*>(prefetch_rng_->generator());
return (*prefetch_rng)();
}

template <typename Dtype>
Dtype 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.";
JoinPrefetchThread();
// Copy the data
caffe_copy(prefetch_data_->count(), prefetch_data_->cpu_data(),
(*top)[0]->mutable_cpu_data());
Expand All @@ -246,9 +270,7 @@ Dtype DataLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
(*top)[1]->mutable_cpu_data());
}
// Start a new prefetch thread
phase_ = Caffe::phase();
CHECK(!pthread_create(&thread_, NULL, DataLayerPrefetch<Dtype>,
reinterpret_cast<void*>(this))) << "Pthread execution failed.";
CreatePrefetchThread();
return Dtype(0.);
}

Expand Down
6 changes: 2 additions & 4 deletions src/caffe/layers/data_layer.cu
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ template <typename Dtype>
Dtype DataLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
// First, join the thread
CHECK(!pthread_join(thread_, NULL)) << "Pthread joining failed.";
JoinPrefetchThread();
// Copy the data
CUDA_CHECK(cudaMemcpy((*top)[0]->mutable_gpu_data(),
prefetch_data_->cpu_data(), sizeof(Dtype) * prefetch_data_->count(),
Expand All @@ -30,9 +30,7 @@ Dtype DataLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom,
cudaMemcpyHostToDevice));
}
// Start a new prefetch thread
phase_ = Caffe::phase();
CHECK(!pthread_create(&thread_, NULL, DataLayerPrefetch<Dtype>,
reinterpret_cast<void*>(this))) << "Pthread execution failed.";
CreatePrefetchThread();
return Dtype(0.);
}

Expand Down
Loading