forked from Dan4ick/Lidar_Muxa
1572 lines
118 KiB
Markdown
1572 lines
118 KiB
Markdown
# Эксперименты
|
||
|
||
Все числа в документе получены скриптами из `tools/` на предоставленных данных и
|
||
воспроизводятся командами, указанными в каждом разделе. Там, где результат оказался
|
||
хуже ожидаемого, он приведён как есть.
|
||
|
||
Машина разработки: Ryzen 5 7600X, 32 ГБ, RTX 5070 Ti. Стенд жюри слабее по CPU
|
||
(i7-9700E, 8 ядер, 2.6 ГГц), поэтому замеры задержки приведены с запасом и обсуждаются
|
||
отдельно в разделе 7.
|
||
|
||
---
|
||
|
||
## 1. Что на самом деле в данных
|
||
|
||
```bash
|
||
python tools/inspect_bags.py --root data/for_hackathon
|
||
```
|
||
|
||
| Бэг | Кадров | Топик | Точек в кадре | Валидных лучей |
|
||
|---|---|---|---|---|
|
||
| `doubleT_obstacle` | 201 | `/sensing/lidar/hesai128/pointcloud` | 921 600 | 37.6 % |
|
||
| `doubleT_platform` | 345 | `/lidar_points` | 307 200 | 60.5 % |
|
||
| `roundT_doubleT` | 252 | `/lidar_points` | 307 200 | 61.7 % |
|
||
| `roundT_pressureGate_roundT` | 268 | `/lidar_points` | 307 200 | 60.6 % |
|
||
| `roundT_squareT_pressureGate_squareT` | 545 | `/lidar_points` | 307 200 | 61.6 % |
|
||
| `squareT_platform_squareT_switch` | 877 | `/lidar_points` | 307 200 | 59.4 % |
|
||
| `new_data` (221 шард) | 11 271 | `/lidar_points` | 307 200 | — |
|
||
|
||
Три вещи, о которых README датасета молчит и которые ломают наивную обработку:
|
||
|
||
1. **Архивы — несжатый tar**, а не `.zst`.
|
||
2. **Раскладка скана различается**: 3600 азимутов на 360° против 1200 на 120°.
|
||
Ничего нельзя захардкодить.
|
||
3. **У каналов постоянный азимутальный сдвиг до 15.6°** (±78 столбцов при шаге 0.1°).
|
||
Без выпрямления «столбец» не является направлением, и все пространственные фильтры
|
||
считают мусор. Руководство Pandar128E3X это подтверждает прямо: «Each laser channel
|
||
has an intrinsic azimuth offset».
|
||
|
||
Различаются и условия съёмки: высота установки сенсора над головкой рельса составляет
|
||
1.31–1.33 м в пяти бэгах и 1.70 м в `doubleT_obstacle`. Решение калибруется по данным
|
||
и работает с обоими без правок.
|
||
|
||
---
|
||
|
||
## 2. Проверка калибровки по паспорту
|
||
|
||
```bash
|
||
python tools/extract_channel_table.py --pdf <руководство> --out .../pandar128_channels.csv
|
||
python tools/validate_calibration.py
|
||
```
|
||
|
||
Решётка лучей восстанавливается **из самих облаков точек**, паспортные углы нигде не
|
||
используются. Поэтому таблица каналов из Приложения A руководства служит независимой
|
||
проверкой:
|
||
|
||
| Величина | Измерено по данным | Паспорт | Расхождение |
|
||
|---|---|---|---|
|
||
| Разброс азимутального сдвига каналов | ±7.80° (размах 15.60°) | −7.811°…+7.804° (15.615°) | 0.015° |
|
||
| Диапазон углов места | −25.1°…+14.4° | −25.016°…+14.436° | < 0.1° |
|
||
| Угол места, поканально | — | — | медиана 0.065°, макс 0.123° |
|
||
| Азимутальный сдвиг, поканально | — | — | медиана 0.044°, макс 0.152° |
|
||
|
||
Расхождение одинаково на всех шести бэгах. Остаток объясняется тем, что в руководстве
|
||
приведены **проектные** значения, а каждый экземпляр прибора поставляется с собственным
|
||
файлом угловой коррекции — именно её и восстанавливает калибровка по данным.
|
||
|
||
Остаточная угловая ошибка после выпрямления образа: **p50 = 0.0000°, p99 = 0.028°,
|
||
макс 0.040°** — меньше половины шага решётки (0.05°).
|
||
|
||
---
|
||
|
||
## 3. Сколько тоннель вообще позволяет увидеть
|
||
|
||
```bash
|
||
python tools/analyze_corridor.py --frames 50
|
||
```
|
||
|
||
| Бэг | Радиус кривой | Прямая видимость (p99.9) |
|
||
|---|---|---|
|
||
| `doubleT_obstacle` | 1690 м | 167 м |
|
||
| `doubleT_platform` | 7310 м | 143 м |
|
||
| `roundT_doubleT` | 1310 м | 126 м |
|
||
| `roundT_pressureGate_roundT` | 2970 м | 121 м |
|
||
| `roundT_squareT_pressureGate_squareT` | 8660 м | 127 м |
|
||
| `squareT_platform_squareT_switch` | 2300 м | 132 м |
|
||
|
||
Максимальное эхо во всём датасете — **208.8 м**, что совпадает с паспортными
|
||
0.3…200 м. Но **реальная прямая видимость 121–167 м**: тоннели кривые, и линия взгляда
|
||
упирается в стену раньше, чем кончается дальнобойность прибора.
|
||
|
||
Это измерение, а не оправдание: заявленные в ТЗ «300 м → отлично» на предоставленных
|
||
участках недостижимы **никаким** алгоритмом, потому что от объекта за поворотом
|
||
до лидара не доходит ни одного фотона. Проверяется прямо: при вставке синтетического
|
||
предмета на 84 м в кадр, где фон в том же направлении стоит на 76 м, ни один луч
|
||
до предмета не доходит — он физически закрыт стеной.
|
||
|
||
---
|
||
|
||
## 4. Реальное препятствие
|
||
|
||
Единственный бэг с настоящим посторонним объектом — `doubleT_obstacle`. Поезд стоит,
|
||
объект **0.67 × 1.35 м на 54.7…56.9 м**, 47–69 лучей, медленно смещается поперёк пути
|
||
(с +1.16 м до −1.98 м и обратно за 20 с, примерно 0.2 м/с).
|
||
|
||
```bash
|
||
python tools/check_obstacle.py --memory artifacts/mushroom_body.npz
|
||
```
|
||
|
||
| Метрика | Значение |
|
||
|---|---|
|
||
| Попал в кандидаты | 100 % кадров |
|
||
| Подтверждён треком | 98.9 % кадров |
|
||
| Новизна (ответ MBON) | 0.62 при фоне 0.13 |
|
||
|
||
---
|
||
|
||
## 5. Обобщаемость: leave-one-bag-out
|
||
|
||
```bash
|
||
python tools/evaluate.py --device cuda
|
||
```
|
||
|
||
Память тоннеля обучается на всех данных **кроме проверяемого бэга** — иначе цифры лгут:
|
||
подавлять конструкции, которые сам же и запомнил, умеет кто угодно, а на приватном тесте
|
||
будет новый участок.
|
||
|
||
| Бэг | Путь | Кадров с тревогой | Разных ложных треков | На километр |
|
||
|---|---|---|---|---|
|
||
| `doubleT_platform` | 201 м | 18.8 % | 2 | 10.0 |
|
||
| `roundT_doubleT` | 201 м | 1.3 % | 1 | 5.0 |
|
||
| `roundT_pressureGate_roundT` | 247 м | 0.0 % | 0 | 0.0 |
|
||
| `roundT_squareT_pressureGate_squareT` | 274 м | 13.4 % | 1 | 3.7 |
|
||
| `squareT_platform_squareT_switch` | 271 м | 13.4 % | 2 | 7.4 |
|
||
| **Итого** | **1193 м** | **9.4 %** | **6** | **5.2** (медиана 5.0) |
|
||
|
||
Реальный объект в `doubleT_obstacle` при этом обнаруживается в **98.9 %** кадров.
|
||
|
||
Две метрики отличаются принципиально. «Кадров с тревогой» завышает картину: одна и та же
|
||
конструкция, попавшая в треки, видна сотню кадров подряд. Для эксплуатации важно другое —
|
||
сколько **разных** ложных объектов возникло, потому что именно столько раз поезд
|
||
затормозил бы напрасно.
|
||
|
||
### 5.1. Что дал разбор худшего бэга
|
||
|
||
`roundT_doubleT` давал 39.8 ложных трека на километр — втрое хуже любого другого. Разбор
|
||
(`tools/diagnose_fp.py`) показал, что пять из восьми треков — один и тот же тип объекта:
|
||
полоса шириной 0.6 м, ростом ровно с габарит, тёмная (интенсивность 9 из 255), с разрывом
|
||
дальности до фона 18–25 м, повторяющаяся вдоль тоннеля каждые 13–20 м.
|
||
|
||
Снятие ограничений по высоте показало, что это **колонна, идущая от полотна до свода**:
|
||
кластер тянется от −0.33 м до 4.45 м, и в габарит 0.28…2.30 попадает лишь **15 %** его
|
||
лучей. Признак «наполненность» этого не видел: контекст кластеризации обрывался на
|
||
`h_hi + 1.2 = 3.5` м — ровно в талии между колонной и сводом, — поэтому срез конструкции
|
||
выглядел целым предметом.
|
||
|
||
Контекст поднят до `h_hi + 4.0 = 6.3` м (параметр `ctx_up`). Результат:
|
||
|
||
| | контекст до 3.5 м | контекст до 6.3 м |
|
||
|---|---|---|
|
||
| `roundT_doubleT`, кадров с тревогой | 39.7 % | **1.3 %** |
|
||
| `roundT_doubleT`, ложных треков | 8 | **1** |
|
||
| Всего ложных треков на км | 12.4 | **5.2** |
|
||
| Реальный объект на 55 м | 98.9 % | **98.9 %** |
|
||
|
||
Значения 2.5, 4.0 и 12.0 дают одинаковый результат: контекст просто дотягивается до свода
|
||
и дальше упирается в пустоту. Взято 4.0 — с запасом на более высокий тоннель.
|
||
|
||
---
|
||
|
||
## 6. Абляция: что именно работает
|
||
|
||
```bash
|
||
python tools/ablation.py --device cuda
|
||
```
|
||
|
||
Каждый вариант отличается от полного ровно одним отключённым механизмом; память во всех
|
||
вариантах обучена без проверяемого бэга.
|
||
|
||
| Вариант | Кадров с ложной тревогой | Разных ложных треков | Объект на 55 м |
|
||
|---|---|---|---|
|
||
| полная система | 10.7 % | 6 | 98.9 % |
|
||
| − память тоннеля | 24.1 % | 16 | 98.9 % |
|
||
| − ось пути (прямой коридор) | 4.4 % | 3 | 98.9 % |
|
||
| − признаки формы | 30.5 % | 21 | 98.9 % |
|
||
| − накопление улик | 37.4 % | **81** | 100.0 % |
|
||
|
||
Что из этого следует.
|
||
|
||
**Накопление улик в центральном комплексе — самый весомый механизм.** Без него число
|
||
разных ложных объектов растёт в 13.5 раза (6 → 81): каждое случайное пятно немедленно
|
||
становится «обнаружением». Это прямое подтверждение того, что подтверждение по
|
||
нескольким кадрам должно быть не эвристическим фильтром, а накопителем.
|
||
|
||
**Грибовидное тело снижает ложные тревоги вдвое** (24.1 % → 10.7 %) и при этом **никак
|
||
не влияет на обнаружение реального объекта** (98.9 % в обоих случаях). Именно этого
|
||
от памяти и ждали: она гасит знакомое, не трогая незнакомое.
|
||
|
||
**Признаки формы** (целостность, компактность вдоль пути, опора снизу) дают почти такой
|
||
же вклад, как память, — втрое меньше ложных треков (21 → 6).
|
||
|
||
**Ось пути — единственный механизм, который сейчас стоит дороже, чем даёт.** Её
|
||
отключение снижает ложные тревоги вдвое (10.7 % → 4.4 %, 6 → 3 трека) и не трогает
|
||
обнаружение реального объекта. Так вышло потому, что в двухпутном тоннеле центр свода
|
||
смещён относительно пути: ось оценивается со сдвигом, и кривой габарит заводит в зону
|
||
поиска куски стены. Держим её ради кривых участков, где без неё объект уезжает из
|
||
габарита, — но это осознанная плата, а не выигрыш.
|
||
|
||
Из этого сделан вывод и изменено решение: габарит теперь **объединение** прямого и
|
||
кривого коридоров, а не замена одного другим. Система безопасности не имеет права
|
||
сужать зону поиска по неуверенной оценке. Итог замены на объединение:
|
||
|
||
| | ось заменяет прямой коридор | ось **дополняет** прямой |
|
||
|---|---|---|
|
||
| Реальный объект на 55 м | 75.3 % | **98.9 %** |
|
||
| Кадров с ложной тревогой | 10.6 % | 17.5 % |
|
||
| Разных ложных треков на км | 7.5 | 12.4 |
|
||
|
||
Размен сознательный: +23.6 п.п. обнаружения за +6.9 п.п. ложных тревог. Пропустить
|
||
человека на пути существенно хуже, чем лишний раз затормозить.
|
||
|
||
Таблица выше пересчитана уже на объединённом коридоре, поэтому «полная система»
|
||
показывает 98.9 % обнаружения.
|
||
|
||
---
|
||
|
||
## 7. Скорость
|
||
|
||
```bash
|
||
python tools/run_pipeline.py --all --memory artifacts/mushroom_body.npz --verbose
|
||
```
|
||
|
||
Медиана по стадиям на кадре 128 × 600 (сектор ±30°), машина разработки:
|
||
|
||
| Стадия | мс |
|
||
|---|---|
|
||
| retina (оконная проекция) | 7.0 |
|
||
| ламина | 6.4 |
|
||
| оценка движения (LPTC) | 5.5 |
|
||
| ось пути | 4.7 |
|
||
| лобула (кандидаты) | 4.5 |
|
||
| стабилизация | 3.5 |
|
||
| грибовидное тело | 1.2 |
|
||
| центральный комплекс | 0.2 |
|
||
| решение | 0.02 |
|
||
| **итого** | **p50 ≈ 35, p95 ≈ 45** |
|
||
|
||
Бюджет по ТЗ — 100 мс на кадр. Запас примерно двукратный, что важно: стенд жюри по CPU
|
||
слабее машины разработки. Если запаса не хватит, первыми кандидатами на перенос в
|
||
numba являются ламина и оценка движения — вместе это 12 мс почти чистой арифметики.
|
||
|
||
Отдельно измерена оптимизация ретины: на круговом скане (921 600 точек) оконная
|
||
проекция сократила стадию с **29 до 7 мс**, причём результат совпадает с полной
|
||
проекцией **побитово** — проверено сравнением массивов.
|
||
|
||
## 7.3. Почему далёкий предмет теряется — и что нужно для 200 м
|
||
|
||
ТЗ просит 300 м как «отлично» и 200 м как «очень хорошо». Разберём честно, чего
|
||
не хватает, потому что причина не та, которая кажется.
|
||
|
||
**Фотоны есть.** Вставленный человек на оси пути, по замерам полигона:
|
||
|
||
| Полоса | Лучей на кадр | Есть эхо | Кадров в полосе | Накоплено лучей | Обнаружено сейчас |
|
||
|---|---|---|---|---|---|
|
||
| 160–190 м | 5 | 100 % | 17 | ~84 | **0 %** |
|
||
| 135–160 м | 7 | 100 % | 17 | ~120 | **0 %** |
|
||
| 110–135 м | 10 | 94 % | 18 | ~176 | **0 %** |
|
||
| 90–110 м | 16 | 92 % | 14 | ~227 | 25 % |
|
||
| 70–90 м | 26 | 87 % | 15 | ~400 | 58 % |
|
||
|
||
На 170 м предмет освещён в **каждом** кадре и за проход набирает под сотню попаданий
|
||
в одну и ту же точку мира. Информация есть — мы её выбрасываем, решая покадрово.
|
||
|
||
**Кандидат при этом формируется.** Покадровый разбор (`doubleT_platform`, человек
|
||
от 200 м) показывает кандидата в большинстве кадров на 140–185 м: 4–9 лучей,
|
||
наполненность до 1.00, размер 0.4 × 1.5 м — верный. Но улика трека остаётся 0.00,
|
||
и виноват один множитель: **`gap` = 0.0 во всех кадрах без исключения**.
|
||
|
||
**Почему.** Кольцо окружения ламины берётся ±6 столбцов, то есть ±0.6°. На 170 м этот
|
||
угол отвечает боковому смещению 1.8 м, а стена тоннеля на таком смещении находится
|
||
на 172 м — там же, где предмет. Центр-окружение перестаёт работать, когда собственный
|
||
градиент тоннеля по глубине сравним с шагом от предмета: предмет не «ближе окружения»,
|
||
он «на той же дальности, что окружение». В `_quality` это даёт
|
||
`contrast = clip(0/3, 0.2, 1) = 0.2`, и улика не набирается ни за 17 кадров, ни за сто.
|
||
|
||
Это не настройка порога. Локальный контраст на больших дальностях в тоннеле физически
|
||
не несёт сигнала, и никакая подстройка ламины этого не изменит.
|
||
|
||
### Что сделано: накопление в координатах пути
|
||
|
||
Предмет неподвижен в мире, а тоннель проплывает мимо. Собственное движение мы уже
|
||
оцениваем, поэтому лучи из габарита складываются не в кадре, а в сетке, привязанной
|
||
к пройденному пути (`fan_body.py`, шаг 2 м вдоль пути × 0.2 м поперёк × 0.25 м по
|
||
высоте, забывание с полураспадом 23 кадра). Так устроено веерное тело центрального
|
||
комплекса мухи: оно копит вектор к цели в координатах мира, а не текущего кадра.
|
||
|
||
**Первая версия порождала собственных кандидатов — и это оказалось тупиком.** Ложных
|
||
треков стало 39 на километр вместо 5.2. Разбор показал, почему: по геометрии
|
||
накопленное скопление предмета и накопленный кусок конструкции тоннеля **неразличимы**.
|
||
Медианы (предмет / ложные), 145 против 761 скопления:
|
||
|
||
| признак | дальность | \|u\| | высота | h_min | ширина | протяжённость | опора | кадров |
|
||
|---|---|---|---|---|---|---|---|---|
|
||
| предмет | 88 | 1.16 | 1.28 | 0.28 | 0.80 | 4.0 | 1.31 | 22.1 |
|
||
| ложные | 100 | 1.10 | 1.27 | 0.28 | 0.80 | 4.0 | 1.44 | 18.5 |
|
||
|
||
Совпадает всё. Разделяет их только память тоннеля, а ей нужны признаки кадра —
|
||
контраст, интенсивность, тень, — которых у скопления нет по построению.
|
||
|
||
**Рабочая версия.** Накопитель не порождает кандидатов вовсе. Он отвечает на один
|
||
вопрос про **уже найденного покадрового кандидата** — возвращались ли лучи из этой
|
||
точки мира кадр за кадром — и эта опора подставляется в вес улики вместо недоступного
|
||
контраста (`contrast = max(по gap, по накоплению)`). Кандидат при этом остаётся под
|
||
судом грибовидного тела со всеми своими признаками, и штатные конструкции по-прежнему
|
||
подавляются.
|
||
|
||
Измеренный результат на вставленном человеке (доля кадров с обнаружением):
|
||
|
||
| Бэг | 55–75 м | 75–100 | 100–130 | 130–170 |
|
||
|---|---|---|---|---|
|
||
| `roundT_squareT_pressureGate_squareT` | 1.00 | 0.38 → **1.00** | 0.00 → **1.00** | 0.00 → **0.55** |
|
||
| `squareT_platform_squareT_switch` | 1.00 | 1.00 | 0.33 → **1.00** | 0.00 → 0.14 |
|
||
| `doubleT_platform` | 1.00 | 0.82 → **0.95** | 0.00 → 0.09 | 0.00 |
|
||
| `roundT_doubleT` | 0.00 | 0.00 | 0.00 | 0.00 |
|
||
| `roundT_pressureGate_roundT` | 0.00 | 0.00 | 0.00 | 0.00 |
|
||
|
||
Рабочая дальность там, где кандидат вообще формируется, **выросла вдвое**: с 75–100
|
||
до 130–170 м. Два круглых тоннеля накопление не спасает — там предмет слипается со
|
||
стеной в одну связную компоненту, кандидата нет, и поддерживать нечего (см. п. 9.3).
|
||
|
||
На полном полигоне (90 сценариев, 14 004 наблюдения):
|
||
|
||
| | без накопления | с накоплением |
|
||
|---|---|---|
|
||
| Рабочая дальность, человек стоя | 62 м | **100 м** |
|
||
| P@100 м, человек стоя | 0.24 | **0.57** |
|
||
| P@150 м, человек стоя | 0.00 | **0.10** |
|
||
| P@100 м, человек сидя | 0.19 | **0.33** |
|
||
| Ложных треков на км (leave-one-bag-out) | **5.2** | 9.1 |
|
||
| Кадров с тревогой | **9.4 %** | 17.2 % |
|
||
| Посторонних тревог на кадр (полигон) | **0.055** | 0.171 |
|
||
| Реальный объект на 55 м | 98.9 % | 98.9 % |
|
||
| Задержка, медиана | 32 мс | 33 мс |
|
||
|
||
**Включено по умолчанию.** Размен здесь принципиально лучше, чем у разделения фигуры
|
||
и фона (п. 9.4): там было вчетверо больше ложных за +29 % дальности, здесь — в 1.75
|
||
раза больше за +61 % рабочей дальности и рост обнаружения на 100 м в 2.4 раза. ТЗ
|
||
прямо оценивает дальность (100 м → «хорошо»), а «важно найти баланс между дальностью,
|
||
надёжностью и количеством ложных тревог» — этот баланс мы и выбираем осознанно.
|
||
Выключается одним параметром: `enable_accumulator: false` возвращает 5.2 ложных
|
||
трека на километр при рабочей дальности 62 м.
|
||
|
||
### Что ещё нужно
|
||
|
||
**Геометрическая карта линии.** Метро — неизменная среда: за несколько проездов
|
||
строится ожидаемый дальностный образ, привязанный к положению вдоль линии. Тогда
|
||
«препятствие» = «луч вернулся ближе, чем говорит карта», и это единственный способ
|
||
получить **и** дальность, **и** околонулевые ложные тревоги: всё постоянное в карте,
|
||
всё остальное — предмет. Грибовидное тело делает то же самое в пространстве
|
||
признаков; карта делает это в пространстве геометрии, где на 170 м ещё есть сигнал.
|
||
|
||
### Чего не будет никогда
|
||
|
||
* **На предоставленных участках 200 м недостижимы геометрически**: прямая видимость
|
||
121–167 м, дальше линия взгляда упирается в стену кривой. Это не свойство алгоритма.
|
||
* **Мелкие предметы на 200 м невозможны с этим сенсором**: ведро (0.1 м²) на 160–190 м
|
||
даёт 1 луч при видимости 2 %, каска и бутылка — ноль. Накопление не поможет там,
|
||
где фотонов нет.
|
||
* Реалистичная планка для предмета размером с человека на прямом участке — **около
|
||
200 м**, и путь к ней измерен выше: накопление плюс карта.
|
||
|
||
---
|
||
|
||
## 8. Что не сработало
|
||
|
||
Раздел намеренно подробный: ТЗ п. 8.7 просит именно этого.
|
||
|
||
**Поиск рельсов по интенсивности.** Идея была привязать ось пути к колее 1520 мм.
|
||
Не вышло: медианная интенсивность на уровне головок рельсов равна 8 из 255, рельсы
|
||
ничем не выделяются на фоне полотна, и пара пиков на расстоянии 1.52 м находится
|
||
где попало — оценки прыгали от −1.18 до +1.37 м в соседних срезах одного кадра.
|
||
Отказались, ось пути оценивается по дрейфу центра свода.
|
||
|
||
**Обычная связность при кластеризации.** Соседние лучи объединялись без учёта глубины,
|
||
и предмет на 55 м слипался со стеной на 150 м в одно пятно размером 5 × 4 м. Реальный
|
||
объект обнаруживался в 16 кадрах из 20. После введения допуска по глубине, растущего
|
||
с расстоянием, — 20 из 20 и правильные габариты 0.67 × 1.35 м.
|
||
|
||
**Грибовидное тело с мушиными параметрами.** 2000 клеток Кеньона и 5 % активных
|
||
насыщаются после нескольких тысяч примеров: подавлено 98 % синапсов, новизна реального
|
||
препятствия падает до 0.001, и оно перестаёт обнаруживаться совсем. Потребовалось
|
||
увеличить популяцию до 50 000 и снизить разрежённость до 0.1 %, а темп депрессии
|
||
согласовать с размером обучающей выборки.
|
||
|
||
**Корреляция продольного профиля «в лоб».** Первая версия оценки скорости залипала
|
||
на нулевом сдвиге: в профиль входила ближняя зона, где на метр пути приходятся тысячи
|
||
лучей, и её вклад подавлял всё остальное. Помогло исключение ближней зоны и вычитание
|
||
скользящего среднего. Отдельно обнаружилась ошибка в перепроекции — использовалась
|
||
высота над рельсом вместо z сенсора, из-за чего согласие держалось на 0.12 вместо 0.9.
|
||
|
||
**Взвешивание срезов по числу точек при оценке оси пути.** У ближних срезов точек
|
||
в сотни раз больше, и подгонка полностью игнорировала дальние, где как раз содержится
|
||
кривизна. Кривые расходились от +10 до −10 м на 200 м в соседних кадрах. Равные веса
|
||
по срезам и линейная (а не квадратичная) экстраполяция за горизонт видимости решили
|
||
проблему.
|
||
|
||
**Оценка оси пути на станции.** Платформа делает сечение резко несимметричным, центр
|
||
свода «уезжает», и габарит заезжает прямо на платформу: радиус кривой падал с 999 до
|
||
225 м за 4.5 с. Это давало 54 % кадров с ложной тревогой на бэге с платформой и
|
||
стрелкой. Помогли два физических ограничения — минимальный радиус 300 м и предел
|
||
скорости изменения оси. Стало 5.4 %.
|
||
|
||
**Срыв оценки скорости на смене типа тоннеля.** На переходе круглого тоннеля
|
||
в двухпутный сопоставление кадров теряло опору и выдавало попеременно 0 и 70 км/ч.
|
||
Помог фильтр с физическим пределом ускорения 3 м/с²: поезд за 0.1 с так не разгоняется.
|
||
|
||
**Полигон без учёта кривизны.** Первая версия синтетических сценариев ставила предмет
|
||
в поперечных координатах сенсора, а не на ось пути. В кривой это уносило его в стену,
|
||
и «рабочая дальность» выходила 32 м вместо реальных 55+. Исправлено привязкой к оси.
|
||
|
||
---
|
||
|
||
## 9. Размеченный полигон: дальность обнаружения
|
||
|
||
```bash
|
||
python tools/make_benchmark.py --memory artifacts/mushroom_body.npz
|
||
python tools/plot_benchmark.py
|
||
```
|
||
|
||
Разметки в датасете нет, а организаторы предупредили, что приватный тест собран
|
||
добавлением синтезированных препятствий. Полигон строится тем же способом: в реальные
|
||
кадры пустого тоннеля трассировкой лучей вставляется предмет, стоящий **на оси пути**
|
||
в фиксированной точке тоннеля, поезд к нему подъезжает, и на каждом кадре известна
|
||
истинная дистанция.
|
||
|
||
Модель сенсора опирается на руководство: поканальная дальность из Приложения A
|
||
(каналы 34–65 берут 200 м, каналы 98–128 смотрят в землю и рассчитаны только на
|
||
ближнее поле), вероятность обнаружения на паспортной дальности PoD = 70 %, шум
|
||
дальности ±2 см, заполнение пятна луча для мелких предметов.
|
||
|
||
Проверка модели: настоящий объект 0.67 × 1.35 м на 55 м даёт 47–69 лучей; синтетический
|
||
человек 0.44 × 1.71 м на 60 м даёт 50 лучей. Совпадает.
|
||
|
||
Результаты приводятся в трёх разрезах, потому что смешивать их нельзя:
|
||
|
||
1. **видимость** — доля кадров, в которых до предмета дошёл хотя бы один луч;
|
||
за поворотом она падает до нуля независимо от алгоритма;
|
||
2. **обнаружение при условии видимости** — собственно качество алгоритма;
|
||
3. **обнаружение как есть** — произведение первых двух, эксплуатационная величина.
|
||
|
||
### 9.1. Результат
|
||
|
||
90 сценариев: 9 предметов × 2 поперечных смещения × 5 бэгов, 14 004 наблюдения
|
||
с известной истинной дистанцией.
|
||
|
||
| Предмет | Площадь | Рабочая дальность | P@50 м | P@100 м | P@150 м | Видимость |
|
||
|---|---|---|---|---|---|---|
|
||
| человек стоя | 0.75 м² | **100 м** | **0.70** | 0.53 | 0.12 | 92.5 % |
|
||
| человек сидя | 0.42 м² | 20 м | 0.62 | 0.34 | 0.00 | 89.3 % |
|
||
| ящик | 0.36 м² | 20 м | 0.49 | 0.00 | 0.00 | 88.1 % |
|
||
| чемодан | 0.25 м² | 62 м | 0.53 | 0.00 | 0.00 | 81.9 % |
|
||
| ведро | 0.10 м² | 8 м | 0.00 | 0.00 | 0.00 | 61.2 % |
|
||
| каска | 0.07 м² | — | 0.00 | 0.00 | 0.00 | 51.1 % |
|
||
| камень | 0.05 м² | — | 0.00 | 0.00 | 0.00 | 45.1 % |
|
||
| бутылка | 0.03 м² | — | 0.00 | 0.00 | 0.00 | 41.2 % |
|
||
| кабель | ~0 м² | — | 0.00 | 0.00 | 0.00 | 25.7 % |
|
||
|
||
Предыдущие замеры для сравнения. Без накопления в координатах пути (п. 7.3):
|
||
человек — рабочая дальность 62 м, P@50 = 0.56, P@100 = 0.24. С накоплением, но без
|
||
разреза по контрасту (п. 9.5): 100 м, P@50 = 0.56, P@100 = 0.57.
|
||
|
||
**«Рабочая дальность» у предметов около порога неустойчива** и её не надо читать как
|
||
физическую величину: метрика идёт от ближнего пояса и обрывается на первом, где доля
|
||
падает ниже 0.5, усредняя при этом два поперечных положения — на оси и со смещением
|
||
0.9 м к краю габарита. У сидящего человека и ящика пояс 25–40 м даёт 0.48 против
|
||
порога 0.50, и число падает с 62 до 20 м, хотя P@50 при этом не ухудшилось.
|
||
Содержательны таблицы по поясам (п. 9.2 и 9.5), а не это одно число.
|
||
|
||
Граница проходит по числу лучей: на 40–55 м человек даёт 68 лучей, чемодан 25, ведро 11,
|
||
каска 6, бутылка 3. Ниже примерно **десяти лучей предмет перестаёт отличаться от шума**
|
||
решётки, и никакая обработка этого не исправит — нужен либо более плотный сенсор, либо
|
||
подъезд ближе.
|
||
|
||
### 9.2. Почему рабочая дальность 62 м, а реальный объект виден на 98.9 %
|
||
|
||
Разброс по бэгам огромный, и он объясняет расхождение:
|
||
|
||
| Бэг (человек стоя, на оси) | 25–40 м | 40–55 м | 55–70 м | 70–90 м | лучей на 50 м |
|
||
|---|---|---|---|---|---|
|
||
| `doubleT_platform` | 1.00 | 1.00 | 1.00 | 1.00 | 68 |
|
||
| `roundT_squareT_pressureGate_squareT` | 1.00 | 1.00 | 1.00 | 0.67 | 68 |
|
||
| `squareT_platform_squareT_switch` | 0.00 | 0.18 | 1.00 | 1.00 | 56 |
|
||
| `roundT_pressureGate_roundT` | 0.73 | 0.00 | 0.00 | 0.00 | 65 |
|
||
| `roundT_doubleT` | 0.27 | 0.00 | 0.00 | 0.00 | 32 |
|
||
|
||
Не «плохо везде понемногу», а **идеально на одних участках и слепо на других**, причём
|
||
при 65 лучах на предмете. То есть дело не в видимости и не в размере.
|
||
|
||
> Таблица снята до накопления в координатах пути (п. 7.3) и до разреза по контрасту
|
||
> (п. 9.5). Актуальные цифры по тем же бэгам — в п. 9.5: `roundT_pressureGate_roundT`
|
||
> из полностью слепого за 40 м стал 0.45 / 1.00 / 0.57 на 40–90 м,
|
||
> `roundT_doubleT` за 40 м слепым остался.
|
||
|
||
### 9.3. Найденная причина слепоты: связная компонента течёт вдоль стены
|
||
|
||
Покадровый разбор провала (`roundT_pressureGate_roundT`, человек на 50 м, 65 лучей
|
||
вставлено) показал: кандидата нет вообще. В кадре всего 5 компонент, и одна из них —
|
||
**42 059 лучей, протянувшиеся по дальности от 4 до 99 м**, наполненность 0.05.
|
||
|
||
Кластеризация с разрывом по глубине объединяет соседние лучи, если их дальности
|
||
отличаются меньше чем на `0.06·R + 0.35` м. Вдоль гладкой стены тоннеля соседние лучи
|
||
отличаются на сантиметры, поэтому стена связна от ближнего поля до горизонта. Предмет,
|
||
стоящий у такой стены, попадает в ту же компоненту и **вместе с ней отбрасывается**
|
||
правилом «ни один предмет не тянется на 15 м вдоль пути».
|
||
|
||
Это не регрессия: мерж одинаков при любой верхней границе контекста, включая исходную.
|
||
|
||
**Попытка первая: разрезать по дальности.** Переглубокая компонента не выбрасывается,
|
||
а пересобирается с более строгим допуском. Предмет при этом действительно выделяется —
|
||
57 лучей, наполненность 1.00. Измеренный размен на `roundT_pressureGate_roundT`
|
||
(человек на 25…90 м) и глобально:
|
||
|
||
| Допуск разреза | Обнаружение | Ложных кадров (бэг) | Ложных треков (бэг) |
|
||
|---|---|---|---|
|
||
| выключен | 28.2 % | 0.0 % | 0 |
|
||
| 0.045 | 28.2 % | 27.2 % | 1 |
|
||
| 0.040 | 61.5 % | 21.5 % | 2 |
|
||
| **0.030** | **94.9 %** | 57.5 % | 5 |
|
||
| 0.015 | 94.9 % | 73.7 % | 16 |
|
||
| 0.006 | 94.9 % | 96.5 % | 47 |
|
||
|
||
Глобально при 0.030: ложных треков **25.8 на км против 5.2**, кадров с тревогой
|
||
**52 % против 9.4 %**. Половина кадров с тревогой — это непрерывное торможение, поэтому
|
||
разрез по умолчанию **выключен**.
|
||
|
||
Проверялось и то, можно ли отделить осколок стены от предмета по признакам: ни один
|
||
не разделяет их. Медианы (предмет / стена): ширина 0.21 / 0.20 м, наполненность
|
||
1.00 / 1.00, лучей 12 / 8, новизна 0.50 / 0.41. Строгий разрез делает стену
|
||
геометрически неотличимой от предметов — потому и цена такая. Этот вариант убран.
|
||
|
||
### 9.4. Разделение фигуры и фона по движению
|
||
|
||
Разрезать по дальности нельзя: предмет и стена рядом с ним стоят на одной дальности.
|
||
Зато они по-разному **приближаются**, и это чистая геометрия. Вдоль фиксированного луча
|
||
стена, параллельная движению, не приближается вовсе: поезд едет, точка пересечения
|
||
скользит по стене, дальность не меняется. Предмет, обращённый к поезду, приближается
|
||
ровно на пройденный путь.
|
||
|
||
Отсюда признак: `advance = (r_прошлый − r_текущий) / ds`. Ноль у фона, единица у фигуры.
|
||
Ничего перепроецировать не нужно — столбец решётки отвечает фиксированному азимуту, а
|
||
рысканье в кривой за кадр (0.06° при радиусе 1300 м) меньше шага решётки. Это тот самый
|
||
канал T4/T5 → LPTC: широкопольный поток задаёт ожидание, а что движется иначе — фигура.
|
||
|
||
Замер на вставленном человеке подтверждает физику: у предмета `advance` = 0.99…1.01,
|
||
у стены на той же дальности — 0.39…0.82 и падает по мере приближения.
|
||
|
||
Разрез по этому признаку (`Params.split_adv`, `lobula.split_by_figure`) не крошит стену:
|
||
из склеенной компоненты в 42 000 лучей остаётся 2.6–5.5 тысяч и **6–15 кандидатов**
|
||
вместо 1259 у разреза по дальности.
|
||
|
||
**Важно для честности замера.** Первая проверка дала 70 % ложных кадров, но она была
|
||
некорректной: память тоннеля обучена на кандидатах **старого** генератора, а разрез
|
||
порождает формы, которых она никогда не видела, — всё выглядит новым. После пересбора
|
||
кэша и переобучения памяти на тех же настройках (`tune_candidates_adv.npz`,
|
||
`new_data_candidates_adv.npz`, 70 273 кандидата) картина такая:
|
||
|
||
**Что это даёт — полигон:**
|
||
|
||
| | без разделения | с разделением |
|
||
|---|---|---|
|
||
| Рабочая дальность, человек стоя | 62 м | **80 м** |
|
||
| P@50 м | 0.56 | **0.71** |
|
||
| P@100 м | 0.24 | **0.36** |
|
||
| Чемодан, P@50 м | 0.57 | 0.67 |
|
||
|
||
По бэгам (человек на оси, доля кадров с обнаружением):
|
||
|
||
| Бэг | 25–40 м | 40–55 | 55–70 | 70–90 | 90–110 |
|
||
|---|---|---|---|---|---|
|
||
| `squareT_platform_squareT_switch` | 0.00 → **1.00** | 0.18 → **1.00** | 1.00 → 1.00 | 1.00 | 1.00 |
|
||
| `roundT_doubleT` | 0.27 → **0.64** | 0.00 | 0.00 | 0.00 | 0.00 |
|
||
| `roundT_pressureGate_roundT` | 0.73 → **0.80** | 0.00 | 0.00 | 0.00 | 0.00 |
|
||
| `roundT_squareT_pressureGate_squareT` | 1.00 | 1.00 | 1.00 | 0.67 → **0.89** | 0.00 |
|
||
| `doubleT_platform` | 1.00 | 1.00 | 1.00 | 1.00 | 0.25 |
|
||
|
||
**Что это стоит:**
|
||
|
||
| | без разделения | с разделением |
|
||
|---|---|---|
|
||
| Кадров с ложной тревогой | 9.4 % | 30.3 % |
|
||
| Разных ложных треков на км | **5.2** | **21.5** |
|
||
| Ложных тревог на полигоне, на кадр | 0.055 | 0.348 |
|
||
| Задержка, медиана | 31 мс | 39 мс |
|
||
| Реальный объект на 55 м | 98.9 % | 98.9 % |
|
||
|
||
**Порогом это не лечится.** Проверены значения 0.6 / 0.8 / 0.9: ложных треков
|
||
21.5 / 21.6 / 21.6 на километр, а доля кадров с тревогой только растёт (30 → 35 → 40 %).
|
||
Причина в том, что ложные срабатывания здесь — **не шум, а настоящие поверхности,
|
||
обращённые к поезду**: рамы гермозатворов, торцы, порталы. По одному признаку движения
|
||
они от предмета неотличимы, потому что физически ведут себя так же.
|
||
|
||
**Решение: разделение по умолчанию выключено** (`split_adv: 0.0`). 21.5 ложного трека
|
||
на километр — это напрасное торможение каждые 47 метров, система в таком виде
|
||
неработоспособна, и +18 м рабочей дальности этого не окупают. Два бэга из пяти
|
||
разделение к тому же не спасает: за 40 м они остаются слепыми.
|
||
|
||
**Чем это лечится по-настоящему.** Не порогом, а памятью: приближающиеся конструкции
|
||
тоннеля постоянны и повторяются от проезда к проезду. Здесь память обучена на пяти
|
||
бэгах и 20 минутах записи; на реальной линии с многими проездами грибовидное тело
|
||
подавило бы их так же, как подавляет всё остальное штатное. Это проверяемое
|
||
предсказание, а не надежда: переобучение памяти уже снизило ложные кадры с 70 % до
|
||
30 % — просто за счёт того, что она увидела эти формы один раз.
|
||
|
||
---
|
||
|
||
## 9.5. Разделение фигуры и фона по контрасту — третья попытка, и она работает
|
||
|
||
Разрез по допуску (п. 9.3) и разрез по движению (п. 9.4) вернули зрение и оба
|
||
оказались слишком дороги. Оставался третий признак фигуры, и он всё это время
|
||
уже вычислялся — просто не участвовал в сегментации.
|
||
|
||
**Физика.** Гладкая стена даёт **нулевой центр-окружение по построению**. Как бы
|
||
сильно дальность ни менялась вдоль стены, она меняется плавно: центр равен своему
|
||
окружению, и контраст равен нулю. Предмет на стене — это ступенька, и она видна.
|
||
Именно этим занята ламина, и её выход `gap` («насколько ближе окружения», м) наш
|
||
конвейер считал с самого начала — но использовал только как **признак кандидата**.
|
||
Сегментация же шла по связности с допуском по глубине, и переглубокая компонента
|
||
отбрасывалась целиком ещё до того, как признак кому-то пригождался.
|
||
|
||
**Замер разделимости** (вставленный человек, два круглых тоннеля, 55 кадров):
|
||
|
||
| Порог `gap` | Лучей предмета | Лучей фона | Компонент фона в кадре |
|
||
|---|---|---|---|
|
||
| 2 м | 90.8 % / 87.5 % | 4.15 % / 3.10 % | 24.6 / 16.3 |
|
||
| 4 м | 89.2 % / 83.4 % | 0.68 % / 0.62 % | 13.7 / 13.5 |
|
||
| **6 м** | **85.7 % / 75.1 %** | **0.13 % / 0.22 %** | **5.0 / 8.9** |
|
||
| 9 м | 80.7 % / 61.7 % | 0.02 % / 0.05 % | 0.7 / 2.6 |
|
||
|
||
Для сравнения: разрез по допуску давал 1259 кандидатов в кадре. Здесь фон
|
||
распадается на 5–9 компонент — на два порядка меньше, и это **настоящие выступы**,
|
||
которые память способна выучить, а не произвольные осколки гладкой стены.
|
||
|
||
Разделение держится до 75 м и разваливается к 90 м: доля лучей предмета, прошедших
|
||
порог 6 м, по полосам — 88 / 96 / 97 / 89 / 61 / 14 / 0 % на 15 / 30 / 45 / 60 / 75 /
|
||
90 / 105 м. Дальше 90 м кольцо окружения снова упирается в стену на той же
|
||
дальности (п. 7.3), и контраста нет.
|
||
|
||
### Почему первая версия всё равно была дорогой
|
||
|
||
Без ограничений разрез дал **9.4 ложных трека на км против 7.4** — и причина
|
||
нашлась замером, а не рассуждением. Медианы кандидатов на `roundT_doubleT`:
|
||
|
||
| признак | без разреза | с разрезом |
|
||
|---|---|---|
|
||
| протяжённость вдоль пути | 2.82 м | **1.00 м** |
|
||
| то же, дальше 55 м | 6.87 м | **0.81 м** |
|
||
| наполненность | 0.47 | 0.57 |
|
||
| контраст `gap` | 1.24 м | 3.29 м |
|
||
|
||
Разрез **отрезает фон**, и вместе с фоном исчезает протяжённость. В весе улики
|
||
(`central_complex._quality`) за неё отвечает множитель компактности
|
||
`clip(1.5 − depth/(3·span))`: при depth 6.9 м и размере 0.65 м он равен 0.1, при
|
||
depth 0.8 м — 1.0. То есть каждое наблюдение вырезанной фигуры стало весить
|
||
**вдесятеро больше**, и подавление протяжённых конструкций, работавшее до разреза,
|
||
выключилось.
|
||
|
||
Порог этого не лечит — проверено сквозным замером:
|
||
|
||
| Порог разреза | Ложных треков на км |
|
||
|---|---|
|
||
| выключен | 7.4 |
|
||
| 6 м | 9.4 |
|
||
| 9 м | 10.4 |
|
||
| 12 м | 9.4 |
|
||
|
||
### Что решило: одна фигура на компоненту
|
||
|
||
Раз каждая лишняя фигура стоит вдесятеро дороже прежнего, их число надо
|
||
ограничить. Из переглубокой компоненты выносится только **сильнейшая** фигура по
|
||
сумме превышения порога. Это тот же приём глобального торможения, которым APL
|
||
оставляет активными считанные проценты клеток Кеньона, а широкопольное торможение —
|
||
считанные колонки LC11.
|
||
|
||
| Фигур на компоненту | Ложных треков на км | Кадров с тревогой |
|
||
|---|---|---|
|
||
| без ограничения | 9.4 | 16.9 % |
|
||
| 2 | 7.4 | 15.5 % |
|
||
| **1** | **6.4** | **15.0 %** |
|
||
|
||
Дальность обнаружения при этом **не меняется вовсе**: и при одной фигуре, и при
|
||
двух, и без ограничения все три конфигурации дают одинаковые доли по полосам.
|
||
Лишние фигуры не добавляли зрения — только ложные тревоги.
|
||
|
||
Разрез вдобавок не применяется ближе 55 м (`split_near`): там покадровый тракт
|
||
видит предмет и без него (100 % на всех пяти бэгах до 70 м), а обстановки,
|
||
дающей контраст, в ближнем поле на порядок больше. Без этого ограничения 75 %
|
||
добавленных ложных треков приходили именно оттуда.
|
||
|
||
### Итог
|
||
|
||
Цифры ниже — leave-one-bag-out с пересобранным кэшем кандидатов и переобученной
|
||
памятью: без этого замер лжёт (п. 9.4).
|
||
|
||
| Конфигурация | Ложных треков на км | Кадров с тревогой | Объект 55 м |
|
||
|---|---|---|---|
|
||
| как было | 9.1 | 17.2 % | 98.9 % |
|
||
| **с разрезом по контрасту** | **7.5** | **16.7 %** | **98.9 %** |
|
||
|
||
То есть разрез не только вернул зрение там, где его не было, но и **снизил** ложные
|
||
тревоги — за счёт того, что переглубокая компонента перестала выбрасываться целиком
|
||
и вместо неё в память попадает одна осмысленная фигура, которую есть чему выучить.
|
||
|
||
Обнаружение вставленного человека на оси, доля кадров. Протокол полигона: предмет
|
||
стоит в точке тоннеля, до которой от начала записи 200 м, поезд подъезжает. Память
|
||
обучена и на этом бэге — как и во всём полигоне.
|
||
|
||
| Бэг | 15–25 м | 25–40 | 40–55 | 55–70 | 70–90 |
|
||
|---|---|---|---|---|---|
|
||
| `roundT_pressureGate_roundT` | 1.00 | 0.73 | 0.00 → **0.45** | 0.00 → **1.00** | 0.00 → **0.57** |
|
||
| `squareT_platform_squareT_switch` | 0.00 | 0.00 | 0.18 → **0.45** | 1.00 | 1.00 |
|
||
| `roundT_doubleT` | 1.00 | 0.27 | 0.00 | 0.00 | 0.00 |
|
||
|
||
**Это ровно тот бэг, который разбирался в п. 9.3.** `roundT_pressureGate_roundT` —
|
||
запись, где компонента из 42 000 лучей течёт вдоль стены от 4 до 99 м и уносит
|
||
предмет с собой. Разрез по контрасту превращает полностью слепую полосу 40–90 м в
|
||
0.45 / 1.00 / 0.57. Разрез по допуску (п. 9.3) и по движению (п. 9.4) добивались
|
||
там же 0.94 и 0.80 ценой 25.8 и 21.5 ложного трека на километр; здесь ложных треков
|
||
стало **меньше**, чем было до разреза.
|
||
|
||
**Второй слепой бэг разрез не спасает**, и причины там две, обе разобраны
|
||
покадрово в п. 9.6: за 50 м до предмета не доходит линия взгляда (98 % лучей
|
||
упираются в преграду ближе него), а на 35–52 м мешает уже наш собственный порог
|
||
`split_near`, снижать который оказалось слишком дорого.
|
||
|
||
**Осторожно с «рабочей дальностью».** Метрика в `plot_benchmark.py` идёт от ближнего
|
||
пояса и останавливается на первом, где доля падает ниже 0.5, а усредняет она два
|
||
поперечных положения сразу — на оси и со смещением 0.9 м к краю габарита. У предметов,
|
||
стоящих около порога, она поэтому скачет: у сидящего человека пояс 25–40 м даёт 0.48
|
||
против 0.50, и «рабочая дальность» падает с 62 до 20 м при том, что P@50 м
|
||
выросло с 0.58 до 0.62. Смотреть надо на таблицу по поясам, а не на одно число.
|
||
|
||
**Где разрез стоит денег — 1: холодный старт.** Всё сказанное верно, когда память
|
||
обучена. На совершенно новой линии, где памяти нет вовсе, разрез, наоборот, дорог:
|
||
21.8 → **31.8** ложных трека на километр. Это логично — он порождает кандидатов из
|
||
настоящих выступов тоннеля, и без памяти отличить их не от чего. Реальный сценарий —
|
||
именно с обученной памятью, она поставляется в образе; но если участок настолько
|
||
новый, что память к нему неприменима, `split_gap: 0.0` возвращает прежнее поведение.
|
||
|
||
**Где разрез стоит денег — 2: стоянка.** На записи со **стоящим** поездом (`doubleT_obstacle`)
|
||
он добавляет один устойчивый трек на 76.6 м, и доля кадров с посторонней тревогой
|
||
растёт с 63 % до 96 %. Это не случайность: при нулевом пройденном пути не работают
|
||
ни накопитель, ни привыкание — оба живут в координатах пути. Число разных ложных
|
||
треков на этом бэге растёт всего с 4 до 5; раздувается именно доля кадров, потому
|
||
что на стоянке ничто не уходит из поля зрения.
|
||
|
||
---
|
||
|
||
---
|
||
|
||
## 9.6. Почему `roundT_doubleT` остаётся слепым за 40 м
|
||
|
||
Разрез по контрасту (п. 9.5) открыл `roundT_pressureGate_roundT`, но второй слепой
|
||
бэг не тронул. Покадровый разбор цепочки «лучи → кандидат → улика → тревога» на
|
||
штатной постановке полигона (предмет в точке, до которой от начала записи 200 м)
|
||
показал **две разные причины в двух разных полосах дальности**. Одна физическая,
|
||
вторая — наша.
|
||
|
||
### Дальше 50 м: смотреть не на что
|
||
|
||
Считаем, сколько лучей доходит до предмета, по этапам:
|
||
|
||
| Дальность до предмета | Геометрически попали | Пережили модель сенсора | Не заслонены |
|
||
|---|---|---|---|
|
||
| 55–105 м | 29 | **29** | **1** |
|
||
| 30–55 м | 109 | 109 | 86 |
|
||
|
||
Модель сенсора не теряет **ни одного** луча: предмет крупный, дальность паспортная.
|
||
Но за 55 м **98 % лучей упираются в эхо, которое ближе предмета**. Дело не в
|
||
отражательной способности и не в числе каналов — до предмета просто не доходит
|
||
линия взгляда.
|
||
|
||
Это не артефакт постановки. Предмет пробовали ставить четырьмя способами — на
|
||
оценённую ось коридора, прямо по оси сенсора, на половину смещения и со сдвигом
|
||
+0.8 м; заслонение одинаково во всех четырёх, и дальность преграды тоже одна и та же:
|
||
|
||
| Дальность до предмета | 104 | 94 | 84 | 74 | 64 | 54 | 45 |
|
||
|---|---|---|---|---|---|---|---|
|
||
| Преграда, м | 90 | 84 | 76 | 66 | 58 | 52 | **49** |
|
||
| Лучей видно (ось коридора) | 3/17 | 1/19 | 0/25 | 0/37 | 1/41 | 8/61 | **63/89** |
|
||
|
||
Преграда приближается вместе с поездом и в какой-то момент **обгоняет** предмет:
|
||
на 45 м обзор доходит до 49 м, предмет оказывается ближе преграды — и 63 луча из 89
|
||
приходят разом. Ровно с этого места и начинается обнаружение.
|
||
|
||
Для сравнения, на том же замере `roundT_pressureGate_roundT` преграда всегда **за**
|
||
предметом (предмет на 104 м — преграда на 113 м; предмет на 56 м — преграда на 70 м),
|
||
поэтому там предмет виден, и разрез по контрасту может ему помочь.
|
||
|
||
**Почему видимость на этом перегоне такая короткая.** По бэгу в целом вдоль оси пути
|
||
видно на 106 м (медиана), но полигон ставит предмет в точку за 200 м от начала
|
||
записи, а это самое начало проезда — как раз худший его участок. Плюс общий для всех
|
||
бэгов эффект: луч, идущий вдоль пути, **скользит по полотну**, и с какой-то дальности
|
||
прирельсовая зона перестаёт наблюдаться вовсе. Нижняя наблюдаемая точка у оси пути
|
||
(5-й процентиль высоты над головкой рельса):
|
||
|
||
| Дальность | 20 м | 40 | 60 | 80 | 90 | 100 |
|
||
|---|---|---|---|---|---|---|
|
||
| `roundT_doubleT` | −0.35 | −0.32 | −0.21 | −0.07 | **+0.36** | **+0.64** |
|
||
| `roundT_pressureGate_roundT` | −0.32 | −0.32 | −0.06 | +0.18 | +0.10 | −0.11 |
|
||
| `doubleT_platform` | −0.35 | −0.36 | −0.34 | −0.06 | +0.08 | +0.35 |
|
||
|
||
За 80–90 м самое низкое, что видно у оси, находится уже **выше рельса** на 0.1–0.6 м.
|
||
Это и есть предел скользящего луча, и он объясняет, почему у мелких лежащих предметов
|
||
видимость в полигоне 25–61 %: их просто нечем осветить.
|
||
|
||
Никакой обработкой это не лечится. Лечится геометрической картой линии (п. 7.3) —
|
||
или вторым сенсором, поднятым выше.
|
||
|
||
### 35–52 м: лучи есть, кандидата нет — и это наш порог
|
||
|
||
Здесь картина обратная: лучей 83…146, а кандидата нет.
|
||
|
||
| Дальность | 41.6 | 38.7 | 35.9 | 33.3 | 30.7 | 28.3 |
|
||
|---|---|---|---|---|---|---|
|
||
| Лучей на предмете | 83 | 101 | 126 | 146 | 168 | 200 |
|
||
| Кандидат при `split_near = 55` | нет | нет | нет | нет | есть | есть |
|
||
| Кандидат при `split_near = 20` | есть | есть | есть | есть | есть | есть |
|
||
|
||
Причина — тот же мерж со стеной, что в п. 9.3, и наш собственный порог: разрез по
|
||
контрасту по умолчанию не применяется ближе 55 м. Порог был введён из соображения
|
||
«ближе покадровый тракт видит предмет и сам» — на этом бэге это неверно.
|
||
|
||
Со сниженным порогом первая тревога наступает на **37.3 м вместо 28.3 м**, а доля
|
||
кадров без кандидата в окне 20–42 м падает с 44 % до 6 %.
|
||
|
||
**Порог всё равно оставлен 55 м.** Цена снижения измерена честно — с пересбором кэша
|
||
кандидатов при `split_near = 20` и переобучением памяти на нём:
|
||
|
||
| `split_near` | Ложных треков на км | Кадров с тревогой |
|
||
|---|---|---|
|
||
| **55 м** | **7.4** | **16.7 %** |
|
||
| 30 м | 14.1 | 25.6 % |
|
||
| 20 м (память не пересобрана) | 18.1 | 28.2 % |
|
||
| 20 м (**честно**, память переобучена) | 17.1 | 27.9 % |
|
||
|
||
Переобучение на этот раз почти ничего не вернуло (18.1 → 17.1): ближние вырезанные
|
||
фигуры от препятствий действительно неотличимы. А выигрыш — девять метров на
|
||
дальности, где он ничего не меняет: ТЗ оценивает 100 / 200 / 300 м, и поезд на
|
||
50 км/ч не останавливается ни за 28, ни за 37 м. Платить за это 2.3-кратным ростом
|
||
ложных тревог нельзя.
|
||
|
||
`split_near: 20.0` в конфиге доступен для линии, где обстановка беднее и ложные
|
||
тревоги дешевле.
|
||
|
||
|
||
---
|
||
|
||
## 10. Новый участок: привыкание внутри проезда — отрицательный результат
|
||
|
||
Обученная память отвечает на вопрос «этот тоннель я уже видел». На новом участке
|
||
она бесполезна по определению, и это измеренная величина, а не абстрактный риск:
|
||
|
||
| | Ложных треков на км | Кадров с тревогой |
|
||
|---|---|---|
|
||
| память обучена на других бэгах (leave-one-bag-out) | 9.1 | 17.2 % |
|
||
| **памяти нет вовсе (новая линия)** | **21.8** | **33.1 %** |
|
||
|
||
Приватный тест — это как раз новый участок, поэтому вопрос важный. Механизм был
|
||
сделан, доведён до работы и **отвергнут по результатам замера**. Ниже — почему,
|
||
потому что отрицательный результат здесь содержательнее положительного.
|
||
|
||
### Замысел
|
||
|
||
**Тоннельная обстановка повторяется вдоль пути, а посторонний предмет — нет.**
|
||
Кабельный кронштейн, рама крепи, стык тюбингов встречаются каждые несколько метров
|
||
в одном и том же виде; разбор худшего бэга (п. 5.1) прямо это показал — пять из
|
||
восьми ложных треков были колоннами, повторяющимися каждые 13–20 м. Упавший же
|
||
предмет лежит в одном месте.
|
||
|
||
Отсюда привыкание, считающее не по времени и не по числу кадров, а по **числу
|
||
разных точек пути**, где встретилась эта форма. Настоящий предмет виден сто кадров
|
||
подряд, но всё это время стоит в одной точке мира: его код депрессируется один раз
|
||
и остаётся новым до конца подъезда. Биологически это familiarity suppression
|
||
MBON-α′3, а момент депрессии разрешает координата пути из центрального комплекса —
|
||
роль, которую у мухи играют дофаминергические PPL1/PAM.
|
||
|
||
### Что пришлось починить, чтобы механизм вообще заработал
|
||
|
||
Обе ошибки найдены замером и сами по себе поучительны.
|
||
|
||
**Полный набор признаков не годится.** Первая версия кодировала кандидата тем же
|
||
дескриптором, что и долговременная память. За двенадцать разных мест новизна упала
|
||
с 1.000 до 0.981 — то есть ни на что. В дескрипторе есть дальность, число лучей,
|
||
угловой размер, интенсивность: код одного и того же кронштейна с 90 и с 40 м
|
||
разъезжается, повторы не узнаются, а подъезжающий предмет каждый кадр выглядит
|
||
новой формой и привыкает сам к себе. Переведено на десять признаков формы, не
|
||
зависящих от дальности.
|
||
|
||
**Нормировка обязана замирать.** Пока среднее и разброс пересчитываются, вместе с
|
||
ними плывёт код. У неподвижного предмета, чьи признаки формы не меняются вовсе,
|
||
набор активных клеток обновлялся настолько, что предмет засчитывался как
|
||
**двадцать шесть разных мест** и гасил сам себя. При пороге заморозки 4000
|
||
кандидатов эффект оставался живуч: в `roundT_doubleT` (около 570 кандидатов за
|
||
проезд) нормировка не замирала никогда, привыкание стояло на 0.20, медианная
|
||
новизна кандидата 1.00, и ложных треков было ровно столько же, сколько без него.
|
||
Порог снижен до 300.
|
||
|
||
### Почему всё равно отвергнуто
|
||
|
||
После починок механизм начал давать цифры: leave-one-bag-out 7.5 → **5.9** ложных
|
||
трека на км, новая линия 31.8 → **26.8**. Выглядело как успех — до проверки
|
||
обратной стороны.
|
||
|
||
**Привыкание глушило сам предмет.** Замер на вставленных предметах
|
||
(`doubleT_platform`, подъезд с 200 м):
|
||
|
||
| | Новизна кандидата, 20–60 м | Обнаружение, 70–90 м |
|
||
|---|---|---|
|
||
| привыкание выключено | 0.75 | 95 % |
|
||
| привыкание включено | **0.24** | **74 %** |
|
||
|
||
И это не «предмет заодно с обстановкой»: медианная новизна обычного кандидата в тех
|
||
же прогонах — 0.43…0.71, то есть **предмет подавлялся сильнее, чем тоннельная
|
||
обстановка**. Избирательность не просто мала, она отрицательна.
|
||
|
||
**Причина — насыщение популяции, а не узнавание повторов.** За проезд набирается
|
||
около 270 событий депрессии по 80 клеток каждое; при популяции 4000 это 5.4 попадания
|
||
на клетку, то есть подавлено всё. Ровно та же ошибка, что описана в п. 8 для
|
||
долговременной памяти с мушиными параметрами, — и проверяется она так же, поднятием
|
||
ёмкости:
|
||
|
||
| Ёмкость короткой памяти | Ложных треков на км (LOO) | Новизна предмета | Обнаружение 70–90 м |
|
||
|---|---|---|---|
|
||
| привыкание выключено | 7.5 | 0.75 | 95 % |
|
||
| 4 000 клеток | **5.9** | **0.24** | **74 %** |
|
||
| 20 000 клеток | 7.5 | 0.47 | 95 % |
|
||
| 50 000 клеток | 7.5 | 0.64 | 95 % |
|
||
|
||
При ёмкости, достаточной чтобы не насыщаться, привыкание не меняет **ничего**: 7.5
|
||
против 7.5 на обученной памяти и 31.8 против 31.8 на новой линии. Весь видимый
|
||
выигрыш был глобальным глушением — а его и так даёт порог решения, который у нас
|
||
уже есть отдельным параметром.
|
||
|
||
Пробовались два способа сделать отсчёт избирательным, оба измерены и оба ничего не
|
||
дали:
|
||
|
||
* **резкий отсчёт MBON**: вместо среднего по активным клеткам — квантиль 0.75 или
|
||
0.90, то есть «знакомо, только если подавлено не меньше трёх четвертей кода».
|
||
Новизну предмета это вернуло (0.75), но и весь эффект тоже (7.5 → 7.5);
|
||
* **огрубление признаков** (coarse coding) до половины и до целого разброса, чтобы
|
||
два похожих кронштейна давали буквально один и тот же код: 7.5 / 7.5 / 7.5.
|
||
|
||
### Что это на самом деле означает
|
||
|
||
Коды двух разных экземпляров одной и той же конструкции не перекрываются настолько,
|
||
чтобы второй узнавал первого, даже после огрубления до целого стандартного
|
||
отклонения. Проще говоря: **в этих данных штатная обстановка повторяется не так
|
||
буквально, как предполагалось**. Разброс между экземплярами одной конструкции —
|
||
по ракурсу, по числу лучей, по тому, какая часть попала в габарит — больше, чем
|
||
разрешение любого разумного кода формы.
|
||
|
||
Поэтому на новом участке работает то, что и работало: долговременная память,
|
||
обученная на других участках, снижает ложные тревоги с 21.8 до 9.1 трека на
|
||
километр. Признаки в дескрипторе намеренно смешаны — форма и угловой размер
|
||
переносятся на любой тоннель, положение в сечении запоминает конкретную обстановку,
|
||
и именно первая половина даёт этот перенос.
|
||
|
||
**Механизм оставлен в коде и выключен** (`enable_habituation: false`) со всеми
|
||
параметрами: ёмкость, квантиль отсчёта, огрубление, шаг «разных мест», путь
|
||
полузабывания. На линии, где обстановка стандартизована сильнее, чем в этих записях,
|
||
он может заработать — но проверять это надо замером на той линии, а не надеждой.
|
||
|
||
---
|
||
|
||
## 11. Обученное считывание MBON: метки из физики
|
||
|
||
До сих пор грибовидное тело училось **без учителя**: оно запоминало частоту
|
||
обстановки и отвечало «знакомо/ново». Вставка предметов трассировкой лучей даёт
|
||
то, чего в датасете нет, — **метку**. `synth.inject` возвращает индексы лучей,
|
||
которые он переписал, поэтому кандидат размечается точным пересечением: предмет,
|
||
если не меньше половины его лучей пришли от вставки (`tools/make_training_set.py`,
|
||
`MIN_OVERLAP = 0.5`). Слои остаются те же — разрежённый код клеток Кеньона,
|
||
торможение APL, один выход MBON, — меняется только учитель: вместо частоты
|
||
обстановки различение «предмет / тоннель» (`flyguard/mbon_readout.py`).
|
||
|
||
### 11.1. Сначала — найденный артефакт: интенсивность выдавала вставку
|
||
|
||
Первое же обучение дало подозрительно красивые цифры: leave-one-bag-out AUC
|
||
**0.9935**, по полосам дальности от 0.998 вблизи до 0.941 на 160–230 м. Разбор
|
||
важности перестановкой поставил наверх не форму, а **интенсивность**:
|
||
|
||
```
|
||
inten +0.0187 ← втрое больше следующего
|
||
elongation +0.0051
|
||
fill +0.0048
|
||
log_rays +0.0030
|
||
```
|
||
|
||
Проверка показала, откуда это взялось. Интенсивность вставки считалась по
|
||
ламбертовой модели ρ·cosθ/r², и произведение `intensity · r²` у вставленных
|
||
предметов держалось в пределах **1.8×** между p10 и p90, тогда как у настоящих
|
||
кандидатов разброс **64×**. Иначе говоря, вставка — и только она — точно
|
||
подчинялась учебниковому закону обратных квадратов, и это распознаётся надёжнее
|
||
любой формы.
|
||
|
||
Хуже того, у нижнего среза шкалы признак переворачивается. Разделяющая
|
||
способность **одной интенсивности** по полосам:
|
||
|
||
| полоса | intensity вставки | intensity обстановки | AUC по одной интенсивности |
|
||
|---|---:|---:|---:|
|
||
| 0–30 м | 37.2 | 5.0 | 0.956 |
|
||
| 30–55 м | 4.6 | 4.5 | 0.513 |
|
||
| 55–80 м | 1.7 | 4.0 | 0.287 |
|
||
| 80–110 м | 1.0 | 3.0 | 0.197 |
|
||
| 110–160 м | 1.0 | 5.0 | **0.049** |
|
||
| 160–230 м | 1.0 | 7.5 | **0.010** |
|
||
|
||
За 110 м расчётная яркость вставки падала ниже единицы, упиралась в срез шкалы —
|
||
и «тускло» становилось почти безошибочным признаком предмета. AUC 0.010 означает
|
||
почти идеальное разделение с обратным знаком.
|
||
|
||
**В реальных данных всё наоборот.** Медиана интенсивности по всему облаку,
|
||
20 кадров на бэг:
|
||
|
||
| бэг | 5–15 м | 15–30 | 30–50 | 50–80 | 80–120 | 120–170 | 170–230 |
|
||
|---|---:|---:|---:|---:|---:|---:|---:|
|
||
| `doubleT_obstacle` | 11 | 9 | 8 | 9 | 6 | 6 | 6 |
|
||
| `roundT_doubleT` | 10 | 8 | 8 | 4 | 2 | 3 | 4 |
|
||
| `squareT_platform_squareT_switch` | 8 | 8 | 7 | 3 | 2 | 2 | 4 |
|
||
|
||
Никакого 1/r². Прибор отдаёт не принятую энергию, а **отражательную способность
|
||
с компенсацией дальности** — то, что в руководстве Hesai называется
|
||
reflectivity. Ламбертова модель описывала физику фотона, а не то число, которое
|
||
лежит в поле `intensity`.
|
||
|
||
Настоящий предмет даёт точку привязки. В `doubleT_obstacle` он стоит на 55.9 м,
|
||
57 лучей, и его медианная интенсивность — **34.5** (p10…p90 = 31…39) при
|
||
медиане окружающих кандидатов 23.5. Старая формула на этой дальности дала бы
|
||
**1.45**, то есть в 24 раза тусклее настоящего.
|
||
|
||
**Первая попытка починки была неправильной.** Раз прибор компенсирует
|
||
дальность, яркость вставки сделали постоянной: `100 · ρ · √cosθ` со шкалой,
|
||
привязанной к настоящему предмету (ρ = 0.35 → около 34). Выборка пересобрана,
|
||
модель переобучена — и артефакт просто перевернулся:
|
||
|
||
| полоса | вставка | обстановка | AUC по одной интенсивности |
|
||
|---|---:|---:|---:|
|
||
| 0–30 м | 35.0 | 5.0 | 0.966 |
|
||
| 30–55 м | 35.2 | 4.5 | 0.960 |
|
||
| 55–80 м | 34.9 | 4.0 | 0.959 |
|
||
| 80–110 м | 35.1 | 3.0 | 0.970 |
|
||
| 110–160 м | 34.8 | 5.0 | 0.832 |
|
||
| 160–230 м | 34.2 | 7.5 | 0.798 |
|
||
|
||
Важность интенсивности при этом выросла втрое (+0.0533 против +0.0187), то есть
|
||
модель стала опираться на подсказку ещё сильнее.
|
||
|
||
**Настоящая причина: абсолютной шкалы в этих данных нет.** Медиана яркости
|
||
кандидатов обстановки по бэгам — 3.0, 4.0, 4.0, 4.0, 7.0, а в
|
||
`doubleT_obstacle`, где лежит настоящий предмет, 23.5 при 34.5 у самого
|
||
предмета. Разброс между записями впятеро больше, чем контраст предмета к фону
|
||
внутри записи. Любое абсолютное число, назначенное вставке, оказывается
|
||
подарком детектору — в ту или в другую сторону.
|
||
|
||
**Как сделано в итоге** (`synth.local_intensity` и `synth.IntensityEnv`):
|
||
вставка берёт яркость **реальных возвратов с тех же самых лучей** — того, что
|
||
предмет заслонил. Лучи, ушедшие в пустоту (за 100 м таких большинство),
|
||
получают образец из реальных возвратов **той же полосы дальности** в этом же
|
||
кадре; разложение кадра по дальности считается один раз и переиспользуется
|
||
всеми 135 сценариями. Ни отражательной способности, ни закона яркости от
|
||
дальности в функции нет; ρ осталась там, где ей место, — в вероятности, что
|
||
эхо вообще вернётся. Проверка вставками в реальные бэги:
|
||
|
||
| дальность | 30 м | 60 м | 100 м | 150 м | 200 м |
|
||
|---|---:|---:|---:|---:|---:|
|
||
| вставка | 8.8 | 6.9 | 4.3 | 4.3 | 10.1 |
|
||
| реальные возвраты рядом | 10.0 | 4.0 | 2.0 | 3.0 | 3.0 |
|
||
|
||
Это **заниженная** оценка: настоящий предмет в записи был в 1.47 раза ярче
|
||
окружения, и этот запас мы себе не засчитываем. На линии с откалиброванной
|
||
яркостью его можно вернуть — замером, а не верой. Тест
|
||
`test_injected_intensity_copies_the_surroundings` держит свойство: среди
|
||
аргументов нет отражения, а без разложения окружения дальность ничего не меняет.
|
||
|
||
Замечание, важное для оценки ущерба: складка, не видевшая `doubleT_obstacle`,
|
||
и с артефактом ставила настоящему предмету **1.000** (p10 = 0.998) против 0.393
|
||
у обстановки — на ближней дальности модель опиралась не только на подсказку.
|
||
Но полигонная дальность, измеренная на таких вставках, мерила бы признак,
|
||
которого в реальности нет. Поэтому все цифры ниже получены на выборке, где
|
||
яркость взята из самой записи.
|
||
|
||
Отдельный урок про метрику: таблицы выше потребовали починить подсчёт AUC.
|
||
Ранги раздавались по порядку в массиве, а не усреднялись на совпадениях, и
|
||
признак, у которого все значения равны, получал 0 или 1 вместо 0.5. Первым
|
||
ложным сигналом такого рода оказался контраст к фону за 160 м — там он
|
||
структурно равен нулю у всех кандидатов сразу. Теперь ранги средние, а сторож
|
||
«что делит выборку само по себе» встроен в `tools/train_mbon.py` и печатается
|
||
перед каждым обучением.
|
||
|
||
### 11.2. Что даёт обученное считывание
|
||
|
||
Обучение — полнопакетный логистический спуск по разрежённому коду: 4 000
|
||
клеток Кеньона, 100 активных после торможения APL, 23 признака кандидата,
|
||
185 252 примера, 19 445 из них предметы. Ёмкость выбрана развёрткой: 8 000 и
|
||
20 000 клеток дают ту же AUC (0.9859 и 0.9850 против 0.9860), а в худшем кадре
|
||
стоят 2.8 и 7.3 мс вместо 1.5 — платить не за что.
|
||
|
||
Проверка — leave-one-bag-out, отдельная модель на каждую складку. Без этого
|
||
сквозные цифры были бы ложными: считывание увидело бы проверяемый бэг ровно
|
||
так же, как память тоннеля, обученная на всём подряд.
|
||
|
||
| бэг | AUC | обстановки при 95 % предметов | бустинг по сырым признакам |
|
||
|---|---:|---:|---:|
|
||
| `doubleT_platform` | 0.9923 | 3.54 % | 0.9951 |
|
||
| `roundT_doubleT` | 0.9939 | 2.79 % | 0.9987 |
|
||
| `roundT_pressureGate_roundT` | 0.9759 | 16.30 % | 0.9866 |
|
||
| `roundT_squareT_pressureGate_squareT` | 0.9828 | 11.65 % | 0.9930 |
|
||
| `squareT_platform_squareT_switch` | 0.9851 | 5.87 % | 0.9902 |
|
||
| **среднее** | **0.9860** | **8.03 %** | 0.9927 |
|
||
|
||
AUC по полосам дальности: 0.995 / 0.996 / 0.992 / 0.973 / 0.955 / 0.738 —
|
||
качество честно падает с дальностью, как и должно быть, когда от предмета
|
||
остаётся четыре луча.
|
||
|
||
Градиентный бустинг по тем же сырым признакам стабильно лучше на 0.005…0.01
|
||
AUC. Это цена разрежённого кода, и мы её знаем: взамен получаем схему, которая
|
||
считается за 1.5 мс на худшем кадре и держит непрерывное дообучение.
|
||
|
||
Наверху важности — форма, а не положение и не яркость:
|
||
|
||
```
|
||
fill +0.0079 abs_lat +0.0051
|
||
elongation +0.0076 acc_support +0.0046
|
||
h +0.0055 lat +0.0044
|
||
```
|
||
|
||
Положение в сечении (`abs_lat`, `lat`) стоит на 4–6 месте. Формально это
|
||
законный признак — опасны именно предметы в габарите, — но границу
|
||
«положительной» области задали наши же расстановки (0, ±0.6, ±1.2 м от оси),
|
||
и на защите это надо называть вслух, а не прятать.
|
||
|
||
**Сквозной результат, leave-one-bag-out:**
|
||
|
||
| | без считывания | со считыванием |
|
||
|---|---:|---:|
|
||
| разных ложных треков на километр | 7.5 | **3.3** |
|
||
| кадров с ложной тревогой | 16.7 % | **4.4 %** |
|
||
| реальный объект на 55 м | 98.9 % | **98.9 %** |
|
||
| задержка кадра, медиана | 33 мс | 35–41 мс |
|
||
|
||
**На размеченном полигоне** (модель по складкам, то есть для каждого бэга та,
|
||
что его не видела):
|
||
|
||
| человек стоя | без считывания | со считыванием |
|
||
|---|---:|---:|
|
||
| рабочая дальность «как есть» | 62 м | **80 м** |
|
||
| P@50 м | 0.70 | 0.70 |
|
||
| P@100 м | 0.19 | **0.31** |
|
||
| посторонних тревог на кадр | 0.169 | **0.030** |
|
||
|
||
Прибавка не только на человеке: ящик P@100 0.02 → 0.24, человек сидя
|
||
0.25 → 0.39, чемодан P@50 0.55 → 0.60, ведро впервые поднялось над нулём
|
||
(рабочая дальность 8 → 20 м).
|
||
|
||
Отдельно: прежние заявленные 100 м рабочей дальности и P@100 = 0.53 получены
|
||
на полигоне с артефактом яркости и **завышены**. Честные числа без считывания —
|
||
80 м и 0.19, со считыванием — 80 м и 0.31.
|
||
|
||
### 11.3. Сколько дальности покупается за ложные тревоги
|
||
|
||
Смысл обученного считывания не в том, чтобы просто показать меньшее число
|
||
ложных. Оно даёт **запас**, а запас надо тратить: поезд движется, и дальность
|
||
обнаружения — это время на торможение. Поэтому пороги решения вынесены в
|
||
`Params` и развёрнуты замером. Все строки — leave-one-bag-out по ложным и
|
||
полигон по дальности, модель по складкам:
|
||
|
||
| конфигурация | ложных треков/км | кадров с тревогой | реальный объект | P@50 | P@100 | тревог на кадр, полигон |
|
||
|---|---:|---:|---:|---:|---:|---:|
|
||
| без считывания | 7.4 | 16.65 % | 98.9 % | 0.70 | 0.19 | 0.169 |
|
||
| считывание, три подтверждения | 3.3 | 4.44 % | 98.9 % | 0.70 | 0.31 | 0.030 |
|
||
| **по умолчанию: считывание, два подтверждения** | **3.3** | **4.52 %** | **99.5 %** | **0.70** | **0.31** | **0.030** |
|
||
| тише: смешивание 0.7 | 2.5 | 4.85 % | 98.9 % | 0.70 | 0.23 | 0.016 |
|
||
| дальше: порог улики 0.40 | 5.3 | 6.19 % | 98.9 % | 0.71 | 0.34 | 0.039 |
|
||
| смешивание 0.7 + порог 0.32 | 4.3 | 7.28 % | 98.9 % | 0.71 | 0.31 | 0.055 |
|
||
| порог 0.30 | 7.8 | 8.37 % | — | — | — | — |
|
||
| порог 0.22 | 9.8 | 10.04 % | — | — | — | — |
|
||
|
||
Три вывода, каждый замером.
|
||
|
||
**Смешивание с ручной формулой — не способ купить дальность.** Строка
|
||
«смешивание 0.7 + порог 0.32» даёт ровно ту же P@100 = 0.31, что и чистая
|
||
модель при штатном пороге, но стоит 4.3 ложных трека вместо 3.3 и вдвое
|
||
больше посторонних тревог на полигоне. Смешивание полезно в другом качестве —
|
||
как **тихий режим**: при штатном пороге оно опускает ложные до 2.5 на км и
|
||
0.016 на кадр, отдавая дальность (P@100 0.31 → 0.23). Оно же — страховка на
|
||
случай, когда предмет не похож ни на что из каталога: ручная формула
|
||
продолжает работать по геометрии.
|
||
|
||
**Понижение порога работает, но дорого.** 0.50 → 0.40 добавляет 0.03 к P@100
|
||
человека и 0.07 ящику, а платит 3.3 → 5.3 ложных трека. Дальше кривая только
|
||
круче: 0.30 стоит 7.8, 0.22 — 9.8, то есть хуже, чем было без считывания
|
||
вообще. Оставлено пресетом, а не умолчанием.
|
||
|
||
**Два подтверждения вместо трёх оказались бесплатными.** Ложные не изменились
|
||
(3.3 на км, 4.44 → 4.52 % кадров), посторонние тревоги на полигоне не
|
||
изменились тоже (0.030 на кадр), а обнаружение выросло: реальный объект
|
||
98.9 → **99.5 %**, рабочая дальность человека сидя 20 → **80 м**, чемодана
|
||
«как есть» 20 → **62 м**. Причина видна из данных: на 60…100 м предмет
|
||
среднего размера виден через кадр, и третьего подтверждения приходится ждать
|
||
дольше, чем он успевает приблизиться. Это стало умолчанием.
|
||
|
||
Строки пресетов измерены при трёх подтверждениях — прежнем умолчании. В
|
||
базовой точке переход на два ложных не изменил, но для пресетов это отдельно
|
||
не перемерялось.
|
||
|
||
**Чего порогами не изменить.** P@150 равна нулю в любой конфигурации. Это не
|
||
алгоритм: прямая видимость в этих тоннелях 121–167 м, а прирельсовая зона за
|
||
80–90 м не наблюдается вовсе — луч скользит по полотну (п. 3 и п. 7.3).
|
||
Потолок здесь геометрический.
|
||
|
||
---
|
||
|
||
## 12. Воронка потерь: где именно пропадает видимый предмет
|
||
|
||
Кривая дальности говорит, сколько мы теряем, но не где. Поэтому полигон
|
||
инструментирован тремя ступенями: попали ли лучи в предмет (видимость),
|
||
появился ли кандидат, собрался ли трек, прошло ли решение. Считается доля
|
||
от **видимых** наблюдений, то есть от тех, где предмет физически освещён
|
||
лучами и претензии к алгоритму осмысленны.
|
||
|
||
Человек стоя, конфигурация по умолчанию:
|
||
|
||
| полоса | видимых | кандидат | трек | решение | нет кандидата | трек без решения |
|
||
|---|---:|---:|---:|---:|---:|---:|
|
||
| 6–30 м | 396 | 0.82 | 0.89 | 0.82 | 0.18 | 0.06 |
|
||
| 30–50 м | 184 | 0.55 | 0.64 | 0.59 | **0.45** | 0.05 |
|
||
| 50–70 м | 147 | 0.75 | 0.82 | 0.81 | 0.25 | 0.01 |
|
||
| 70–90 м | 131 | 0.73 | 0.68 | 0.62 | 0.27 | 0.06 |
|
||
| 90–120 м | 177 | 0.66 | 0.54 | 0.24 | 0.34 | **0.31** |
|
||
| 120–160 м | 251 | 0.62 | 0.37 | 0.00 | 0.38 | **0.37** |
|
||
|
||
Столбец «трек» бывает выше «кандидата»: трек живёт между кадрами и
|
||
переживает кадр без кандидата — это не ошибка таблицы, а работа накопителя.
|
||
|
||
Видны **две разные** болезни, и лечатся они по-разному.
|
||
|
||
### 12.1. Ближняя: 30–50 м, кандидат не рождается
|
||
|
||
Худшая полоса во всём диапазоне — хуже, чем 120–160 м. Причина известна:
|
||
разрез компоненты по контрасту запрещён ближе 55 м (`split_near`), и предмет,
|
||
слипшийся со стеной, уходит вместе с ней. Запрет стоял потому, что снятие
|
||
стоило слишком дорого по ложным. Обученное считывание удвоило бюджет, и
|
||
проверку повторили:
|
||
|
||
| не резать ближе | ложных треков/км | кадров с тревогой |
|
||
|---|---:|---:|
|
||
| **55 м (принято)** | **3.3** | **4.5 %** |
|
||
| 40 м | 6.3 | 7.5 % |
|
||
| 30 м | 7.3 | 9.6 % |
|
||
| 20 м | 8.3 | 12.1 % |
|
||
| резать везде | 8.3 | 12.7 % |
|
||
|
||
Весь выигрыш считывания съедается уже к 30 м, а на 20 м мы хуже, чем были
|
||
без модели вообще. Запрет оставлен. Дополнительный довод: при служебном
|
||
торможении с 60 км/ч тормозной путь с реакцией около 160 м, то есть полоса
|
||
30–50 м для полной остановки поздняя в любом случае — платить за неё
|
||
ложными тревогами на всей дистанции невыгодно.
|
||
|
||
### 12.2. Дальняя: за 90 м трек есть, решения нет
|
||
|
||
Здесь теряется 0.31 и 0.37 видимых наблюдений уже **после** того, как трек
|
||
собран. Первая догадка — порог. Проверена и отвергнута: порог тревоги,
|
||
линейно опущенный с 0.5 до 0.3 начиная с 90 м, не изменил ни ложных
|
||
(3.3 на км), ни обнаружения (P@100 = 0.31, решения за 120 м по-прежнему 0).
|
||
Порог новизны тоже ни при чём: с нулём вместо 0.10 всё то же самое.
|
||
|
||
Настоящая причина считается на бумаге. Улика растёт на `gain · качество` за
|
||
попадание и падает на `leak` за промах, при `gain` 0.34 и `leak` 0.12. При
|
||
доле попаданий p улика не убывает только если `p·gain·w > (1-p)·leak`. На
|
||
120–160 м кандидат появляется в 62 % наблюдений, откуда порог по качеству
|
||
**w > 0.22** — столько далёкое наблюдение из четырёх лучей не даёт никогда.
|
||
Поэтому улика далёкого трека не «чуть ниже порога», а колеблется около нуля,
|
||
и снижать порог бессмысленно.
|
||
|
||
Промах на 150 м, однако, не свидетельство отсутствия предмета, а свойство
|
||
решётки: там предмет виден через кадр. Ровно по этой причине число лучей уже
|
||
нормируется на ожидаемое для этой дальности (`_quality`), и промах надо
|
||
нормировать так же. Утечка сделана зависящей от дальности (`leak_far`).
|
||
Цена замерена сразу на двух сценах:
|
||
|
||
| утечка на дальнем краю | ложных/км, память обучена | то же на новой линии |
|
||
|---|---:|---:|
|
||
| 0.12 (было) | 3.3 | 20.6 |
|
||
| 0.06 | 3.3 | 21.6 |
|
||
| 0.03 | 3.3 | 21.6 |
|
||
| 0.01 | 3.3 | 21.6 |
|
||
|
||
Цена плоская: появление долгоживущих далёких треков стоит примерно одного
|
||
лишнего трека на километр на незнакомой линии и ничего — на знакомой.
|
||
|
||
### 12.3. Из чего на самом деле состоит улика далёкого предмета
|
||
|
||
Три ручки подряд ничего не дали, и это был знак, что ограничитель другой.
|
||
Поэтому вместо четвёртой развёртки — прямая трассировка: человек стоя
|
||
вставлен на 150 м, 178 кадров, и на каждом выписаны все множители улики.
|
||
|
||
| величина | медиана | p90 |
|
||
|---|---:|---:|
|
||
| лучей в предмете | 6 | 8 |
|
||
| кандидат найден | 164 из 178 кадров | |
|
||
| оценка MBON | **0.078** | 0.493 |
|
||
| новизна | **0.153** | 0.221 |
|
||
| качество улики (произведение) | **0.005** | 0.034 |
|
||
|
||
Новый трек выживает, только если `gain · качество > 0.02`, то есть при
|
||
качестве выше 0.059. Таких наблюдений **5.5 %**. Материал, стало быть, есть
|
||
— кандидат находится в 92 % кадров, — а улику копить нечем. Ни порогом, ни
|
||
утечкой это не лечится, потому что ноль на любой множитель остаётся нулём.
|
||
|
||
Дальше видно, какой из двух множителей виноват. На 120–185 м, 299
|
||
кандидатов, из них 231 — предмет:
|
||
|
||
| множитель | предмет | обстановка | AUC |
|
||
|---|---:|---:|---:|
|
||
| новизна | 0.150 | 0.199 | **0.293** |
|
||
| оценка MBON | 0.051 | 0.003 | 0.743 |
|
||
|
||
**Новизна на дальности перевёрнута.** Настоящий предмет выглядит более
|
||
знакомым, чем окружающая обстановка: на шести лучах дескриптор вырождается,
|
||
и память узнаёт в предмете любую далёкую конструкцию. Мы этим множителем
|
||
гасили собственный сигнал.
|
||
|
||
**Модель различает, но её ответ раздавлен редкостью.** Доля предметов среди
|
||
кандидатов падает с 42 % на 0–30 м до 3.1 % за 160 м, и калиброванная
|
||
апостериорная вероятность обязана падать вместе с ней — даже когда улика
|
||
по существу та же. Различие при этом сохраняется: 0.051 против 0.003, в
|
||
семнадцать раз.
|
||
|
||
Отсюда две правки, обе — нормировка на то, что достижимо на этой дальности,
|
||
ровно как уже сделано для числа лучей в `_quality`:
|
||
|
||
* **гашение знакомости с дальностью** (`nov_fade_from`): за 90 м вклад
|
||
новизны плавно сходит к нулю, вблизи остаётся как был;
|
||
* **поправка на распространённость** (`mbon_prior_from`): из логита модели
|
||
вычитается типичный для этой полосы, то есть апостериорная вероятность
|
||
превращается в отношение правдоподобий.
|
||
|
||
Поправка на распространённость **сама по себе не дала ничего**: ни ложных
|
||
(3.3 на км), ни обнаружения (P@100 = 0.31, за 120 м ноль), воронка не
|
||
сдвинулась ни на сотую. Это ожидаемо и поучительно: пока второй множитель
|
||
обнуляет произведение, правильная правка первого бесполезна.
|
||
|
||
Гашение знакомости дало главный результат дня:
|
||
|
||
| человек стоя | было | стало |
|
||
|---|---:|---:|
|
||
| P@50 | 0.70 | 0.70 |
|
||
| P@100 | 0.31 | **0.48** |
|
||
| P@150 | 0.00 | **0.32** |
|
||
| решений в полосе 120–160 м | 0.00 | **0.40** |
|
||
| ложных треков/км, память обучена | 3.3 | 5.6 |
|
||
| то же на новой линии | 21.6 | **21.6** |
|
||
| посторонних тревог на кадр, полигон | 0.030 | 0.047 |
|
||
|
||
Впервые предмет вообще обнаруживается на 150 м. Цена — полтора лишних
|
||
ложных трека на километр **на знакомой линии**; на незнакомой правка
|
||
бесплатна, потому что отказываться там не от чего. Приватный тест — это
|
||
именно незнакомая линия.
|
||
|
||
Отдельно про характер цены: лишние далёкие треки дают **предупреждения, а не
|
||
торможение**. Экстренный уровень требует `d ≤ max(тормозной путь, 25 м)`
|
||
(`descending.py`), поэтому далёкий ложный трек физически не может вызвать
|
||
экстренное торможение. Мы платим предупреждениями за дальность обнаружения —
|
||
для движущегося поезда это правильная сторона размена.
|
||
|
||
### 12.4. Что из этого принято
|
||
|
||
Обе правки и зависящая от дальности утечка проверены порознь и вместе,
|
||
каждая на двух сценах — линия с обученной памятью и первый проезд по
|
||
незнакомой:
|
||
|
||
| конфигурация | ложных/км, память | то же, новая линия | P@100 | P@150 | тревог на кадр |
|
||
|---|---:|---:|---:|---:|---:|
|
||
| как было | 3.3 | 20.6 | 0.31 | 0.00 | 0.030 |
|
||
| утечка 0.03 | 3.3 | 21.6 | 0.33 | 0.00 | 0.030 |
|
||
| поправка на распространённость | 3.3 | 20.6 | 0.31 | 0.00 | 0.030 |
|
||
| **гашение знакомости с 90 м** | **5.6** | **20.6** | **0.48** | **0.32** | 0.046 |
|
||
| гашение + утечка | 5.6 | 21.6 | 0.48 | 0.32 | 0.047 |
|
||
| гашение + утечка + поправка | 5.6 | 21.6 | 0.48 | 0.32 | 0.048 |
|
||
|
||
**Принято одно гашение знакомости.** Утечка добавляет к нему сотые доли
|
||
(человек сидя P@100 0.44 → 0.48, решений в полосе 120–160 м 0.37 → 0.40) и
|
||
стоит одного лишнего ложного трека на километр ровно на той сцене, которая
|
||
соответствует приватному тесту. Поправка на распространённость не даёт
|
||
ничего ни отдельно, ни в связке — таблицы обнаружения совпадают до сотой.
|
||
|
||
Обе отвергнутые правки **оставлены в коде выключенными** (`leak_far`,
|
||
`mbon_prior_from`, `warn_far`): они верны по сути, измеримы одним ключом и
|
||
могут пригодиться на линии с другой статистикой. Значения по умолчанию
|
||
выключают их полностью.
|
||
|
||
Итоговая конфигурация и её цена:
|
||
|
||
| | без гашения | **принято** |
|
||
|---|---:|---:|
|
||
| реальный объект на 55 м | 99.5 % | **99.5 %** |
|
||
| P@50, человек стоя | 0.70 | **0.70** |
|
||
| P@100 | 0.31 | **0.48** |
|
||
| P@150 | 0.00 | **0.32** |
|
||
| ложных треков/км, знакомая линия | 3.3 | 5.6 |
|
||
| кадров с тревогой, знакомая линия | 4.5 % | 9.4 % |
|
||
| ложных треков/км, новая линия | 20.6 | **20.6** |
|
||
| задержка кадра, медиана | 33 мс | **32 мс** |
|
||
|
||
Размен честный и его надо называть вслух: на **знакомой** линии доля кадров
|
||
с тревогой удваивается. Взамен появляется обнаружение на 150 м, которого не
|
||
было вовсе, а на **незнакомой** линии — там, где будет приватный тест, —
|
||
плата нулевая. Кому дороже тишина, чем дальность, ставит `nov_fade_from: 0`
|
||
и возвращается к 3.3 трека на километр.
|
||
|
||
### 12.5. Порог по числу лучей не должен быть одинаковым на всех дальностях
|
||
|
||
После того как знакомость перестала гасить далёкую улику, в воронке осталась
|
||
вторая дыра: за 120 м **0.38 видимых наблюдений не дают кандидата вовсе**.
|
||
Причина прямая — кандидатом считается компонента из четырёх лучей и больше,
|
||
а на 150 м у человека их медианно шесть, и кадры с тремя выпадают целиком.
|
||
|
||
Разрешить тройки везде — плохая замена. Вблизи обрывок из трёх лучей это
|
||
кусок чего-то большего, он дробит настоящий предмет и растаскивает
|
||
сопоставление между треками:
|
||
|
||
| человек стоя | 4 луча | 3 луча везде | **4 вблизи, 3 за 90 м** |
|
||
|---|---:|---:|---:|
|
||
| P@50 | **0.70** | 0.64 | **0.70** |
|
||
| P@100 | 0.48 | 0.48 | 0.48 |
|
||
| P@150 | 0.32 | 0.37 | **0.37** |
|
||
| человек сидя, рабочая дальность | 80 м | 100 м | **100 м** |
|
||
| человек сидя, P@100 | 0.44 | 0.53 | **0.53** |
|
||
| ящик, P@100 | 0.31 | 0.36 | **0.36** |
|
||
| ложных треков/км, знакомая линия | 5.6 | 6.3 | **5.6** |
|
||
| то же, незнакомая линия | 20.6 | 21.3 | **20.6** |
|
||
| кадров с тревогой, знакомая линия | 9.4 % | 11.4 % | 10.7 % |
|
||
|
||
Порог, зависящий от дальности, забирает **весь** дальний выигрыш тройки и не
|
||
стоит ни одного лишнего ложного трека ни на одной из двух сцен. Это третий
|
||
случай подряд, когда правильным оказалось не «подобрать значение», а
|
||
**нормировать требование на то, что физически достижимо на этой дальности**
|
||
— как уже сделано для числа лучей в весе улики и для знакомости.
|
||
|
||
Чего порог не забирает: ведро на 50 м (0.02 против 0.20 при тройке везде) и
|
||
рабочую дальность чемодана (62 м против 80 м). Это ближние эффекты, и
|
||
приходят они в комплекте с потерей 0.06 у человека стоя на 50 м — размен,
|
||
который мы не берём.
|
||
|
||
Оговорка к цифрам выше: они получены моделью, обученной на выборке с порогом
|
||
в четыре луча, то есть далёких кандидатов из трёх лучей считывание в
|
||
обучении не видело ни одного. Это **нижняя** оценка; после пересборки
|
||
выборки на итоговой конфигурации цифры в п. 11.2 и в README обновлены.
|
||
|
||
### 12.6. Пересборка выборки и итоговая конфигурация
|
||
|
||
Порог по лучам, зависящий от дальности, меняет **состав кандидатов**, а
|
||
считывание обучалось на прежнем: далёких компонент из трёх лучей в выборке
|
||
не было ни одной. Поэтому выборка пересобрана на итоговой конфигурации —
|
||
214 958 кандидатов против 185 252, предметов 20 150 (9.4 %). Прибавка почти
|
||
в 30 тысяч — это и есть далёкая мелочь, которую модель раньше не видела.
|
||
|
||
Переобучение дало AUC **0.9829** против 0.9860: задача стала труднее, потому
|
||
что в неё добавили самые бедные наблюдения. По полосам дальности
|
||
0.995 / 0.996 / 0.992 / 0.968 / 0.950 / 0.758.
|
||
|
||
Результат пересборки — **размен, а не чистый выигрыш**:
|
||
|
||
| человек стоя | модель на прежней выборке | модель на новой |
|
||
|---|---:|---:|
|
||
| рабочая дальность | 80 м | **100 м** |
|
||
| P@100 | 0.48 | **0.53** |
|
||
| P@150 | 0.37 | 0.33 |
|
||
| чемодан, P@100 | 0.13 | **0.21** |
|
||
| ложных треков/км, знакомая линия | 5.6 | 8.0 |
|
||
| то же, незнакомая линия | 20.6 | **20.3** |
|
||
|
||
Ложные на знакомой линии выросли до 8.0, и это сначала выглядело как
|
||
поражение: опора без считывания была 7.4. Но опора мерилась при **других**
|
||
настройках. При итоговых та же оценка без считывания даёт **12.9 трека на
|
||
км и 25.9 % кадров**, то есть считывание по-прежнему срезает больше трети.
|
||
Сравнивать надо равное с равным — это стоило одного лишнего прогона и
|
||
спасло от ложного вывода.
|
||
|
||
Разложение цены на знакомой линии (новая модель):
|
||
|
||
| конфигурация | ложных/км | кадров |
|
||
|---|---:|---:|
|
||
| без считывания вовсе | 12.9 | 25.9 % |
|
||
| считывание, без гашения знакомости | 3.5 | 5.0 % |
|
||
| + гашение, 4 луча везде | 6.5 | 8.7 % |
|
||
| **+ гашение, 3 луча за 90 м (принято)** | **8.0** | **11.0 %** |
|
||
|
||
Промежуточный вариант (гашение, четыре луча) измерен полностью: на человеке
|
||
стоя он неотличим (рабочая дальность 100 м, P@50 0.70, P@100 0.53,
|
||
P@150 0.32), а на всём, что меньше, — заметно хуже: человек сидя 80 м против
|
||
100 м рабочей дальности и P@100 0.44 против 0.53, ящик 0.32 против 0.38,
|
||
чемодан 0.12 против 0.21. На незнакомой линии варианты неразличимы
|
||
(20.5 и 20.3).
|
||
|
||
**Принят дальнобойный.** Упавший или сидящий человек — самый тяжёлый по
|
||
наблюдаемости и самый важный по безопасности случай, и рабочая дальность по
|
||
нему растёт с 80 до 100 м. Полтора лишних ложных трека в километре платятся
|
||
только там, где линия уже знакома; на незнакомой разницы нет.
|
||
|
||
Лестница режимов, все три измерены:
|
||
|
||
| режим | как включить | ложных/км | дальняя зона |
|
||
|---|---|---:|---|
|
||
| тихий | `nov_fade_from: 0` | 3.5 | за 90 м почти нет |
|
||
| средний | `min_rays_far: 0` | 6.5 | человек стоя есть, мелочь хуже |
|
||
| **дальнобойный (умолчание)** | — | 8.0 | полная |
|
||
|
||
### 12.7. Ближняя потеря: причина найдена, лечение отвергнуто
|
||
|
||
В воронке оставалась последняя необъяснённая дыра: на 6–30 м, где предмет
|
||
даёт сотни лучей, кандидат не появлялся в 18 % видимых наблюдений. Прямая
|
||
трассировка вставки на 6.5, 8, 10, 12, 20 и 28 м ничего не воспроизвела —
|
||
кандидат находился в **100 %** случаев (616 из 616). Ответ нашёлся в самих
|
||
данных полигона:
|
||
|
||
| смещение предмета от оси | наблюдений | без кандидата |
|
||
|---|---:|---:|
|
||
| 0.0 м | 198 | 0.01 |
|
||
| +0.9 м | 198 | **0.34** |
|
||
|
||
Хуже всего там, где есть платформа: `doubleT_platform` и
|
||
`squareT_platform_squareT_switch` по 0.27 против 0.11–0.14 у остальных.
|
||
Предмет у края габарита слипается с кромкой платформы в одну связную
|
||
компоненту и отбрасывается вместе с ней — **то же самое, что и в полосе
|
||
30–50 м**. Причина общая: разрез по контрасту запрещён ближе 55 м.
|
||
|
||
Комментарий в коде объяснял этот запрет тем, что вблизи предмет со стеной
|
||
не слипается. Замер показал, что это неверно, и объяснение исправлено.
|
||
|
||
Лечение пробовалось не «в лоб» (резать везде — уже отвергнуто в п. 12.1), а
|
||
избирательно: резать вблизи только компоненты, **слишком растянутые по
|
||
глубине**, чтобы быть предметом. Мерой служит разброс дальности внутри
|
||
компоненты: человек занимает десятки сантиметров, кромка платформы —
|
||
десятки метров. Две свёртки по меткам, доли миллисекунды.
|
||
|
||
| порог растянутости | ложных/км, знакомая | незнакомая |
|
||
|---|---:|---:|
|
||
| выключено | **8.0** | **20.3** |
|
||
| > 8 м | 10.0 | 25.2 |
|
||
| > 4 м | 12.0 | — |
|
||
| > 2 м | 12.0 | — |
|
||
|
||
Воронка при самом строгом пороге (решений от видимых наблюдений):
|
||
|
||
| полоса | без разреза | с разрезом |
|
||
|---|---:|---:|
|
||
| 6–30 м | 0.83 | **0.90** |
|
||
| 30–50 м | 0.59 | **0.68** |
|
||
| 50–70 м | **0.81** | 0.71 |
|
||
| 70–90 м | **0.62** | 0.54 |
|
||
|
||
**Отвергнуто.** Ближние полосы вылечились, но сломались средние: человек
|
||
стоя P@50 0.70 → 0.67, рабочая дальность «как есть» 80 → 62 м, посторонних
|
||
тревог на кадр 0.071 → 0.102. Механизм тот же, что и у тройки лучей вблизи:
|
||
разрез на 50–55 м дробит предмет на конкурирующие обрывки, и настоящий трек
|
||
проигрывает им в торможении по соседству.
|
||
|
||
Итог размена: мы вылечили бы полосу, которая при служебном торможении с
|
||
60 км/ч и так за тормозным путём, сломав ту, что внутри него, и заплатили бы
|
||
четвертью ложных треков на обеих сценах. Механизм оставлен в коде выключенным
|
||
(`near_long: 0`): на линии без платформ у самого габарита он может оказаться
|
||
дешевле — но проверять это надо замером на той линии.
|