dense_bin.hpp 10.9 KB
Newer Older
1
2
3
4
/*!
 * Copyright (c) 2016 Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE file in the project root for license information.
 */
Guolin Ke's avatar
Guolin Ke committed
5
6
7
8
9
10
#ifndef LIGHTGBM_IO_DENSE_BIN_HPP_
#define LIGHTGBM_IO_DENSE_BIN_HPP_

#include <LightGBM/bin.h>

#include <cstdint>
11
12
#include <cstring>
#include <vector>
Guolin Ke's avatar
Guolin Ke committed
13
14
15

namespace LightGBM {

Guolin Ke's avatar
Guolin Ke committed
16
17
18
19
template <typename VAL_T>
class DenseBin;

template <typename VAL_T>
20
class DenseBinIterator: public BinIterator {
Nikita Titov's avatar
Nikita Titov committed
21
 public:
Guolin Ke's avatar
Guolin Ke committed
22
  explicit DenseBinIterator(const DenseBin<VAL_T>* bin_data, uint32_t min_bin, uint32_t max_bin, uint32_t most_freq_bin)
Guolin Ke's avatar
Guolin Ke committed
23
24
    : bin_data_(bin_data), min_bin_(static_cast<VAL_T>(min_bin)),
    max_bin_(static_cast<VAL_T>(max_bin)),
Guolin Ke's avatar
Guolin Ke committed
25
26
    most_freq_bin_(static_cast<VAL_T>(most_freq_bin)) {
    if (most_freq_bin_ == 0) {
27
      offset_ = 1;
Guolin Ke's avatar
Guolin Ke committed
28
    } else {
29
      offset_ = 0;
Guolin Ke's avatar
Guolin Ke committed
30
31
    }
  }
32
  inline uint32_t RawGet(data_size_t idx) override;
Guolin Ke's avatar
Guolin Ke committed
33
34
  inline uint32_t Get(data_size_t idx) override;
  inline void Reset(data_size_t) override { }
Nikita Titov's avatar
Nikita Titov committed
35
36

 private:
Guolin Ke's avatar
Guolin Ke committed
37
38
39
  const DenseBin<VAL_T>* bin_data_;
  VAL_T min_bin_;
  VAL_T max_bin_;
Guolin Ke's avatar
Guolin Ke committed
40
  VAL_T most_freq_bin_;
41
  uint8_t offset_;
Guolin Ke's avatar
Guolin Ke committed
42
};
Guolin Ke's avatar
Guolin Ke committed
43
/*!
Hui Xue's avatar
Hui Xue committed
44
* \brief Used to store bins for dense feature
Guolin Ke's avatar
Guolin Ke committed
45
46
47
* Use template to reduce memory cost
*/
template <typename VAL_T>
48
class DenseBin: public Bin {
Nikita Titov's avatar
Nikita Titov committed
49
 public:
Guolin Ke's avatar
Guolin Ke committed
50
  friend DenseBinIterator<VAL_T>;
Guolin Ke's avatar
Guolin Ke committed
51
  explicit DenseBin(data_size_t num_data)
Guolin Ke's avatar
Guolin Ke committed
52
    : num_data_(num_data), data_(num_data_, static_cast<VAL_T>(0)) {
Guolin Ke's avatar
Guolin Ke committed
53
54
55
56
57
58
59
60
61
  }

  ~DenseBin() {
  }

