File size: 3,674 Bytes
437c134
 
 
 
 
 
 
 
 
 
 
 
 
 
f53d7e4
 
 
 
 
 
437c134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
---
license: other
tags:
  - eating-detection
  - wearable
  - ppg
  - accelerometer
  - time-series
---

# EatingDetection checkpoint

Ten leave-one-participant-out checkpoints for binary eating detection from the
smart earring — green PPG + tri-axial accelerometer, no gyroscope, no
microphone.

Trained on the 8-second windowed split of a 10-participant earring study. The
study data is not public yet, so these weights are released ahead of it: the
model, the evaluation protocol and the per-fold scores are all here, but the
numbers below cannot be re-derived from raw data until the dataset is released.

Code: https://github.com/FengYe476/Eating_Detection/tree/Feng/eating_detection

## Result

| | macro-F1 |
|---|---:|
| **Pooled over all held-out decisions** | **0.9535** |
| Mean over the 10 participants | 0.9486 ± 0.0253 |

Same ten models, two reductions: pooling concatenates every held-out decision
and scores once (each window counts equally); the per-participant mean scores
each fold then averages (each person counts equally).

| P2 | P3 | P4 | P5 | P7 | P8 | P9 | P10 | P11 | P12 |
|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
| .944 | .947 | .947 | .947 | .960 | .996 | .913 | .901 | .964 | .966 |

`checkpoint_scores.json` holds the per-fold table, including the score stored
inside each checkpoint at training time — re-scoring reproduces all ten to four
decimals.

## Files

`fold_P<user>.pt` — one per held-out participant. **`fold_P<u>.pt` never saw
participant `<u>`** during training, standardisation or checkpoint selection;
that is what makes its score subject-independent. For a participant outside this
cohort, any fold is equally valid.

Each file is a dict: `state_dict`, `mu`, `sd` (per-channel standardisation fitted
on that fold's training subjects), `channels`, `window_samples`, `in_channels`,
`test_user`, `val_f1`, `test_macro_f1`.

## Model

`CoincidenceTCN`, **9,433 parameters**. Input `(N, 4, 400)` — 8 s at 50 Hz,
channel order **`[ppg_green, acc_x, acc_y, acc_z]`**. Output: one logit per
window; eating if `logit > 0`.

```python
import torch
from eating_detection.models.coincidence_tcn import CoincidenceTCN

d = torch.load("fold_P2.pt", map_location="cpu", weights_only=False)
m = CoincidenceTCN(d["in_channels"]); m.load_state_dict(d["state_dict"]); m.eval()

X = ...                                   # (N, 4, 400) float32, raw window values
X = (X - d["mu"]) / d["sd"]               # the fold's own statistics — do not refit
eating = m(torch.from_numpy(X.astype("float32"))) > 0
```

## Evaluation protocol

10-fold leave-one-participant-out over P2, P3, P4, P5, P7, P8, P9, P10, P11,
P12; both earrings merged as independent windows; 8 s windows on a 1 s stride.
Negatives follow "Strategy-2": every eating window, every idle window within two
minutes of eating, and far background idle subsampled to 1:1 with eating — so
majority-class accuracy would be 0.62, not 0.9.

Reported as macro-F1 with the decision fixed at `logit > 0`; no per-participant
threshold selection and no per-participant calibration.

## Reading these numbers honestly

- Negatives are not uniformly hard: false-positive rate is 0.138 on pauses
  *inside* a food block against 0.039 on rest *between* blocks. Hard-negative
  balanced accuracy is **0.90** — quote that for a deployment claim.
- P9 and P10 fail in opposite directions (under-detection and over-alarming) and
  do so reproducibly; the decision rule has no threshold selection.
- Run-to-run spread for this configuration is about 0.8 pp, and CUDA vs MPS
  alone moves it 0.3–0.4 pp. A single run does not separate two configurations
  that differ by ~1 pp.