CharlesCNorton commited on
Commit
335d7ff
·
1 Parent(s): 1e410e6

spec-decode-ops: grid-stride cast_kernel rows so M may exceed the 65535 gridDim.y cap

Browse files
Files changed (1) hide show
  1. spec_decode_cuda/spec_decode_ops.cu +41 -8
spec_decode_cuda/spec_decode_ops.cu CHANGED
@@ -94,10 +94,19 @@ __device__ void block_argmax(float v, int64_t idx, float* out_v, int64_t* out_i)
94
  template <typename T>
95
  __global__ void cast_kernel(const T* __restrict__ logits, int64_t M, int64_t V,
96
  float* __restrict__ out) {
97
- const int64_t row = blockIdx.y;
98
- for (int64_t v = blockIdx.x * (int64_t)blockDim.x + threadIdx.x; v < V;
99
- v += (int64_t)gridDim.x * blockDim.x) {
100
- out[row * V + v] = ldf(logits, row * V + v);
 
 
 
 
 
 
 
 
 
101
  }
102
  }
103
 
@@ -133,7 +142,27 @@ __global__ void sorted_sample_kernel(const float* __restrict__ sorted_logits,
133
  const float* sl = sorted_logits + row * V;
134
  const int* si = sorted_idx + row * V;
135
  const float lmax = sl[0] * inv_temp;
136
- const int64_t kk = (top_k > 0 && top_k < V) ? top_k : V;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  // Z over the top_k prefix (post-temperature).
139
  float part = 0.f;
@@ -197,9 +226,12 @@ __global__ void sorted_sample_kernel(const float* __restrict__ sorted_logits,
197
  __syncthreads();
198
 
199
  if (write_mask) {
 
 
 
200
  float* mo = masked_out + row * V;
201
  for (int64_t i = threadIdx.x; i < V; i += blockDim.x) {
202
- mo[si[i]] = (i < L) ? sl[i] * inv_temp : kNegInf;
203
  }
204
  return;
205
  }
@@ -498,7 +530,7 @@ void run_sample(const torch::Tensor& logits, const c10::optional<torch::Tensor>&
498
  TORCH_CHECK(M * V < INT32_MAX, "M * V must fit in int32 for the segmented sort");
499
  auto work = torch::empty({M, V}, opts_f);
500
  {
501
- dim3 grid((unsigned)grid_x_for(V), (unsigned)M);
502
  cast_kernel<T><<<grid, kThreads, 0, stream>>>(tptr<T>(logits), M, V, work.data_ptr<float>());
503
  if (prev.has_value() && rep != 1.0) {
504
  penalty_kernel<<<M, kThreads, 0, stream>>>(work.data_ptr<float>(), V,
@@ -509,7 +541,8 @@ void run_sample(const torch::Tensor& logits, const c10::optional<torch::Tensor>&
509
 
510
  // segmented descending sort with indices
511
  auto sorted = torch::empty({M, V}, opts_f);
512
- auto idx_in = torch::arange(V, logits.options().dtype(torch::kInt32)).repeat({M, 1}).contiguous();
 
513
  auto idx_out = torch::empty({M, V}, logits.options().dtype(torch::kInt32));
514
  auto offs = torch::arange(0, (M + 1) * V, V, logits.options().dtype(torch::kInt32)).contiguous();
515
  size_t temp_bytes = 0;
 
94
  template <typename T>
95
  __global__ void cast_kernel(const T* __restrict__ logits, int64_t M, int64_t V,
96
  float* __restrict__ out) {
97
+ // grid-stride over rows so M may exceed the 65535 gridDim.y hardware cap.
98
+ for (int64_t row = blockIdx.y; row < M; row += gridDim.y) {
99
+ for (int64_t v = blockIdx.x * (int64_t)blockDim.x + threadIdx.x; v < V;
100
+ v += (int64_t)gridDim.x * blockDim.x) {
101
+ out[row * V + v] = ldf(logits, row * V + v);
102
+ }
103
+ }
104
+ }
105
+
106
+ __global__ void iota_kernel(int* __restrict__ out, int64_t M, int64_t V) {
107
+ for (int64_t i = blockIdx.x * (int64_t)blockDim.x + threadIdx.x; i < M * V;
108
+ i += (int64_t)gridDim.x * blockDim.x) {
109
+ out[i] = (int)(i % V);
110
  }
111
  }
112
 
 
142
  const float* sl = sorted_logits + row * V;
143
  const int* si = sorted_idx + row * V;
144
  const float lmax = sl[0] * inv_temp;
145
+
146
+ // top-k with tie inclusion: transformers removes only values strictly
147
+ // below the k-th, so equal-valued tokens past position k stay kept.
148
+ int64_t kk = V;
149
+ if (top_k > 0 && top_k < V) {
150
+ const float kth = sl[top_k - 1];
151
+ __shared__ int64_t s_kk;
152
+ if (threadIdx.x == 0) s_kk = V;
153
+ __syncthreads();
154
+ const int64_t start = (top_k / kThreads) * kThreads;
155
+ for (int64_t base = start; base < V; base += blockDim.x) {
156
+ const int64_t i = base + threadIdx.x;
157
+ if (i >= top_k && i < V && sl[i] < kth) {
158
+ atomicMin((unsigned long long*)&s_kk, (unsigned long long)i);
159
+ }
160
+ __syncthreads();
161
+ if (s_kk < base + (int64_t)kThreads) break;
162
+ }
163
+ kk = s_kk;
164
+ __syncthreads();
165
+ }
166
 
167
  // Z over the top_k prefix (post-temperature).
168
  float part = 0.f;
 
226
  __syncthreads();
227
 
228
  if (write_mask) {
229
+ // masked entries carry true -inf, matching the transformers chain's
230
+ // filter_value; -FLT_MAX would evaluate identically under softmax but
231
+ // fails isinf-based consumers.
232
  float* mo = masked_out + row * V;
233
  for (int64_t i = threadIdx.x; i < V; i += blockDim.x) {
234
+ mo[si[i]] = (i < L) ? sl[i] * inv_temp : -INFINITY;
235
  }
236
  return;
237
  }
 
530
  TORCH_CHECK(M * V < INT32_MAX, "M * V must fit in int32 for the segmented sort");
531
  auto work = torch::empty({M, V}, opts_f);
532
  {
533
+ dim3 grid((unsigned)grid_x_for(V), (unsigned)std::min<int64_t>(M, 65535));
534
  cast_kernel<T><<<grid, kThreads, 0, stream>>>(tptr<T>(logits), M, V, work.data_ptr<float>());
535
  if (prev.has_value() && rep != 1.0) {
536
  penalty_kernel<<<M, kThreads, 0, stream>>>(work.data_ptr<float>(), V,
 
541
 
542
  // segmented descending sort with indices
543
  auto sorted = torch::empty({M, V}, opts_f);
544
+ auto idx_in = torch::empty({M, V}, logits.options().dtype(torch::kInt32));
545
+ iota_kernel<<<grid_x_for(M * V), kThreads, 0, stream>>>(idx_in.data_ptr<int>(), M, V);
546
  auto idx_out = torch::empty({M, V}, logits.options().dtype(torch::kInt32));
547
  auto offs = torch::arange(0, (M + 1) * V, V, logits.options().dtype(torch::kInt32)).contiguous();
548
  size_t temp_bytes = 0;