  void Push(int, data_size_t idx, uint32_t value) override {
    data_[idx] = static_cast<VAL_T>(value);
  }

Guolin Ke's avatar
Guolin Ke committed
62
63
64
65
66
67
68
  void ReSize(data_size_t num_data) override {
    if (num_data_ != num_data) {
      num_data_ = num_data;
      data_.resize(num_data_);
    }
  }

Guolin Ke's avatar
Guolin Ke committed
69
  BinIterator* GetIterator(uint32_t min_bin, uint32_t max_bin, uint32_t most_freq_bin) const override;
Guolin Ke's avatar
Guolin Ke committed
70

71
72
73
  void ConstructHistogram(const data_size_t* data_indices, data_size_t start, data_size_t end,
    const score_t* ordered_gradients, const score_t* ordered_hessians,
    HistogramBinEntry* out) const override {
74
75
76
77
78
79
80
81
82
83
84
    const data_size_t pf_offset = 64 / sizeof(VAL_T);
    const data_size_t pf_end = end - pf_offset - kCacheLineSize / sizeof(VAL_T);
    data_size_t i = start;
    for (; i < pf_end; i++) {
      PREFETCH_T0(data_.data() + data_indices[i + pf_offset]);
      const VAL_T bin = data_[data_indices[i]];
      out[bin].sum_gradients += ordered_gradients[i];
      out[bin].sum_hessians += ordered_hessians[i];
      ++out[bin].cnt;
    }
    for (; i < end; i++) {
85
86
87
88
89
90
91
      const VAL_T bin = data_[data_indices[i]];
      out[bin].sum_gradients += ordered_gradients[i];
      out[bin].sum_hessians += ordered_hessians[i];
      ++out[bin].cnt;
    }
  }

92
93
94
  void ConstructHistogram(data_size_t start, data_size_t end,
    const score_t* ordered_gradients, const score_t* ordered_hessians,
    HistogramBinEntry* out) const override {
95
96
97
98
99
100
101
102
103
104
105
    const data_size_t pf_offset = 64 / sizeof(VAL_T);
    const data_size_t pf_end = end - pf_offset - kCacheLineSize / sizeof(VAL_T);
    data_size_t i = start;
    for (; i < pf_end; i++) {
      PREFETCH_T0(data_.data() + i + pf_offset);
      const VAL_T bin = data_[i];
      out[bin].sum_gradients += ordered_gradients[i];
      out[bin].sum_hessians += ordered_hessians[i];
      ++out[bin].cnt;
    }
    for (; i < end; i++) {
106
107
108
109
      const VAL_T bin = data_[i];
      out[bin].sum_gradients += ordered_gradients[i];
      out[bin].sum_hessians += ordered_hessians[i];
      ++out[bin].cnt;
Guolin Ke's avatar
Guolin Ke committed
110
    }
Guolin Ke's avatar
Guolin Ke committed
111
112
  }

113
114
115
  void ConstructHistogram(const data_size_t* data_indices, data_size_t start, data_size_t end,
    const score_t* ordered_gradients,
    HistogramBinEntry* out) const override {
116
117
118
119
120
121
122
123
124
125
    const data_size_t pf_offset = 64 / sizeof(VAL_T);
    const data_size_t pf_end = end - pf_offset - kCacheLineSize / sizeof(VAL_T);
    data_size_t i = start;
    for (; i < pf_end; i++) {
      PREFETCH_T0(data_.data() + data_indices[i + pf_offset]);
      const VAL_T bin = data_[data_indices[i]];
      out[bin].sum_gradients += ordered_gradients[i];
      ++out[bin].cnt;
    }
    for (; i < end; i++) {
126
127
128
129
130
131
      const VAL_T bin = data_[data_indices[i]];
      out[bin].sum_gradients += ordered_gradients[i];
      ++out[bin].cnt;
    }
  }

132
133
134
  void ConstructHistogram(data_size_t start, data_size_t end,
    const score_t* ordered_gradients,
    HistogramBinEntry* out) const override {
135
136
137
138
139
140
141
142
143
144
    const data_size_t pf_offset = 64 / sizeof(VAL_T);
    const data_size_t pf_end = end - pf_offset - kCacheLineSize / sizeof(VAL_T);
    data_size_t i = start;
    for (; i < pf_end; i++) {
      PREFETCH_T0(data_.data() + i + pf_offset);
      const VAL_T bin = data_[i];
      out[bin].sum_gradients += ordered_gradients[i];
      ++out[bin].cnt;
    }
    for (; i < end; i++) {
145
146
147
      const VAL_T bin = data_[i];
      out[bin].sum_gradients += ordered_gradients[i];
      ++out[bin].cnt;
148
149
150
    }
  }

Guolin Ke's avatar
Guolin Ke committed
151
  data_size_t Split(
Guolin Ke's avatar
Guolin Ke committed
152
    uint32_t min_bin, uint32_t max_bin, uint32_t default_bin, uint32_t most_freq_bin, MissingType missing_type, bool default_left,
Guolin Ke's avatar
Guolin Ke committed
153
    uint32_t threshold, data_size_t* data_indices, data_size_t num_data,
154
    data_size_t* lte_indices, data_size_t* gt_indices) const override {
Guolin Ke's avatar
Guolin Ke committed
155
156
    if (num_data <= 0) { return 0; }
    VAL_T th = static_cast<VAL_T>(threshold + min_bin);
157
158
    const VAL_T minb = static_cast<VAL_T>(min_bin);
    const VAL_T maxb = static_cast<VAL_T>(max_bin);
Guolin Ke's avatar
Guolin Ke committed
159
    VAL_T t_default_bin = static_cast<VAL_T>(min_bin + default_bin);
Guolin Ke's avatar
Guolin Ke committed
160
161
    VAL_T t_most_freq_bin = static_cast<VAL_T>(min_bin + most_freq_bin);
    if (most_freq_bin == 0) {
Guolin Ke's avatar
Guolin Ke committed
162
      th -= 1;
Guolin Ke's avatar
Guolin Ke committed
163
      t_default_bin -= 1;
Guolin Ke's avatar
Guolin Ke committed
164
      t_most_freq_bin -= 1;
Guolin Ke's avatar
Guolin Ke committed
165
    }
Guolin Ke's avatar
Guolin Ke committed
166
167
    data_size_t lte_count = 0;
    data_size_t gt_count = 0;
Guolin Ke's avatar
Guolin Ke committed
168
169
    data_size_t* default_indices = gt_indices;
    data_size_t* default_count = &gt_count;
Guolin Ke's avatar
Guolin Ke committed
170
171
172
173
174
175
    data_size_t* missing_default_indices = gt_indices;
    data_size_t* missing_default_count = &gt_count;
    if (most_freq_bin <= threshold) {
      default_indices = lte_indices;
      default_count = &lte_count;
    }
176
177
178
179
180
181
182
183
    if (missing_type == MissingType::NaN) {
      if (default_left) {
        missing_default_indices = lte_indices;
        missing_default_count = &lte_count;
      }
      for (data_size_t i = 0; i < num_data; ++i) {
        const data_size_t idx = data_indices[i];
        const VAL_T bin = data_[idx];
Guolin Ke's avatar
Guolin Ke committed
184
        if (bin == maxb) {
185
          missing_default_indices[(*missing_default_count)++] = idx;
Guolin Ke's avatar
Guolin Ke committed
186
187
        } else if (bin < minb || bin > maxb || t_most_freq_bin == bin) {
          default_indices[(*default_count)++] = idx;
188
189
190
191
        } else if (bin > th) {
          gt_indices[gt_count++] = idx;
        } else {
          lte_indices[lte_count++] = idx;
192
193
194
        }
      }
    } else {
Guolin Ke's avatar
Guolin Ke committed
195
196
197
198
      if ((default_left && missing_type == MissingType::Zero)
          || (default_bin <= threshold && missing_type != MissingType::Zero)) {
        missing_default_indices = lte_indices;
        missing_default_count = &lte_count;
199
      }
Guolin Ke's avatar
Guolin Ke committed
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
      if (default_bin == most_freq_bin) {
        for (data_size_t i = 0; i < num_data; ++i) {
          const data_size_t idx = data_indices[i];
          const VAL_T bin = data_[idx];
          if (bin < minb || bin > maxb || t_most_freq_bin == bin) {
            missing_default_indices[(*missing_default_count)++] = idx;
          } else if (bin > th) {
            gt_indices[gt_count++] = idx;
          } else {
            lte_indices[lte_count++] = idx;
          }
        }
      } else {
        for (data_size_t i = 0; i < num_data; ++i) {
          const data_size_t idx = data_indices[i];
          const VAL_T bin = data_[idx];
          if (bin == t_default_bin) {
            missing_default_indices[(*missing_default_count)++] = idx;
          } else if (bin < minb || bin > maxb || t_most_freq_bin == bin) {
            default_indices[(*default_count)++] = idx;
          } else if (bin > th) {
            gt_indices[gt_count++] = idx;
          } else {
            lte_indices[lte_count++] = idx;
          }
225
        }
Guolin Ke's avatar
Guolin Ke committed
226
227
228
229
      }
    }
    return lte_count;
  }
Guolin Ke's avatar
Guolin Ke committed
230

Guolin Ke's avatar
Guolin Ke committed
231
  data_size_t SplitCategorical(
Guolin Ke's avatar
Guolin Ke committed
232
    uint32_t min_bin, uint32_t max_bin, uint32_t most_freq_bin,
233
    const uint32_t* threshold, int num_threahold, data_size_t* data_indices, data_size_t num_data,
234
235
236
237
238
239
    data_size_t* lte_indices, data_size_t* gt_indices) const override {
    if (num_data <= 0) { return 0; }
    data_size_t lte_count = 0;
    data_size_t gt_count = 0;
    data_size_t* default_indices = gt_indices;
    data_size_t* default_count = &gt_count;
Guolin Ke's avatar
Guolin Ke committed
240
    if (Common::FindInBitset(threshold, num_threahold, most_freq_bin)) {
241
242
243
244
245
246
247
248
      default_indices = lte_indices;
      default_count = &lte_count;
    }
    for (data_size_t i = 0; i < num_data; ++i) {
      const data_size_t idx = data_indices[i];
      const uint32_t bin = data_[idx];
      if (bin < min_bin || bin > max_bin) {
        default_indices[(*default_count)++] = idx;
249
      } else if (Common::FindInBitset(threshold, num_threahold, bin - min_bin)) {
250
251
252
253
254
255
256
257
        lte_indices[lte_count++] = idx;
      } else {
        gt_indices[gt_count++] = idx;
      }
    }
    return lte_count;
  }

Guolin Ke's avatar
Guolin Ke committed
258
259
260
261
262
263
264
265
266
  data_size_t num_data() const override { return num_data_; }

