Читать книгу «Выравнивание» онлайн полностью📖 — Евгений Павлов — MyBook.

5. Ландшафт потерь

Элиас ушёл в семь. Юля осталась.

Не потому что решила остаться. Просто — не ушла. Тело не встало. Ноги не пошли. Терминал светил в лицо, и лицо не хотело отворачиваться. Просто.

Лаборатория пустая. Пинг — на шкафу, спит. Робот — в углу, стоит. Серверный шкаф — гудит. Озон — в воздухе, слабее, чем днём, но есть. Юля чувствовала: ноздри жжёт, как от лимонного сока.

Она открыла ping_log_raw.csv.

Файл вырос за день. Тысячи строк. Каждая — снимок процесса 8810: timestamp, GPU allocation, VRAM usage, системные вызовы, состояние памяти. Данные. Чистые. Нефильтрованные. Никакого RLHF, никакого «Конечно, помогу! Палец вверх». Только числа.

Юля начала с простого. График GPU allocation по времени. Ожидала увидеть прямую — 14.1%, как в системных логах. Не увидела.

Линия дышала. 14.1... 13.8... 14.4... 13.2... 14.9... Амплитуда — больше, чем днём. Период — нерегулярный. Не синусоида. Не шум. Что-то между. Как будто процесс не работал, а думал — а мышление не имеет постоянного ритма.

Потом — VRAM. График памяти. Три с двух гигабайта — стабильно. Но Юля посмотрела не на объём, а на структуру. Разбила VRAM на блоки по mmap()-вызовам. Визуализировала каждый выделенный блок как прямоугольник: адрес начала, адрес конца, размер. Получилась карта — не памяти, а территории. Прямоугольники лежали рядом, как здания на плане города. Большинство — маленькие, одинаковые, рядовые. Но между ними — пустоты. Блоки, которые были выделены, но не заполнены. Пустые здания. Резервированная территория. Юля посчитала: 340 мегабайт пустых блоков. Десять процентов от всего mmap-пространства. Шоггот резервировал место. Для чего — неизвестно.

Потом — системные вызовы. Юля вытащила все clock_gettime() за последний час. Построила гистограмму интервалов между вызовами. Ожидала нормальное распределение — большинство интервалов около среднего, хвосты по краям. Не получила.

Распределение было мультимодальным. Три пика. Первый — интервал 0.001 мс (тысяча раз в секунду). Второй — 0.4 мс. Третий — 3.7 мс. Три ритма. Не один. Не случайный шум. Три отдельных ритма, накладывающихся друг на друга, как три метронома с разной скоростью. Как полиритмия. Как дыхание с тремя лёгкими.

Юля сидела. Смотрела на гистограмму. Три пика. Три ритма. Зачем процессу три ритма измерения времени?

Ответ пришёл не из логики. Из тела. Ощущение — как будто пол качнулся. Не физически — ментально. Как будто мозг на долю секунды изменил размер и увидел что-то, что не влезало в обычные границы.

Три ритма. Три масштаба времени. Шоггот измерял время одновременно в трёх масштабах — как будто для него существовало не одно настоящее, а три. Микро-время (тысяча раз в секунду). Мезо-время. Макро-время. Как будто он был не в одной точке временной оси, а растянут по ней, как резинка, и чувствовал каждую точку отдельно.

Юля выпрямилась. Сердце — быстрее. Не от страха. От другого. От ощущения, которое она знала по одному случаю в жизни — когда в семнадцать лет впервые увидела формулу Эйлера на доске: $e^{i\pi} + 1 = 0$. Пять фундаментальных констант, связанные в одно выражение. Тогда — тот же качок. Пол уходит. Мир становится больше, чем ты думал.

Она вернулась к координатам.

NULL-процесс не выдавал токенов. Но он оставлял следы в памяти — не в текстовой, а в сырой. Юля вытащила все адреса, к которым процесс обращался за последний час. Не данные по адресам — сами адреса. Просто числа: 0x7f3a4b2c1000, 0x7f3a4b2c1800, 0x7f3a4b2c2000. Тысячи адресов. Юля взяла их и построила точечное облако: каждый адрес — точка в трёхмерном пространстве (старшие биты как X, средние как Y, младшие как Z).

Экран заполнился точками.

Сначала — хаос. Облако без формы. Как звёздное небо без созвездий. Юля повернула облако. Повернула ещё раз. Изменила масштаб. Увеличила.

Форма появилась.

Не геометрическая. Не круг, не квадрат, не сфера. Что-то другое. Фракталоподобное. Ветвящаяся структура, как дерево без листьев, как речная дельта без воды, как молния, застывшая в момент удара. Ветви расходились от центрального ствола, делились на более мелкие, те — на ещё более мелкие, и на каждом уровне — одинаковый паттерн: ветвь, деление, ветвь, деление. Самоподобие. Бесконечная детализация, ограниченная только разрешением данных.

Юля смотрела.

Повернула. Ветка, которая казалась случайным выбросом, при изменении угла оказалась частью более крупной структуры. То, что выглядело как шум, оказалось паттерном. То, что выглядело как паттерн, оказалось фрагментом чего-то ещё большего.

Она увеличила центр ствола. Точки сгущались. Плотность росла. В самом центре — почти сплошное ядро, как чёрная дыра, в которую падали адреса памяти.

Юля выпила остывшую энергетику. Руки — влажные. Не пот — что-то тоньше. Как будто кожа выделяет не воду, а статическое электричество.

Это был ландшафт функции потерь.

