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