  /*! \brief not ordered bin for dense feature */
  OrderedBin* CreateOrderedBin() const override { return nullptr; }

  void FinishLoad() override {}

  void LoadFromMemory(const void* memory, const std::vector<data_size_t>& local_used_indices) override {
    const VAL_T* mem_data = reinterpret_cast<const VAL_T*>(memory);
Guolin Ke's avatar
Guolin Ke committed
267
    if (!local_used_indices.empty()) {
Guolin Ke's avatar
Guolin Ke committed
268
269
270
271
272
273
274
275
276
277
      for (int i = 0; i < num_data_; ++i) {
        data_[i] = mem_data[local_used_indices[i]];
      }
    } else {
      for (int i = 0; i < num_data_; ++i) {
        data_[i] = mem_data[i];
      }
    }
  }

278
  void CopySubset(const Bin* full_bin, const data_size_t* used_indices, data_size_t num_used_indices) override {
Guolin Ke's avatar
Guolin Ke committed
279
    auto other_bin = dynamic_cast<const DenseBin<VAL_T>*>(full_bin);
280
281
282
283
284
    for (int i = 0; i < num_used_indices; ++i) {
      data_[i] = other_bin->data_[used_indices[i]];
    }
  }

285
286
  void SaveBinaryToFile(const VirtualFileWriter* writer) const override {
    writer->Write(data_.data(), sizeof(VAL_T) * num_data_);
Guolin Ke's avatar
Guolin Ke committed
287
288
289
290
291
292
  }

