multi_val_dense_bin.hpp 8.54 KB
Newer Older
1
2
3
4
5
6
7
/*!
 * Copyright (c) 2020 Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE file in the project root for license information.
 */
#ifndef LIGHTGBM_IO_MULTI_VAL_DENSE_BIN_HPP_
#define LIGHTGBM_IO_MULTI_VAL_DENSE_BIN_HPP_

8
9
#include <LightGBM/bin.h>
#include <LightGBM/utils/openmp_wrapper.h>
10
#include <LightGBM/utils/threading.h>
11

Nikita Titov's avatar
Nikita Titov committed
12
#include <algorithm>
13
14
15
16
17
18
19
20
#include <cstdint>
#include <cstring>
#include <vector>

namespace LightGBM {

template <typename VAL_T>
class MultiValDenseBin : public MultiValBin {
21
 public:
22
23
24
25
  explicit MultiValDenseBin(data_size_t num_data, int num_bin, int num_feature,
    const std::vector<uint32_t>& offsets)
    : num_data_(num_data), num_bin_(num_bin), num_feature_(num_feature),
      offsets_(offsets) {
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    data_.resize(static_cast<size_t>(num_data_) * num_feature_, static_cast<VAL_T>(0));
  }

  ~MultiValDenseBin() {
  }

  data_size_t num_data() const override {
    return num_data_;
  }

  int num_bin() const override {
    return num_bin_;
  }

40
41
  double num_element_per_row() const override { return num_feature_; }

42
43
  const std::vector<uint32_t>& offsets() const override { return offsets_; }

44
45
46
47
48
49
50
51
52
53
  void PushOneRow(int , data_size_t idx, const std::vector<uint32_t>& values) override {
    auto start = RowPtr(idx);
    for (auto i = 0; i < num_feature_; ++i) {
      data_[start + i] = static_cast<VAL_T>(values[i]);
    }
  }

  void FinishLoad() override {
  }

54
  bool IsSparse() override {
55
56
57
    return false;
  }

Guolin Ke's avatar
Guolin Ke committed
58
  template<bool USE_INDICES, bool USE_PREFETCH, bool ORDERED>
59
60
61
  void ConstructHistogramInner(const data_size_t* data_indices, data_size_t start, data_size_t end,
    const score_t* gradients, const score_t* hessians, hist_t* out) const {
    data_size_t i = start;
Guolin Ke's avatar
Guolin Ke committed
62
63
    hist_t* grad = out;
    hist_t* hess = out + 1;
64

Guolin Ke's avatar
Guolin Ke committed
65
    if (USE_PREFETCH) {
66
67
68
69
      const data_size_t pf_offset = 32 / sizeof(VAL_T);
      const data_size_t pf_end = end - pf_offset;

      for (; i < pf_end; ++i) {
Guolin Ke's avatar
Guolin Ke committed
70
71
72
73
        const auto idx = USE_INDICES ? data_indices[i] : i;
        const auto pf_idx = USE_INDICES ? data_indices[i + pf_offset] : i + pf_offset;
        if (!ORDERED) {
          PREFETCH_T0(gradients + pf_idx);
74
75
76
77
          PREFETCH_T0(hessians + pf_idx);
        }
        PREFETCH_T0(data_.data() + RowPtr(pf_idx));
        const auto j_start = RowPtr(idx);
78
79
80
81
82
83
84
85
        const VAL_T* data_ptr = data_.data() + j_start;
        const score_t gradient = ORDERED ? gradients[i] : gradients[idx];
        const score_t hessian = ORDERED ? hessians[i] : hessians[idx];
        for (int j = 0; j < num_feature_; ++j) {
          const uint32_t bin = static_cast<uint32_t>(data_ptr[j]);
          const auto ti = (bin + offsets_[j]) << 1;
          grad[ti] += gradient;
          hess[ti] += hessian;
86
87
88
89
        }
      }
    }
    for (; i < end; ++i) {
Guolin Ke's avatar
Guolin Ke committed
90
      const auto idx = USE_INDICES ? data_indices[i] : i;
91
      const auto j_start = RowPtr(idx);
92
93
94
95
96
97
98
99
      const VAL_T* data_ptr = data_.data() + j_start;
      const score_t gradient = ORDERED ? gradients[i] : gradients[idx];
      const score_t hessian = ORDERED ? hessians[i] : hessians[idx];
      for (int j = 0; j < num_feature_; ++j) {
        const uint32_t bin = static_cast<uint32_t>(data_ptr[j]);
        const auto ti = (bin + offsets_[j]) << 1;
        grad[ti] += gradient;
        hess[ti] += hessian;
100
101
102
103
      }
    }
  }

Guolin Ke's avatar
Guolin Ke committed
104
105
106
107
  void ConstructHistogram(const data_size_t* data_indices, data_size_t start,
                          data_size_t end, const score_t* gradients,
                          const score_t* hessians, hist_t* out) const override {
    ConstructHistogramInner<true, true, false>(data_indices, start, end,
Nikita Titov's avatar
Nikita Titov committed
108
                                               gradients, hessians, out);
109
110
111
  }

