workingset.h
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2019-2024, NVIDIA CORPORATION.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #pragma once
7 
8 #include <cuml/common/logger.hpp>
10 
11 #include <raft/core/handle.hpp>
12 
13 #include <rmm/device_scalar.hpp>
14 #include <rmm/device_uvector.hpp>
15 
16 #include <algorithm>
17 #include <cstddef>
18 #include <limits>
19 
20 namespace ML {
21 namespace SVM {
22 
33 template <typename math_t>
34 class WorkingSet {
35  public:
37  bool FIFO_strategy = true;
38 
48  WorkingSet(const raft::handle_t& handle,
49  cudaStream_t stream,
50  int n_rows = 0,
51  int n_ws = 0,
52  SvmType svmType = C_SVC)
53  : handle(handle),
54  stream(stream),
55  svmType(svmType),
56  n_rows(n_rows),
57  available(0, stream),
58  available_sorted(0, stream),
59  cub_storage(0, stream),
60  f_idx(0, stream),
61  f_idx_sorted(0, stream),
62  f_sorted(0, stream),
63  idx_tmp(0, stream),
64  idx(0, stream),
65  ws_idx_sorted(0, stream),
66  ws_idx_selected(0, stream),
67  ws_idx_save(0, stream),
68  ws_priority(0, stream),
69  ws_priority_sorted(0, stream),
70  d_num_selected(stream)
71  {
72  n_train = (svmType == EPSILON_SVR) ? n_rows * 2 : n_rows;
73  SetSize(n_train, n_ws);
74  }
75 
77 
84  void SetSize(int n_train, int n_ws = 0)
85  {
86  if (n_ws == 0 || n_ws > n_train) { n_ws = n_train; }
87  n_ws = std::min(1024, n_ws);
88  this->n_ws = n_ws;
89  CUML_LOG_DEBUG("Creating working set with %d elements", n_ws);
90  AllocateBuffers();
91  }
92 
94  int GetSize() { return n_ws; }
95 
101  int* GetIndices() { return idx.data(); }
102 
128  math_t* f, math_t* alpha, math_t* y, const math_t* C, int n_already_selected = 0);
129 
148  void Select(math_t* f, math_t* alpha, math_t* y, const math_t* C)
149  {
150  if (n_ws >= n_train) {
151  // All elements are selected, we have initialized idx to cover this case
152  return;
153  }
154  int nc = n_ws / 4;
155  int n_selected = 0;
156  if (firstcall) {
157  if (nc >= 1) {
158  firstcall = false;
159  } else {
160  // This can only happen for n_ws < 4.
161  // We keep the calculation always in firstcall mode (only SimpleSelect
162  // is used, no advanced strategies because we do not have enough elements)
163  //
164  // Nothing to do, firstcall is already true
165  }
166  } else {
167  // keep 1/2 of the old working set
168  if (FIFO_strategy) {
169  // FIFO selection following ThunderSVM
170  raft::copy(idx.data(), ws_idx_save.data() + 2 * nc, 2 * nc, stream);
171  n_selected = nc * 2;
172  } else {
173  // priority based selection preferring to keep newer elements in ws
174  n_selected = PrioritySelect(alpha, C, nc);
175  }
176  }
177  SimpleSelect(f, alpha, y, C, n_selected);
178  raft::copy(ws_idx_save.data(), idx.data(), n_ws, stream);
179  }
180 
199  int PrioritySelect(math_t* alpha, const math_t* C, int nc);
200 
201  private:
202  const raft::handle_t& handle;
203  cudaStream_t stream;
204 
205  bool firstcall = true;
206  int n_train = 0;
207  int n_rows = 0;
208  int n_ws = 0;
209 
210  SvmType svmType;
211 
212  int TPB = 256;
213 
214  // Buffers for the domain size [n_train]
215  rmm::device_uvector<int> f_idx;
216  rmm::device_uvector<int> f_idx_sorted;
218  rmm::device_uvector<int> idx_tmp;
219  rmm::device_uvector<math_t> f_sorted;
221  rmm::device_uvector<bool> available;
222  rmm::device_uvector<bool> available_sorted;
223 
224  // working set buffers size [n_ws]
225  rmm::device_uvector<int> idx;
226  rmm::device_uvector<int> ws_idx_sorted;
227  rmm::device_uvector<int> ws_idx_selected;
228  rmm::device_uvector<int> ws_idx_save;
229 
230  rmm::device_uvector<int> ws_priority;
231  rmm::device_uvector<int> ws_priority_sorted;
232 
233  rmm::device_scalar<int> d_num_selected;
234  std::size_t cub_bytes = 0;
235  rmm::device_uvector<char> cub_storage;
236 
237  void AllocateBuffers();
238 
253  int GatherAvailable(int n_already_selected, int n_needed, bool copy_front);
254 
255  void Initialize();
256 
267  template <typename select_op>
268  int SelectPrevWs(int n_needed, int n_already_selected, select_op op);
269 };
270 
271 }; // end namespace SVM
272 }; // end namespace ML
Definition: workingset.h:34
int GetSize()
Definition: workingset.h:94
void Select(math_t *f, math_t *alpha, math_t *y, const math_t *C)
Select working set indices.
Definition: workingset.h:148
WorkingSet(const raft::handle_t &handle, cudaStream_t stream, int n_rows=0, int n_ws=0, SvmType svmType=C_SVC)
Manage a working set.
Definition: workingset.h:48
bool FIFO_strategy
Workspace selection strategy, note that only FIFO is tested so far
Definition: workingset.h:37
void SetSize(int n_train, int n_ws=0)
Set the size of the working set and allocate buffers accordingly.
Definition: workingset.h:84
~WorkingSet()
Definition: workingset.h:76
void SimpleSelect(math_t *f, math_t *alpha, math_t *y, const math_t *C, int n_already_selected=0)
Select new elements for a working set.
int * GetIndices()
Return a device pointer to the the working set indices.
Definition: workingset.h:101
int PrioritySelect(math_t *alpha, const math_t *C, int nc)
Select elements from the previous working set based on their priority.
SvmType
Definition: svm_parameter.h:12
@ EPSILON_SVR
Definition: svm_parameter.h:12
@ C_SVC
Definition: svm_parameter.h:12
Definition: dbscan.hpp:18
const_agnostic_same_t< T, U > copy(buffer< T > &dst, buffer< U > const &src, typename buffer< T >::index_type dst_offset, typename buffer< U >::index_type src_offset, typename buffer< T >::index_type size, cuda_stream stream)
Definition: buffer.hpp:316