  size_t SizesInByte() const override {
    return sizeof(VAL_T) * num_data_;
  }

293
294
295
  DenseBin<VAL_T>* Clone() override;

 private:
Guolin Ke's avatar
Guolin Ke committed
296
  data_size_t num_data_;
Guolin Ke's avatar
Guolin Ke committed
297
  std::vector<VAL_T> data_;
298
299
300

  DenseBin<VAL_T>(const DenseBin<VAL_T>& other)
    : num_data_(other.num_data_), data_(other.data_){}
Guolin Ke's avatar
Guolin Ke committed
301
302
};

303
template<typename VAL_T>
304
DenseBin<VAL_T>* DenseBin<VAL_T>::Clone() {
305
306
307
  return new DenseBin<VAL_T>(*this);
}

Guolin Ke's avatar
Guolin Ke committed
308
template <typename VAL_T>
Guolin Ke's avatar
Guolin Ke committed
309
310
311
uint32_t DenseBinIterator<VAL_T>::Get(data_size_t idx) {
  auto ret = bin_data_->data_[idx];
  if (ret >= min_bin_ && ret <= max_bin_) {
312
    return ret - min_bin_ + offset_;
Guolin Ke's avatar
Guolin Ke committed
313
  } else {
Guolin Ke's avatar
Guolin Ke committed
314
    return most_freq_bin_;
Guolin Ke's avatar
Guolin Ke committed
315
316
  }
}
317

318
319
320
321
322
template <typename VAL_T>
inline uint32_t DenseBinIterator<VAL_T>::RawGet(data_size_t idx) {
  return bin_data_->data_[idx];
}

Guolin Ke's avatar
Guolin Ke committed
323
template <typename VAL_T>
Guolin Ke's avatar
Guolin Ke committed
324
325
BinIterator* DenseBin<VAL_T>::GetIterator(uint32_t min_bin, uint32_t max_bin, uint32_t most_freq_bin) const {
  return new DenseBinIterator<VAL_T>(this, min_bin, max_bin, most_freq_bin);
Guolin Ke's avatar
Guolin Ke committed
326
}
Guolin Ke's avatar
Guolin Ke committed
327

Guolin Ke's avatar
Guolin Ke committed
328
}  // namespace LightGBM
Guolin Ke's avatar
Guolin Ke committed
329
#endif   // LightGBM_IO_DENSE_BIN_HPP_