  void ConstructHistogram(data_size_t start, data_size_t end,
Guolin Ke's avatar
Guolin Ke committed
112
113
114
115
                          const score_t* gradients, const score_t* hessians,
                          hist_t* out) const override {
    ConstructHistogramInner<false, false, false>(
        nullptr, start, end, gradients, hessians, out);
116
117
  }

Guolin Ke's avatar
Guolin Ke committed
118
119
120
121
122
123
  void ConstructHistogramOrdered(const data_size_t* data_indices,
                                 data_size_t start, data_size_t end,
                                 const score_t* gradients,
                                 const score_t* hessians,
                                 hist_t* out) const override {
    ConstructHistogramInner<true, true, true>(data_indices, start, end,
Nikita Titov's avatar
Nikita Titov committed
124
                                              gradients, hessians, out);
125
126
  }

127
128
129
  MultiValBin* CreateLike(data_size_t num_data, int num_bin, int num_feature, double,
    const std::vector<uint32_t>& offsets) const override {
    return new MultiValDenseBin<VAL_T>(num_data, num_bin, num_feature, offsets);
130
131
  }

132
  void ReSize(data_size_t num_data, int num_bin, int num_feature,
133
              double, const std::vector<uint32_t>& offsets) override {
134
    num_data_ = num_data;
135
136
    num_bin_ = num_bin;
    num_feature_ = num_feature;
137
    offsets_ = offsets;
138
139
140
141
142
143
    size_t new_size = static_cast<size_t>(num_feature_) * num_data_;
    if (data_.size() < new_size) {
      data_.resize(new_size, 0);
    }
  }

144
145
146
  template <bool SUBROW, bool SUBCOL>
  void CopyInner(const MultiValBin* full_bin, const data_size_t* used_indices,
                 data_size_t num_used_indices,
147
                 const std::vector<int>& used_feature_index) {
148
    const auto other_bin =
Guolin Ke's avatar
Guolin Ke committed
149
        reinterpret_cast<const MultiValDenseBin<VAL_T>*>(full_bin);
150
    if (SUBROW) {
Nikita Titov's avatar
Nikita Titov committed
151
      CHECK_EQ(num_data_, num_used_indices);
152
    }
Guolin Ke's avatar
Guolin Ke committed
153
154
    int n_block = 1;
    data_size_t block_size = num_data_;
155
156
    Threading::BlockInfo<data_size_t>(num_data_, 1024, &n_block,
                                      &block_size);
157
158
159
160
161
162
#pragma omp parallel for schedule(static, 1)
    for (int tid = 0; tid < n_block; ++tid) {
      data_size_t start = tid * block_size;
      data_size_t end = std::min(num_data_, start + block_size);
      for (data_size_t i = start; i < end; ++i) {
        const auto j_start = RowPtr(i);
163
164
        const auto other_j_start =
            SUBROW ? other_bin->RowPtr(used_indices[i]) : other_bin->RowPtr(i);
165
        for (int j = 0; j < num_feature_; ++j) {
166
167
168
          if (SUBCOL) {
            if (other_bin->data_[other_j_start + used_feature_index[j]] > 0) {
              data_[j_start + j] = static_cast<VAL_T>(
169
                  other_bin->data_[other_j_start + used_feature_index[j]]);
170
171
172
            } else {
              data_[j_start + j] = 0;
            }
173
          } else {
174
175
            data_[j_start + j] =
                static_cast<VAL_T>(other_bin->data_[other_j_start + j]);
176
177
          }
        }
178
179
180
181
      }
    }
  }

182
183
184
185

  void CopySubrow(const MultiValBin* full_bin, const data_size_t* used_indices,
                  data_size_t num_used_indices) override {
    CopyInner<true, false>(full_bin, used_indices, num_used_indices,
186
                           std::vector<int>());
187
188
189
  }

  void CopySubcol(const MultiValBin* full_bin,
Nikita Titov's avatar
Nikita Titov committed
190
191
192
                  const std::vector<int>& used_feature_index,
                  const std::vector<uint32_t>&,
                  const std::vector<uint32_t>&,
193
194
                  const std::vector<uint32_t>&) override {
    CopyInner<false, true>(full_bin, nullptr, num_data_, used_feature_index);
195
196
197
  }

  void CopySubrowAndSubcol(const MultiValBin* full_bin,
Nikita Titov's avatar
Nikita Titov committed
198
199
200
201
202
                           const data_size_t* used_indices,
                           data_size_t num_used_indices,
                           const std::vector<int>& used_feature_index,
                           const std::vector<uint32_t>&,
                           const std::vector<uint32_t>&,
203
                           const std::vector<uint32_t>&) override {
204
    CopyInner<true, true>(full_bin, used_indices, num_used_indices,
205
                          used_feature_index);
206
207
  }

208
209
  inline size_t RowPtr(data_size_t idx) const {
    return static_cast<size_t>(idx) * num_feature_;
210
211
212
213
  }

  MultiValDenseBin<VAL_T>* Clone() override;

214
215
216
217
218
219
220
221
  #ifdef USE_CUDA_EXP
  const void* GetRowWiseData(uint8_t* bit_type,
    size_t* total_size,
    bool* is_sparse,
    const void** out_data_ptr,
    uint8_t* data_ptr_bit_type) const override;
  #endif  // USE_CUDA_EXP

222
 private:
223
224
225
  data_size_t num_data_;
  int num_bin_;
  int num_feature_;
226
  std::vector<uint32_t> offsets_;
227
228
229
  std::vector<VAL_T, Common::AlignmentAllocator<VAL_T, 32>> data_;

  MultiValDenseBin<VAL_T>(const MultiValDenseBin<VAL_T>& other)
230
231
    : num_data_(other.num_data_), num_bin_(other.num_bin_), num_feature_(other.num_feature_),
      offsets_(other.offsets_), data_(other.data_) {
232
233
234
235
236
237
238
239
240
  }
};

template<typename VAL_T>
MultiValDenseBin<VAL_T>* MultiValDenseBin<VAL_T>::Clone() {
  return new MultiValDenseBin<VAL_T>(*this);
}

}  // namespace LightGBM
241

242
#endif   // LIGHTGBM_IO_MULTI_VAL_DENSE_BIN_HPP_