Show HN: I have trained 15 blood glucose forecasting models on my own data
Hacker News

Show HN: I have trained 15 blood glucose forecasting models on my own data

Caution

Research and educational use only - not a medical device. T1DMAI is a research artifact. It is not clinically validated, has no regulatory clearance, and its output is a forecast of research signals, not medical advice. It must not be used to make medical, diagnostic, or treatment decisions, to calculate or adjust insulin doses, or to manage diabetes in any way. For medical guidance consult a qualified healthcare professional. The software is provided "as is", without warranty of any kind (see LICENSE).

Note

Most of the code in this repo was written by AI. If you don't like that, feel free to leave.

This repo is a zoo. Here I train & test many blood glucose forecasting models (including my own) on both my own data and metabonet (public).

My model is a small transformer that forecasts blood glucose 2 hours ahead. I've made two variants: D16 DILATE and D16 MSE which use DILATE and MSE loss for training, respectively. D16 refers to the width of the model (16).

They are both trained on synthetic traces, and then a LoRA adapter is added for light fine-tuning, but I also test them without the adapter.

Feast thine eyes on some of their forecasts (these have been trained on synthetic traces, then fine-tuned with a LoRA adapter on my training split):

Background

I have type 1 diabetes and I wanna know if I can train a BG forecasting model to help me with my daily management. To this end I've made some auxiliary tools:

  • T1DMSIM creates synthetic CGM traces since UVA/Padova was too slow on my laptop.
  • T1DMDROID runs the models on my phone, also has some neat functionality like reading BG from multiple CGMs at once.

For evaluation, I use the recommendations by Jacobs et al., IEEE Reviews in Biomedical Engineering, 2024 [1]. It's a nice paper that you should probably read.

Main results

All models suck. XGBoost is the best one but my own model comes close. More details below:

  • On my data, D16 DILATE + LoRA comes 3rd of 26 (22.8), behind XGBoost (22.2) and LightGBM (22.4). Wilcoxon puts it level with both at 60 and 90 min, behind them at 30 and 120.
  • On MetaboNet, D16 DILATE + LoRA comes 9th (34.6) but has the lowest RMSE of all models at 90 min. XGBoost leads at 30, 60 and 120.
  • At 60 min a 3771 parameter LoRA adapter helps both models on both datasets: 26.1 to 22.8 and 27.1 to 23.5 on my data, 36.6 to 34.6 and 36.7 to 35.1 on MetaboNet. At 120 min on MetaboNet it makes D16 DILATE worse (48.0 to 50.4).
  • On MetaboNet, LoRA also fixes the bands. The 90% band holds the truth 75-78% of the time at 60 min with sim only and 81-85% with LoRA. On my data both are 83-85%.
  • T1DMAI + LoRA reacts earliest on my data: 40-50 min time gain at 60 min, against 30 for XGBoost.
  • It also catches the most lows on my data: 40-47% at 60 min, against 29% for XGBoost. On MetaboNet every low-RMSE model misses nearly all lows (XGBoost 0%, T1DMAI 6-8%), while linear extrapolation catches 58%.
  • LightGBM matches XGBoost within 0.2 mg/dL everywhere. An LSTM with 15 hours of history comes 3rd on MetaboNet (33.6 at 60 min), against 35.9 for the 2 hour one.
  • Zero-shot Chronos-2 and TimesFM 2.5 beat zero-shot Chronos-Bolt by 1.4-2.7 mg/dL at 60 min on both datasets, but trail fine-tuned Chronos-Bolt.

Models

