dense_bin.hpp 10.8 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
  inline uint32_t Get(data_size_t idx) override;
34
  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 {
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
74
75
76
77
78
  #define ACC_GH(hist, i, g, h) \
  const auto ti = static_cast<int>(i) << 1; \
  hist[ti] += g; \
  hist[ti + 1] += h; \

  template<bool use_indices, bool use_prefetch, bool use_hessians>
  void ConstructHistogramInner(const data_size_t* data_indices, data_size_t start, data_size_t end,
    const score_t* ordered_gradients, const score_t* ordered_hessians, hist_t* out) const {
79
    data_size_t i = start;
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

    if (use_prefetch) {
      const data_size_t pf_offset = 64 / sizeof(VAL_T);
      const data_size_t pf_end = end - pf_offset;
      for (; i < pf_end; ++i) {
        const auto idx = use_indices ? data_indices[i] : i;
        const auto pf_idx = use_indices ? data_indices[i + pf_offset] : i + pf_offset;
        PREFETCH_T0(data_.data() + pf_idx);
        const VAL_T bin = data_[idx];
        if (use_hessians) {
          ACC_GH(out, bin, ordered_gradients[i], ordered_hessians[i]);
        } else {
          ACC_GH(out, bin, ordered_gradients[i], 1.0f);
        }
      }
95
    }
96
97
98
99
100
101
102
103
    for (; i < end; ++i) {
      const auto idx = use_indices ? data_indices[i] : i;
      const VAL_T bin = data_[idx];
      if (use_hessians) {
        ACC_GH(out, bin, ordered_gradients[i], ordered_hessians[i]);
      } else {
        ACC_GH(out, bin, ordered_gradients[i], 1.0f);
      }
104
105
    }
  }
106
107
108
109
110
111
112
  #undef ACC_GH

  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,
    hist_t* out) const override {
    ConstructHistogramInner<true, true, true>(data_indices, start, end, ordered_gradients, ordered_hessians, out);
  }
113

114
115
  void ConstructHistogram(data_size_t start, data_size_t end,
    const score_t* ordered_gradients, const score_t* ordered_hessians,
116
117
    hist_t* out) const override {
    ConstructHistogramInner<false, false, true>(nullptr, start, end, ordered_gradients, ordered_hessians, out);
Guolin Ke's avatar
Guolin Ke committed
118
119
  }

120
121
  void ConstructHistogram(const data_size_t* data_indices, data_size_t start, data_size_t end,
    const score_t* ordered_gradients,
122
123
    hist_t* out) const override {
    ConstructHistogramInner<true, true, false>(data_indices, start, end, ordered_gradients, nullptr, out);
124
125
  }

126
127
  void ConstructHistogram(data_size_t start, data_size_t end,
    const score_t* ordered_gradients,
128
129
    hist_t* out) const override {
    ConstructHistogramInner<false, false, false>(nullptr, start, end, ordered_gradients, nullptr, out);
130
131
  }

Guolin Ke's avatar
Guolin Ke committed
132
  data_size_t Split(
Guolin Ke's avatar
Guolin Ke committed
133
    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
134
    uint32_t threshold, data_size_t* data_indices, data_size_t num_data,
135
    data_size_t* lte_indices, data_size_t* gt_indices) const override {
Guolin Ke's avatar
Guolin Ke committed
136
137
    if (num_data <= 0) { return 0; }
    VAL_T th = static_cast<VAL_T>(threshold + min_bin);
138
139
    const VAL_T minb = static_cast<VAL_T>(min_bin);
    const VAL_T maxb = static_cast<VAL_T>(max_bin);
140
    VAL_T t_zero_bin = static_cast<VAL_T>(min_bin + default_bin);
Guolin Ke's avatar
Guolin Ke committed
141
142
    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
143
      th -= 1;
144
      t_zero_bin -= 1;
Guolin Ke's avatar
Guolin Ke committed
145
      t_most_freq_bin -= 1;
Guolin Ke's avatar
Guolin Ke committed
146
    }
Guolin Ke's avatar
Guolin Ke committed
147
148
    data_size_t lte_count = 0;
    data_size_t gt_count = 0;
Guolin Ke's avatar
Guolin Ke committed
149
150
    data_size_t* default_indices = gt_indices;
    data_size_t* default_count = &gt_count;
Guolin Ke's avatar
Guolin Ke committed
151
152
153
154
155
156
    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;
    }
