#include #include #include "caffe/blob.hpp" #include "caffe/data_transformer.hpp" #include "caffe/internal_thread.hpp" #include "caffe/layer.hpp" #include "caffe/layers/base_data_layer.hpp" #include "caffe/proto/caffe.pb.h" #include "caffe/util/blocking_queue.hpp" namespace caffe { template BaseDataLayer::BaseDataLayer(const LayerParameter& param) : Layer(param), transform_param_(param.transform_param()) { } template void BaseDataLayer::LayerSetUp(const vector*>& bottom, const vector*>& top) { if (top.size() == 1) { output_labels_ = false; } else { output_labels_ = true; } data_transformer_.reset( new DataTransformer(transform_param_, this->phase_)); data_transformer_->InitRand(); // The subclasses should setup the size of bottom and top DataLayerSetUp(bottom, top); } template BasePrefetchingDataLayer::BasePrefetchingDataLayer( const LayerParameter& param) : BaseDataLayer(param), prefetch_(param.data_param().prefetch()), prefetch_free_(), prefetch_full_(), prefetch_current_() { for (int i = 0; i < prefetch_.size(); ++i) { prefetch_[i].reset(new Batch()); prefetch_free_.push(prefetch_[i].get()); } } template void BasePrefetchingDataLayer::LayerSetUp( const vector*>& bottom, const vector*>& top) { BaseDataLayer::LayerSetUp(bottom, top); // Before starting the prefetch thread, we make cpu_data and gpu_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. for (int i = 0; i < prefetch_.size(); ++i) { prefetch_[i]->data_.mutable_cpu_data(); if (this->output_labels_) { prefetch_[i]->label_.mutable_cpu_data(); } } #ifndef CPU_ONLY if (Caffe::mode() == Caffe::GPU) { for (int i = 0; i < prefetch_.size(); ++i) { prefetch_[i]->data_.mutable_gpu_data(); if (this->output_labels_) { prefetch_[i]->label_.mutable_gpu_data(); } } } #endif DLOG(INFO) << "Initializing prefetch"; this->data_transformer_->InitRand(); StartInternalThread(); DLOG(INFO) << "Prefetch initialized."; } template void BasePrefetchingDataLayer::InternalThreadEntry() { #ifndef CPU_ONLY cudaStream_t stream; if (Caffe::mode() == Caffe::GPU) { CUDA_CHECK(cudaStreamCreateWithFlags(&stream, cudaStreamNonBlocking)); } #endif try { while (!must_stop()) { Batch* batch = prefetch_free_.pop(); load_batch(batch); #ifndef CPU_ONLY if (Caffe::mode() == Caffe::GPU) { batch->data_.data().get()->async_gpu_push(stream); if (this->output_labels_) { batch->label_.data().get()->async_gpu_push(stream); } CUDA_CHECK(cudaStreamSynchronize(stream)); } #endif prefetch_full_.push(batch); } } catch (boost::thread_interrupted&) { // Interrupted exception is expected on shutdown } #ifndef CPU_ONLY if (Caffe::mode() == Caffe::GPU) { CUDA_CHECK(cudaStreamDestroy(stream)); } #endif } template void BasePrefetchingDataLayer::Forward_cpu( const vector*>& bottom, const vector*>& top) { if (prefetch_current_) { prefetch_free_.push(prefetch_current_); } prefetch_current_ = prefetch_full_.pop("Waiting for data"); // Reshape to loaded data. top[0]->ReshapeLike(prefetch_current_->data_); top[0]->set_cpu_data(prefetch_current_->data_.mutable_cpu_data()); if (this->output_labels_) { // Reshape to loaded labels. top[1]->ReshapeLike(prefetch_current_->label_); top[1]->set_cpu_data(prefetch_current_->label_.mutable_cpu_data()); } } #ifdef CPU_ONLY STUB_GPU_FORWARD(BasePrefetchingDataLayer, Forward); #endif INSTANTIATE_CLASS(BaseDataLayer); INSTANTIATE_CLASS(BasePrefetchingDataLayer); } // namespace caffe