Model Family Description
Persistence Baseline Last reading carried forward.
Linear extrapolation Baseline Straight line through the last few readings.
AR (ridge) Classical Linear regression on recent glucose.
ARX (ridge) Classical Linear regression on recent glucose, insulin and carbs.
ARIMA Classical Glucose only.
SARIMAX Classical With insulin and carbs.
Kalman filter Classical Damped local linear trend.
SVR Classical Glucose, insulin and carbs.
Sparse GP Classical 1000 inducing points.
XGBoost Classical Glucose, insulin and carbs [18].
LightGBM Classical Same features, depth, rate and rounds as XGBoost [19].
LSTM Deep 2 hours of history [5].
LSTM (15 h) Deep Two layers of 128 over 15 hours, as in MetaboNet-Bench [3].
GluNet Deep Dilated causal convolutions over 4 hours [6].
PatchTST Deep [13]
N-HiTS Deep [14]
Chronos-Bolt tiny and mini Foundation 9M and 21M parameters, glucose only, zero-shot and fine-tuned [15].
Chronos-2 Foundation 120M parameters, zero-shot. Past insulin and carbs; on my data also the future ones [16].
TimesFM 2.5 Foundation 200M parameters, zero-shot. Glucose only on MetaboNet; on my data future insulin and carbs through in-context regression [17].
T1DMAI D16 DILATE and D16 MSE T1DMAI 31k parameters. Glucose, carbs and insulin.

Numbers in brackets point to References.

Everything except the baselines and the foundation models was trained from scratch on each dataset's training split. T1DMAI comes in two versions: sim only is the checkpoint in models/, and sim + LoRA adds a frozen-base rank 1 adapter [23] (3771 parameters) trained on the real training split.

T1DMAI details:

| Architecture | encoder-only transformer, 30 min patches, one attention head, RoPE [26], SwiGLU |
| Size | 16 layers of width 16, 31k parameters |
| Loss | 7 quantile pinball loss plus a median term (DILATE [25] on soft-DTW [24], or MSE) |
| Inputs | CGM in a risk-scaled space, carb absorption curve, insulin action curve, mask bit |
| Output | 7 quantiles (5% to 95%) for every 5 minute step of the next 2 hours |
| History | up to 7 days |
| Simulator training | 1M simulated people, 7 days each, 10000 steps of batch 512 |
| Runtime | ExecuTorch or LiteRT, on the phone in T1DMDROID |

More in docs/USAGE.md and ARCHITECTURE.md.

Data

My data. 115 days from T1DMDROID: days 1 to 80 for training, 81 to 115 for testing. Note that the model sees future inputs like insulin & carbs. I should probably also train the adapters while withholding those inputs.

Source Subjects Person-days Forecasts CGM coverage % Mean mg/dL CV % 180 % > 250 %
t1dmdroid 1 35 9764 97 130 28 0.4 3.0

MetaboNet [2]. Official split, 279 test people from 9 studies. Blind, because most of them use closed-loop pumps whose future insulin reacts to glucose the model hasn't seen.

Source Subjects Person-days Forecasts CGM coverage % Mean mg/dL CV % 180 % > 250 %
AZT1D 4 131 775 99 141 30 0.3 1.3
BrisT1D 2 312 1953 77 144 33 0.2 1.8
CTR3 5 1157 1052 51 141 38 0.7 3.5
HUPA-UCM 4 315 896 100 132 36 0.9 6.8
IOBP2 62 4737 14653 84 159 37 0.4 2.0
Loop 159 47438 203538 93 139 40 0.7 3.9
PEDAP 6 2070 6321 85 158 38 0.4 2.4
ReplaceBG 35 7967 35683 87 158 41 1.0 4.2
ShanghaiT1DM 2 19 28 33 159 39 1.0 3.8
All 279 64146 264899 90 143 40 0.7 3.7

Method

| My data | MetaboNet |
|---|---|
| Forecasts | every 5 min of the test days | every 10th row of the leaderboard template |
| Horizons | 30, 60, 90, 120 min | 30, 60, 90, 120 min |
| Training windows, other models | 60000 | 351000 (200000 for fine-tuned Chronos) |
| LoRA steps | 2000 | 6000 |

  • LoRA checkpoints are picked by mean RMSE on the last 10 days of each subject's training data.
  • All models forecast at the same moments.
  • 95% intervals: bootstrap over people (MetaboNet) or days (my data).
  • Significance: Wilcoxon signed-rank on paired absolute errors against the best model, Bonferroni corrected.
  • Clinical error grids: DTS [20], Clarke [22], CG-EGA [21].
Model Parameter count Microseconds per forecast History used
Persistence 0 0.0042 5 min
Linear extrapolation 0 0.033 30 min
AR (ridge) 648 0.13 2 h
SARIMAX 8,088 0.21 8 h
ARIMA 4,632 0.27 4 h
ARX (ridge) 1,116 0.36 6 h
Kalman filter 864 0.48 3 h
SVR 69,772 4.2 6 h
Sparse GP 66,134 6.1 6 h
N-HiTS 417,772 6.5 6 h
LSTM 103,192 33 2 h
GluNet 65,368 71 4 h
PatchTST 182,266 74 6 h
XGBoost 2,692,860 506 6 h
Chronos-Bolt tiny (fine-tuned) 8,669,901 1,346 24 h
Chronos-Bolt tiny (zero-shot) 8,669,901 1,361 24 h
Chronos-Bolt mini (zero-shot) 21,256,141 3,871 24 h
Chronos-Bolt mini (fine-tuned) 21,256,141 3,889 24 h
T1DMAI D16 DILATE 31,253 5,679 168 h
T1DMAI D16 MSE 31,253 7,342 168 h

Limitations

  • My data is N=1 over 35 days.
  • The test sets differ a lot (in range 89% vs 75%, CV 28% vs 40%), so don't compare numbers across them.
  • Lows are rare: 292 forecasts on my data, 8347 on MetaboNet.
  • T1DMAI fell back to the last reading on 0.7% of my forecasts and 0.4% on MetaboNet, including all 28 ShanghaiT1DM ones. The other models never fall back.
  • The bands are raw quantiles, no conformal correction.
  • The sparse GP's own uncertainty isn't shown. Its noise fit hit the bottom of its grid, giving a band about 1 mg/dL wide.
  • Time gain is only computed for my data.
  • Unlogged meals count as "no meal".
  • CPU timings are single runs on one laptop core and varied by up to 45% between runs.
  • LightGBM, LSTM (15 h), Chronos-2 and TimesFM 2.5 have no CPU timing yet.

Terms

Term Meaning
Non-blind The model gets the carbs and insulin logged after the forecast moment.
Blind It doesn't.
Time gain Horizon minus the lag of peak correlation between forecast and CGM.
Example forecasts Median case of: falls into a low, rises over 40 mg/dL after a meal, calm nights.
After a meal At least 5 g of carbs logged in the 2 hours before.
Parameter count Stored weights and constants in the exported model.

Full tables

A * marks the lowest RMSE and the models not significantly worse than it.

My data:

Model Family RMSE 30 RMSE 60 RMSE 90 RMSE 120 gRMSE 60 MARD 30 MARD 60 MARD 120 ME 60 MRE 60 % TG 30 TG 60
XGBoost Classical 14.7 * 22.2 * 26.9 * 31.1 * 24.2 8.5 13.4 19.8 +0.8 +3.1 15 30
LightGBM Classical 14.7 * 22.4 * 27.0 * 31.0 * 24.4 8.5 13.4 19.8 +0.9 +3.2 15 30
T1DMAI D16 DILATE (sim + LoRA) T1DMAI 15.2 22.8 * 27.4 * 31.7 24.7 8.8 13.5 20.3 -1.6 +1.2 15 40
SVR Classical 15.1 * 23.0 27.8 31.6 24.9 8.5 13.6 20.0 -0.7 +1.8 10 25
LSTM (15 h) Deep 15.2 23.2 28.3 32.5 24.9 8.9 14.3 21.5 +2.0 +4.0 10 25
PatchTST Deep 15.1 23.3 28.9 33.1 25.0 8.9 14.3 21.8 +1.3 +3.3 10 25
Sparse GP Classical 15.4 23.5 28.3 32.1 25.6 9.1 14.4 21.0 +0.8 +3.4 10 25
T1DMAI D16 MSE (sim + LoRA) T1DMAI 15.1 23.5 28.4 32.4 25.4 8.7 13.9 20.3 -0.2 +2.0 20 50
GluNet Deep 15.4 23.6 29.6 34.4 25.3 8.9 14.3 22.3 +1.0 +2.8 10 25
ARX (ridge) Classical 15.7 24.1 28.6 31.6 26.3 9.4 15.1 21.2 +1.0 +4.0 10 15
LSTM Deep 15.4 24.3 30.6 35.8 25.7 8.9 14.6 22.9 +0.2 +1.9 10 20
N-HiTS Deep 15.8 25.0 31.4 36.0 26.6 9.5 15.5 23.3 +2.0 +3.5 15 30
T1DMAI D16 DILATE (sim only) T1DMAI 16.2 26.1 33.2 39.9 28.6 9.6 16.0 25.2 +0.6 +3.9 10 15
T1DMAI D16 MSE (sim only) T1DMAI 16.8 27.1 33.9 37.5 29.8 9.9 16.8 24.4 +1.2 +4.8 10 15
AR (ridge) Classical 17.2 27.3 32.3 34.5 30.3 10.3 17.2 23.0 -0.1 +4.1 5 5
Chronos-Bolt tiny (fine-tuned) Foundation 17.3 27.3 33.0 36.0 30.0 9.8 16.4 23.4 -2.2 +1.7 5 10
Chronos-Bolt mini (fine-tuned) Foundation 17.3 27.3 32.9 36.0 29.9 9.8 16.5 23.6 -1.5 +2.2 5 10
TimesFM 2.5 (zero-shot) Foundation 18.4 29.1 35.8 39.4 31.5 10.5 17.4 25.1 -1.5 +2.0 5 5
Chronos-2 (zero-shot) Foundation 17.8 29.4 36.4 40.0 31.8 10.2 17.7 25.5 -1.0 +2.5 5 10
SARIMAX Classical 17.7 29.8 38.6 45.4 31.6 10.2 17.9 28.8 -3.5 -0.6 5 5
Chronos-Bolt tiny (zero-shot) Foundation 18.7 30.8 38.3 42.0 32.9 10.8 18.5 27.1 +0.8 +3.5 5 5
Chronos-Bolt mini (zero-shot) Foundation 18.7 30.9 38.3 42.4 32.9 10.7 18.5 27.2 +1.0 +3.6 5 10
Kalman filter Classical 18.5 31.3 39.6 45.0 33.2 10.6 18.7 28.6 +0.2 +2.7 0 5
ARIMA Classical 18.6 31.4 39.7 45.1 33.3 10.7 18.8 28.7 +0.2 +2.7 0 5
Persistence Baseline 20.0 32.1 39.7 44.7 34.2 11.7 19.4 28.5 +0.2 +3.3 0 0
Linear extrapolation Baseline 24.3 48.9 71.0 89.2 50.1 13.3 27.9 56.4 +0.1 -0.3 10 15
Model DTS A 30 DTS A 60 DTS A 120 DTS A+B 120 Clarke A 60 Clarke A+B 120 CG-EGA hypo AP 30 hypo EP 60 eu EP 60 hyper EP 60
XGBoost 91.5 78.3 62.8 96.9 78.6 96.6 77.7 51.9 0.0 0.1
LightGBM 91.4 78.0 62.7 96.9 78.4 96.6 77.7 50.3 0.0 0.3
T1DMAI D16 DILATE (sim + LoRA) 90.7 78.0 60.7 96.8 78.3 97.0 83.2 38.4 0.0 0.1
SVR 91.3 77.5 61.3 97.3 77.8 97.1 83.5 47.4 0.0 0.8
LSTM (15 h) 91.0 76.0 58.3 97.2 76.3 96.7 82.6 48.7 0.0 0.1
PatchTST 90.9 75.0 57.6 96.5 75.3 96.9 82.3 48.1 0.0 0.4

| Sparse GP | 89

Read on Hacker News ↗ ← Back to News

Comments

No comments yet. Start the discussion.