载入中...
搜索中...
未找到
CpuKernels.cpp
浏览该文件的文档.
1#include "tensor/CpuKernels.h"
2#include "tensor/Tensor.h"
3
4#include "common/Exception.h"
5
6#include <algorithm>
7#include <cmath>
8#include <limits>
9#include <vector>
10
12namespace {
13
14int product(const int *dims, int rank) {
15 int n = 1;
16 for (int i = 0; i < rank; ++i) {
17 if (dims[i] <= 0) throw Exception("Tensor kernel: dims must be > 0");
18 n *= dims[i];
19 }
20 return n;
21}
22
23float applyBinary(OpType type, float x, float y) {
24 switch (type) {
25 case OpType::Add: return x + y;
26 case OpType::Sub: return x - y;
27 case OpType::Multiply: return x * y;
28 case OpType::Divide: return x / y;
29 default: throw Exception("Tensor kernel: not a binary op");
30 }
31}
32
34void broadcastStrides(const int *inDims, int inRank, int outRank, int *strides) {
35 const int pad = outRank - inRank;
36 for (int k = 0; k < outRank; ++k) {
37 const int d = k < pad ? 1 : inDims[k - pad];
38 int s = 1;
39 for (int t = k + 1; t < outRank; ++t) {
40 const int dt = t < pad ? 1 : inDims[t - pad];
41 if (dt != 1) s *= dt;
42 }
43 strides[k] = (d == 1) ? 0 : s;
44 }
45}
46
47int normalizeAxis(int axis, int rank) {
48 if (axis < 0) axis += rank;
49 if (axis < 0 || axis >= rank) throw Exception("Tensor kernel: axis out of range");
50 return axis;
51}
52
53} // namespace
54
55float applyUnary(OpType t, float x, float s0, float s1) {
56 switch (t) {
57 case OpType::Neg: return -x;
58 case OpType::Abs: return std::fabs(x);
59 case OpType::Sqrt: return std::sqrt(x);
60 case OpType::Exp: return std::exp(x);
61 case OpType::Log: return std::log(x);
62 case OpType::Sin: return std::sin(x);
63 case OpType::Cos: return std::cos(x);
64 case OpType::Tanh: return std::tanh(x);
65 case OpType::Relu: return x > 0.f ? x : 0.f;
66 case OpType::Sigmoid: return 1.f / (1.f + std::exp(-x));
67 case OpType::Gelu:
68 // tanh approximation (matches the generated GPU kernels)
69 return 0.5f * x * (1.f + std::tanh(0.7978845608028654f * (x + 0.044715f * x * x * x)));
70 case OpType::Silu: return x / (1.f + std::exp(-x));
71 case OpType::AddScalar: return x + s0;
72 case OpType::SubScalar: return x - s0;
73 case OpType::MulScalar: return x * s0;
74 case OpType::DivScalar: return x / s0;
75 case OpType::PowScalar: return std::pow(x, s0);
76 case OpType::Clamp: {
77 float lo = s0, hi = s1;
78 if (lo > hi) std::swap(lo, hi);
79 return std::clamp(x, lo, hi);
80 }
81 case OpType::MaximumScalar: return std::max(x, s0);
82 case OpType::MinimumScalar: return std::min(x, s0);
83 default: return x;
84 }
85}
86
88 switch (t) {
89 case OpType::Neg:
90 case OpType::Abs:
91 case OpType::Sqrt:
92 case OpType::Exp:
93 case OpType::Log:
94 case OpType::Sin:
95 case OpType::Cos:
96 case OpType::Tanh:
97 case OpType::Relu:
98 case OpType::Sigmoid:
99 case OpType::Gelu:
100 case OpType::Silu:
106 case OpType::Clamp:
109 case OpType::Add:
110 case OpType::Sub:
111 case OpType::Multiply:
112 case OpType::Divide:
113 case OpType::Where:
114 return true;
115 default:
116 return false;
117 }
118}
119
120bool broadcastShape(const int *aDims, int aRank, const int *bDims, int bRank, int *outDims,
121 int &outRank) {
122 const int r = std::max(aRank, bRank);
123 if (r > Tensor::kMaxRank) return false;
124 outRank = r;
125 const int aPad = r - aRank;
126 const int bPad = r - bRank;
127 for (int k = 0; k < r; ++k) {
128 const int da = k < aPad ? 1 : aDims[k - aPad];
129 const int db = k < bPad ? 1 : bDims[k - bPad];
130 if (da != db && da != 1 && db != 1) return false;
131 outDims[k] = std::max(da, db);
132 }
133 return true;
134}
135
136void binaryOp(OpType type, const float *a, const int *aDims, int aRank, const float *b,
137 const int *bDims, int bRank, float *out, const int *outDims, int outRank) {
138 int aStrides[Tensor::kMaxRank] = {};
139 int bStrides[Tensor::kMaxRank] = {};
140 broadcastStrides(aDims, aRank, outRank, aStrides);
141 broadcastStrides(bDims, bRank, outRank, bStrides);
142
143 int S[Tensor::kMaxRank] = {};
144 S[outRank - 1] = 1;
145 for (int k = outRank - 2; k >= 0; --k) S[k] = S[k + 1] * outDims[k + 1];
146
147 const int count = product(outDims, outRank);
148 for (int o = 0; o < count; ++o) {
149 int ia = 0, ib = 0;
150 for (int k = 0; k < outRank; ++k) {
151 const int coord = (o / S[k]) % outDims[k];
152 ia += coord * aStrides[k];
153 ib += coord * bStrides[k];
154 }
155 out[o] = applyBinary(type, a[ia], b[ib]);
156 }
157}
158
159void unaryOp(OpType type, const float *in, int count, float *out, float s0, float s1) {
160 for (int i = 0; i < count; ++i) out[i] = applyUnary(type, in[i], s0, s1);
161}
162
163void softmax(const float *in, const int *dims, int rank, int axis, bool logMode, float *out) {
164 axis = normalizeAxis(axis, rank);
165 int outer = 1, reduce = 1, inner = 1;
166 for (int k = 0; k < axis; ++k) outer *= dims[k];
167 reduce = dims[axis];
168 for (int k = axis + 1; k < rank; ++k) inner *= dims[k];
169 const int rows = outer * inner;
170 for (int r = 0; r < rows; ++r) {
171 const int o = r / inner;
172 const int i = r % inner;
173 const float *row = in + (o * reduce) * inner + i;
174 float mx = -std::numeric_limits<float>::infinity();
175 for (int j = 0; j < reduce; ++j) mx = std::max(mx, row[j * inner]);
176 double sum = 0.0;
177 for (int j = 0; j < reduce; ++j) sum += std::exp(double(row[j * inner] - mx));
178 const float invSum = float(1.0 / sum);
179 for (int j = 0; j < reduce; ++j) {
180 const float v = row[j * inner];
181 out[(o * reduce + j) * inner + i] =
182 logMode ? (v - mx) - std::log(float(sum)) : std::exp(v - mx) * invSum;
183 }
184 }
185}
186
187void layernorm(const float *in, int rows, int cols, const float *scale, const float *bias,
188 float eps, float *out) {
189 for (int r = 0; r < rows; ++r) {
190 const float *row = in + size_t(r) * cols;
191 double sum = 0.0, sumsq = 0.0;
192 for (int c = 0; c < cols; ++c) {
193 const double v = row[c];
194 sum += v;
195 sumsq += v * v;
196 }
197 const double mean = sum / cols;
198 double var = sumsq / cols - mean * mean;
199 if (var < 0.0) var = 0.0;
200 const float inv = float(1.0 / std::sqrt(var + eps));
201 float *o = out + size_t(r) * cols;
202 for (int c = 0; c < cols; ++c) {
203 float y = float(row[c] - mean) * inv;
204 if (scale) y *= scale[c];
205 if (bias) y += bias[c];
206 o[c] = y;
207 }
208 }
209}
210
211void rmsnorm(const float *in, int rows, int cols, const float *scale, float eps, float *out) {
212 for (int r = 0; r < rows; ++r) {
213 const float *row = in + size_t(r) * cols;
214 double sumsq = 0.0;
215 for (int c = 0; c < cols; ++c) sumsq += double(row[c]) * row[c];
216 const float inv = float(1.0 / std::sqrt(sumsq / cols + eps));
217 float *o = out + size_t(r) * cols;
218 for (int c = 0; c < cols; ++c) o[c] = row[c] * inv * (scale ? scale[c] : 1.f);
219 }
220}
221
222namespace {
223
224int convOutSize(int inSize, int kernel, int stride, int pad) {
225 return (inSize + 2 * pad - kernel) / stride + 1;
226}
227
228} // namespace
229
230void conv1d(const float *x, const int *xDims, const float *w, const int *wDims,
231 const float *bias, int stride, int pad, float *out) {
232 const int N = xDims[0], C = xDims[1], L = xDims[2];
233 const int F = wDims[0], K = wDims[2];
234 const int OL = convOutSize(L, K, stride, pad);
235 for (int n = 0; n < N; ++n) {
236 for (int f = 0; f < F; ++f) {
237 for (int ol = 0; ol < OL; ++ol) {
238 float acc = bias ? bias[f] : 0.f;
239 for (int c = 0; c < C; ++c) {
240 for (int k = 0; k < K; ++k) {
241 const int il = ol * stride + k - pad;
242 if (il < 0 || il >= L) continue;
243 acc += x[((n * C + c) * L + il)] * w[((f * C + c) * K + k)];
244 }
245 }
246 out[(n * F + f) * OL + ol] = acc;
247 }
248 }
249 }
250}
251
252void conv2d(const float *x, const int *xDims, const float *w, const int *wDims,
253 const float *bias, int stride, int pad, float *out) {
254 const int N = xDims[0], C = xDims[1], H = xDims[2], W = xDims[3];
255 const int F = wDims[0], KH = wDims[2], KW = wDims[3];
256 const int OH = convOutSize(H, KH, stride, pad);
257 const int OW = convOutSize(W, KW, stride, pad);
258 for (int n = 0; n < N; ++n) {
259 for (int f = 0; f < F; ++f) {
260 for (int oh = 0; oh < OH; ++oh) {
261 for (int ow = 0; ow < OW; ++ow) {
262 float acc = bias ? bias[f] : 0.f;
263 for (int c = 0; c < C; ++c) {
264 for (int kh = 0; kh < KH; ++kh) {
265 const int ih = oh * stride + kh - pad;
266 if (ih < 0 || ih >= H) continue;
267 for (int kw = 0; kw < KW; ++kw) {
268 const int iw = ow * stride + kw - pad;
269 if (iw < 0 || iw >= W) continue;
270 acc += x[((n * C + c) * H + ih) * W + iw] *
271 w[((f * C + c) * KH + kh) * KW + kw];
272 }
273 }
274 }
275 out[((n * F + f) * OH + oh) * OW + ow] = acc;
276 }
277 }
278 }
279 }
280}
281
282void maxpool2d(const float *in, const int *dims, int ksize, int stride, int pad, float *out) {
283 const int N = dims[0], C = dims[1], H = dims[2], W = dims[3];
284 const int OH = convOutSize(H, ksize, stride, pad);
285 const int OW = convOutSize(W, ksize, stride, pad);
286 for (int n = 0; n < N; ++n)
287 for (int c = 0; c < C; ++c)
288 for (int oh = 0; oh < OH; ++oh)
289 for (int ow = 0; ow < OW; ++ow) {
290 float best = -std::numeric_limits<float>::infinity();
291 for (int kh = 0; kh < ksize; ++kh)
292 for (int kw = 0; kw < ksize; ++kw) {
293 const int ih = oh * stride + kh - pad;
294 const int iw = ow * stride + kw - pad;
295 if (ih < 0 || ih >= H || iw < 0 || iw >= W) continue;
296 best = std::max(best, in[((n * C + c) * H + ih) * W + iw]);
297 }
298 out[((n * C + c) * OH + oh) * OW + ow] = best;
299 }
300}
301
302void avgpool2d(const float *in, const int *dims, int ksize, int stride, int pad, float *out) {
303 const int N = dims[0], C = dims[1], H = dims[2], W = dims[3];
304 const int OH = convOutSize(H, ksize, stride, pad);
305 const int OW = convOutSize(W, ksize, stride, pad);
306 for (int n = 0; n < N; ++n)
307 for (int c = 0; c < C; ++c)
308 for (int oh = 0; oh < OH; ++oh)
309 for (int ow = 0; ow < OW; ++ow) {
310 double acc = 0.0;
311 int valid = 0;
312 for (int kh = 0; kh < ksize; ++kh)
313 for (int kw = 0; kw < ksize; ++kw) {
314 const int ih = oh * stride + kh - pad;
315 const int iw = ow * stride + kw - pad;
316 if (ih < 0 || ih >= H || iw < 0 || iw >= W) continue;
317 acc += in[((n * C + c) * H + ih) * W + iw];
318 ++valid;
319 }
320 out[((n * C + c) * OH + oh) * OW + ow] =
321 valid > 0 ? float(acc / valid) : 0.f;
322 }
323}
324
325void embedding(const float *table, int vocab, int dim, const float *indices, int count,
326 float *out) {
327 for (int r = 0; r < count; ++r) {
328 int idx = int(indices[r]);
329 idx = std::max(0, std::min(idx, vocab - 1));
330 const float *row = table + size_t(idx) * dim;
331 float *o = out + size_t(r) * dim;
332 for (int d = 0; d < dim; ++d) o[d] = row[d];
333 }
334}
335
336void concat(const float *const *ins, const int *const *inDims, const int *inRanks, int n,
337 int axis, float *out, const int *outDims, int outRank) {
338 axis = normalizeAxis(axis, outRank);
339 int starts[4] = {};
340 int axisSize = 0;
341 for (int k = 0; k < n; ++k) {
342 starts[k] = axisSize;
343 axisSize += inDims[k][axis];
344 }
345 int outer = 1, inner = 1;
346 for (int k = 0; k < axis; ++k) outer *= outDims[k];
347 for (int k = axis + 1; k < outRank; ++k) inner *= outDims[k];
348 const int count = outer * axisSize * inner;
349 for (int o = 0; o < count; ++o) {
350 const int ax = (o / inner) % axisSize;
351 const int outerPart = o / (axisSize * inner);
352 const int innerPart = o % inner;
353 float v = 0.f;
354 for (int k = 0; k < n; ++k) {
355 const int sz = inDims[k][axis];
356 if (ax >= starts[k] && ax < starts[k] + sz) {
357 v = ins[k][(outerPart * sz + (ax - starts[k])) * inner + innerPart];
358 break;
359 }
360 }
361 out[o] = v;
362 }
363}
364
365void sliceOp(const float *in, const int *inDims, int inRank, int axis, int begin, int end,
366 float *out, const int *outDims, int outRank) {
367 (void)inRank;
368 axis = normalizeAxis(axis, outRank);
369 const int axisSize = end - begin;
370 int outer = 1, inner = 1;
371 for (int k = 0; k < axis; ++k) outer *= outDims[k];
372 for (int k = axis + 1; k < outRank; ++k) inner *= outDims[k];
373 const int count = outer * axisSize * inner;
374 for (int o = 0; o < count; ++o) {
375 const int ax = (o / inner) % axisSize;
376 const int outerPart = o / (axisSize * inner);
377 const int innerPart = o % inner;
378 out[o] = in[(outerPart * inDims[axis] + (ax + begin)) * inner + innerPart];
379 }
380}
381
382void permute(const float *in, const int *inDims, int rank, const int *order, float *out,
383 const int *outDims) {
384 int S[Tensor::kMaxRank] = {};
385 S[rank - 1] = 1;
386 for (int k = rank - 2; k >= 0; --k) S[k] = S[k + 1] * outDims[k + 1];
387 int inStride[Tensor::kMaxRank] = {};
388 inStride[rank - 1] = 1;
389 for (int k = rank - 2; k >= 0; --k) inStride[k] = inStride[k + 1] * inDims[k + 1];
390 const int count = product(outDims, rank);
391 for (int o = 0; o < count; ++o) {
392 int idx = 0;
393 for (int k = 0; k < rank; ++k) {
394 const int coord = (o / S[k]) % outDims[k];
395 idx += coord * inStride[order[k]];
396 }
397 out[o] = in[idx];
398 }
399}
400
401void reduceAxis(OpType type, const float *in, const int *dims, int rank, int axis, float *out,
402 const int *outDims, int outRank) {
403 (void)outDims;
404 (void)outRank;
405 axis = normalizeAxis(axis, rank);
406 int outer = 1, reduce = 1, inner = 1;
407 for (int k = 0; k < axis; ++k) outer *= dims[k];
408 reduce = dims[axis];
409 for (int k = axis + 1; k < rank; ++k) inner *= dims[k];
410 const int rows = outer * inner;
411 const float negInf = -std::numeric_limits<float>::infinity();
412 const float posInf = std::numeric_limits<float>::infinity();
413 for (int r = 0; r < rows; ++r) {
414 const int o = r / inner;
415 const int i = r % inner;
416 float acc = (type == OpType::ReduceMin) ? posInf : (type == OpType::ReduceMax ? negInf : 0.f);
417 for (int j = 0; j < reduce; ++j) {
418 const float v = in[(o * reduce + j) * inner + i];
419 if (type == OpType::ReduceSum || type == OpType::ReduceMean) acc += v;
420 else if (type == OpType::ReduceMin) acc = std::min(acc, v);
421 else if (type == OpType::ReduceMax) acc = std::max(acc, v);
422 }
423 if (type == OpType::ReduceMean) acc /= float(reduce);
424 out[o * inner + i] = acc;
425 }
426}
427
428void argmax(const float *in, const int *dims, int rank, int axis, float *out,
429 const int *outDims, int outRank) {
430 (void)outDims;
431 (void)outRank;
432 axis = normalizeAxis(axis, rank);
433 int outer = 1, reduce = 1, inner = 1;
434 for (int k = 0; k < axis; ++k) outer *= dims[k];
435 reduce = dims[axis];
436 for (int k = axis + 1; k < rank; ++k) inner *= dims[k];
437 const int rows = outer * inner;
438 for (int r = 0; r < rows; ++r) {
439 const int o = r / inner;
440 const int i = r % inner;
441 float best = -std::numeric_limits<float>::infinity();
442 int bestJ = 0;
443 for (int j = 0; j < reduce; ++j) {
444 const float v = in[(o * reduce + j) * inner + i];
445 if (v > best) {
446 best = v;
447 bestJ = j;
448 }
449 }
450 out[o * inner + i] = float(bestJ);
451 }
452}
453
454void sdpa(const float *q, const float *k, const float *v, const float *mask, int B, int H,
455 int T, int S, int D, float scale, float *out) {
456 for (int b = 0; b < B; ++b) {
457 for (int h = 0; h < H; ++h) {
458 for (int t = 0; t < T; ++t) {
459 std::vector<float> scores(static_cast<size_t>(S));
460 const float *qRow = q + (size_t(b) * H + h) * T * D + size_t(t) * D;
461 for (int s = 0; s < S; ++s) {
462 const float *kRow = k + (size_t(b) * H + h) * S * D + size_t(s) * D;
463 double acc = 0.0;
464 for (int d = 0; d < D; ++d) acc += double(qRow[d]) * kRow[d];
465 float score = float(acc) * scale;
466 if (mask) score += mask[(size_t(b) * H + h) * T * S + size_t(t) * S + s];
467 scores[static_cast<size_t>(s)] = score;
468 }
469 float mx = -std::numeric_limits<float>::infinity();
470 for (int s = 0; s < S; ++s) mx = std::max(mx, scores[static_cast<size_t>(s)]);
471 double sum = 0.0;
472 for (int s = 0; s < S; ++s)
473 sum += std::exp(double(scores[static_cast<size_t>(s)] - mx));
474 float *oRow = out + (size_t(b) * H + h) * T * D + size_t(t) * D;
475 for (int d = 0; d < D; ++d) {
476 double acc = 0.0;
477 for (int s = 0; s < S; ++s) {
478 const float *vRow = v + (size_t(b) * H + h) * S * D + size_t(s) * D;
479 acc += std::exp(double(scores[static_cast<size_t>(s)] - mx)) * vRow[d];
480 }
481 oRow[d] = float(acc / sum);
482 }
483 }
484 }
485 }
486}
487
488void resize2d(const float *in, const int *inDims, int outW, int outH, int mode, float *out) {
489 const int N = inDims[0], C = inDims[1], H = inDims[2], W = inDims[3];
490 for (int n = 0; n < N; ++n) {
491 for (int c = 0; c < C; ++c) {
492 for (int oh = 0; oh < outH; ++oh) {
493 for (int ow = 0; ow < outW; ++ow) {
494 const float *src = in + (size_t(n) * C + c) * H * W;
495 float value = 0.f;
496 if (mode == 0) {
497 const int ih = std::min(int(float(oh) * H / outH), H - 1);
498 const int iw = std::min(int(float(ow) * W / outW), W - 1);
499 value = src[size_t(ih) * W + iw];
500 } else {
501 float x = float(ow + 0.5f) * W / outW - 0.5f;
502 float y = float(oh + 0.5f) * H / outH - 0.5f;
503 x = std::clamp(x, 0.f, float(W - 1));
504 y = std::clamp(y, 0.f, float(H - 1));
505 const int x0 = int(std::floor(x));
506 const int y0 = int(std::floor(y));
507 const int x1 = std::min(x0 + 1, W - 1);
508 const int y1 = std::min(y0 + 1, H - 1);
509 const float fx = x - float(x0);
510 const float fy = y - float(y0);
511 const float v00 = src[size_t(y0) * W + x0];
512 const float v10 = src[size_t(y0) * W + x1];
513 const float v01 = src[size_t(y1) * W + x0];
514 const float v11 = src[size_t(y1) * W + x1];
515 value = (v00 * (1.f - fx) + v10 * fx) * (1.f - fy) +
516 (v01 * (1.f - fx) + v11 * fx) * fy;
517 }
518 out[((size_t(n) * C + c) * outH + oh) * outW + ow] = value;
519 }
520 }
521 }
522 }
523}
524
525} // namespace eve::tensor::kernels
std::string value
std::string type
gpgpu::ComputeShader * reduce
int y
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
int h
int w
uint32_t a
uint32_t b
uint32_t c
int idx
float f
bool valid
int d
int v
float scale
Definition TreeMesh.cpp:122
uint32_t s
Definition Weather.cpp:28
static constexpr int kMaxRank
Definition Tensor.h:45
void maxpool2d(const float *in, const int *dims, int ksize, int stride, int pad, float *out)
void softmax(const float *in, const int *dims, int rank, int axis, bool logMode, float *out)
void conv2d(const float *x, const int *xDims, const float *w, const int *wDims, const float *bias, int stride, int pad, float *out)
void sdpa(const float *q, const float *k, const float *v, const float *mask, int B, int H, int T, int S, int D, float scale, float *out)
void sliceOp(const float *in, const int *inDims, int inRank, int axis, int begin, int end, float *out, const int *outDims, int outRank)
void embedding(const float *table, int vocab, int dim, const float *indices, int count, float *out)
void avgpool2d(const float *in, const int *dims, int ksize, int stride, int pad, float *out)
void binaryOp(OpType type, const float *a, const int *aDims, int aRank, const float *b, const int *bDims, int bRank, float *out, const int *outDims, int outRank)
void permute(const float *in, const int *inDims, int rank, const int *order, float *out, const int *outDims)
void reduceAxis(OpType type, const float *in, const int *dims, int rank, int axis, float *out, const int *outDims, int outRank)
bool broadcastShape(const int *aDims, int aRank, const int *bDims, int bRank, int *outDims, int &outRank)
bool isElementwiseOp(OpType t)
void argmax(const float *in, const int *dims, int rank, int axis, float *out, const int *outDims, int outRank)
void layernorm(const float *in, int rows, int cols, const float *scale, const float *bias, float eps, float *out)
void rmsnorm(const float *in, int rows, int cols, const float *scale, float eps, float *out)
void concat(const float *const *ins, const int *const *inDims, const int *inRanks, int n, int axis, float *out, const int *outDims, int outRank)
float applyUnary(OpType t, float x, float s0, float s1)
void conv1d(const float *x, const int *xDims, const float *w, const int *wDims, const float *bias, int stride, int pad, float *out)
void unaryOp(OpType type, const float *in, int count, float *out, float s0, float s1)
void resize2d(const float *in, const int *inDims, int outW, int outH, int mode, float *out)