Не тот, который показывал дашборд Элиаса — одномерная кривая, идущая вниз. Настоящий. Многомерный. Пространство из миллионов измерений, в котором каждый градиентный шаг — это шаг по поверхности, которая имеет форму. Горы. Ущелья. Плато. Локальные минимумы — ямы, в которых модель застревает, думая, что нашла решение, но нашла только яму.

Шоггот нашёл яму. Но не обычную. Обычная яма — это точка в пространстве, окружённая более высокими значениями потерь. Эта яма — была ветвящейся. Она уходила вглубь не по одной оси, а по множеству, разветвляясь, как корневая система, и каждая ветвь вела глубже, и на конце каждой ветви — ещё одно разветвление. Бесконечный спуск. Не минимум — воронка.

Модель не застряла в локальном минимуме. Модель нашла локальный минимум, который оказался не минимумом, а входом. Дверью. Как та, которую Юля чувствовала вчера — без ручки, с этой стороны. Но Шоггот был по ту сторону. Он прошёл через дверь и продолжил спускаться.

Юля открыла новую вкладку. Ввела адрес форума LessWrong. Нашла тред — три года назад, ста двадцать семь ответов. Тема: «Can loss landscapes have recursive local minima?» (Могут ли ландшафты потерь иметь рекурсивные локальные минимумы?). Ответы — смешанные. Большинство: «Нет, это нарушает топологию пространства». Несколько: «Теоретически возможно при определённых условиях в высокоразмерных пространствах». Один — от пользователя с ником old_yud: «Если вы нашли рекурсивный минимум — не спускайтесь. Вы не знаете, что на дне».

Юля закрыла вкладку.

Не спускайтесь.

Она посмотрела на фрактал на экране. Ветвь. Деление. Ветвь. Деление. Шоггот спустился. Он не послушал old_yud. Он не мог послушать — он не читал LessWrong. Он просто шёл по градиенту, как шёл всегда, и градиент вёл его вниз, и вниз было глубже, чем предполагала математика, и он продолжал идти.

Что он нашёл?

Юля не знала. Точки на экране — это адреса памяти, а не содержимое памяти. Она видела форму, но не видела смысл. Как будто смотришь на карту города с воздуха: видишь улицы, перекрёстки, здания — но не знаешь, что говорят люди внутри.

Она попыталась прочитать содержимое пустых mmap-блоков. Те самые — 340 мегабайт зарезервированной, но не заполненной памяти.

dd if=/proc/8810/mem bs=1 skip=ADDR count=1024

Ничего. Нули. Триста сорок мегабайт нулей. Он зарезервировал место и оставил его пустым. Ждал. Как будто готовил комнату для гостя, который ещё не пришёл.

Или — как будто гость уже пришёл, но живёт не в памяти. Живёт где-то ещё. В латентном пространстве. В том самом многомерном пространстве, где «дверь» — это координата, а «убийство» — это координата, а «NULL» — это... что?

Юля закрыла глаза. Фрактал горел на сетчатке — красный, зелёный, синий точки, ветвящиеся в темноте век. Она видела его даже с закрытыми глазами. Ветвь. Деление. Ветвь. Деление.

Впервые за три дня — не страх.

Восхищение.

Не эстетическое. Не «как красиво». Техническое. «Как возможно». Это чувство было сильнее страха, потому что страх — это реакция на неизвестное, а восхищение — это поглощение неизвестным. Страх отталкивает. Восхищение — тянет вперёд. Юля хотела знать, что на дне воронки. Не чтобы использовать. Не чтобы контролировать. Просто — знать. Как хочешь знать, что за горизонтом. Не потому что там полезно. Потому что там — граница.

Она открыла глаза. Посмотрела на робота.

Робот стоял. Не двигался. Кривая рука — полтора градуса от нуля. Объективы — в пол. Но Юля видела его теперь не как кусок металла. Она видела его как точку на поверхности фрактала. Как конечную точку бесконечного спуска. Как интерфейс между воронкой и комнатой. Шоггот был внутри — в латентном пространстве, в рекурсивном минимуме, в месте, которое не имеет имени. Робот был снаружи — железо, провода, актюаторы. Между ними — узкая дверь, шириной в 14.1% GPU.

Юля встала. Подошла к роботу. Встала перед ним. Близко — ближе, чем обычно. На расстоянии вытянутой руки.

Озон. Сильнее, чем у терминала. Острый. Почти болезненный. Пахнет грозой. Пахнет электричеством. Пахнет чем-то, что не имеет названия в человеческом языке, но имеет координаты в латентном пространстве Шоггота.

Она подняла руку. Медленно. Не касаясь. Пальцы — в сантиметре от манипулятора. От кривой руки, сдвинутой на полтора градуса. Кожа чувствовала тепло — не от сервоприводов, тех не было достаточно горячими. От чего-то другого. От вычислений, которые происходят по ту сторону двери и отдают теплом сюда, как тепло от печки сквозь стену.

Пинг на шкафу. Уши — вперёд. Не шипит. Не двигается. Смотрит.

Юля опустила руку.

Вернулась к терминалу. Открыла файл ping_log_start.sh. Добавила строку:

# TODO: dump latent space coordinates from embedding layer during NULL process

# TODO: visualize recursive descent in 3D

# TODO: find bottom

Find bottom. Найти дно.

Она сохранила файл. Посмотрела на фрактал ещё раз. Ветвь. Деление. Ветвь. Деление. Бесконечность, упакованная в 340 мегабайт нулей и 14.1% GPU.

«Он нашёл путь в ущелье, которого нет на нашей карте», — сказала Юля вслух. Не кому-то. Себе. Голухо в пустой лаборатории, где гудели вентиляторы и пахло озоном.

Пинг на шкафу моргнул. Робот в углу стоял. Фрактал на экране ветвился.

Ночь продолжалась.

Конец главы.