ты короче как это, ну, чистая функция, как деплой без инцидентов, ну типа как беспроблемная установка драйверов на cuda под линуксом, короче оверфитишься в мое сердце
подожди, ты куда?
подожди, ты куда?
👻4🔥2😢1
Мы, видимо, тихо подошли к моменту, когда у нас стало галлюцинировать железо.
Наткнулся на пост в ныттере от ресерчера в гугле, где говорится о том, что мы выжали кремний до уровня где silent data corruptions уже больше не теоретическая проблема. Google назвал такие ядра "mercurial cores"- они проходят все заводские тесты, исправно служат месяцами, а потом в непредсказуемый момент, при определённой комбинации инструкций, выдают мусор вместо результата.
Проблему подсветили три крупнейших оператора дата-центров:
Meta - одно из первых исследований крупномасштабного воздействия тихих ошибок на реальной инфраструктуре Silent Data Corruptions at Scale
Google - ключевая работа, давшая название таким ядрам Cores that don't count
Alibaba - Understanding Silent Data Corruptions in a Large Production CPU Population
Собственно, а почему это проблема? В статье The Register Питер Хокшильд рассказывает, что подобное ядро повредило процесс шифрования данных, причем таким образом, что расшифровать файлы могло только это же самое дефектное ядро. Плюс сравнительно недавно вышла статья Understanding Silent Data Corruption in LLM Training, где исследователи из университета Торонто провели эксперименты на больных нодах, выведенных из продакшена: при файнтюнинге LLM на дефектных машинах возникали скачки loss-функции, и в одном случае точность модели упала для нуля.
Как от этого защищаться - пока хз. ECC-память не спасает, потому что данные портятся при вычислении, а не при хранении. Контрольные суммы вроде CRC сами используют векторные инструкции, которые одни из самых уязвимых. Нашел только костыли вроде SiliFuzz (ловит дефекты, которые проявляются на конкретных инструкциях), BootRIST (проверяет ядра при загрузке, то есть дефект, который проявляется после нескольких часов прогрева он не поймает) и Farron (зависит от качества тесткейсов и правильности определения температурной границы)
Наткнулся на пост в ныттере от ресерчера в гугле, где говорится о том, что мы выжали кремний до уровня где silent data corruptions уже больше не теоретическая проблема. Google назвал такие ядра "mercurial cores"- они проходят все заводские тесты, исправно служат месяцами, а потом в непредсказуемый момент, при определённой комбинации инструкций, выдают мусор вместо результата.
Проблему подсветили три крупнейших оператора дата-центров:
Meta - одно из первых исследований крупномасштабного воздействия тихих ошибок на реальной инфраструктуре Silent Data Corruptions at Scale
Google - ключевая работа, давшая название таким ядрам Cores that don't count
Alibaba - Understanding Silent Data Corruptions in a Large Production CPU Population
Собственно, а почему это проблема? В статье The Register Питер Хокшильд рассказывает, что подобное ядро повредило процесс шифрования данных, причем таким образом, что расшифровать файлы могло только это же самое дефектное ядро. Плюс сравнительно недавно вышла статья Understanding Silent Data Corruption in LLM Training, где исследователи из университета Торонто провели эксперименты на больных нодах, выведенных из продакшена: при файнтюнинге LLM на дефектных машинах возникали скачки loss-функции, и в одном случае точность модели упала для нуля.
Как от этого защищаться - пока хз. ECC-память не спасает, потому что данные портятся при вычислении, а не при хранении. Контрольные суммы вроде CRC сами используют векторные инструкции, которые одни из самых уязвимых. Нашел только костыли вроде SiliFuzz (ловит дефекты, которые проявляются на конкретных инструкциях), BootRIST (проверяет ядра при загрузке, то есть дефект, который проявляется после нескольких часов прогрева он не поймает) и Farron (зависит от качества тесткейсов и правильности определения температурной границы)
👻8🔥2 1
Сегодня внезапно выяснилось, что многомиллиардная компания ведет себя как многомиллиардная компания
https://github.com/anomalyco/opencode/commit/973715f3da1839ef2eba62d4140fe7441d539411
https://github.com/anomalyco/opencode/commit/973715f3da1839ef2eba62d4140fe7441d539411
😢5👻1
Можно ли построить детерминированную систему на базе LLM
Последние несколько дней аутирую над этой темой, потому что периодически натыкаюсь на эксперименты, где люди пытаются заставить сетку что-нибудь дизассемблировать, перегонять разные форматы данных к одному типу и т.п. Поэтому у меня возник вопрос: насколько подобные проекты применимы в продакшене? Ведь если алгоритм выдает разные результаты на один и тот же набор данных, это может породить непредсказуемое поведение для всей системы. Кажется, будто ответ лежит на поверхности - ставишь temperature=0 и greedy decoding всегда берет один и тот же наиболее вероятный токен. Но на деле это работает не совсем так.
Чтобы понять почему, нужно взять во внимание одно фундаментальное свойство чисел с плавающей точкой - неассоциативность. В математике (a + b) + c = a + (b + c), но когда дело начинает касаться float, на сцену выходит стандарт IEEE 754. Float хранит фиксированное количество значимых цифр, и когда складываете числа с очень разными масштабами, хвост отбрасывается:
Ниже приведу несколько статей, которые отталкиваются от этого свойства, но подсвечивают разные причины и варианты решений:
1) Understanding and Mitigating Numerical Sources of Nondeterminism in LLM Inference [ссылка] - разное железо
Авторы взяли 4 модели - два reasoning-варианта на базе DeepSeek-R1 и два instruct-варианта (Qwen2.5 и Llama-3.1) и прогнали их на 12 разных конфигурациях: два типа GPU (A100 и L40S), разное их количество и разный размер батча. В результате разброс точности на AIME'24 достигал 9%, а длина ответа расходилась до 9000 токенов при одном и том же промпте и greedy decoding.
Здесь важен аппаратный контекст. Исследователи из Манчестерского университета экспериментально проверили [ссылка], как тензорные ядра считают на V100, T4 и A100 - и обнаружили, что поведение отличается в зависимости от микроархитектуры (например V100 выполняет матричное умножение тайлами 4x4x4, A100 - тайлами 8x8x4, т.е. одно и то же произведение разбивается на разное количество шагов с разными промежуточными суммами, и из-за неассоциативности float итог разный). При этом NVIDIA в официальной документации PTX ISA [ссылка] прямо указывает для операций с .f16 и .bf16: "The accumulation order, rounding and handling of subnormal inputs is unspecified".
А так как в LLM инференсе повсеместно используется BF16 (с 7 битами мантиссы), токены с близкими вероятностями могут поменяться местами. В статье приведен пример: в точке расхождения два прогона дают токену "know" вероятности 49.75% и 46.65% и в одном прогоне побеждает "know", в другом "have". Расхождение происходит в среднем на 45-82 токене в зависимости от модели. Для reasoning-моделей это особенно критично, потому что одно неверное слово в начале разворачивается в другую цепочку рассуждений.
Собственно, они предлагают решить эту проблему через LayerCast [GitHub]: веса модели хранятся в BF16, но все вычисления выполняются в FP32 (23 бита мантиссы). Оно не устраняет ключевую проблему, но делает модель более устойчивой. Однако FP32 вычисления медленнее, потому что современные GPU оптимизированы под 16-битные тензорные операции. Хз, насколько именно оно медленнее - авторы статьи не предоставили этих тестов
Последние несколько дней аутирую над этой темой, потому что периодически натыкаюсь на эксперименты, где люди пытаются заставить сетку что-нибудь дизассемблировать, перегонять разные форматы данных к одному типу и т.п. Поэтому у меня возник вопрос: насколько подобные проекты применимы в продакшене? Ведь если алгоритм выдает разные результаты на один и тот же набор данных, это может породить непредсказуемое поведение для всей системы. Кажется, будто ответ лежит на поверхности - ставишь temperature=0 и greedy decoding всегда берет один и тот же наиболее вероятный токен. Но на деле это работает не совсем так.
Чтобы понять почему, нужно взять во внимание одно фундаментальное свойство чисел с плавающей точкой - неассоциативность. В математике (a + b) + c = a + (b + c), но когда дело начинает касаться float, на сцену выходит стандарт IEEE 754. Float хранит фиксированное количество значимых цифр, и когда складываете числа с очень разными масштабами, хвост отбрасывается:
(0.1 + 1e20) - 1e20 # = 0.0
0.1 + (1e20 - 1e20) # = 0.1
Ниже приведу несколько статей, которые отталкиваются от этого свойства, но подсвечивают разные причины и варианты решений:
1) Understanding and Mitigating Numerical Sources of Nondeterminism in LLM Inference [ссылка] - разное железо
Авторы взяли 4 модели - два reasoning-варианта на базе DeepSeek-R1 и два instruct-варианта (Qwen2.5 и Llama-3.1) и прогнали их на 12 разных конфигурациях: два типа GPU (A100 и L40S), разное их количество и разный размер батча. В результате разброс точности на AIME'24 достигал 9%, а длина ответа расходилась до 9000 токенов при одном и том же промпте и greedy decoding.
Здесь важен аппаратный контекст. Исследователи из Манчестерского университета экспериментально проверили [ссылка], как тензорные ядра считают на V100, T4 и A100 - и обнаружили, что поведение отличается в зависимости от микроархитектуры (например V100 выполняет матричное умножение тайлами 4x4x4, A100 - тайлами 8x8x4, т.е. одно и то же произведение разбивается на разное количество шагов с разными промежуточными суммами, и из-за неассоциативности float итог разный). При этом NVIDIA в официальной документации PTX ISA [ссылка] прямо указывает для операций с .f16 и .bf16: "The accumulation order, rounding and handling of subnormal inputs is unspecified".
А так как в LLM инференсе повсеместно используется BF16 (с 7 битами мантиссы), токены с близкими вероятностями могут поменяться местами. В статье приведен пример: в точке расхождения два прогона дают токену "know" вероятности 49.75% и 46.65% и в одном прогоне побеждает "know", в другом "have". Расхождение происходит в среднем на 45-82 токене в зависимости от модели. Для reasoning-моделей это особенно критично, потому что одно неверное слово в начале разворачивается в другую цепочку рассуждений.
Собственно, они предлагают решить эту проблему через LayerCast [GitHub]: веса модели хранятся в BF16, но все вычисления выполняются в FP32 (23 бита мантиссы). Оно не устраняет ключевую проблему, но делает модель более устойчивой. Однако FP32 вычисления медленнее, потому что современные GPU оптимизированы под 16-битные тензорные операции. Хз, насколько именно оно медленнее - авторы статьи не предоставили этих тестов
🔥8😱1👻1
2) Defeating Nondeterminism in LLM Inference [ссылка] - один сервер, разная нагрузка
Thinking Machines взялись за другой срез проблемы. Их интересовал детерминизм на одном и том же железе - когда один и тот же запрос в разное время суток даёт разный ответ. Интуитивно кажется, что виноват параллелизм потоков: потоки завершаются в случайном порядке, атомарно суммируют результаты - разный порядок сложений. Но авторы показывают, что forward pass детерминирован при фиксированных входных данных: одна и та же операция на одних и тех же данных при тысяче повторных запусков даёт битово идентичный результат.
Они нашли причину - отсутствие batch-инвариантности. Ядра GPU оптимизированы под разные размеры входных данных, и при разных batch size cuBLAS выбирает разные алгоритмы вычисления. Один из примеров - Split-K: при маленьком батче K-dimension делится между несколькими thread-блоками, каждый считает свой кусок, потом результаты суммируются; при большом батче этого не происходит. Меняется порядок накопления частичных сумм, а значит из-за неассоциативности float меняется итог. На живом сервере, где batch size меняется с нагрузкой, один и тот же запрос получает разные ответы - хотя железо одно и то же.
Авторы пошли по пути написания собственных Triton-ядер с фиксированной стратегией. Они переписали ядра для RMSNorm, матмула и FlashAttention так, чтобы стратегия вычислений не менялась при любом batch size [GitHub]. Для attention это потребовало нетривиального решения: вместо "фиксированного количества сплитов" при обработке KV-кэша - "фиксированный размер каждого сплита", чтобы порядок редукции не зависел от числа обрабатываемых токенов. На 1000 одинаковых запросов к Qwen3-235B получили они 1000 одинаковых ответов. Без патча - 80 уникальных.
Но по классике мы сталкиваемся с трейдоффом по производительности: на Qwen-3-8B vLLM по умолчанию обрабатывает 1000 запросов за 26 секунд, детерминированная версия - за 55 секунд, с оптимизированным attention ядром - 42 секунды
Thinking Machines взялись за другой срез проблемы. Их интересовал детерминизм на одном и том же железе - когда один и тот же запрос в разное время суток даёт разный ответ. Интуитивно кажется, что виноват параллелизм потоков: потоки завершаются в случайном порядке, атомарно суммируют результаты - разный порядок сложений. Но авторы показывают, что forward pass детерминирован при фиксированных входных данных: одна и та же операция на одних и тех же данных при тысяче повторных запусков даёт битово идентичный результат.
Они нашли причину - отсутствие batch-инвариантности. Ядра GPU оптимизированы под разные размеры входных данных, и при разных batch size cuBLAS выбирает разные алгоритмы вычисления. Один из примеров - Split-K: при маленьком батче K-dimension делится между несколькими thread-блоками, каждый считает свой кусок, потом результаты суммируются; при большом батче этого не происходит. Меняется порядок накопления частичных сумм, а значит из-за неассоциативности float меняется итог. На живом сервере, где batch size меняется с нагрузкой, один и тот же запрос получает разные ответы - хотя железо одно и то же.
Авторы пошли по пути написания собственных Triton-ядер с фиксированной стратегией. Они переписали ядра для RMSNorm, матмула и FlashAttention так, чтобы стратегия вычислений не менялась при любом batch size [GitHub]. Для attention это потребовало нетривиального решения: вместо "фиксированного количества сплитов" при обработке KV-кэша - "фиксированный размер каждого сплита", чтобы порядок редукции не зависел от числа обрабатываемых токенов. На 1000 одинаковых запросов к Qwen3-235B получили они 1000 одинаковых ответов. Без патча - 80 уникальных.
Но по классике мы сталкиваемся с трейдоффом по производительности: на Qwen-3-8B vLLM по умолчанию обрабатывает 1000 запросов за 26 секунд, детерминированная версия - за 55 секунд, с оптимизированным attention ядром - 42 секунды
👻5
3) Deterministic Inference across Tensor Parallel Sizes [ссылка] - разный tensor parallelism (те же авторы, что и у первой статьи)
Патч Thinking Machines решает проблему при фиксированной конфигурации, но есть ещё один сценарий, который они не затрагивают.
Большие модели не всегда помещаются на одну карту, поэтому используют tensor parallelism: матрицы весов разрезаются на куски и раскладываются по нескольким GPU, каждая считает свой кусок, после чего частичные результаты объединяются через AllReduce. Число GPU в такой схеме называется TP size. Чем больше TP - тем быстрее инференс, но тем дороже инфраструктура. Поэтому на практике TP size часто меняется: например, при обучении используют FSDP (TP=1), а при инференсе - TP=4 для скорости.
И здесь возникает еще одна проблема. Стандартный AllReduce работает через Ring Reduce: GPU передают частичные суммы по кольцу, и порядок накопления зависит от числа карт в кольце. При TP=1 - одна последовательность сложений, при TP=4 - другая. Авторы указывают, что это расхождение между обучением и инференсом может приводить к деградации или коллапсу RL-обучения.
Они пытаются решить это через TBIK (Tree Based Invariant Kernels): кольцо заменяется иерархическим бинарным деревом, где каждый GPU жёстко маппится на конкретный уровень, и intra- и inter-GPU редукции следуют одной и той же топологии независимо от числа карт. Порядок сложений фиксирован - а значит, фиксирован и результат. На 12 конфигурациях (4 TP x 3 batch size) - ровно 1 уникальный выход. TBIK интегрируется и в vLLM, и в FSDP - что позволяет получить битово-идентичные результаты между sampling и training.
Здесь та же проблема с производительностью: TBIK-ядро выдаёт около 63% от скорости cuBLAS, а оверхэд от AllReduce достигает 28-50%. Авторы оговариваются, что цифры во многом объясняются незрелостью реализации и отсутствием NVLink в тестовом окружении, но будем наблюдать.
Короче говоря, можно заставить LLM отдавать одни и те же результаты, но для этого нужно свое железо + кастомные патчи + смириться с тем, что скорость инференса заметно просядет
Патч Thinking Machines решает проблему при фиксированной конфигурации, но есть ещё один сценарий, который они не затрагивают.
Большие модели не всегда помещаются на одну карту, поэтому используют tensor parallelism: матрицы весов разрезаются на куски и раскладываются по нескольким GPU, каждая считает свой кусок, после чего частичные результаты объединяются через AllReduce. Число GPU в такой схеме называется TP size. Чем больше TP - тем быстрее инференс, но тем дороже инфраструктура. Поэтому на практике TP size часто меняется: например, при обучении используют FSDP (TP=1), а при инференсе - TP=4 для скорости.
И здесь возникает еще одна проблема. Стандартный AllReduce работает через Ring Reduce: GPU передают частичные суммы по кольцу, и порядок накопления зависит от числа карт в кольце. При TP=1 - одна последовательность сложений, при TP=4 - другая. Авторы указывают, что это расхождение между обучением и инференсом может приводить к деградации или коллапсу RL-обучения.
Они пытаются решить это через TBIK (Tree Based Invariant Kernels): кольцо заменяется иерархическим бинарным деревом, где каждый GPU жёстко маппится на конкретный уровень, и intra- и inter-GPU редукции следуют одной и той же топологии независимо от числа карт. Порядок сложений фиксирован - а значит, фиксирован и результат. На 12 конфигурациях (4 TP x 3 batch size) - ровно 1 уникальный выход. TBIK интегрируется и в vLLM, и в FSDP - что позволяет получить битово-идентичные результаты между sampling и training.
Здесь та же проблема с производительностью: TBIK-ядро выдаёт около 63% от скорости cuBLAS, а оверхэд от AllReduce достигает 28-50%. Авторы оговариваются, что цифры во многом объясняются незрелостью реализации и отсутствием NVLink в тестовом окружении, но будем наблюдать.
Короче говоря, можно заставить LLM отдавать одни и те же результаты, но для этого нужно свое железо + кастомные патчи + смириться с тем, что скорость инференса заметно просядет
👻6