Replaced std::vector-based interfaces with HostDeviceVector-based interfaces. (#3116)

* Replaced std::vector-based interfaces with HostDeviceVector-based interfaces.

- replacement was performed in the learner, boosters, predictors,
  updaters, and objective functions
- only interfaces used in training were replaced;
  interfaces like PredictInstance() still use std::vector
- refactoring necessary for replacement of interfaces was also performed,
  such as using HostDeviceVector in prediction cache

* HostDeviceVector-based interfaces for custom objective function example plugin.
This commit is contained in:
Andrew V. Adinetz
2018-02-28 01:00:04 +01:00
committed by Rory Mitchell
parent 11bfa8584d
commit d5992dd881
38 changed files with 371 additions and 519 deletions

View File

@@ -12,13 +12,27 @@ namespace xgboost {
template <typename T>
struct HostDeviceVectorImpl {
explicit HostDeviceVectorImpl(size_t size) : data_h_(size) {}
explicit HostDeviceVectorImpl(size_t size, T v) : data_h_(size, v) {}
explicit HostDeviceVectorImpl(std::initializer_list<T> init) : data_h_(init) {}
explicit HostDeviceVectorImpl(const std::vector<T>& init) : data_h_(init) {}
std::vector<T> data_h_;
};
template <typename T>
HostDeviceVector<T>::HostDeviceVector(size_t size, int device) : impl_(nullptr) {
impl_ = new HostDeviceVectorImpl<T>(size);
HostDeviceVector<T>::HostDeviceVector(size_t size, T v, int device) : impl_(nullptr) {
impl_ = new HostDeviceVectorImpl<T>(size, v);
}
template <typename T>
HostDeviceVector<T>::HostDeviceVector(std::initializer_list<T> init, int device)
: impl_(nullptr) {
impl_ = new HostDeviceVectorImpl<T>(init);
}
template <typename T>
HostDeviceVector<T>::HostDeviceVector(const std::vector<T>& init, int device)
: impl_(nullptr) {
impl_ = new HostDeviceVectorImpl<T>(init);
}
template <typename T>
@@ -41,8 +55,8 @@ template <typename T>
std::vector<T>& HostDeviceVector<T>::data_h() { return impl_->data_h_; }
template <typename T>
void HostDeviceVector<T>::resize(size_t new_size, int new_device) {
impl_->data_h_.resize(new_size);
void HostDeviceVector<T>::resize(size_t new_size, T v, int new_device) {
impl_->data_h_.resize(new_size, v);
}
// explicit instantiations are required, as HostDeviceVector isn't header-only

View File

@@ -1,6 +1,7 @@
/*!
* Copyright 2017 XGBoost contributors
*/
#include "./host_device_vector.h"
#include "./device_helpers.cuh"
@@ -8,13 +9,25 @@ namespace xgboost {
template <typename T>
struct HostDeviceVectorImpl {
HostDeviceVectorImpl(size_t size, int device)
HostDeviceVectorImpl(size_t size, T v, int device)
: device_(device), on_d_(device >= 0) {
if (on_d_) {
dh::safe_cuda(cudaSetDevice(device_));
data_d_.resize(size);
data_d_.resize(size, v);
} else {
data_h_.resize(size);
data_h_.resize(size, v);
}
}
// Init can be std::vector<T> or std::initializer_list<T>
template <class Init>
HostDeviceVectorImpl(const Init& init, int device)
: device_(device), on_d_(device >= 0) {
if (on_d_) {
dh::safe_cuda(cudaSetDevice(device_));
data_d_.resize(init.size());
thrust::copy(init.begin(), init.end(), data_d_.begin());
} else {
data_h_ = init;
}
}
HostDeviceVectorImpl(const HostDeviceVectorImpl<T>&) = delete;
@@ -41,17 +54,18 @@ struct HostDeviceVectorImpl {
lazy_sync_host();
return data_h_;
}
void resize(size_t new_size, int new_device) {
void resize(size_t new_size, T v, int new_device) {
if (new_size == this->size() && new_device == device_)
return;
device_ = new_device;
if (new_device != -1)
device_ = new_device;
// if !on_d_, but the data size is 0 and the device is set,
// resize the data on device instead
if (!on_d_ && (data_h_.size() > 0 || device_ == -1)) {
data_h_.resize(new_size);
data_h_.resize(new_size, v);
} else {
dh::safe_cuda(cudaSetDevice(device_));
data_d_.resize(new_size);
data_d_.resize(new_size, v);
on_d_ = true;
}
}
@@ -90,8 +104,20 @@ struct HostDeviceVectorImpl {
};
template <typename T>
HostDeviceVector<T>::HostDeviceVector(size_t size, int device) : impl_(nullptr) {
impl_ = new HostDeviceVectorImpl<T>(size, device);
HostDeviceVector<T>::HostDeviceVector(size_t size, T v, int device) : impl_(nullptr) {
impl_ = new HostDeviceVectorImpl<T>(size, v, device);
}
template <typename T>
HostDeviceVector<T>::HostDeviceVector(std::initializer_list<T> init, int device)
: impl_(nullptr) {
impl_ = new HostDeviceVectorImpl<T>(init, device);
}
template <typename T>
HostDeviceVector<T>::HostDeviceVector(const std::vector<T>& init, int device)
: impl_(nullptr) {
impl_ = new HostDeviceVectorImpl<T>(init, device);
}
template <typename T>
@@ -124,8 +150,8 @@ template <typename T>
std::vector<T>& HostDeviceVector<T>::data_h() { return impl_->data_h(); }
template <typename T>
void HostDeviceVector<T>::resize(size_t new_size, int new_device) {
impl_->resize(new_size, new_device);
void HostDeviceVector<T>::resize(size_t new_size, T v, int new_device) {
impl_->resize(new_size, v, new_device);
}
// explicit instantiations are required, as HostDeviceVector isn't header-only

View File

@@ -5,6 +5,7 @@
#define XGBOOST_COMMON_HOST_DEVICE_VECTOR_H_
#include <cstdlib>
#include <initializer_list>
#include <vector>
// only include thrust-related files if host_device_vector.h
@@ -61,7 +62,9 @@ template <typename T> struct HostDeviceVectorImpl;
template <typename T>
class HostDeviceVector {
public:
explicit HostDeviceVector(size_t size = 0, int device = -1);
explicit HostDeviceVector(size_t size = 0, T v = T(), int device = -1);
HostDeviceVector(std::initializer_list<T> init, int device = -1);
explicit HostDeviceVector(const std::vector<T>& init, int device = -1);
~HostDeviceVector();
HostDeviceVector(const HostDeviceVector<T>&) = delete;
HostDeviceVector(HostDeviceVector<T>&&) = delete;
@@ -70,6 +73,7 @@ class HostDeviceVector {
size_t size() const;
int device() const;
T* ptr_d(int device);
T* ptr_h() { return data_h().data(); }
// only define functions returning device_ptr
// if HostDeviceVector.h is included from a .cu file
@@ -79,17 +83,9 @@ class HostDeviceVector {
#endif
std::vector<T>& data_h();
void resize(size_t new_size, int new_device);
// helper functions in case a function needs to be templated
// to work for both HostDeviceVector and std::vector
static std::vector<T>& data_h(HostDeviceVector<T>* v) {
return v->data_h();
}
static std::vector<T>& data_h(std::vector<T>* v) {
return *v;
}
// passing in new_device == -1 keeps the device as is
void resize(size_t new_size, T v = T(), int new_device = -1);
private:
HostDeviceVectorImpl<T>* impl_;