File size: 3,493 Bytes
bb9db96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
---

license: apache-2.0
library_name: pytorch
pipeline_tag: tabular-classification
tags:
  - executorch
  - zephyr
  - tinyml
  - anomaly-detection
  - time-series
  - industrial
  - cortex-m
  - int8
datasets:
  - eoinedge/heater-anomaly-windows
metrics:
  - accuracy
  - precision
  - recall
model-index:
  - name: AnomalyNet
    results:
      - task:
          type: tabular-classification
          name: Temperature-window anomaly detection
        dataset:
          type: eoinedge/heater-anomaly-windows
          name: heater-anomaly-windows (test split)
        metrics:
          - type: accuracy
            value: 0.9962
          - type: precision
            value: 1.0
          - type: recall
            value: 0.9925
---


# AnomalyNet

An 842-parameter MLP that looks at 32 consecutive temperature samples (3.2 s at 10 Hz) and
says whether the window is normal or contains an anomaly: a spike, a dropout, a runaway
ramp or a burst of noise. It is the "second brain" in my dual-brain PLC demos: ExecuTorch
runs it on the microcontroller next to a ladder-logic scan task or a Linux SoC, and only a
shared variable (`p(anomaly)`) crosses between them.

```

fc1 32->24, ReLU

fc2 24->2            logits [normal, anomaly]

```

Input: `(1, 32)` float, Celsius normalised as `(t - 50) / 20`. Output: 2 logits; softmax
gives `p(anomaly)`.

## Files

| File | What |
|---|---|
| `anomaly_net.py` | model definition and the normalisation constants |
| `anomaly_net.pt` | trained state dict, fp32 |
| `executorch/fp32.pte` | ExecuTorch program, portable fp32 kernels (5.5 KB) |
| `executorch/int8-cmsis-m0plus.pte`, `-m4.pte`, `-m33.pte`, `-m7.pte` | int8 via the ExecuTorch Cortex-M quantizer (3.6 KB) |
| `tflite/fp32.tflite`, `tflite/int8.tflite` | the same weights through a Keras twin for TensorFlow Lite Micro |
| `test_vectors.h` | one normal and one anomaly window with reference logits |

## Results

Held-out synthetic windows (dataset test split, 4,000 windows, 50 % anomalies):

| Metric | Value |
|---|---|
| Accuracy | 99.62 % |
| Precision | 100 % |
| Recall | 99.25 % |
| Parameters | 842 |
| Inference, STM32U585 @ 160 MHz, fp32 | 1.6 ms |
| Inference, nRF52833 @ 64 MHz, fp32 | 4.3 ms |
| Inference, nRF9160 @ 64 MHz, fp32 | 4.0 ms |

## Training

Synthetic data only: the generator in `train/train_anomaly.py` of the
[UNO Q repo](https://github.com/eoinjordan/executorch-zephyr-arduino-uno-q) simulates a
heater loop around 50 C with slow drift and sensor noise, and injects four anomaly types.
The same generator produced the
[heater-anomaly-windows](https://huggingface.co/datasets/eoinedge/heater-anomaly-windows)
dataset. Adam, cross-entropy, a few hundred epochs on CPU in under a minute.

## Where it runs

- [executorch-zephyr-arduino-uno-q](https://github.com/eoinjordan/executorch-zephyr-arduino-uno-q): STM32U585 + Linux side, 13x8 LED matrix chart
- [executorch-zephyr-arduino-opta](https://github.com/eoinjordan/executorch-zephyr-arduino-opta): beside a ladder-logic scan task on a PLC
- micro:bit v2, Thingy:91, LAUNCHXL-CC1352P1 self-tests, and the
  [ExecuTorch vs TFLM benchmarks](https://github.com/eoinjordan/executorch-vs-tflm-benchmarks)

Background: [AI for Industrial Control Systems: Bringing Edge AI to PLCs](https://www.edgeimpulse.com/blog/transform-industrial-control-systems-with-ai-anomaly-detection-made-easy/).

## License

Apache-2.0.