- nFlow
- Status (implemented & verified)
- Verified ONNX interop ✅
- Extensible custom ops (Rhai)
- Real execution (Simulate)
- Composite nodes (build new nodes from fundamentals)
- Example: generated code
- Architecture (data-flow)
- Build & run
- High-performance graph rendering (why these choices)
- Repo layout
- License
- Generated by ML Intern
- Usage
- Status (implemented & verified)
nFlow
A node-based visual deep-learning model creator — design models as graphs, see live tensor shapes as you wire nodes, and design models, run real CPU inference, and export to PyTorch / ONNX. Built as a cross-platform Tauri v2 desktop app: Rust core (authoritative graph IR + shape-inference engine) + React/xyflow frontend.
Architecture & research docs live in the companion repo:
krystv/nflow-architecture-spec(SRS, ENGINE, ONNX_BASELINE).
Status (implemented & verified)
| Layer | Crate / dir | Verified |
|---|---|---|
| Graph IR (slotmap SSA, types, affine Dim algebra) | crates/nflow-ir |
✅ cargo test (6) |
| Inference (DimSolver unify/assume, broadcast) | crates/nflow-infer |
✅ cargo test (7) |
| Operators (Layer-0 prims + composites + Rhai custom ops) | crates/nflow-ops |
✅ cargo test (14) |
| Session (event-sourced undo/redo + live inference + view) | crates/nflow-events |
✅ cargo test (6) |
| Exporters (PyTorch + ONNX text & binary protobuf) | crates/nflow-codegen |
✅ cargo test (5) |
Execution (Backend trait + CPU evaluator, real numeric inference) |
crates/nflow-exec |
✅ cargo test (4) |
Tauri v2 IPC backend (incl. export_code) |
src-tauri |
builds with Tauri toolchain |
| Frontend (3-pane pro UI, xyflow, dark design system) | src/ |
✅ npm run build |
54 backend tests pass across 6 crates. The shape engine genuinely infers e.g. a ResNet stem Conv2D([B,3,224,224], [64,3,7,7], stride=2, pad=3) → [B,64,112,112] symbolically.
Verified ONNX interop ✅
nFlow exports a real binary .onnx (hand-encoded ModelProto, opset 21). Verified this session: the exported MatMul→Add→Relu model passes onnx.checker and runs in onnxruntime, matching the reference relu(x@w+b) numerically. Download via Export → .onnx.
Extensible custom ops (Rhai)
Researchers define a new op's shape logic in a Rhai script (fn infer(inputs)), loaded at runtime — no recompile (ENGINE §6.3). Verified with a double_last op.
Real execution (Simulate)
The Backend trait + a pure-Rust CPU evaluator actually compute the graph: x@w+b → relu with inputs returns the exact numeric tensor (verified in tests). A burn-wgpu backend implements the same trait for GPU — scaffolded behind the off-by-default wgpu feature (cargo test -p nflow-exec --features wgpu on a GPU host); the portable build/tests never depend on a GPU. This is the SRS §7.2 abstraction proven end-to-end.
Composite nodes (build new nodes from fundamentals)
nn.linear, nn.silu, nn.attention are composites defined purely as a decomposition into Layer-0 primitives (PyTorch-style). The inline pass materializes them, so inference, export, and (future) execution work with zero extra code — attention → transpose → matmul → softmax → matmul. New high-level nodes need only an expand() recipe. Export auto-inlines composites so they emit as primitives; double-click a Block node to "dive in" and edit its primitives.
Example: generated code
A 3-node graph x @ w + b -> relu exports (verified, AST-valid Python) to:
class Model(torch.nn.Module):
def forward(self, x, w, b):
v0 = torch.matmul(x, w)
v1 = v0 + b
v2 = F.relu(v1)
return v2
and to ONNX text MatMul -> Add -> Relu carrying inferred symbolic shapes [s0, 4].
Revision highlights (robustness + UX)
- Snapshot-based undo/redo — uniform across every edit (add/connect/disconnect/delete/attr/move/dive-in); eliminates the prior "undo not implemented" gaps. O(1) node-id index with a graph-scan fallback.
- Edge-case guards: rejects self-connections, cycles (DAG-preserving), dtype-mismatched wires;
deletecleans up orphaned edges; missing-node intents fail gracefully; inference surfaces shape errors as per-node diagnostics (never panics). - Cost model: real params + FLOPs per node and model totals (conv 3→64 7×7 = 9.4K params, verified), symbolic dims marked as estimates.
- LLM-builder composites:
nn.linear,nn.layernorm,nn.feedforward,nn.mha,nn.transformer_block(composite-of-composites) — drop one node, export a full transformer; all lower to primitives for ONNX/PyTorch. - UX: live cost HUD, model-totals + dive-in in the inspector, one-click Template (transformer), error toasts for rejected edits, a status bar (validity / node·edge counts / assumptions), Delete-key + edge-delete→disconnect.
Architecture (data-flow)
React/xyflow UI --invoke(intent)--> Tauri command --> Session.apply()
^ |
| GraphView (nodes+edges+live shapes+assumptions) <------ run_inference()
The Rust core is the single source of truth; the UI is a read-only projection. Every edit is a reversible event (undo/redo). Shapes are inferred in Rust and streamed to the UI.
Beta UI repair — declared input ports
Fixed a critical graph-model bug: node input handles are now rendered from the operator/composite declared port contract, not only from already-connected inputs. Newly added nodes like math.matmul show both a and b input ports immediately; composites like nn.linear show x, w, b before wiring. This is locked by regression tests.
Fixes this revision
- Performance + draggable nodes: Canvas now uses xyflow local state (
useNodesState/useEdgesState); syncs from the backend only on topology/shape changes and commits moves on drag-stop. Removedtransition-allfrom nodes. No more full re-render on every mouse move. - Input / Output nodes: every model starts from an
io.input(configurable shape/dtype) and ends at anio.output. New projects are seeded withInput → Output. Graph validity is enforced and shown in the status bar; ONNX export registers Input as a graph input / Output as the graph output (verified: passesonnx.checker+ runs inonnxruntime).
Build & run
Workspace note:
src-tauriis a workspace member (required sotauri dev/cargo metadataresolve).default-memberspoints at the pure crates, socargo testat the root is fast and needs no GPU/webkit;tauri devbuildssrc-tauriexplicitly.
Prerequrisites: Rust (stable), Node 20+, and the Tauri v2 system deps (webkit2gtk etc. — see https://tauri.app/start/prerequisites/).
npm install
# Rust core tests (no GUI deps needed):
cargo test
# Dev (desktop app with hot-reload frontend):
npm run tauri dev
# Production bundle:
npm run tauri build
# Frontend-only preview (uses an in-browser mock of the Rust engine):
npm run dev
High-performance graph rendering (why these choices)
Heavy graphs must never hang the UI. Decisions:
- xyflow (React Flow) with
onlyRenderVisibleElements— viewport virtualization renders only on-screen nodes, so 1000+ node graphs stay smooth. - Backend does all heavy work. Shape inference, validation, and graph mutation run in Rust off the webview thread; the UI only renders the resulting
GraphView. The webview main thread is never blocked by computation. - Move coalescing. Node drags commit to the core only on drag-stop (not every frame), keeping IPC traffic minimal (SRS §5.3).
memo-ised custom nodes + fine-grained zustand selectors → only changed nodes re-render.- Dotted canvas background + smoothstep edges are GPU-cheap; the minimap uses a flat node color function (no per-node React render).
- Future: for >5k nodes, swap the xyflow renderer layer for a WebGL edge/node layer while keeping the same
GraphViewcontract.
Repo layout
crates/ # Rust workspace: ir, infer, ops, events (pure, fully tested)
src-tauri/ # Tauri v2 desktop backend (IPC commands)
src/ # React 19 + xyflow + Tailwind v4 frontend
bridge/ # the ONLY place that talks to Rust (typed invoke + dev mock)
store/ # zustand read-only view projection
editor/ # xyflow canvas + custom NFlowNode
panels/ # Header, palette (SidebarLeft), inspector (SidebarRight)
License
Apache-2.0
Generated by ML Intern
This model repository was generated by ML Intern, an agent for machine learning research and development on the Hugging Face Hub.
- Try ML Intern: https://smolagents-ml-intern.hf.space
- Source code: https://github.com/huggingface/ml-intern
Usage
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = 'krystv/nflow'
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
For non-causal architectures, replace AutoModelForCausalLM with the appropriate AutoModel class.