157
158
159
160
161
    if (missing_type == MissingType::NaN) {
      if (default_left) {
        missing_default_indices = lte_indices;
        missing_default_count = &lte_count;
      }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
      if (t_most_freq_bin == maxb) {
        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 (t_most_freq_bin == bin || bin < minb || bin > maxb) {
            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 == maxb) {
            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;
          }
187
188
189
        }
      }
    } else {
Guolin Ke's avatar
Guolin Ke committed
190
191
192
193
      if ((default_left && missing_type == MissingType::Zero)
          || (default_bin <= threshold && missing_type != MissingType::Zero)) {
        missing_default_indices = lte_indices;
        missing_default_count = &lte_count;
194
      }
Guolin Ke's avatar
Guolin Ke committed
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
      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];
211
          if (bin == t_zero_bin) {
Guolin Ke's avatar
Guolin Ke committed
212
213
214
215
216
217
218
219
            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;
          }
220
        }
Guolin Ke's avatar
Guolin Ke committed
221
222
223
224
      }
    }
    return lte_count;
  }
Guolin Ke's avatar
Guolin Ke committed
225

Guolin Ke's avatar
Guolin Ke committed
226
  data_size_t SplitCategorical(
Guolin Ke's avatar
Guolin Ke committed
227
    uint32_t min_bin, uint32_t max_bin, uint32_t most_freq_bin,
228
    const uint32_t* threshold, int num_threahold, data_size_t* data_indices, data_size_t num_data,
229
230
231
232
233
234
    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
235
    if (Common::FindInBitset(threshold, num_threahold, most_freq_bin)) {
236
237
238
239
240
241
242
243
      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;
244
      } else if (Common::FindInBitset(threshold, num_threahold, bin - min_bin)) {
245
246
247
248
249
250
251
252
        lte_indices[lte_count++] = idx;
      } else {
        gt_indices[gt_count++] = idx;
      }
    }
    return lte_count;
  }

Guolin Ke's avatar
Guolin Ke committed
253
254
255
256
257
258
  data_size_t num_data() const override { return num_data_; }

  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
259
    if (!local_used_indices.empty()) {
Guolin Ke's avatar
Guolin Ke committed
260
261
262
263
264
265
266
267
268
269
      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];
      }
    }
  }

270
  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
271
    auto other_bin = dynamic_cast<const DenseBin<VAL_T>*>(full_bin);
272
273
274
275
276
    for (int i = 0; i < num_used_indices; ++i) {
      data_[i] = other_bin->data_[used_indices[i]];
    }
  }

277
278
  void SaveBinaryToFile(const VirtualFileWriter* writer) const override {
    writer->Write(data_.data(), sizeof(VAL_T) * num_data_);
Guolin Ke's avatar
Guolin Ke committed
279
280
281
  }

  size_t SizesInByte() const override {
282
    return sizeof(VAL_T) * num_data_;
Guolin Ke's avatar
Guolin Ke committed
283
284
  }

285
286
  DenseBin<VAL_T>* Clone() override;

287
 private:
Guolin Ke's avatar
Guolin Ke committed
288
  data_size_t num_data_;
289
  std::vector<VAL_T, Common::AlignmentAllocator<VAL_T, kAlignedSize>> data_;
290
291

  DenseBin<VAL_T>(const DenseBin<VAL_T>& other)
292
293
    : num_data_(other.num_data_), data_(other.data_) {
  }
Guolin Ke's avatar
Guolin Ke committed
294
295
};

296
template<typename VAL_T>
297
DenseBin<VAL_T>* DenseBin<VAL_T>::Clone() {
298
299
300
  return new DenseBin<VAL_T>(*this);
}

Guolin Ke's avatar
Guolin Ke committed
301
template <typename VAL_T>
Guolin Ke's avatar
Guolin Ke committed
302
303
304
uint32_t DenseBinIterator<VAL_T>::Get(data_size_t idx) {
  auto ret = bin_data_->data_[idx];
  if (ret >= min_bin_ && ret <= max_bin_) {
305
    return ret - min_bin_ + offset_;
Guolin Ke's avatar
Guolin Ke committed
306
  } else {
Guolin Ke's avatar
Guolin Ke committed
307
    return most_freq_bin_;
Guolin Ke's avatar
Guolin Ke committed
308
309
  }
}
310

311
312
313
314
315
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
316
template <typename VAL_T>
Guolin Ke's avatar
Guolin Ke committed
317
318
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
319
}
Guolin Ke's avatar
Guolin Ke committed
320

Guolin Ke's avatar
Guolin Ke committed
321
}  // namespace LightGBM
Guolin Ke's avatar
Guolin Ke committed
322
#endif   // LightGBM_IO_DENSE_BIN_HPP_