air-nn — журнал хода работ

Журнал продолжается в tools/dp: docs/plan/air-nn/ (tools/dp status air-nn, tools/dp log air-nn). Ниже — история до 02.10 23:00.

План — docs/plan/air_nn.md; контракты — docs/contracts/air-nn.md. Ветка feature/air-nn (от main 9360397), копия ~/deltaplan-air-nn. Координатор — dp-coordinator.

Текущая цель (02.10.2026, от главной сессии)

Подготовить этап П к запуску: окружение, данные, один скрипт run_pilot.sh (досчёт → обучение → оценка → отчёт, с продолжением после прерывания), проверка мини-прогоном и прерываниями. Сам пилот запускает пользователь.

Решения

  • 02.10: AIR_NN_DATA=~/air_nn_data (корневой диск, ~48 ГБ свободно; диск 1–2 ТБ — открытый вопрос §10.0).
  • 02.10: решения air-lite (49/688) не сохранились — fields/*.npz были вне git в удалённой копии; в ветке есть только out/runs.jsonl (метаданные и время). Пересчитываются генератором пилота с нуля (дёшево, см. ниже).
  • 02.10: время случая по runs.jsonl (сумма t_init + t_solve всех решений случая): встроенные места — 21,8 с (область 13,7 с), синтетика — 9,9 с (область 7,9 с); 8 из 49 случаев — max (предел итераций). Оценка плана 688 случаев ≈ 3–4 ч GPU; +40 процедурных рельефов × ~30 условий ≈ 4 ч — меньше одной ночи.
  • 02.10: окружение пилота — свой .venv (uv, Python 3.12), версии — requirements.lock (torch cu126, cupy-cuda12x, onnx, onnxruntime), setup_env.sh; системный python не трогаем.
  • 02.10: контракты пилота П1 (образец набора), П2 (вход/выход сети), П3 (отчёт) — docs/contracts/air-nn.md.
  • 02.10: формат образца — раскладка air-lite (npz, fp16) без изменений; Zarr и полный state.sqlite волны 0 — не в пилоте (кроме статусов случаев в SQLite и атомарной записи — §4.6).

Задачи

ЗадачаСтатусИсполнительКопия / веткаКоммитыЧисла, решения
NN-P1 — генератор набора пилота (досчёт air-lite + процедурные рельефы, SQLite, продолжение)принята (02.10)dp-researcherвлита, копия удаленаa02ec7c, f071978, 514422e, ad1fcf1; слияние f015853dataset.py plan/run/status/export/path; main = 690 air-lite (не 688 — опечатка плана) + 40 p_* × 30 = 1890 случаев; план air-lite воспроизведён побитно (тест); тест прерывания: 4×kill -9 + SIGINT → 8/8 файлов побитно равны непрерванному; замер: встроенные ~23 с/случай, синтетика ~10 с, процедурные ~4–12 с; оценка ~7,5 ч GPU, ~3,8 ГБ; версия решателя s0-3acd749
NN-P2 — обучение, оценка (а)/(б)/(в), отчёт, ORT, run_pilot.shпринята (02.10)dp-researcherвлита (b40931c), копия удалена4135bcc, 7082e50, 01f4d08, 9415419, 34c062a, 9efabd0, 8374401, 875a5cc, bb5eedcU-Net+FiLM 3,22 млн парам.; эпоха 1220 образцов 10,6 с (детерм.); оценка полного прогона без досчёта ≈ 1,25 ч (150 эпох, верхняя граница); тест прерываний smoke: 913 чисел metrics.json побитно равны непрерванному; ORT↔PyTorch 1,55e-6; ONNX 13 МБ fp32, ORT Xeon 4 потока 18–20 мс, 1 поток 45–49 мс; dev (48 случаев): ветер на 60 м медиана 0,67 против 1,18 м/с у профиля притока; контракт П2 → v2 (координатные карты x′, y′) ; smoke = ongudai, s_hill, p_000…p_002 × 3 (15 случаев) — все разделы отчёта (а)/(б)/(в 2 точки) заполнены; тест прерываний на новом smoke: 1712 чисел, отличалось только gpu_lock_wait_s (не метрика, исключено); test_prep зелёный (перепроверено)
NN-P3 — независимая проверка: мини-прогон по README, прерывания, оценка времениотменена (02.10, решение пользователя)dp-mechanic (Sonnet)——ждала конца досчёта main; ничего не запускала; пилот пользователь запускает сам
  • 02.10 (пользователь, через главную сессию): run_pilot.sh в tmux показывает «этап n из N: название» + одну обновляемую строку «сделано/всего, %, ETA» в единицах этапа; после продолжения счётчики учитывают сделанное; подробный лог — в файл. Передано NN-P2 (владелец скрипта) и NN-P1 (вывод run в файл, прогресс status --json).
  • 02.10: полный досчёт main запущен координатором фоном: dp job start airnn_gen_main 57600 … dataset.py run --dataset main --log ~/air_nn_data/pilot/logs/dataset_main_precompute.log (PID 79562, 14:16); первые ETA 4–6 ч. Прерывание безопасно — run_pilot.sh продолжит.
  • 02.10 (пользователь, через главную сессию): параллельно с пилотом — NN-2а (таблица параметров поверхности по литературе, Sonnet) и NN-7а (пробник ORT ↔ Godot GDExtension, Linux + выяснить Windows/macOS); без GPU, пилот приоритетнее. Контракты П4, П5.
ЗадачаСтатусИсполнительКопия / веткаКоммитыЧисла, решения
NN-2а — таблица α, β, z0, G/Rn по WorldCover (литература)принята (02.10)dp-researcher (Sonnet)влита, копия удалена778c2abdocs/research/surface_params.{md,csv}, 11 классов + snow_fresh/snow_old, CSV по П4 (столбцы и диапазоны проверены); прямо прочитаны Oke 1987 и Wilson 2002, остальное — вторично (помечено); 6+ оценок EST (β кустарника, мхов, мангров, влажного грунта; G/Rn мангров; α скал и кода 70); для NN-2: H по формуле Боуэна для тающего снега неприменим — ограничивать H снега; замыкание баланса FLUXNET ≈ 80 %; вопрос: делить ли класс 10 на хвойный/лиственный
NN-7а — пробник ORT ↔ Godot (GDExtension), Windows-сборкапринята (02.10)dp-engineerвлита, копия удалена5c1b5f7native/air_nn_probe/ (build.sh all с нуля 3 мин 31 с), тест tests/air_nn/test_air_nn_probe.gd (без сборки — пропуск); перепроверено: max|Δ| = 0 против ORT Python, run 1,5 мс (1 поток) / 0,9 мс (4 потока) на пустышке [1,4,96,96]; ORT 1.30.0, godot-cpp 10.0.0 (API 4.7); Linux .so 0,64 МБ + ORT 28,9 МБ; Windows DLL собрана llvm-mingw, запуск не проверен (нет wine), нужны VC++ DLL; macOS — только способ (CI macos-14, ORT только arm64); находка: libdd3d (debug_draw_3d) экспортирует символы libstdc++ как GNU_UNIQUE → ORT падал → ORT грузится через dlmopen; контракт П5 → v2
  • 02.10: открытые вопросы NN-7а для NN-7/N5 (не решаются сейчас): штатный путь на Linux — dlmopen или пересборка libdd3d со скрытыми символами; проверка на экспортированной сборке; размер ORT (+29 МБ Linux / +16,5 МБ Windows, minimal build — своя сборка ORT); проверка запуска на Windows (CI или машина пилота); Intel-Mac без готового ORT.
  • 02.10 (пользователь, через главную сессию): addons/debug_draw_3d удаляем полностью вместе с Debug Menu (F2); остаётся FPS по F1, стрелки ветра F5 — свой меш. В плане — задача NN-7б (предусловие NN-7, dp-engineer, 0,5 д), сейчас не исполняется (пилот приоритетнее). Контракт П5: после NN-7б — обычный dlopen.
  • 02.10 (пользователь подтвердил): F5 (стрелки ветра) остаётся, перерисовать своим мешем — решение пользователя, не вариант по умолчанию.
  • 02.10 18:08: досчёт main мягко остановлен координатором (SIGTERM, код 2) на 1263/1890 (max 147, failed 0): GpuLock NN-P1 ждёт опросом LOCK_NB и голодает, пока run main перезахватывает замок сразу после пачки (нашёл NN-P2 — smoke 40+ мин не мог взять замок). Правка (пауза после пачки + блокирующий flock с прерыванием сигналом) — в ветке NN-P2; досчёт перезапускается с исправленным кодом.
  • 02.10: правка замка GPU в dataset.py (NN-P2) отклонена системой прав — не обходим, вопрос пользователю в отчёте; досчёт main перезапущен на прежнем коде (шаги обучения/оценки ждут блокирующим flock и проходят между пачками; голодает только второй dataset.py run при идущем main).
  • 02.10 (решение пользователя): правка замка GPU в tools/research/air_nn_pilot/dataset.py (GpuLock) одобрена — блокирующий flock с прерыванием сигналом вместо опроса LOCK_NB + пауза ~2 с после пачки; только скрипт пилота, чужие скрипты и путь замка не меняются. Задача NN-P1б (dp-researcher, Sonnet), ~/deltaplan-air-nn-lockfix, air-nn/lockfix. Идущий досчёт main не прерывается — новый код подхватится при следующем запуске.
  • 02.10: NN-P1б принята (dp-researcher Sonnet, b28d6a0, слияние в feature/air-nn): GpuLock — блокирующий flock + stop.in_lock → Abandon по сигналу; пауза 2 с после пачки. Тест прерывания NN-P1 зелёный (8/8 файлов побитно, дублей 0) при идущем main: ожидание замка 297/313/304 с — голодания нет; SIGINT во время ожидания замка → код 2, замок не взят. Идущий досчёт main — на старом коде (не прерывался), новый код — со следующего запуска.
  • 02.10 (решение пользователя): NN-P3 не проводить; пилот пользователь запускает сам сразу после досчёта main. Команда: cd ~/deltaplan-air-nn/tools/research/air_nn_pilot && ./setup_env.sh && tmux new -s pilot './run_pilot.sh; exec bash'; оценка ≈ 1,25 ч (верхняя граница) + остаток досчёта. Этап П подготовлен; дальше — шлюз ШП по отчёту ~/air_nn_data/pilot/reports/<дата>_pilot/report.md.

Этап П-2 (повторный пилот на реальных рельефах)

  • 02.10: итог ШП (прогон 2026-10-02_pilot, pilot/reports/2026-10-02_pilot/report.md): правилом — «правим подход и повторяем пилот». Сеть лучше базовых линий (ветер на 60 м в ~2,5 раза точнее профиля притока на знакомом и отложенных процедурных; подъём 89–92 % < 0,1 м/с; ORT 19 мс / 4 потока); переобучение (проверка на полке ≈ 0,42 с ~30-й эпохи; 1188 случаев, 44 рельефа); Онгудай — завышение ветра при сильном ветре (ongudai_007 +1,7 м/с, +14 %), вход вне диапазона: медианный уклон 400 м Онгудая 0,22 (p95 0,39, размах 1964 м) против процедурных 0,016 (p95 0,12, ~720 м); кривая (в) по ветру падает (ongudai 1,16 → 0,82), подъём — полка; решения max (238/1890) ошибку не меняют.
  • 02.10 (решения пользователя — в плане «02.10.2026, итог первого пилота»): П-2 на 300 реальных рельефах (+ готовые 1890); рельеф путём рантайма игры (Terrarium как terrarium_loader.gd, без сглаживания, клетки 400 м); 300 квадратов 38,4 км стратифицированно по уклону/размаху, отложенные горные системы — главная оценка, Онгудай вне обучения; вход —
    • карты уклона вдоль/поперёк точного ветра, TPI ~2 и ~8 км, затенённость на ветер; только область 400 м, 10–12 условий на место; критерий ШП-2 — ветер ≤ max(0,3; 10 %) и подъём < 0,1 в ≥ 90 % точек + нет смещения; стадии пачкой, параллельно CPU/GPU, прерываемо; массовый счёт — по согласованию.
  • 02.10: контракты — П1 v2 (набор terrain: только область, места t_*, несколько наборов), П2 v3 (9 карт: + уклон вдоль/поперёк, TPI 2/8 км, Sx Winstral; деление с отложенными системами, кривая 25…300, точка 300 = основная сеть), П3 v2 (точки — вся область на 60 м и гребни; ок ветра ≤ max(0,3; 10 %); смещение по высотам/U10/гребням), П6 v1 (вырезка места: путь рантайма → сетка 25 м → клетки 400 м, index.csv, cut/<id>.npz; контрактный тест tests/test_contract_terrain.py). Расхождение с игрой записано: AirPlace.block_mean на слое рантайма берёт f = round(400/s) узлов (клетка f·s ≠ 400 м) — исправлять в NN-4/N1.
  • 02.10: решения координатора (в пределах плана): вода у мест t_* — нет (озёра как суша, граница пилота); дата — reference_context (как игра для выбранной точки; в южном полушарии — зима); отложенные системы — сверх 300 мест пула (кривая до 300); точка кривой 300 = основная сеть (экономия обучения); порог смещения — предложение (max(0,1 м/с; 2 %)), подтверждает пользователь.
ЗадачаСтатусИсполнительКопия / веткаКоммитыЧисла, решения
NN-P4 — рельефы: выбор, скачивание, нарезка (П6)остановлена (02.10, СТОП)dp-researcher~/deltaplan-air-nn-terrain / air-nn/terrain (на 4d9d663)— (кода нет)разбор: Terrarium ~1 с/тайл, 50–100 КБ, 16 потоков ≈ 15 тайлов/с; над океаном — отрицательные глубины (правило «≤ 0,5 м — море» работает; Каспийская низменность отсеется); для побитного R.grid_domain = hc400 — h в float64 в places.location; requests не нужен (urllib). План: screen z5 (маска гор) → z8 (все кандидаты) → z10 (~2–3 тыс. + отложенные), сетка кандидатов без перекрытия; select — слои уклона p50 0/0,06/0,12/0,2/0,3/0,4/∞ по 50 мест, предел доли системы; отложенные Кавказ/Пиренеи/Аппалачи по 15; оценка ≈ 19 тыс. тайлов z12, ~1,7 ГБ сырья + ~2,8 ГБ вырезок, ~25 мин загрузки (+ экран ~1–1,5 ГБ) — не проверено пробой
NN-P5 — вход П2 v3, деление, оценка и отчёт П3 v2остановлена (02.10, СТОП), часть сделанаdp-researcher~/deltaplan-air-nn-inputs / air-nn/inputs28b0ac5 (не влит)готово: 9 карт П2 v3 в prep.py (константы — как в контракте), test_prep.py (плоскость при любом угле — ±1e-9, гора: TPI/Sx/уклон, поворот ×4, MAP_NAMES) зелёный на smoke; не сделано: split.py v3, data.py (несколько наборов), кеш подготовки по набору (prep_dirs), pilot.py, evaluate.py/report.py П3 v2, подставной П6 (tests/make_mock_p6.py: t_0000…t_0009 из случаев main), удаление профиля dev, README, замер времени обучения; кривая/оценка/test_interrupt_train с 9 картами не перепроверены
NN-P6 — генератор П-2: только область, воркеры GPU, замеростановлена (02.10, СТОП)dp-researcher~/deltaplan-air-nn-gen2 / air-nn/gen2 (на 4d9d663)— (кода нет)разбор по main (только область, сумма двух решений): встроенные ср. 10,1 с (мед. 2,3; max 16 %), процедурные 7,5 (1,7; 12 %), синтетика 5,5 (1,3; 9 %); случай max ~55–60 с ≈ 90 % времени GPU; ~100 итер/с на 96×96×~40 — похоже на упор в задержки (воркеры должны помочь — проверить). План: окна = пустой список в solve_case; terrain/probe (probe — подмножество плана terrain); lru_cache мест чистить (345 × ~10 МБ); подстановка П6 AIRNN_TILES_SHIM=1 до NN-P4; воркеры: родитель держит runner.lock и замок GPU, N spawn-воркеров с «шлюзом» на пачку, PDEATHSIG, workers.lock, SIGUSR1 — бросить случай; замер N=1…4 на 12 случаях main (4 max + 8 ok) с проверкой побитности
NN-P7 — сборка П-2 в run_pilot.sh, smoke, прерыванияне начата———ждёт NN-P4…P6
  • 02.10: СТОП по решению пользователя (меняется способ ведения журналов и заданий — утилита dp; продолжим позже). Исполнители остановлены, фоновых прогонов и процессов модуля нет; в main ничего не вливалось, не пушилось. Копии задач оставлены (в каждой незакоммиченный симлинк tools/research/air_nn_pilot/.venv → venv копии модуля — не коммитить): ~/deltaplan-air-nn-terrain, ~/deltaplan-air-nn-inputs (28b0ac5), ~/deltaplan-air-nn-gen2.
  • 02.10: контракт П6 v1 уточнён (вопрос NN-P4): неперекрытие квадратов пула — |Δx| ≥ 38,4 км или |Δy| ≥ 38,4 км.
  • Открытые вопросы (пользователю при продолжении): верхний предел размаха квадрата (NN-P4 предлагает ~3000 м — в Гималаях 4–5 км, число уровней решателя растёт с размахом); порог смещения ШП-2 max(0,1 м/с; 2 %); выбор отложенных систем (Кавказ, Пиренеи, Аппалачи).
  • Следующий шаг: перезапустить NN-P4, NN-P5, NN-P6 свежими исполнителями в тех же копиях/ветках с прежними заданиями + планы из строк выше (NN-P5 — с пункта «split.py v3», поверх 28b0ac5); затем NN-P7; затем пробный замер времени и готовая команда массового счёта — на согласование пользователю.