InFeeo
Language

PrintGuard 2.0 — ShuffleNetV2 + few-shot prototypical network, TFLite via LiteRT, ≈5 MB, runs unmodified in the browser (Pyodide) and on CPython [P](reddit.com)

×
Link preview PrintGuard 2.0 — ShuffleNetV2 + few-shot prototypical network, TFLite via LiteRT, ≈5 MB, runs unmodified in the browser (Pyodide) and on CPython [P] Hi everyone, I shared PrintGuard here about a year ago as a few-shot FDM failure detector built on a ShuffleNetV2 backbone classified by a prototypical network — the model from my dissertation, packaged with a hub and a web UI. v2.0 ships today and is a complete rewrite of everything around the model, so I wanted to walk you through what's changed and what hasn't. What hasn't changed is the model. It's still a ShuffleNetV2 encoder classified by nearest prototype, trained for few-shot FDM fault detection in Edge-FDM-Fault-Detection (with a technical write-up in the repo). What has changed is the runtime: the model is now a ≈5 MB TFLite export via LiteRT, classified by nearest prototype, with per-printer sensitivity and threshold sliders that map directly onto the prototype distances — so you can tune for camera and lighting without retraining. The interesting bit for this sub is the architecture around the model. v2.0 is a single Python engine that runs unmodified on CPython (hub mode) and on Pyodide in the browser (local mode). Everything mode-specific is confined to one Platform implementation per runtime — the two modes cannot drift apart because they execute the same files. The methods on the Platform contract are exactly the ones that aren't portable: infer(rgb), discover_cameras(), open_camera(id, source), http(...), encode_jpeg(rgb), load_state / save_state. On the CPython side, infer is ai-edge-litert on CPU threads, discover_cameras walks the MediaMTX path list, and open_camera is a PyAV reader thread per RTSP stream. On the browser side, infer is LiteRT.js in WASM via a JS bridge, discover_cameras is enumerateDevices(), and open_camera is getUserMedia + canvas grabs. The UI is presentation-only and speaks one JSON command/event protocol — over a WebSocket in hub mode, over an in-page Pyodide bridge in local mode. The engine cannot tell which transport it is on. No mode-specific logic lives anywhere else; if a feature needs a runtime service, it extends the Platform contract on both sides. Inference scheduling is fully dynamic and fairness-aware: A smoothed estimate of observed inference latency continuously yields the sustainable total rate (workers / latency). That capacity is water-filled across in-use cameras (max-min fairness): no camera is allocated beyond its native fps, and surplus flows to cameras that can use it. A free worker takes the most overdue camera and grabs its freshest frame at dispatch time. Frames carry a sequence identity, so the same frame is never inferred twice, and results always describe the present, not a backlog. On RTSP, MediaMTX bursts the buffered GOP on connect, so stream fps is trusted from the SDP average_rate where available, and measured only after a warm-up otherwise. The defect pipeline is a monitor on top of a per-printer score stream. score ≥ threshold for N consecutive frames triggers the configured action (alert only, pause, or cancel) on the linked OctoPrint or Moonraker service, with retries on failure; the alert event carries the action and its outcome, the UI error feed gets a copy, and the snapshot goes out to every enabled notification channel (ntfy, Telegram, Discord). The fail-safe behaviour is the part I most want feedback on, because I have strong opinions about it. A printer's watching state gates inference: Linked service reports Watched? Why no service linked yes nothing to gate on printing yes the job needs eyes no state yet / unknown yes can't tell → watch offline (unreachable) yes losing the signal must not stop monitoring idle / paused / error no (standby) positively not printing Only a positive "not printing" stands inference down. The watchdog then warns on the dashboard and through notification channels when a camera drops, a feed freezes or a printer service stops answering, and a failed pause is announced, never swallowed. I'd be very interested to hear how this stance interacts with people who run multiple printers with mixed reliability on their printer services. There's a live browser demo (the whole engine in Pyodide + LiteRT.js WASM), the Docker image is multi-arch, and the architecture doc goes into all of the above in more detail with diagrams of the engine layout and the defect pipeline. This is a major version — nothing from 1.x migrates, and a 2.0 hub starts from a fresh configuration. Issues, especially around the fairness scheduler, the CORS / mixed-content / host.docker.internal edge cases, and the LiteRT ↔ Pyodide bridge, are very welcome. Let's keep failure detection open-source, local and accessible for all. submitted by /u/oliverbravery [link] [Kommentare] reddit.com · reddit.com
Hi everyone, I shared PrintGuard here about a year ago as a few-shot FDM failure detector built on a ShuffleNetV2 backbone classified by a prototypical network — the model from my dissertation, packaged with a hub and a web UI. v2.0 ships today and is a complete rewrite of everything around the model, so I wanted to walk you through what's changed and what hasn't. What hasn't changed is the model. It's still a ShuffleNetV2 encoder classified by nearest prototype, trained for few-shot FDM fault detection in Edge-FDM-Fault-Detection (with a technical write-up in the repo). What has changed is the runtime: the model is now a ≈5 MB TFLite export via LiteRT, classified by nearest prototype, with per-printer sensitivity and threshold sliders that map directly onto the prototype distances — so you can tune for camera and lighting without retraining. The interesting bit for this sub is the architecture around the model. v2.0 is a single Python engine that runs unmodified on CPython (hub mode) and on Pyodide in the browser (local mode). Everything mode-specific is confined to one Platform implementation per runtime — the two modes cannot drift apart because they execute the same files. The methods on the Platform contract are exactly the ones that aren't portable: infer(rgb), discover_cameras(), open_camera(id, source), http(...), encode_jpeg(rgb), load_state / save_state. On the CPython side, infer is ai-edge-litert on CPU threads, discover_cameras walks the MediaMTX path list, and open_camera is a PyAV reader thread per RTSP stream. On the browser side, infer is LiteRT.js in WASM via a JS bridge, discover_cameras is enumerateDevices(), and open_camera is getUserMedia + canvas grabs. The UI is presentation-only and speaks one JSON command/event protocol — over a WebSocket in hub mode, over an in-page Pyodide bridge in local mode. The engine cannot tell which transport it is on. No mode-specific logic lives anywhere else; if a feature needs a runtime service, it extends the Platform contract on both sides. Inference scheduling is fully dynamic and fairness-aware: A smoothed estimate of observed inference latency continuously yields the sustainable total rate (workers / latency). That capacity is water-filled across in-use cameras (max-min fairness): no camera is allocated beyond its native fps, and surplus flows to cameras that can use it. A free worker takes the most overdue camera and grabs its freshest frame at dispatch time. Frames carry a sequence identity, so the same frame is never inferred twice, and results always describe the present, not a backlog. On RTSP, MediaMTX bursts the buffered GOP on connect, so stream fps is trusted from the SDP average_rate where available, and measured only after a warm-up otherwise. The defect pipeline is a monitor on top of a per-printer score stream. score ≥ threshold for N consecutive frames triggers the configured action (alert only, pause, or cancel) on the linked OctoPrint or Moonraker service, with retries on failure; the alert event carries the action and its outcome, the UI error feed gets a copy, and the snapshot goes out to every enabled notification channel (ntfy, Telegram, Discord). The fail-safe behaviour is the part I most want feedback on, because I have strong opinions about it. A printer's watching state gates inference: Linked service reports Watched? Why no service linked yes nothing to gate on printing yes the job needs eyes no state yet / unknown yes can't tell → watch offline (unreachable) yes losing the signal must not stop monitoring idle / paused / error no (standby) positively not printing Only a positive "not printing" stands inference down. The watchdog then warns on the dashboard and through notification channels when a camera drops, a feed freezes or a printer service stops answering, and a failed pause is announced, never swallowed. I'd be very interested to hear how this stance interacts with people who run multiple printers with mixed reliability on their printer services. There's a live browser demo (the whole engine in Pyodide + LiteRT.js WASM), the Docker image is multi-arch, and the architecture doc goes into all of the above in more detail with diagrams of the engine layout and the defect pipeline. This is a major version — nothing from 1.x migrates, and a 2.0 hub starts from a fresh configuration. Issues, especially around the fairness scheduler, the CORS / mixed-content / host.docker.internal edge cases, and the LiteRT ↔ Pyodide bridge, are very welcome. Let's keep failure detection open-source, local and accessible for all. submitted by /u/oliverbravery [link] [Kommentare]

Log in Log in to comment.

No comments yet.