Skip to content

Commit

Permalink
added multilane label reading python modules, interfaced with C++
Browse files Browse the repository at this point in the history
using boost numpy
  • Loading branch information
Tao Wang committed Nov 29, 2014
1 parent ff97eab commit 801de4f
Show file tree
Hide file tree
Showing 28 changed files with 5,767 additions and 23 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,12 @@ LIBRARIES += pthread \
glog gflags protobuf leveldb snappy \
lmdb \
boost_system \
python2.7 \
boost_python \
boost_numpy \
hdf5_hl hdf5 \
opencv_core opencv_highgui opencv_imgproc
PYTHON_LIBRARIES := boost_python python2.7
PYTHON_LIBRARIES := boost_python boost_numpy python2.7 opencv_core opencv_highgui opencv_imgproc
WARNINGS := -Wall -Wno-sign-compare

##############################
Expand Down
35 changes: 33 additions & 2 deletions include/caffe/data_layers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <opencv2/imgproc/imgproc.hpp>

namespace caffe {

#define HDF5_DATA_DATASET_NAME "data"
Expand Down Expand Up @@ -302,17 +301,49 @@ class VideoDataLayer : public BasePrefetchingDataLayer<Dtype> {
virtual void InternalThreadEntry();
bool ReadVideoFrameToDatum(const string& filename, size_t id,
size_t persp, const int height, const int width, Datum* datum);

void setPerspective();
//inline bool ReadVideoBatchToDatum(const string& filename, std::vector<size_t> frameIds,
// std::vector<size_t>trans, Datum* datum) {
// return ReadVideoBatchToDatum(filename, frameIds, trans, 0, 0, datum);
//}

vector<std::pair<std::string, std::pair<std::vector<size_t>, std::vector<size_t> > > > lines_;
int lines_id_;
std::vector<cv::Mat> mTransforms;
cv::VideoCapture* cap;
};


/**
* @brief Provides multilane labels to the Net.
*
* TODO(dox): thorough documentation for Forward and proto params.
*/
template <typename Dtype>
class MultilaneLabelLayer : public BasePrefetchingDataLayer<Dtype> {
public:
explicit MultilaneLabelLayer(const LayerParameter& param)
: BasePrefetchingDataLayer<Dtype>(param) {}
virtual ~MultilaneLabelLayer();
virtual void DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top);

virtual inline LayerParameter_LayerType type() const {
return LayerParameter_LayerType_VIDEO_DATA;
}
virtual inline int ExactNumBottomBlobs() const { return 0; }
virtual inline int ExactNumTopBlobs() const { return 1; }

protected:
shared_ptr<Caffe::RNG> prefetch_rng_;
virtual void ShuffleBatches();
virtual void InternalThreadEntry();
//boost::numpy::ndarray ReadLabelBatch(const string& filename, std::vector<size_t> &frame_ids, std::vector<size_t> trans, const int height, const int width);

vector<std::pair<std::string, std::pair<std::vector<int>, std::vector<int> > > > lines_;
int lines_id_;
};

