载入中...
搜索中...
未找到
Graph.cpp
浏览该文件的文档.
1#include "tensor/Graph.h"
2#include "tensor/CpuKernels.h"
3#include "tensor/GpuBackend.h"
4#include "tensor/Optimizer.h"
5#include "tensor/Quant.h"
6#include "tensor/TF.h"
7
8#include "common/Exception.h"
9
10#include <algorithm>
11#include <cmath>
12#include <cstring>
13
14namespace eve::tensor {
15
16// ---------------------------------------------------------------------------
17// Func: tracing graph builder
18// ---------------------------------------------------------------------------
19
20Func::Func(TF *owner) : owner_(owner) {
21 if (!owner_) throw eve::Exception("Func: null owner");
22 owner_->pushTrace(this);
23}
24
26 if (tracing_ && owner_) owner_->popTrace(this);
27}
28
29GraphNode Func::makeShapeNode(OpType type, const int *dims, int rank) {
31 n.type = type;
32 n.rank = rank;
33 for (int i = 0; i < Tensor::kMaxRank; ++i) n.dims[i] = 0;
34 for (int i = 0; i < rank; ++i) n.dims[i] = dims[i];
35 n.size = Graph::product(dims, rank);
36 return n;
37}
38
39Tensor *Func::makeSymbolicFromNode(int nodeId) {
40 const auto &n = graph_.node(nodeId);
41 auto *t = Tensor::makeSymbolic(&graph_, nodeId, n.dims, n.rank);
42 t->setDtype(static_cast<DType>(n.dtype));
43 return t;
44}
45
46namespace {
47
48GraphNode makeInputNode(Graph &graph, OpType type, const int *dims, int rank, int slot) {
49 GraphNode n;
50 n.type = type;
51 n.rank = rank;
52 for (int i = 0; i < Tensor::kMaxRank; ++i) n.dims[i] = 0;
53 for (int i = 0; i < rank; ++i) n.dims[i] = dims[i];
54 n.size = Graph::product(dims, rank);
55 n.placeholderSlot = slot;
56 return n;
57}
58
59int normalizeAxisChecked(int axis, int rank) {
60 if (axis < 0) axis += rank;
61 if (axis < 0 || axis >= rank) throw eve::Exception("Func: axis out of range");
62 return axis;
63}
64
65int convOutSize(int inSize, int kernel, int stride, int pad) {
66 const int out = (inSize + 2 * pad - kernel) / stride + 1;
67 if (out <= 0) throw eve::Exception("Func: conv output size must be > 0");
68 return out;
69}
70
71} // namespace
72
74 int d[] = {d0};
75 int id = graph_.addNode(makeInputNode(graph_, OpType::Placeholder, d, 1, placeholderCount_++));
76 return makeSymbolicFromNode(id);
77}
78
79Tensor *Func::input2(int d0, int d1) {
80 int d[] = {d0, d1};
81 int id = graph_.addNode(makeInputNode(graph_, OpType::Placeholder, d, 2, placeholderCount_++));
82 return makeSymbolicFromNode(id);
83}
84
85Tensor *Func::input3(int d0, int d1, int d2) {
86 int d[] = {d0, d1, d2};
87 int id = graph_.addNode(makeInputNode(graph_, OpType::Placeholder, d, 3, placeholderCount_++));
88 return makeSymbolicFromNode(id);
89}
90
91Tensor *Func::input4(int d0, int d1, int d2, int d3) {
92 int d[] = {d0, d1, d2, d3};
93 int id = graph_.addNode(makeInputNode(graph_, OpType::Placeholder, d, 4, placeholderCount_++));
94 return makeSymbolicFromNode(id);
95}
96
97Tensor *Func::input5(int d0, int d1, int d2, int d3, int d4) {
98 int d[] = {d0, d1, d2, d3, d4};
99 int id = graph_.addNode(makeInputNode(graph_, OpType::Placeholder, d, 5, placeholderCount_++));
100 return makeSymbolicFromNode(id);
101}
102
103Tensor *Func::input6(int d0, int d1, int d2, int d3, int d4, int d5) {
104 int d[] = {d0, d1, d2, d3, d4, d5};
105 int id = graph_.addNode(makeInputNode(graph_, OpType::Placeholder, d, 6, placeholderCount_++));
106 return makeSymbolicFromNode(id);
107}
108
110 if (!t) throw eve::Exception("Func.setOutput: null");
111 outputNode_ = ensureNode(t);
112}
113
115 if (!t) throw eve::Exception("Func.ensureNode: null");
116 if (t->isSymbolic()) {
117 if (t->graph() != &graph_) throw eve::Exception("Func: tensor from another graph");
118 return t->nodeId();
119 }
120 t->ensureEager("capture");
121 auto n = makeShapeNode(OpType::Const, t->dims_, t->rank_);
122 if (t->isQuantized()) {
123 n.constBytes = t->qBytes();
124 n.constScales = t->qScales();
125 n.qGroup = t->qGroup();
126 } else {
127 n.constData.assign(t->data(), t->data() + t->getSize());
128 }
129 n.dtype = static_cast<int>(t->dtype_);
130 return graph_.addNode(std::move(n));
131}
132
133Tensor *Func::emitFill(const int *dims, int rank, float value) {
134 auto n = makeShapeNode(OpType::Const, dims, rank);
135 n.constData.assign(static_cast<size_t>(n.size), value);
136 int id = graph_.addNode(std::move(n));
137 return makeSymbolicFromNode(id);
138}
139
141 int ix = ensureNode(x);
142 const auto &src = graph_.node(ix);
143 auto n = makeShapeNode(type, src.dims, src.rank);
144 n.in0 = ix;
145 n.dtype = src.dtype;
146 int id = graph_.addNode(std::move(n));
147 return makeSymbolicFromNode(id);
148}
149
150Tensor *Func::emitUnaryScalar(OpType type, const Tensor *x, float s0, float s1) {
151 int ix = ensureNode(x);
152 const auto &src = graph_.node(ix);
153 auto n = makeShapeNode(type, src.dims, src.rank);
154 n.in0 = ix;
155 n.s0 = s0;
156 n.s1 = s1;
157 n.dtype = src.dtype;
158 int id = graph_.addNode(std::move(n));
159 return makeSymbolicFromNode(id);
160}
161
163 int ia = ensureNode(a);
164 int ib = ensureNode(b);
165 const auto &na = graph_.node(ia);
166 const auto &nb = graph_.node(ib);
167 int od[Tensor::kMaxRank] = {};
168 int orank = 0;
169 if (!kernels::broadcastShape(na.dims, na.rank, nb.dims, nb.rank, od, orank))
170 throw eve::Exception("Func binary: broadcast shape mismatch");
171 auto n = makeShapeNode(type, od, orank);
172 n.in0 = ia;
173 n.in1 = ib;
174 int id = graph_.addNode(std::move(n));
175 return makeSymbolicFromNode(id);
176}
177
179 int ia = ensureNode(a);
180 int ib = ensureNode(b);
181 int ic = ensureNode(c);
182 const auto &na = graph_.node(ia);
183 auto n = makeShapeNode(type, na.dims, na.rank);
184 n.in0 = ia;
185 n.in1 = ib;
186 n.in2 = ic;
187 int id = graph_.addNode(std::move(n));
188 return makeSymbolicFromNode(id);
189}
190
192 int ia = ensureNode(a);
193 int ib = ensureNode(b);
194 const auto &na = graph_.node(ia);
195 const auto &nb = graph_.node(ib);
196 if (na.rank == 2 && nb.rank == 2) {
197 if (na.dims[1] != nb.dims[0]) throw eve::Exception("Func.matmul: inner dims mismatch");
198 int od[] = {na.dims[0], nb.dims[1]};
199 auto n = makeShapeNode(OpType::MatMul, od, 2);
200 n.in0 = ia;
201 n.in1 = ib;
202 int id = graph_.addNode(std::move(n));
203 return makeSymbolicFromNode(id);
204 }
205 if (na.rank == 3 && nb.rank == 3) {
206 if (na.dims[0] != nb.dims[0] || na.dims[2] != nb.dims[1])
207 throw eve::Exception("Func.matmul: batched dims mismatch");
208 int od[] = {na.dims[0], na.dims[1], nb.dims[2]};
209 auto n = makeShapeNode(OpType::MatMul, od, 3);
210 n.in0 = ia;
211 n.in1 = ib;
212 int id = graph_.addNode(std::move(n));
213 return makeSymbolicFromNode(id);
214 }
215 throw eve::Exception("Func.matmul: rank 2x2 or 3x3 required");
216}
217
219 int ix = ensureNode(x);
220 const auto &src = graph_.node(ix);
221 if (src.rank != 2) throw eve::Exception("Func.transpose: rank 2 required");
222 int order[] = {1, 0};
223 return emitPermute(x, order, 2);
224}
225
226Tensor *Func::emitPermute(const Tensor *x, const int *order, int rank) {
227 int ix = ensureNode(x);
228 const auto &src = graph_.node(ix);
229 if (rank != src.rank) throw eve::Exception("Func.permute: rank mismatch");
230 int od[Tensor::kMaxRank] = {};
231 for (int k = 0; k < rank; ++k) {
232 if (order[k] < 0 || order[k] >= rank)
233 throw eve::Exception("Func.permute: order out of range");
234 od[k] = src.dims[order[k]];
235 }
236 auto n = makeShapeNode(OpType::Permute, od, rank);
237 n.in0 = ix;
238 for (int k = 0; k < rank; ++k) n.perm[k] = order[k];
239 n.permRank = rank;
240 int id = graph_.addNode(std::move(n));
241 return makeSymbolicFromNode(id);
242}
243
244Tensor *Func::emitReshape(const Tensor *x, const int *dims, int rank) {
245 int ix = ensureNode(x);
246 const auto &src = graph_.node(ix);
247 int newSize = Graph::product(dims, rank);
248 if (newSize != src.size) throw eve::Exception("Func.reshape: size mismatch");
249 auto n = makeShapeNode(OpType::Reshape, dims, rank);
250 n.in0 = ix;
251 n.dtype = src.dtype;
252 int id = graph_.addNode(std::move(n));
253 return makeSymbolicFromNode(id);
254}
255
256Tensor *Func::emitSoftmax(const Tensor *x, int axis, bool logMode) {
257 int ix = ensureNode(x);
258 const auto &src = graph_.node(ix);
259 axis = normalizeAxisChecked(axis, src.rank);
260 auto n = makeShapeNode(logMode ? OpType::LogSoftmax : OpType::Softmax, src.dims, src.rank);
261 n.in0 = ix;
262 n.i0 = axis;
263 int id = graph_.addNode(std::move(n));
264 return makeSymbolicFromNode(id);
265}
266
267namespace {
268
269void checkParamVector(const GraphNode &src, int cols, const char *what) {
270 if (src.rank == 1 && src.dims[0] == cols) return;
271 if (src.rank == 2 && src.dims[0] == 1 && src.dims[1] == cols) return;
272 throw eve::Exception("Func.%s: expected shape [%d]", what, cols);
273}
274
275} // namespace
276
277Tensor *Func::emitLayerNorm(const Tensor *x, const Tensor *scale, const Tensor *bias, float eps) {
278 int ix = ensureNode(x);
279 const auto &src = graph_.node(ix);
280 if (src.rank < 1) throw eve::Exception("Func.layernorm: rank >= 1 required");
281 const int cols = src.dims[src.rank - 1];
282 auto n = makeShapeNode(OpType::LayerNorm, src.dims, src.rank);
283 n.in0 = ix;
284 n.s0 = eps;
285 if (scale) {
286 int is = ensureNode(scale);
287 checkParamVector(graph_.node(is), cols, "layernorm scale");
288 n.in1 = is;
289 }
290 if (bias) {
291 int ib = ensureNode(bias);
292 checkParamVector(graph_.node(ib), cols, "layernorm bias");
293 n.in2 = ib;
294 }
295 int id = graph_.addNode(std::move(n));
296 return makeSymbolicFromNode(id);
297}
298
299Tensor *Func::emitRMSNorm(const Tensor *x, const Tensor *scale, float eps) {
300 int ix = ensureNode(x);
301 const auto &src = graph_.node(ix);
302 if (src.rank < 1) throw eve::Exception("Func.rmsnorm: rank >= 1 required");
303 const int cols = src.dims[src.rank - 1];
304 auto n = makeShapeNode(OpType::RMSNorm, src.dims, src.rank);
305 n.in0 = ix;
306 n.s0 = eps;
307 if (scale) {
308 int is = ensureNode(scale);
309 checkParamVector(graph_.node(is), cols, "rmsnorm scale");
310 n.in1 = is;
311 }
312 int id = graph_.addNode(std::move(n));
313 return makeSymbolicFromNode(id);
314}
315
316Tensor *Func::emitConv1d(const Tensor *x, const Tensor *w, const Tensor *bias, int stride,
317 int pad) {
318 int ix = ensureNode(x);
319 int iw = ensureNode(w);
320 const auto &nx = graph_.node(ix);
321 const auto &nw = graph_.node(iw);
322 if (nx.rank != 3 || nw.rank != 3) throw eve::Exception("Func.conv1d: rank 3 required");
323 if (nx.dims[1] != nw.dims[1]) throw eve::Exception("Func.conv1d: channel mismatch");
324 const int OL = convOutSize(nx.dims[2], nw.dims[2], stride, pad);
325 int od[] = {nx.dims[0], nw.dims[0], OL};
326 auto n = makeShapeNode(OpType::Conv1d, od, 3);
327 n.in0 = ix;
328 n.in1 = iw;
329 n.i0 = stride;
330 n.i1 = pad;
331 if (bias) {
332 int ib = ensureNode(bias);
333 const auto &nb = graph_.node(ib);
334 if (nb.rank != 1 || nb.dims[0] != n.dims[1]) throw eve::Exception("Func.conv1d: bias shape mismatch");
335 n.in2 = ib;
336 }
337 int id = graph_.addNode(std::move(n));
338 return makeSymbolicFromNode(id);
339}
340
341Tensor *Func::emitConv2d(const Tensor *x, const Tensor *w, const Tensor *bias, int stride,
342 int pad) {
343 int ix = ensureNode(x);
344 int iw = ensureNode(w);
345 const auto &nx = graph_.node(ix);
346 const auto &nw = graph_.node(iw);
347 if (nx.rank != 4 || nw.rank != 4) throw eve::Exception("Func.conv2d: rank 4 required");
348 if (nx.dims[1] != nw.dims[1]) throw eve::Exception("Func.conv2d: channel mismatch");
349 const int OH = convOutSize(nx.dims[2], nw.dims[2], stride, pad);
350 const int OW = convOutSize(nx.dims[3], nw.dims[3], stride, pad);
351 int od[] = {nx.dims[0], nw.dims[0], OH, OW};
352 auto n = makeShapeNode(OpType::Conv2d, od, 4);
353 n.in0 = ix;
354 n.in1 = iw;
355 n.i0 = stride;
356 n.i1 = pad;
357 if (bias) {
358 int ib = ensureNode(bias);
359 const auto &nb = graph_.node(ib);
360 if (nb.rank != 1 || nb.dims[0] != n.dims[1]) throw eve::Exception("Func.conv2d: bias shape mismatch");
361 n.in2 = ib;
362 }
363 int id = graph_.addNode(std::move(n));
364 return makeSymbolicFromNode(id);
365}
366
367Tensor *Func::emitPool(OpType type, const Tensor *x, int ksize, int stride, int pad) {
368 int ix = ensureNode(x);
369 const auto &src = graph_.node(ix);
370 if (src.rank != 4) throw eve::Exception("Func.pool: rank 4 required");
371 const int OH = convOutSize(src.dims[2], ksize, stride, pad);
372 const int OW = convOutSize(src.dims[3], ksize, stride, pad);
373 int od[] = {src.dims[0], src.dims[1], OH, OW};
374 auto n = makeShapeNode(type, od, 4);
375 n.in0 = ix;
376 n.i0 = ksize;
377 n.i1 = stride;
378 n.i2 = pad;
379 int id = graph_.addNode(std::move(n));
380 return makeSymbolicFromNode(id);
381}
382
384 int it = ensureNode(table);
385 int ii = ensureNode(indices);
386 const auto &nt = graph_.node(it);
387 const auto &ni = graph_.node(ii);
388 if (nt.rank != 2) throw eve::Exception("Func.embedding: table rank 2 required");
389 if (ni.rank < 1 || ni.rank + 1 > Tensor::kMaxRank)
390 throw eve::Exception("Func.embedding: index rank out of range");
391 int od[Tensor::kMaxRank] = {};
392 for (int k = 0; k < ni.rank; ++k) od[k] = ni.dims[k];
393 od[ni.rank] = nt.dims[1];
394 auto n = makeShapeNode(OpType::Embedding, od, ni.rank + 1);
395 n.in0 = it;
396 n.in1 = ii;
397 int id = graph_.addNode(std::move(n));
398 return makeSymbolicFromNode(id);
399}
400
401Tensor *Func::emitConcat(const Tensor *const *ins, int n, int axis) {
402 if (!ins || n < 2 || n > 4) throw eve::Exception("Func.concat: 2..4 inputs required");
403 int ids[4] = {};
404 const GraphNode *ns[4] = {};
405 // Importing an eager input may reallocate the graph's node array.
406 for (int k = 0; k < n; ++k) ids[k] = ensureNode(ins[k]);
407 for (int k = 0; k < n; ++k) {
408 ns[k] = &graph_.node(ids[k]);
409 if (ns[k]->rank != ns[0]->rank)
410 throw eve::Exception("Func.concat: rank mismatch");
411 }
412 axis = normalizeAxisChecked(axis, ns[0]->rank);
413 int od[Tensor::kMaxRank] = {};
414 for (int k = 0; k < ns[0]->rank; ++k) {
415 if (k == axis) {
416 int total = 0;
417 for (int t = 0; t < n; ++t) total += ns[t]->dims[k];
418 od[k] = total;
419 } else {
420 od[k] = ns[0]->dims[k];
421 for (int t = 1; t < n; ++t)
422 if (ns[t]->dims[k] != od[k])
423 throw eve::Exception("Func.concat: dims mismatch on axis %d", k);
424 }
425 }
426 auto g = makeShapeNode(OpType::Concat, od, ns[0]->rank);
427 g.in0 = ids[0];
428 g.in1 = ids[1];
429 if (n > 2) g.in2 = ids[2];
430 if (n > 3) g.in3 = ids[3];
431 g.i0 = axis;
432 int id = graph_.addNode(std::move(g));
433 return makeSymbolicFromNode(id);
434}
435
436Tensor *Func::emitSlice(const Tensor *x, int axis, int begin, int end) {
437 int ix = ensureNode(x);
438 const auto &src = graph_.node(ix);
439 axis = normalizeAxisChecked(axis, src.rank);
440 if (begin < 0 || end < begin || end > src.dims[axis])
441 throw eve::Exception("Func.slice: range out of bounds");
442 int od[Tensor::kMaxRank] = {};
443 for (int k = 0; k < src.rank; ++k) od[k] = src.dims[k];
444 od[axis] = end - begin;
445 auto n = makeShapeNode(OpType::Slice, od, src.rank);
446 n.in0 = ix;
447 n.i0 = axis;
448 n.i1 = begin;
449 n.i2 = end;
450 int id = graph_.addNode(std::move(n));
451 return makeSymbolicFromNode(id);
452}
453
454Tensor *Func::emitReduce(OpType type, const Tensor *x, int axis, bool keepDims) {
455 int ix = ensureNode(x);
456 const auto &src = graph_.node(ix);
457 axis = normalizeAxisChecked(axis, src.rank);
458 int od[Tensor::kMaxRank] = {};
459 int orank = src.rank;
460 for (int k = 0; k < src.rank; ++k) od[k] = src.dims[k];
461 if (keepDims) {
462 od[axis] = 1;
463 } else {
464 if (orank == 1) {
465 od[0] = 1; // Tensor rank must stay >= 1
466 } else {
467 for (int k = axis; k < orank - 1; ++k) od[k] = od[k + 1];
468 od[orank - 1] = 0;
469 --orank;
470 }
471 }
472 auto n = makeShapeNode(type, od, orank);
473 n.in0 = ix;
474 n.i0 = axis;
475 n.i1 = keepDims ? 1 : 0;
476 int id = graph_.addNode(std::move(n));
477 return makeSymbolicFromNode(id);
478}
479
480Tensor *Func::emitArgMax(const Tensor *x, int axis, bool keepDims) {
481 int ix = ensureNode(x);
482 const auto &src = graph_.node(ix);
483 axis = normalizeAxisChecked(axis, src.rank);
484 int od[Tensor::kMaxRank] = {};
485 int orank = src.rank;
486 for (int k = 0; k < src.rank; ++k) od[k] = src.dims[k];
487 if (keepDims) {
488 od[axis] = 1;
489 } else {
490 if (orank == 1) {
491 od[0] = 1;
492 } else {
493 for (int k = axis; k < orank - 1; ++k) od[k] = od[k + 1];
494 od[orank - 1] = 0;
495 --orank;
496 }
497 }
498 auto n = makeShapeNode(OpType::ArgMax, od, orank);
499 n.in0 = ix;
500 n.i0 = axis;
501 n.i1 = keepDims ? 1 : 0;
502 n.dtype = static_cast<int>(DType::Int32);
503 int id = graph_.addNode(std::move(n));
504 return makeSymbolicFromNode(id);
505}
506
508 int ix = ensureNode(x);
509 const auto &src = graph_.node(ix);
510 auto n = makeShapeNode(OpType::Cast, src.dims, src.rank);
511 n.in0 = ix;
512 n.dtype = static_cast<int>(dtype);
513 int id = graph_.addNode(std::move(n));
514 return makeSymbolicFromNode(id);
515}
516
517Tensor *Func::emitSdpa(const Tensor *q, const Tensor *k, const Tensor *v, const Tensor *mask,
518 float scale) {
519 int iq = ensureNode(q);
520 int ik = ensureNode(k);
521 int iv = ensureNode(v);
522 const int im = mask ? ensureNode(mask) : -1;
523 const auto &nq = graph_.node(iq);
524 const auto &nk = graph_.node(ik);
525 const auto &nv = graph_.node(iv);
526 if (nq.rank != 4 || nk.rank != 4 || nv.rank != 4)
527 throw eve::Exception("Func.sdpa: rank 4 required");
528 if (nq.dims[0] != nk.dims[0] || nq.dims[1] != nk.dims[1] ||
529 nq.dims[3] != nk.dims[3] || nk.dims[2] != nv.dims[2] || nq.dims[3] != nv.dims[3])
530 throw eve::Exception("Func.sdpa: q/k/v shape mismatch");
531 auto n = makeShapeNode(OpType::ScaledDotProductAttention, nq.dims, 4);
532 n.in0 = iq;
533 n.in1 = ik;
534 n.in2 = iv;
535 n.s0 = scale;
536 if (mask) {
537 const auto &nm = graph_.node(im);
538 if (nm.rank != 4 || nm.dims[0] != nq.dims[0] || nm.dims[1] != nq.dims[1] ||
539 nm.dims[2] != nq.dims[2] || nm.dims[3] != nk.dims[2])
540 throw eve::Exception("Func.sdpa: mask shape mismatch");
541 n.in3 = im;
542 }
543 int id = graph_.addNode(std::move(n));
544 return makeSymbolicFromNode(id);
545}
546
547Tensor *Func::emitResize2d(const Tensor *x, int outH, int outW, int mode) {
548 int ix = ensureNode(x);
549 const auto &src = graph_.node(ix);
550 if (src.rank != 4) throw eve::Exception("Func.resize2d: rank 4 required");
551 if (outH <= 0 || outW <= 0) throw eve::Exception("Func.resize2d: bad output size");
552 int od[] = {src.dims[0], src.dims[1], outH, outW};
553 auto n = makeShapeNode(OpType::Resize2d, od, 4);
554 n.in0 = ix;
555 n.i0 = mode;
556 int id = graph_.addNode(std::move(n));
557 return makeSymbolicFromNode(id);
558}
559
560// ---------------------------------------------------------------------------
561// CompiledFunction
562// ---------------------------------------------------------------------------
563
566
568 if (outputNode_ < 0) throw eve::Exception("Func.compile: setOutput required");
569 tracing_ = false;
570 if (owner_) owner_->popTrace(this);
571 return CompiledFunction::fromFunc(this);
572}
573
575 if (!fn) throw eve::Exception("CompiledFunction: null func");
576 auto *cf = new CompiledFunction();
577 cf->graph_ = fn->graph(); // copy
578 cf->outputNode_ = fn->outputNode();
579 cf->placeholderCount_ = fn->placeholderCount();
580 cf->device_ = "cpu";
581 cf->optimized_ = std::make_unique<OptimizedGraph>(optimizeGraph(cf->graph_, cf->outputNode_));
582 cf->order_ = cf->optimized_->order;
583
584 // Best-effort: run on GPU via eve::gpgpu compute shaders when a Vulkan
585 // device is available. Falls back to the CPU interpreter below otherwise.
586 try {
587 cf->gpuProgram_.reset(GpuProgram::tryBuild(cf->graph_, *cf->optimized_, cf->outputNode_));
588 } catch (...) {
589 cf->gpuProgram_.reset();
590 }
591 if (cf->gpuProgram_) cf->device_ = "gpu";
592 return cf;
593}
594
595Tensor *CompiledFunction::run0() { return runWithFeeds(nullptr, 0); }
596
598 Tensor *feeds[] = {in0};
599 return runWithFeeds(feeds, 1);
600}
601
603 Tensor *feeds[] = {in0, in1};
604 return runWithFeeds(feeds, 2);
605}
606
608 Tensor *feeds[] = {in0, in1, in2};
609 return runWithFeeds(feeds, 3);
610}
611
613 Tensor *feeds[] = {in0, in1, in2, in3};
614 return runWithFeeds(feeds, 4);
615}
616
618 Tensor *feeds[] = {in0, in1, in2, in3, in4};
619 return runWithFeeds(feeds, 5);
620}
621
623 Tensor *in5) {
624 Tensor *feeds[] = {in0, in1, in2, in3, in4, in5};
625 return runWithFeeds(feeds, 6);
626}
627
628Tensor *CompiledFunction::runWithFeeds(Tensor *const *feeds, int nFeeds) {
629 if (nFeeds != placeholderCount_)
630 throw eve::Exception("CompiledFunction.run: expected %d feeds, got %d", placeholderCount_,
631 nFeeds);
632 for (int i = 0; i < nFeeds; ++i) {
633 if (!feeds[i]) throw eve::Exception("CompiledFunction.run: null feed");
634 feeds[i]->ensureEager("run");
635 }
636
637 const int n = graph_.nodeCount();
638
639 // Validate placeholder shapes (shared by the GPU and CPU execution paths).
640 for (int i = 0; i < n; ++i) {
641 const auto &nd = graph_.node(i);
642 if (nd.type != OpType::Placeholder) continue;
643 const int slot = nd.placeholderSlot;
644 if (slot < 0 || slot >= nFeeds) throw eve::Exception("CompiledFunction: bad placeholder slot");
645 Tensor *feed = feeds[slot];
646 if (feed->getRank() != nd.rank || feed->getSize() != nd.size)
647 throw eve::Exception("CompiledFunction: feed shape mismatch");
648 for (int a = 0; a < nd.rank; ++a)
649 if (feed->getDim(a) != nd.dims[a])
650 throw eve::Exception("CompiledFunction: feed shape mismatch");
651 }
652
653 const auto &outN = graph_.node(outputNode_);
654
655 if (gpuProgram_) {
656 std::vector<const float *> ptrs(static_cast<size_t>(nFeeds));
657 for (int i = 0; i < nFeeds; ++i) ptrs[static_cast<size_t>(i)] = feeds[i]->data();
658 std::vector<float> result = gpuProgram_->run(ptrs);
659 auto *out = new Tensor(static_cast<DType>(outN.dtype), outN.dims, outN.rank);
660 if (int(result.size()) != out->getSize())
661 throw eve::Exception("CompiledFunction: gpu output size mismatch");
662 std::memcpy(out->data(), result.data(), sizeof(float) * static_cast<size_t>(out->getSize()));
663 return out;
664 }
665
666 std::vector<std::vector<float>> bufs(static_cast<size_t>(n));
667 for (int i = 0; i < n; ++i) {
668 const auto &nd = graph_.node(i);
669 if (nd.type != OpType::Placeholder) continue;
670 Tensor *feed = feeds[nd.placeholderSlot];
671 bufs[static_cast<size_t>(i)].assign(feed->data(), feed->data() + feed->getSize());
672 }
673
674 for (int nodeId : order_) executeNode(nodeId, bufs);
675
676 auto *out = new Tensor(static_cast<DType>(outN.dtype), outN.dims, outN.rank);
677 const auto &src = bufs[static_cast<size_t>(outputNode_)];
678 if (int(src.size()) != out->getSize())
679 throw eve::Exception("CompiledFunction: output size mismatch");
680 std::memcpy(out->data(), src.data(), sizeof(float) * static_cast<size_t>(out->getSize()));
681 return out;
682}
683
684void CompiledFunction::executeNode(int nodeId, std::vector<std::vector<float>> &bufs) const {
685 const auto &nd = graph_.node(nodeId);
686 auto &out = bufs[static_cast<size_t>(nodeId)];
687 const auto in = [&](int id) -> const std::vector<float> & {
688 return bufs[static_cast<size_t>(id)];
689 };
690
691 switch (nd.type) {
693 return; // already filled
694 case OpType::Const:
695 if (!nd.constBytes.empty()) {
696 out.assign(static_cast<size_t>(nd.size), 0.f);
697 q::dequantizeAll(static_cast<DType>(nd.dtype), nd.constBytes.data(),
698 nd.constScales.data(), nd.qGroup, nd.size, out.data());
699 } else {
700 out = nd.constData;
701 }
702 return;
703 case OpType::Add:
704 case OpType::Sub:
705 case OpType::Multiply:
706 case OpType::Divide: {
707 const auto &na = graph_.node(nd.in0);
708 const auto &nb = graph_.node(nd.in1);
709 out.resize(static_cast<size_t>(nd.size));
710 kernels::binaryOp(nd.type, in(nd.in0).data(), na.dims, na.rank, in(nd.in1).data(),
711 nb.dims, nb.rank, out.data(), nd.dims, nd.rank);
712 return;
713 }
714 case OpType::Neg:
715 case OpType::Abs:
716 case OpType::Sqrt:
717 case OpType::Exp:
718 case OpType::Log:
719 case OpType::Sin:
720 case OpType::Cos:
721 case OpType::Tanh:
722 case OpType::Relu:
723 case OpType::Sigmoid:
724 case OpType::Gelu:
725 case OpType::Silu:
731 case OpType::Clamp:
734 out.resize(static_cast<size_t>(nd.size));
735 kernels::unaryOp(nd.type, in(nd.in0).data(), nd.size, out.data(), nd.s0, nd.s1);
736 return;
737 }
738 case OpType::Where: {
739 const auto &c = in(nd.in0);
740 const auto &a = in(nd.in1);
741 const auto &b = in(nd.in2);
742 out.resize(static_cast<size_t>(nd.size));
743 for (int i = 0; i < nd.size; ++i)
744 out[static_cast<size_t>(i)] =
745 c[static_cast<size_t>(i)] > 0.5f ? a[static_cast<size_t>(i)]
746 : b[static_cast<size_t>(i)];
747 return;
748 }
749 case OpType::MatMul: {
750 const auto &A = graph_.node(nd.in0);
751 const auto &B = graph_.node(nd.in1);
752 const auto &a = in(nd.in0);
753 const auto &b = in(nd.in1);
754 out.assign(static_cast<size_t>(nd.size), 0.f);
755 if (nd.rank == 2) {
756 const int m = A.dims[0], k = A.dims[1], n = B.dims[1];
757 for (int i = 0; i < m; ++i) {
758 for (int j = 0; j < n; ++j) {
759 double acc = 0.0;
760 for (int t = 0; t < k; ++t)
761 acc += double(a[static_cast<size_t>(i * k + t)]) *
762 double(b[static_cast<size_t>(t * n + j)]);
763 out[static_cast<size_t>(i * n + j)] = float(acc);
764 }
765 }
766 } else {
767 const int batch = A.dims[0], m = A.dims[1], k = A.dims[2], n = B.dims[2];
768 for (int bb = 0; bb < batch; ++bb) {
769 const float *ap = a.data() + size_t(bb) * m * k;
770 const float *bp = b.data() + size_t(bb) * k * n;
771 float *cp = out.data() + size_t(bb) * m * n;
772 for (int i = 0; i < m; ++i)
773 for (int j = 0; j < n; ++j) {
774 double acc = 0.0;
775 for (int t = 0; t < k; ++t) acc += double(ap[i * k + t]) * double(bp[t * n + j]);
776 cp[i * n + j] = float(acc);
777 }
778 }
779 }
780 return;
781 }
783 case OpType::Permute: {
784 const auto &X = graph_.node(nd.in0);
785 out.resize(static_cast<size_t>(nd.size));
786 int order[Tensor::kMaxRank] = {};
787 for (int k = 0; k < nd.rank; ++k)
788 order[k] = nd.type == OpType::Transpose ? (k == 0 ? 1 : 0) : nd.perm[k];
789 kernels::permute(in(nd.in0).data(), X.dims, nd.rank, order, out.data(), nd.dims);
790 return;
791 }
792 case OpType::Reshape:
793 case OpType::Flatten:
794 case OpType::Cast:
795 out = in(nd.in0);
796 return;
797 case OpType::Softmax:
798 case OpType::LogSoftmax: {
799 out.resize(static_cast<size_t>(nd.size));
800 kernels::softmax(in(nd.in0).data(), nd.dims, nd.rank, nd.i0,
801 nd.type == OpType::LogSoftmax, out.data());
802 return;
803 }
804 case OpType::LayerNorm: {
805 out.resize(static_cast<size_t>(nd.size));
806 const int cols = nd.dims[nd.rank - 1];
807 const int rows = nd.size / cols;
808 kernels::layernorm(in(nd.in0).data(), rows, cols,
809 nd.in1 >= 0 ? in(nd.in1).data() : nullptr,
810 nd.in2 >= 0 ? in(nd.in2).data() : nullptr, nd.s0, out.data());
811 return;
812 }
813 case OpType::RMSNorm: {
814 out.resize(static_cast<size_t>(nd.size));
815 const int cols = nd.dims[nd.rank - 1];
816 const int rows = nd.size / cols;
817 kernels::rmsnorm(in(nd.in0).data(), rows, cols,
818 nd.in1 >= 0 ? in(nd.in1).data() : nullptr, nd.s0, out.data());
819 return;
820 }
821 case OpType::Conv1d:
822 case OpType::Conv2d: {
823 out.resize(static_cast<size_t>(nd.size));
824 const auto &X = graph_.node(nd.in0);
825 const auto &W = graph_.node(nd.in1);
826 if (nd.type == OpType::Conv1d)
827 kernels::conv1d(in(nd.in0).data(), X.dims, in(nd.in1).data(), W.dims,
828 nd.in2 >= 0 ? in(nd.in2).data() : nullptr, nd.i0, nd.i1, out.data());
829 else
830 kernels::conv2d(in(nd.in0).data(), X.dims, in(nd.in1).data(), W.dims,
831 nd.in2 >= 0 ? in(nd.in2).data() : nullptr, nd.i0, nd.i1, out.data());
832 return;
833 }
835 case OpType::AvgPool2d: {
836 out.resize(static_cast<size_t>(nd.size));
837 const auto &X = graph_.node(nd.in0);
838 if (nd.type == OpType::MaxPool2d)
839 kernels::maxpool2d(in(nd.in0).data(), X.dims, nd.i0, nd.i1, nd.i2, out.data());
840 else
841 kernels::avgpool2d(in(nd.in0).data(), X.dims, nd.i0, nd.i1, nd.i2, out.data());
842 return;
843 }
844 case OpType::Embedding: {
845 out.resize(static_cast<size_t>(nd.size));
846 const auto &T = graph_.node(nd.in0);
847 const auto &I = graph_.node(nd.in1);
848 kernels::embedding(in(nd.in0).data(), T.dims[0], T.dims[1], in(nd.in1).data(),
849 I.size, out.data());
850 return;
851 }
852 case OpType::Concat: {
853 out.resize(static_cast<size_t>(nd.size));
854 const float *ins[4] = {};
855 const int *dims[4] = {};
856 int ranks[4] = {};
857 int n = 2;
858 if (nd.in3 >= 0) n = 4;
859 else if (nd.in2 >= 0) n = 3;
860 const int ids[4] = {nd.in0, nd.in1, nd.in2, nd.in3};
861 for (int k = 0; k < n; ++k) {
862 ins[k] = in(ids[k]).data();
863 dims[k] = graph_.node(ids[k]).dims;
864 ranks[k] = graph_.node(ids[k]).rank;
865 }
866 kernels::concat(ins, dims, ranks, n, nd.i0, out.data(), nd.dims, nd.rank);
867 return;
868 }
869 case OpType::Slice: {
870 out.resize(static_cast<size_t>(nd.size));
871 const auto &X = graph_.node(nd.in0);
872 kernels::sliceOp(in(nd.in0).data(), X.dims, X.rank, nd.i0, nd.i1, nd.i2, out.data(),
873 nd.dims, nd.rank);
874 return;
875 }
879 case OpType::ReduceMax: {
880 out.resize(static_cast<size_t>(nd.size));
881 const auto &X = graph_.node(nd.in0);
882 kernels::reduceAxis(nd.type, in(nd.in0).data(), X.dims, X.rank, nd.i0, out.data(),
883 nd.dims, nd.rank);
884 return;
885 }
886 case OpType::ArgMax: {
887 out.resize(static_cast<size_t>(nd.size));
888 const auto &X = graph_.node(nd.in0);
889 kernels::argmax(in(nd.in0).data(), X.dims, X.rank, nd.i0, out.data(), nd.dims,
890 nd.rank);
891 return;
892 }
894 out.resize(static_cast<size_t>(nd.size));
895 const auto &Q = graph_.node(nd.in0);
896 const auto &K = graph_.node(nd.in1);
897 const int B = Q.dims[0], H = Q.dims[1], T = Q.dims[2], D = Q.dims[3];
898 const int S = K.dims[2];
899 kernels::sdpa(in(nd.in0).data(), in(nd.in1).data(), in(nd.in2).data(),
900 nd.in3 >= 0 ? in(nd.in3).data() : nullptr, B, H, T, S, D, nd.s0,
901 out.data());
902 return;
903 }
904 case OpType::Resize2d: {
905 out.resize(static_cast<size_t>(nd.size));
906 const auto &X = graph_.node(nd.in0);
907 kernels::resize2d(in(nd.in0).data(), X.dims, nd.dims[3], nd.dims[2], nd.i0,
908 out.data());
909 return;
910 }
911 }
912}
913
914} // namespace eve::tensor
double value
float w
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
int mask
float nx
std::string nodeId
int rows
int cols
tensor::Graph g
Definition GpuGraph.cpp:7
glm::uvec4 ids
uint32_t i1
Definition Grass.cpp:61
uint32_t i0
Definition Grass.cpp:61
glm::vec3 n
Definition Grass.cpp:63
std::array< double, 10 > q
std::vector< std::uint32_t > indices
float v
std::int32_t c
std::array< float, 3 > scale
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
std::vector< std::int32_t > order
std::map< std::string, std::vector< std::string > > graph
Definition Package.cpp:59
std::string id
Definition PlayHost.cpp:108
float begin
float d
float t
float bias
float m[16]
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
Optimized / scheduled graph ready to run with feeds.
Definition Graph.h:242
Tensor * run1(Tensor *in0)
Run 1.
Definition Graph.cpp:597
Tensor * run2(Tensor *in0, Tensor *in1)
Run 2.
Definition Graph.cpp:602
Tensor * run5(Tensor *in0, Tensor *in1, Tensor *in2, Tensor *in3, Tensor *in4)
Run 5.
Definition Graph.cpp:617
Tensor * run4(Tensor *in0, Tensor *in1, Tensor *in2, Tensor *in3)
Run 4.
Definition Graph.cpp:612
CompiledFunction()
Compiled function.
~CompiledFunction()
Compiled function.
Tensor * run3(Tensor *in0, Tensor *in1, Tensor *in2)
Run 3.
Definition Graph.cpp:607
Tensor * run6(Tensor *in0, Tensor *in1, Tensor *in2, Tensor *in3, Tensor *in4, Tensor *in5)
Run 6.
Definition Graph.cpp:622
Tensor * run0()
Run 0.
Definition Graph.cpp:595
static CompiledFunction * fromFunc(Func *fn)
From func.
Definition Graph.cpp:574
Trace builder — TF2 tf.function analogue (tf.func in scripts). While active, TF ops record into this ...
Definition Graph.h:137
Tensor * emitReduce(OpType type, const Tensor *x, int axis, bool keepDims)
Emit reduce.
Definition Graph.cpp:454
Tensor * emitCast(const Tensor *x, DType dtype)
Emit cast.
Definition Graph.cpp:507
Tensor * emitPermute(const Tensor *x, const int *order, int rank)
Emit permute.
Definition Graph.cpp:226
class CompiledFunction * compile()
Compiles compile.
Definition Graph.cpp:567
Tensor * input6(int d0, int d1, int d2, int d3, int d4, int d5)
Input 6.
Definition Graph.cpp:103
Tensor * emitResize2d(const Tensor *x, int outH, int outW, int mode)
Emit resize 2 d.
Definition Graph.cpp:547
Tensor * input4(int d0, int d1, int d2, int d3)
Input 4.
Definition Graph.cpp:91
Tensor * emitConcat(const Tensor *const *ins, int n, int axis)
Emit concat.
Definition Graph.cpp:401
Tensor * input1(int d0)
Input 1.
Definition Graph.cpp:73
Tensor * input5(int d0, int d1, int d2, int d3, int d4)
Input 5.
Definition Graph.cpp:97
Tensor * emitPool(OpType type, const Tensor *x, int ksize, int stride, int pad)
Emit pool.
Definition Graph.cpp:367
Tensor * emitSdpa(const Tensor *q, const Tensor *k, const Tensor *v, const Tensor *mask, float scale)
Emit sdpa.
Definition Graph.cpp:517
Tensor * emitBinary(OpType type, const Tensor *a, const Tensor *b)
Emit binary.
Definition Graph.cpp:162
Tensor * emitSoftmax(const Tensor *x, int axis, bool logMode)
Emit softmax.
Definition Graph.cpp:256
Tensor * emitConv1d(const Tensor *x, const Tensor *w, const Tensor *bias, int stride, int pad)
Emit conv 1 d.
Definition Graph.cpp:316
Tensor * emitTernary(OpType type, const Tensor *a, const Tensor *b, const Tensor *c)
Emit ternary.
Definition Graph.cpp:178
Tensor * emitFill(const int *dims, int rank, float value)
Emit fill.
Definition Graph.cpp:133
Func(TF *owner)
Func.
Definition Graph.cpp:20
void setOutput(Tensor *t)
Sets the output.
Definition Graph.cpp:109
Tensor * emitEmbedding(const Tensor *table, const Tensor *indices)
Emit embedding.
Definition Graph.cpp:383
Tensor * emitConv2d(const Tensor *x, const Tensor *w, const Tensor *bias, int stride, int pad)
Emit conv 2 d.
Definition Graph.cpp:341
Tensor * emitArgMax(const Tensor *x, int axis, bool keepDims)
Emit arg max.
Definition Graph.cpp:480
Tensor * emitMatMul(const Tensor *a, const Tensor *b)
Emit mat mul.
Definition Graph.cpp:191
Tensor * emitUnaryScalar(OpType type, const Tensor *x, float s0, float s1=0.f)
Emit unary scalar.
Definition Graph.cpp:150
Tensor * input2(int d0, int d1)
Input 2.
Definition Graph.cpp:79
Tensor * emitReshape(const Tensor *x, const int *dims, int rank)
Emit reshape.
Definition Graph.cpp:244
Tensor * emitSlice(const Tensor *x, int axis, int begin, int end)
Emit slice.
Definition Graph.cpp:436
Tensor * emitUnary(OpType type, const Tensor *x)
Emit unary.
Definition Graph.cpp:140
Tensor * emitTranspose(const Tensor *x)
Emit transpose.
Definition Graph.cpp:218
Tensor * input3(int d0, int d1, int d2)
Input 3.
Definition Graph.cpp:85
int ensureNode(const Tensor *t)
Ensure tensor is a node in this graph (Const-capture if eager).
Definition Graph.cpp:114
Tensor * emitLayerNorm(const Tensor *x, const Tensor *scale, const Tensor *bias, float eps)
Emit layer norm.
Definition Graph.cpp:277
Tensor * emitRMSNorm(const Tensor *x, const Tensor *scale, float eps)
Emit rms norm.
Definition Graph.cpp:299
static GpuProgram * tryBuild(const Graph &graph, const OptimizedGraph &opt, int outputNode)
Try build.
int addNode(GraphNode node)
Adds node.
const GraphNode & node(int id) const
Node.
Definition Graph.h:116
int nodeCount() const
Node count.
Definition Graph.h:120
static int product(const int *dims, int rank)
Product.
TF2-like namespace module. Script: tf <- eve.TF(); Default eager; tf.func() traces a graph for compil...
Definition TF.h:20
void popTrace(Func *f)
Pops trace.
Definition TF.cpp:77
void pushTrace(Func *f)
Pushes trace.
Definition TF.cpp:73
float32 / int32 tensor (rank 1–6), row-major. Eager: owns a buffer. Symbolic: node in a Func graph (n...
Definition Tensor.h:48
void ensureEager(const char *op) const
Ensure eager.
Definition Tensor.cpp:136
static constexpr int kMaxRank
Definition Tensor.h:50
float * data()
原始数据指针(eager)。
Definition Tensor.cpp:185
static Tensor * makeSymbolic(Graph *graph, int nodeId, const int *dims, int rank)
Symbolic handle into a graph node.
Definition Tensor.cpp:122
void maxpool2d(const float *in, const int *dims, int ksize, int stride, int pad, float *out)
Maxpool 2 d.
void conv2d(const float *x, const int *xDims, const float *w, const int *wDims, const float *bias, int stride, int pad, float *out)
Conv 2 d.
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)
Sdpa.
void sliceOp(const float *in, const int *inDims, int inRank, int axis, int begin, int end, float *out, const int *outDims, int outRank)
Slice op.
void embedding(const float *table, int vocab, int dim, const float *indices, int count, float *out)
Embedding.
void avgpool2d(const float *in, const int *dims, int ksize, int stride, int pad, float *out)
Avgpool 2 d.
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)
Binary op.
void permute(const float *in, const int *inDims, int rank, const int *order, float *out, const int *outDims)
Permute.
void reduceAxis(OpType type, const float *in, const int *dims, int rank, int axis, float *out, const int *outDims, int outRank)
Reduce axis.
bool broadcastShape(const int *aDims, int aRank, const int *bDims, int bRank, int *outDims, int &outRank)
Broadcast shape.
void argmax(const float *in, const int *dims, int rank, int axis, float *out, const int *outDims, int outRank)
Argmax.
void layernorm(const float *in, int rows, int cols, const float *scale, const float *bias, float eps, float *out)
Layernorm.
void rmsnorm(const float *in, int rows, int cols, const float *scale, float eps, float *out)
Rmsnorm.
void softmax(const float *in, const int *dims, int rank, int axis, bool logMode, float *out)
Softmax.
void concat(const float *const *ins, const int *const *inDims, const int *inRanks, int n, int axis, float *out, const int *outDims, int outRank)
Concat.
void conv1d(const float *x, const int *xDims, const float *w, const int *wDims, const float *bias, int stride, int pad, float *out)
Conv 1 d.
void unaryOp(OpType type, const float *in, int count, float *out, float s0, float s1)
Unary op.
void resize2d(const float *in, const int *inDims, int outW, int outH, int mode, float *out)
Resize 2 d.
int axis(int64_t a, size_t rank)
Axis.
void dequantizeAll(DType dt, const uint8_t *bytes, const float *scales, int group, int count, float *out)
Dequantize all.
Definition Quant.h:234
DType
Tensor element types.
Definition Tensor.h:24
OpType
OpType public API.
Definition Graph.h:22
OptimizedGraph optimizeGraph(const Graph &graph, int outputNode)
Optimize graph.
SettlementPipeline::Stage fn
GraphNode public API.
Definition Graph.h:80
int dims[Tensor::kMaxRank]
Definition Graph.h:82
uint32_t pad[2]