Automatic Differentiation
 
Loading...
Searching...
No Matches
categorical_logit_glm_lpmf.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_OPENCL_KERNELS_CATEGORICAL_LOGIT_GLM_LPMF_HPP
2#define STAN_MATH_OPENCL_KERNELS_CATEGORICAL_LOGIT_GLM_LPMF_HPP
3#ifdef STAN_OPENCL
4
6#include <string>
7
8namespace stan {
9namespace math {
10namespace opencl_kernels {
11
12// \cond
13static constexpr const char* categorical_logit_glm_kernel_code = STRINGIFY(
14 // \endcond
42 __kernel void categorical_logit_glm(
43 __global double* logp_global, __global double* exp_lin_global,
44 __global double* inv_sum_exp_lin_global,
45 __global double* neg_softmax_lin_global,
46 __global double* alpha_derivative, const __global int* y_global,
47 const __global double* x_beta_global,
48 const __global double* alpha_global, const int N_instances,
49 const int N_attributes, const int N_classes, const int is_y_vector,
50 const int need_alpha_derivative,
51 const int need_neg_softmax_lin_global) {
52 const int gid = get_global_id(0);
53 const int lid = get_local_id(0);
54 const int lsize = get_local_size(0);
55 const int wg_id = get_group_id(0);
56 const int ngroups = get_num_groups(0);
57
58 __local double local_storage[LOCAL_SIZE_];
59
60 double logp = 0;
61 double inv_sum_exp_lin;
62 int class_idx = -1;
63 // Most calculations only happen for relevant data within next if.
64 // Exceptions are reductions between threads that need barriers.
65 if (gid < N_instances) {
66 double lin_max = -INFINITY;
67 for (int i = 0; i < N_classes; i++) {
68 double lin = x_beta_global[i * N_instances + gid] + alpha_global[i];
69 if (lin > lin_max) {
70 lin_max = lin;
71 }
72 }
73 double sum_exp_lin = 0;
74 for (int i = 0; i < N_classes; i++) {
75 double lin = x_beta_global[i * N_instances + gid] + alpha_global[i];
76 double exp_lin = exp(lin - lin_max);
77 sum_exp_lin += exp_lin;
78 exp_lin_global[i * N_instances + gid] = exp_lin;
79 }
80 inv_sum_exp_lin = 1 / sum_exp_lin;
81 inv_sum_exp_lin_global[gid] = inv_sum_exp_lin;
82
83 class_idx = y_global[gid * is_y_vector] - 1;
84 if (class_idx < 0 || class_idx >= N_classes) {
85 logp = NAN;
86 } else {
87 logp = log(inv_sum_exp_lin) - lin_max
88 + x_beta_global[class_idx * N_instances + gid]
89 + alpha_global[class_idx];
90 }
91 }
92 barrier(CLK_GLOBAL_MEM_FENCE);
93 double neg_softmax_lin_sum = 0;
94 if (need_alpha_derivative || need_neg_softmax_lin_global) {
95 for (int i = 0; i < N_classes; i++) {
96 double neg_softmax_lin = 0;
97 if (gid < N_instances) {
98 int idx = i * N_instances + gid;
99 neg_softmax_lin = -exp_lin_global[idx] * inv_sum_exp_lin;
100 if (need_neg_softmax_lin_global) {
101 neg_softmax_lin_global[idx] = neg_softmax_lin;
102 }
103 }
104 if (need_alpha_derivative) {
105 local_storage[lid] = neg_softmax_lin + (class_idx == i);
106 barrier(CLK_LOCAL_MEM_FENCE);
107 for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
108 step /= REDUCTION_STEP_SIZE) {
109 if (lid < step) {
110 for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
111 local_storage[lid] += local_storage[lid + step * i];
112 }
113 }
114 barrier(CLK_LOCAL_MEM_FENCE);
115 }
116 if (lid == 0) {
117 alpha_derivative[i + wg_id * N_classes] = local_storage[0];
118 }
119 barrier(CLK_LOCAL_MEM_FENCE);
120 }
121 }
122 }
123 // Sum logp, calculated by different threads.
124 // Since we can't sum between different work groups, we emit one number
125 // per work group. These must be summed on CPU for final result.
126 local_storage[lid] = logp;
127 barrier(CLK_LOCAL_MEM_FENCE);
128 for (int step = lsize / REDUCTION_STEP_SIZE; step > 0;
129 step /= REDUCTION_STEP_SIZE) {
130 if (lid < step) {
131 for (int i = 1; i < REDUCTION_STEP_SIZE; i++) {
132 local_storage[lid] += local_storage[lid + step * i];
133 }
134 }
135 barrier(CLK_LOCAL_MEM_FENCE);
136 }
137 if (lid == 0) {
138 logp_global[wg_id] = local_storage[0];
139 }
140 }
141 // \cond
142);
143// \endcond
144
149const kernel_cl<out_buffer, out_buffer, out_buffer, out_buffer, out_buffer,
150 in_buffer, in_buffer, in_buffer, int, int, int, int, int, int>
151 categorical_logit_glm("categorical_logit_glm",
152 {categorical_logit_glm_kernel_code},
153 {{"REDUCTION_STEP_SIZE", 4}, {"LOCAL_SIZE_", 64}});
154
155// \cond
156static const std::string categorical_logit_glm_beta_derivative_kernel_code
157 = STRINGIFY(
158 // \endcond
174 __global double* beta_derivative, __global double* temp,
175 const __global int* y, const __global double* x,
176 const int N_instances, const int N_attributes, const int N_classes,
177 const int is_y_vector) {
178 const int gid = get_global_id(0);
179 const int lid = get_local_id(0);
180 const int lsize = get_local_size(0);
181 const int wg_id = get_group_id(0);
182
183 for (int i = 0; i < N_classes; i++) {
184 temp[gid * N_classes + i] = 0;
185 }
186 for (int i = lid; i < N_instances; i += lsize) {
187 int pos = y[i * is_y_vector] - 1;
188 temp[gid * N_classes + pos] += x[wg_id * N_instances + i];
189 }
190 barrier(CLK_GLOBAL_MEM_FENCE);
191 for (int i = lid; i < N_classes; i += lsize) {
192 double res = 0;
193 for (int j = 0; j < lsize; j++) {
194 res += temp[(wg_id * lsize + j) * N_classes + i];
195 }
196 beta_derivative[i * N_attributes + wg_id] += res;
197 }
198 }
199 // \cond
200 ); // NOLINT
201// \endcond
202
207const kernel_cl<in_out_buffer, in_out_buffer, in_buffer, in_buffer, int, int,
208 int, int>
210 "categorical_logit_glm_beta_derivative",
211 {categorical_logit_glm_beta_derivative_kernel_code});
212
213} // namespace opencl_kernels
214
215} // namespace math
216} // namespace stan
217#endif
218#endif
const kernel_cl< out_buffer, out_buffer, out_buffer, out_buffer, out_buffer, in_buffer, in_buffer, in_buffer, int, int, int, int, int, int > categorical_logit_glm("categorical_logit_glm", {categorical_logit_glm_kernel_code}, {{"REDUCTION_STEP_SIZE", 4}, {"LOCAL_SIZE_", 64}})
See the docs for categorical_logit_glm() .
const kernel_cl< in_out_buffer, in_out_buffer, in_buffer, in_buffer, int, int, int, int > categorical_logit_glm_beta_derivative("categorical_logit_glm_beta_derivative", {categorical_logit_glm_beta_derivative_kernel_code})
See the docs for categorical_logit_glm_beta_derivative() .
T step(const T &y)
The step, or Heaviside, function.
Definition step.hpp:31
fvar< T > log(const fvar< T > &x)
Definition log.hpp:18
fvar< T > exp(const fvar< T > &x)
Definition exp.hpp:15
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
#define STRINGIFY(...)
Definition stringify.hpp:9