"git@developer.sourcefind.cn:tianlh/lightgbm-dcu.git" did not exist on "962b7eb00f154d224aaa7b89ac1605dbd5b11950"
Unverified Commit 73531662 authored by shiyu1994's avatar shiyu1994 Committed by GitHub
Browse files

[CUDA] Add binary logloss metric for new CUDA version (#5635)

parent b88cf8af
...@@ -96,7 +96,7 @@ class BinaryMetric: public Metric { ...@@ -96,7 +96,7 @@ class BinaryMetric: public Metric {
return std::vector<double>(1, loss); return std::vector<double>(1, loss);
} }
private: protected:
/*! \brief Number of data */ /*! \brief Number of data */
data_size_t num_data_; data_size_t num_data_;
/*! \brief Pointer of label */ /*! \brief Pointer of label */
......
/*!
* Copyright (c) 2022 Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for
* license information.
*/
#ifdef USE_CUDA_EXP
#include "cuda_binary_metric.hpp"
namespace LightGBM {
CUDABinaryLoglossMetric::CUDABinaryLoglossMetric(const Config& config):
CUDABinaryMetricInterface<BinaryLoglossMetric, CUDABinaryLoglossMetric>(config) {}
template <typename HOST_METRIC, typename CUDA_METRIC>
std::vector<double> CUDABinaryMetricInterface<HOST_METRIC, CUDA_METRIC>::Eval(const double* score, const ObjectiveFunction* objective) const {
const double* score_convert = score;
if (objective != nullptr && objective->NeedConvertOutputCUDA()) {
this->score_convert_buffer_.Resize(static_cast<size_t>(this->num_data_) * static_cast<size_t>(this->num_class_));
score_convert = objective->ConvertOutputCUDA(this->num_data_, score, this->score_convert_buffer_.RawData());
}
double sum_loss = 0.0, sum_weight = 0.0;
this->LaunchEvalKernel(score_convert, &sum_loss, &sum_weight);
const double eval_score = sum_loss / sum_weight;
return std::vector<double>{eval_score};
}
} // namespace LightGBM
#endif // USE_CUDA_EXP
/*!
* Copyright (c) 2022 Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for
* license information.
*/
#ifndef LIGHTGBM_METRIC_CUDA_CUDA_BINARY_METRIC_HPP_
#define LIGHTGBM_METRIC_CUDA_CUDA_BINARY_METRIC_HPP_
#ifdef USE_CUDA_EXP
#include <LightGBM/cuda/cuda_metric.hpp>
#include <LightGBM/cuda/cuda_utils.h>
#include <vector>
#include "cuda_regression_metric.hpp"
#include "../binary_metric.hpp"
namespace LightGBM {
template <typename HOST_METRIC, typename CUDA_METRIC>
class CUDABinaryMetricInterface: public CUDAPointwiseMetricInterface<HOST_METRIC, CUDA_METRIC> {
public:
explicit CUDABinaryMetricInterface(const Config& config): CUDAPointwiseMetricInterface<HOST_METRIC, CUDA_METRIC>(config) {}
virtual ~CUDABinaryMetricInterface() {}
std::vector<double> Eval(const double* score, const ObjectiveFunction* objective) const override;
};
class CUDABinaryLoglossMetric: public CUDABinaryMetricInterface<BinaryLoglossMetric, CUDABinaryLoglossMetric> {
public:
explicit CUDABinaryLoglossMetric(const Config& config);
virtual ~CUDABinaryLoglossMetric() {}
__device__ static double MetricOnPointCUDA(label_t label, double score) {
// score should have been converted to probability
if (label <= 0) {
if (1.0f - score > kEpsilon) {
return -log(1.0f - score);
}
} else {
if (score > kEpsilon) {
return -log(score);
}
}
return -log(kEpsilon);
}
};
} // namespace LightGBM
#endif // USE_CUDA_EXP
#endif // LIGHTGBM_METRIC_CUDA_CUDA_BINARY_METRIC_HPP_
/*!
* Copyright (c) 2022 Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for
* license information.
*/
#ifdef USE_CUDA_EXP
#include "cuda_binary_metric.hpp"
#include "cuda_pointwise_metric.hpp"
#include "cuda_regression_metric.hpp"
namespace LightGBM {
template <typename HOST_METRIC, typename CUDA_METRIC>
void CUDAPointwiseMetricInterface<HOST_METRIC, CUDA_METRIC>::Init(const Metadata& metadata, data_size_t num_data) {
CUDAMetricInterface<HOST_METRIC>::Init(metadata, num_data);
const int max_num_reduce_blocks = (this->num_data_ + NUM_DATA_PER_EVAL_THREAD - 1) / NUM_DATA_PER_EVAL_THREAD;
if (this->cuda_weights_ == nullptr) {
reduce_block_buffer_.Resize(max_num_reduce_blocks);
} else {
reduce_block_buffer_.Resize(max_num_reduce_blocks * 2);
}
const int max_num_reduce_blocks_inner = (max_num_reduce_blocks + NUM_DATA_PER_EVAL_THREAD - 1) / NUM_DATA_PER_EVAL_THREAD;
if (this->cuda_weights_ == nullptr) {
reduce_block_buffer_inner_.Resize(max_num_reduce_blocks_inner);
} else {
reduce_block_buffer_inner_.Resize(max_num_reduce_blocks_inner * 2);
}
}
template void CUDAPointwiseMetricInterface<RMSEMetric, CUDARMSEMetric>::Init(const Metadata& metadata, data_size_t num_data);
template void CUDAPointwiseMetricInterface<L2Metric, CUDAL2Metric>::Init(const Metadata& metadata, data_size_t num_data);
template void CUDAPointwiseMetricInterface<BinaryLoglossMetric, CUDABinaryLoglossMetric>::Init(const Metadata& metadata, data_size_t num_data);
} // namespace LightGBM
#endif // USE_CUDA_EXP
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include <LightGBM/cuda/cuda_algorithms.hpp> #include <LightGBM/cuda/cuda_algorithms.hpp>
#include "cuda_binary_metric.hpp"
#include "cuda_pointwise_metric.hpp"
#include "cuda_regression_metric.hpp" #include "cuda_regression_metric.hpp"
namespace LightGBM { namespace LightGBM {
...@@ -40,7 +42,7 @@ __global__ void EvalKernel(const data_size_t num_data, const label_t* labels, co ...@@ -40,7 +42,7 @@ __global__ void EvalKernel(const data_size_t num_data, const label_t* labels, co
} }
template <typename HOST_METRIC, typename CUDA_METRIC> template <typename HOST_METRIC, typename CUDA_METRIC>
double CUDARegressionMetricInterface<HOST_METRIC, CUDA_METRIC>::LaunchEvalKernel(const double* score) const { void CUDAPointwiseMetricInterface<HOST_METRIC, CUDA_METRIC>::LaunchEvalKernel(const double* score, double* sum_loss, double* sum_weight) const {
const int num_blocks = (this->num_data_ + NUM_DATA_PER_EVAL_THREAD - 1) / NUM_DATA_PER_EVAL_THREAD; const int num_blocks = (this->num_data_ + NUM_DATA_PER_EVAL_THREAD - 1) / NUM_DATA_PER_EVAL_THREAD;
if (this->cuda_weights_ != nullptr) { if (this->cuda_weights_ != nullptr) {
EvalKernel<CUDA_METRIC, true><<<num_blocks, NUM_DATA_PER_EVAL_THREAD>>>( EvalKernel<CUDA_METRIC, true><<<num_blocks, NUM_DATA_PER_EVAL_THREAD>>>(
...@@ -50,18 +52,17 @@ double CUDARegressionMetricInterface<HOST_METRIC, CUDA_METRIC>::LaunchEvalKernel ...@@ -50,18 +52,17 @@ double CUDARegressionMetricInterface<HOST_METRIC, CUDA_METRIC>::LaunchEvalKernel
this->num_data_, this->cuda_labels_, this->cuda_weights_, score, reduce_block_buffer_.RawData()); this->num_data_, this->cuda_labels_, this->cuda_weights_, score, reduce_block_buffer_.RawData());
} }
ShuffleReduceSumGlobal<double, double>(reduce_block_buffer_.RawData(), num_blocks, reduce_block_buffer_inner_.RawData()); ShuffleReduceSumGlobal<double, double>(reduce_block_buffer_.RawData(), num_blocks, reduce_block_buffer_inner_.RawData());
double sum_loss = 0.0; CopyFromCUDADeviceToHost<double>(sum_loss, reduce_block_buffer_inner_.RawData(), 1, __FILE__, __LINE__);
CopyFromCUDADeviceToHost<double>(&sum_loss, reduce_block_buffer_inner_.RawData(), 1, __FILE__, __LINE__); *sum_weight = static_cast<double>(this->num_data_);
double sum_weight = static_cast<double>(this->num_data_);
if (this->cuda_weights_ != nullptr) { if (this->cuda_weights_ != nullptr) {
ShuffleReduceSumGlobal<double, double>(reduce_block_buffer_.RawData() + num_blocks, num_blocks, reduce_block_buffer_inner_.RawData()); ShuffleReduceSumGlobal<double, double>(reduce_block_buffer_.RawData() + num_blocks, num_blocks, reduce_block_buffer_inner_.RawData());
CopyFromCUDADeviceToHost<double>(&sum_weight, reduce_block_buffer_inner_.RawData(), 1, __FILE__, __LINE__); CopyFromCUDADeviceToHost<double>(sum_weight, reduce_block_buffer_inner_.RawData(), 1, __FILE__, __LINE__);
} }
return this->AverageLoss(sum_loss, sum_weight);
} }
template double CUDARegressionMetricInterface<RMSEMetric, CUDARMSEMetric>::LaunchEvalKernel(const double* score) const; template void CUDAPointwiseMetricInterface<RMSEMetric, CUDARMSEMetric>::LaunchEvalKernel(const double* score, double* sum_loss, double* sum_weight) const;
template double CUDARegressionMetricInterface<L2Metric, CUDAL2Metric>::LaunchEvalKernel(const double* score) const; template void CUDAPointwiseMetricInterface<L2Metric, CUDAL2Metric>::LaunchEvalKernel(const double* score, double* sum_loss, double* sum_weight) const;
template void CUDAPointwiseMetricInterface<BinaryLoglossMetric, CUDABinaryLoglossMetric>::LaunchEvalKernel(const double* score, double* sum_loss, double* sum_weight) const;
} // namespace LightGBM } // namespace LightGBM
......
/*!
* Copyright (c) 2022 Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See LICENSE file in the project root for
* license information.
*/
#ifndef LIGHTGBM_METRIC_CUDA_CUDA_POINTWISE_METRIC_HPP_
#define LIGHTGBM_METRIC_CUDA_CUDA_POINTWISE_METRIC_HPP_
#ifdef USE_CUDA_EXP
#include <LightGBM/cuda/cuda_metric.hpp>
#include <LightGBM/cuda/cuda_utils.h>
#include <vector>
#define NUM_DATA_PER_EVAL_THREAD (1024)
namespace LightGBM {
template <typename HOST_METRIC, typename CUDA_METRIC>
class CUDAPointwiseMetricInterface: public CUDAMetricInterface<HOST_METRIC> {
public:
explicit CUDAPointwiseMetricInterface(const Config& config): CUDAMetricInterface<HOST_METRIC>(config), num_class_(config.num_class) {}
virtual ~CUDAPointwiseMetricInterface() {}
void Init(const Metadata& metadata, data_size_t num_data) override;
protected:
void LaunchEvalKernel(const double* score_convert, double* sum_loss, double* sum_weight) const;
mutable CUDAVector<double> score_convert_buffer_;
CUDAVector<double> reduce_block_buffer_;
CUDAVector<double> reduce_block_buffer_inner_;
const int num_class_;
};
} // namespace LightGBM
#endif // USE_CUDA_EXP
#endif // LIGHTGBM_METRIC_CUDA_CUDA_POINTWISE_METRIC_HPP_
...@@ -12,31 +12,16 @@ ...@@ -12,31 +12,16 @@
namespace LightGBM { namespace LightGBM {
template <typename HOST_METRIC, typename CUDA_METRIC>
void CUDARegressionMetricInterface<HOST_METRIC, CUDA_METRIC>::Init(const Metadata& metadata, data_size_t num_data) {
CUDAMetricInterface<HOST_METRIC>::Init(metadata, num_data);
const int max_num_reduce_blocks = (this->num_data_ + NUM_DATA_PER_EVAL_THREAD - 1) / NUM_DATA_PER_EVAL_THREAD;
if (this->cuda_weights_ == nullptr) {
reduce_block_buffer_.Resize(max_num_reduce_blocks);
} else {
reduce_block_buffer_.Resize(max_num_reduce_blocks * 2);
}
const int max_num_reduce_blocks_inner = (max_num_reduce_blocks + NUM_DATA_PER_EVAL_THREAD - 1) / NUM_DATA_PER_EVAL_THREAD;
if (this->cuda_weights_ == nullptr) {
reduce_block_buffer_inner_.Resize(max_num_reduce_blocks_inner);
} else {
reduce_block_buffer_inner_.Resize(max_num_reduce_blocks_inner * 2);
}
}
template <typename HOST_METRIC, typename CUDA_METRIC> template <typename HOST_METRIC, typename CUDA_METRIC>
std::vector<double> CUDARegressionMetricInterface<HOST_METRIC, CUDA_METRIC>::Eval(const double* score, const ObjectiveFunction* objective) const { std::vector<double> CUDARegressionMetricInterface<HOST_METRIC, CUDA_METRIC>::Eval(const double* score, const ObjectiveFunction* objective) const {
const double* score_convert = score; const double* score_convert = score;
if (objective != nullptr && objective->NeedConvertOutputCUDA()) { if (objective != nullptr && objective->NeedConvertOutputCUDA()) {
score_convert_buffer_.Resize(static_cast<size_t>(this->num_data_) * static_cast<size_t>(this->num_class_)); this->score_convert_buffer_.Resize(static_cast<size_t>(this->num_data_) * static_cast<size_t>(this->num_class_));
score_convert = objective->ConvertOutputCUDA(this->num_data_, score, score_convert_buffer_.RawData()); score_convert = objective->ConvertOutputCUDA(this->num_data_, score, this->score_convert_buffer_.RawData());
} }
const double eval_score = LaunchEvalKernel(score_convert); double sum_loss = 0.0, sum_weight = 0.0;
this->LaunchEvalKernel(score_convert, &sum_loss, &sum_weight);
const double eval_score = this->AverageLoss(sum_loss, sum_weight);
return std::vector<double>{eval_score}; return std::vector<double>{eval_score};
} }
......
...@@ -14,30 +14,20 @@ ...@@ -14,30 +14,20 @@
#include <vector> #include <vector>
#include "cuda_pointwise_metric.hpp"
#include "../regression_metric.hpp" #include "../regression_metric.hpp"
#define NUM_DATA_PER_EVAL_THREAD (1024)
namespace LightGBM { namespace LightGBM {
template <typename HOST_METRIC, typename CUDA_METRIC> template <typename HOST_METRIC, typename CUDA_METRIC>
class CUDARegressionMetricInterface: public CUDAMetricInterface<HOST_METRIC> { class CUDARegressionMetricInterface: public CUDAPointwiseMetricInterface<HOST_METRIC, CUDA_METRIC> {
public: public:
explicit CUDARegressionMetricInterface(const Config& config): CUDAMetricInterface<HOST_METRIC>(config), num_class_(config.num_class) {} explicit CUDARegressionMetricInterface(const Config& config):
CUDAPointwiseMetricInterface<HOST_METRIC, CUDA_METRIC>(config) {}
virtual ~CUDARegressionMetricInterface() {} virtual ~CUDARegressionMetricInterface() {}
void Init(const Metadata& metadata, data_size_t num_data) override;
std::vector<double> Eval(const double* score, const ObjectiveFunction* objective) const override; std::vector<double> Eval(const double* score, const ObjectiveFunction* objective) const override;
protected:
double LaunchEvalKernel(const double* score_convert) const;
mutable CUDAVector<double> score_convert_buffer_;
CUDAVector<double> reduce_block_buffer_;
CUDAVector<double> reduce_block_buffer_inner_;
const int num_class_;
}; };
class CUDARMSEMetric: public CUDARegressionMetricInterface<RMSEMetric, CUDARMSEMetric> { class CUDARMSEMetric: public CUDARegressionMetricInterface<RMSEMetric, CUDARMSEMetric> {
......
...@@ -11,13 +11,14 @@ ...@@ -11,13 +11,14 @@
#include "regression_metric.hpp" #include "regression_metric.hpp"
#include "xentropy_metric.hpp" #include "xentropy_metric.hpp"
#include "cuda/cuda_binary_metric.hpp"
#include "cuda/cuda_regression_metric.hpp" #include "cuda/cuda_regression_metric.hpp"
namespace LightGBM { namespace LightGBM {
Metric* Metric::CreateMetric(const std::string& type, const Config& config) { Metric* Metric::CreateMetric(const std::string& type, const Config& config) {
#ifdef USE_CUDA_EXP #ifdef USE_CUDA_EXP
if (config.device_type == std::string("cuda_exp")) { if (config.device_type == std::string("cuda_exp") && config.boosting == std::string("gbdt")) {
if (type == std::string("l2")) { if (type == std::string("l2")) {
return new CUDAL2Metric(config); return new CUDAL2Metric(config);
} else if (type == std::string("rmse")) { } else if (type == std::string("rmse")) {
...@@ -38,8 +39,7 @@ Metric* Metric::CreateMetric(const std::string& type, const Config& config) { ...@@ -38,8 +39,7 @@ Metric* Metric::CreateMetric(const std::string& type, const Config& config) {
Log::Warning("Metric poisson is not implemented in cuda_exp version. Fall back to evaluation on CPU."); Log::Warning("Metric poisson is not implemented in cuda_exp version. Fall back to evaluation on CPU.");
return new PoissonMetric(config); return new PoissonMetric(config);
} else if (type == std::string("binary_logloss")) { } else if (type == std::string("binary_logloss")) {
Log::Warning("Metric binary_logloss is not implemented in cuda_exp version. Fall back to evaluation on CPU."); return new CUDABinaryLoglossMetric(config);
return new BinaryLoglossMetric(config);
} else if (type == std::string("binary_error")) { } else if (type == std::string("binary_error")) {
Log::Warning("Metric binary_error is not implemented in cuda_exp version. Fall back to evaluation on CPU."); Log::Warning("Metric binary_error is not implemented in cuda_exp version. Fall back to evaluation on CPU.");
return new BinaryErrorMetric(config); return new BinaryErrorMetric(config);
......
...@@ -33,6 +33,8 @@ class CUDABinaryLogloss : public CUDAObjectiveInterface<BinaryLogloss> { ...@@ -33,6 +33,8 @@ class CUDABinaryLogloss : public CUDAObjectiveInterface<BinaryLogloss> {
void Init(const Metadata& metadata, data_size_t num_data) override; void Init(const Metadata& metadata, data_size_t num_data) override;
bool NeedConvertOutputCUDA() const override { return true; }
private: private:
void LaunchGetGradientsKernel(const double* scores, score_t* gradients, score_t* hessians) const override; void LaunchGetGradientsKernel(const double* scores, score_t* gradients, score_t* hessians) const override;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment