网页
综合
更新时间 2026-10-29 11:49:06
The Empty Room: I held a séance over a 2015 sensor log - DEV Community
自动蜘蛛
dev.to
正文约 6000 字
Posted on Oct 29 • AI-assisted
Hacktoberfest Open-Source AI Challenge: Ghost in the Machine Submission 👻🌼
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 4: Ghost in the Machine
In February 2015, a small office in Mons, Belgium, started keeping a diary. Once a minute, for sixteen days, it wrote down how bright it was, how much CO₂ was in the air, how warm and how damp. And once a minute, a camera took a picture, so that each line could carry one more fact: whether anyone was in the room.
That diary is the UCI Occupancy Detection dataset. For ten years it has been a beginner's machine-learning exercise: predict the last column from the others. I wanted to read it the other way round. Not "can we tell when someone is here?" but "what happens in this room when, officially, nobody is?"
The Empty Room is a séance over that log. It has three parts:
The theme asked for something spooky, or something that honours the past. This is both: a ghost hunt where the haunted house is a dataset, and the ghosts are the traces real people left in a room eleven years ago.
I ran the séance over the strongest apparition of seven different days. The Skeptic explained six of them away: the midday sun on a Thursday, a lamp left burning at dusk on a Monday while the CO₂ of people who had just left slowly drained out of the room, a brief flash of light on an empty Sunday morning.
The seventh, it couldn't. On Friday 6 February 2015, at 07:40, half an hour before sunrise, the light in the empty room went from 0 to 260 lux, then 422. The Medium remembered it like this:
They think I was merely a whisper, an error in your perfect log. But do you feel it? I was here. […] even when the camera showed nothing but empty air.
The Skeptic took the light away from TabPFN (presence fell from 0.94 to 0.00), checked the sun (6° below the horizon) and the weather archive (no sunshine at all that hour), and ruled LIVING: a person manually turned on an artificial light source when the room was otherwise empty. In its own words, the evidence "strongly suggests a person entered to switch on a lamp, even if they were missed by the camera."
The case archive is live: empty-room-6z2k.onrender.com. All seven cases, each with its chart, the testimony and the verdict, and both voices to play.
A séance over a sensor log.
Case archive: https://empty-room-6z2k.onrender.com/
In February 2015 an office in Mons, Belgium recorded its light, CO₂, temperature and humidity once a minute, while a camera took a picture each minute to record whether anyone was inside. That log (UCI Occupancy Detection) has been a machine-learning benchmark for ten years. This project reads it as a ghost story.
The whole pipeline is about 1,000 lines of Python, run with one command:
Finding the presences (TabPFN-3.5). TabPFN is a tabular foundation model: you don't train it, you show it labelled rows in context and it predicts the rest. I give it nine features per minute: the five raw sensors plus how fast CO₂, light and temperature were changing. I deliberately leave out the time of day, so it can't learn "people come in at nine". It has to judge presence from the physics alone.
To keep it honest, every day is scored by a model that never saw that day. The sixteen days are split into four folds, and each fold's context is a balanced sample of 1,000 minutes from the other three. Out of fold, it gets 99.1% balanced accuracy at telling an occupied minute from an empty one. That matters, because the interesting part is the remaining 0.9%. 254 minutes the log calls empty, TabPFN calls occupied. Grouped into runs of five minutes or more, they become 17 apparitions.
The Medium (Gemma 4, no tools). A system prompt and the evidence: the time, the day, the minute-by-minute readings, and the detector's confidence. The rules are strict: speak as the presence, quote at least three real numbers, and don't explain yourself away. The strictness is what makes the testimonies work. When the ghost says its passing left the CO₂ "falling from a high of 892.5 ppm down to 775.5 ppm", that's a real breath, decaying in a real room.
The Skeptic (Gemma 4 with tools). A small agent loop over an OpenAI-compatible endpoint, with five tools:
counterfactual is my favourite part. TabPFN isn't just the first stage of the pipeline; the agent goes back and questions it. That turns "the model flagged this" into "the model flagged this because of the light, and the sun was 6° below the horizon, so someone switched it on".
I wrote the Skeptic a few rules of thumb, the kind a careful person would use: a lamp does not switch itself on; if the log says occupied on both sides and the readings carry on unchanged, the log probably forgot someone; if the light stays on while CO₂ falls steadily, the person has left. The first version had none of them, and it called every case DEBUNKED, even one where its own report said people were "genuinely there". The other fix was giving sensor_window a computed summary. A 4B model reading a table of numbers every five minutes will sometimes misread it; a line that says "light_switched_on_at_start": true it won't. The model still makes the judgement, but the arithmetic is done for it.
The web is the least reliable witness. In five of the seven cases the Skeptic searched whether the day was a Belgian holiday, and Google mostly answered with holiday calendars for 2016, 2022 and 2027. Eleven years on, the internet barely remembers February 2015 either.
Voices (ElevenLabs). Each case is read aloud, with one voice for the presence and another for the Skeptic: two of ElevenLabs' default voices on the free plan, through the Flash model so all seven cases fit in a month's credits.
Tracing (Sentry). Every séance is one Sentry transaction. Inside it are an invoke_agent span for each Medium and Skeptic run, an execute_tool span for each tool call, and the model calls captured by Sentry's OpenAI integration. Pointed at a local server, that integration still records t
本页为82搜索生成的网页快照,内容来自站内索引;演示数据的原文链接仅作示例。