/**
* @brief Provides data to the Net from memory.
*
Expand Down
7 changes: 3 additions & 4 deletions models/brody/train_val_brody.prototxt
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ layers {
# Bounding box label and pixel label.
layers {
name: "label"
type: DATA
type: MULTILANE_LABEL
top: "label"
data_param {
source: "/deep/group/driving_data/twangcat/lmdb/driving_label_train"
backend: LMDB
multilane_label_param {
source: "/scail/group/deeplearning/driving_data/twangcat/schedules/q50_multilane_planar_train_schedule1_batch20_2cam.txt"
batch_size: 20
}
include: { phase: TRAIN }
Expand Down
6 changes: 6 additions & 0 deletions prep_opencv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
export PKG_CONFIG_PATH=/deep/group/driving_data/twangcat/env_deep6/opencv/lib/pkgconfig/
export LD_LIBRARY_PATH=/deep/group/driving_data/twangcat/env_deep6/opencv/lib/:$LD_LIBRARY_PATH
export PATH=/deep/group/driving_data/twangcat/env_deep6/opencv/include/:$PATH
export CPLUS_INCLUDE_PATH=/deep/group/driving_data/twangcat/env_deep6/opencv/include/:$CPLUS_INCLUDE_PATH

2 changes: 2 additions & 0 deletions src/caffe/layer_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ Layer<Dtype>* GetLayer(const LayerParameter& param) {
return new LRNLayer<Dtype>(param);
case LayerParameter_LayerType_MEMORY_DATA:
return new MemoryDataLayer<Dtype>(param);
case LayerParameter_LayerType_MULTILANE_LABEL:
return new MultilaneLabelLayer<Dtype>(param);
case LayerParameter_LayerType_MVN:
return new MVNLayer<Dtype>(param);
case LayerParameter_LayerType_MULTINOMIAL_LOGISTIC_LOSS:
Expand Down
213 changes: 213 additions & 0 deletions src/caffe/layers/multilane_label_layer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#include <fstream> // NOLINT(readability/streams)
#include <iostream> // NOLINT(readability/streams)
#include <string>
#include <utility>
#include <vector>
#include <stdlib.h>
#include "caffe/data_layers.hpp"
#include "caffe/layer.hpp"
#include "caffe/util/io.hpp"
#include "caffe/util/math_functions.hpp"
#include "caffe/util/rng.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/python.hpp>
#include <boost/numpy.hpp>
#include <numpy/arrayobject.h>


namespace py = boost::python; // create namespace variable for boost::python
namespace np = boost::numpy; // create namespace variable for boost::python
namespace caffe {

//np::ndarray ReadLabelBatch(const string& filename, std::vector<size_t> &frame_ids, std::vector<size_t> &trans,
// const int height, const int width) {
//};
template <typename Dtype>
MultilaneLabelLayer<Dtype>::~MultilaneLabelLayer<Dtype>() {
this->JoinPrefetchThread();
}


template <typename Dtype>
void MultilaneLabelLayer<Dtype>::DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
const int new_height = this->layer_param_.multilane_label_param().new_height();
const int new_width = this->layer_param_.multilane_label_param().new_width();
CHECK((new_height == 0 && new_width == 0) ||
(new_height > 0 && new_width > 0)) << "Current implementation requires "
"new_height and new_width to be set at the same time.";
// Read the file with filenames and labels
const string& source = this->layer_param_.multilane_label_param().source();
LOG(INFO) << "Opening schedule file " << source;
std::ifstream infile(source.c_str());



string batch_string;

string filename;
//while (infile >> batch_string) {
while (getline (infile, batch_string)) {
if(!infile)
{
if(infile.eof())
{
LOG(INFO) << "Reached EOF of schedule file.";
break;
}
else
LOG(FATAL)<< "Error while reading schedule file. Possibly corrupted.";
}
std::vector<string> batch_fields;
// first split a line into fields with delimiter ",". Fields should be [filename, frame_ids, transform_ids]
boost::split(batch_fields, batch_string, boost::is_any_of(","),
boost::token_compress_on);
if(batch_fields.size()!=3)
LOG(FATAL) << "Each line must have 3 fields separated by comma, "
<<batch_fields.size()<<" found instead";
// store filename
filename = batch_fields[0];
// store frame ids
std::vector<string> frame_ids_str;
std::vector<int> frame_ids;
boost::split(frame_ids_str, batch_fields[1], boost::is_any_of(" "),
boost::token_compress_on);
for (int f=0; f<frame_ids_str.size(); ++f) {
frame_ids.push_back((int)atoi(frame_ids_str[f].c_str()));
}

// store persp transform ids
std::vector<string> trans_ids_str;
std::vector<int> trans_ids;
boost::split(trans_ids_str, batch_fields[2], boost::is_any_of(" "),
boost::token_compress_on);
for (int f=0; f<trans_ids_str.size(); ++f) {
trans_ids.push_back((int)atoi(trans_ids_str[f].c_str()));
}

lines_.push_back(std::make_pair(filename, std::make_pair(frame_ids, trans_ids)));
}

if (this->layer_param_.multilane_label_param().shuffle()) {
// randomly shuffle data
LOG(INFO) << "Shuffling batches";
const unsigned int prefetch_rng_seed = caffe_rng_rand();
prefetch_rng_.reset(new Caffe::RNG(prefetch_rng_seed));
ShuffleBatches();
}
LOG(INFO) << "A total of " << lines_.size() << " batches.";

lines_id_ = 0;
// Check if we would need to randomly skip a few data points
if (this->layer_param_.multilane_label_param().rand_skip()) {
unsigned int skip = caffe_rng_rand() %
this->layer_param_.multilane_label_param().rand_skip();
LOG(INFO) << "Skipping first " << skip << " data points.";
CHECK_GT(lines_.size(), skip) << "Not enough points to skip";
lines_id_ = skip;
}
const int crop_size = this->layer_param_.transform_param().crop_size();
const int batch_size = this->layer_param_.multilane_label_param().batch_size();
if (crop_size > 0) {
(*top)[0]->Reshape(batch_size, 80, crop_size, crop_size);
this->prefetch_data_.Reshape(batch_size, 80, crop_size,
crop_size);
} else {
(*top)[0]->Reshape(batch_size, 80, 15,20);
this->prefetch_data_.Reshape(batch_size, 80, 15,20);
}
LOG(INFO) << "output data size: " << (*top)[0]->num() << ","
<< (*top)[0]->channels() << "," << (*top)[0]->height() << ","
<< (*top)[0]->width();
// label
//(*top)[1]->Reshape(batch_size, 1, 1, 1);
this->prefetch_label_.Reshape(batch_size, 1, 1, 1);
// datum size
this->datum_channels_ = 80;
this->datum_height_ = 15;
this->datum_width_ = 20;
this->datum_size_ = 80*15*20;
}

template <typename Dtype>
void MultilaneLabelLayer<Dtype>::ShuffleBatches() {
caffe::rng_t* prefetch_rng =
static_cast<caffe::rng_t*>(prefetch_rng_->generator());
shuffle(lines_.begin(), lines_.end(), prefetch_rng);
}



// This function is used to create a thread that prefetches the data.
template <typename Dtype>
void MultilaneLabelLayer<Dtype>::InternalThreadEntry() {
CHECK(this->prefetch_data_.count());
Dtype* top_data = this->prefetch_data_.mutable_cpu_data();
//Dtype* top_label = this->prefetch_label_.mutable_cpu_data();
MultilaneLabelParameter multilane_label_param = this->layer_param_.multilane_label_param();
const int batch_size = multilane_label_param.batch_size();
const int new_height = multilane_label_param.new_height();
const int new_width = multilane_label_param.new_width();

// datum scales
const int lines_size = lines_.size();
string filename = lines_[lines_id_].first;
std::vector<int> frameIds = lines_[lines_id_].second.first;
std::vector<int> trans = lines_[lines_id_].second.second;
if (batch_size!=frameIds.size() || batch_size!=trans.size())
LOG(ERROR)<<"Frame count mismatch!";
LOG(INFO)<<"reading label batch "<<filename;

try{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\"/afs/cs.stanford.edu/u/twangcat/scratch/caffenet/src/caffe/py_lane_label_reader/\")");
np::initialize();
}catch(py::error_already_set const &){
PyErr_Print();
LOG(FATAL) <<"boost python and numpy initialization failed.";
}
py::object arr_handle;
// get a label blob from python helper class
try{
// initialize python helper class
py::object module = py::import("multilane_label_reader");
py::object readerClass = module.attr("MultilaneLabelReader");
py::object reader = readerClass();
// initialize arguments to python helper class function
np::dtype dt = np::dtype::get_builtin<int>();
py::tuple shape = py::make_tuple(batch_size) ;
py::tuple stride = py::make_tuple(4) ;
py::object own1;
py::object own2;
int* framePtr = const_cast<int *>(&frameIds[0]);
int* transPtr = const_cast<int *>(&trans[0]);
np::ndarray frameArr = np::from_data(framePtr,dt,shape,stride,own1);
np::ndarray transArr = np::from_data(transPtr,dt,shape,stride,own2);
// call function
arr_handle = reader.attr("runLabelling")(filename, frameArr, transArr);
}catch(py::error_already_set const &){
PyErr_Print();
LOG(FATAL) <<"numpy label reading function failed!";
}
np::ndarray pArray = np::from_object(arr_handle);

int array_size = py::extract<int>(pArray.attr("size"));
LOG(INFO)<<"numpy array size = "<<array_size;
float* pArrayPtr = (float*)(pArray.get_data());
std::copy(pArrayPtr, pArrayPtr+array_size, top_data);
// go to the next iter
lines_id_++;
if (lines_id_ >= lines_size) {
// We have reached the end. Restart from the first.
DLOG(INFO) << "Restarting data prefetching from start.";
lines_id_ = 0;
if (this->layer_param_.image_data_param().shuffle()) {
ShuffleBatches();
}
}
}

INSTANTIATE_CLASS(MultilaneLabelLayer);

} // namespace caffe
Loading

0 comments on commit 801de4f

Please sign in to comment.