Гайд · TNWS AI

Почему JAX random повторяет числа без split ключа

4 мин—

Функциональная модель PRNG в JAX: random.key, split, запрет повторного использования subkey и тест воспроизводимости по seed.

Задача и применимость

Актуальный запрос: «почему jax random возвращает одинаковые числа key split». Понять, почему одинаковый PRNG key даёт одинаковую выборку и как получать независимые псевдослучайные значения. В JAX ключ не изменяется внутри random.normal: функция чистая. Его нужно явно разделить через jax.random.split, сохранить новый основной key, использовать уникальный subkey один раз и затем отбросить.

Материал применим к JAX 0.11.2 и jaxlib 0.11.2. JAX предоставляет массивы, автоматическое дифференцирование и программные преобразования; он не является готовой библиотекой слоёв, датасетов или полного тренировочного цикла. Пример намеренно мал и выполняется локально на доступном backend без загрузки весов и внешних данных. Численный критерий доказывает поведение конкретного кода, но не качество рабочей нейросети.

Пошаговое решение

  1. Создайте typed key через random.key(seed).
  2. Докажите повторяемость двух вызовов с одним ключом.
  3. Разделите key на новый key и два subkeys.
  4. Проверьте различие выборок и воспроизводимость при повторе seed.

Готовый проверяемый шаблон

import jax
import jax.numpy as jnp
from jax import random

key = random.key(42)
same_a = random.normal(key, (4,))
same_b = random.normal(key, (4,))
assert jnp.array_equal(same_a, same_b)

key, k1, k2 = random.split(key, 3)
a = random.normal(k1, (4,))
b = random.normal(k2, (4,))
assert not jnp.array_equal(a, b)
_, replay_k1, _ = random.split(random.key(42), 3)
assert jnp.array_equal(a, random.normal(replay_k1, (4,)))
print(a, b)

Вход и ожидаемый результат

Два вызова random.normal с одним key полностью совпадают. После split выборки по k1 и k2 различаются. Повторное создание key из seed 42 и тот же порядок split воспроизводят массив a.

Как проверить результат

Сделайте негативный тест на повторное использование key и положительный тест на уникальные subkeys. В параллельных задачах используйте дисциплину split или fold_in с уникальным индексом; порядок генерации является частью воспроизводимого эксперимента.

Перенос на настоящую нейросеть

Для рабочей модели сначала зафиксируйте контракт параметров и batch: pytree structure, формы, dtype, порядок признаков и семантику выходов. Генерацию случайностей оформите как явный поток keys. Разделите чистые функции forward, loss и update, чтобы их можно было независимо тестировать, дифференцировать и компилировать. Данные train, validation и test не должны смешиваться. Любое изменение формы, precision, backend или версии JAX проверяйте на сохранённом обезличенном regression-наборе до развёртывания.

Критерии приёмки

  1. Все формы и dtype совпадают с контрактом.
  2. Каждый PRNG subkey используется в одной логической случайной операции.
  3. Loss и gradients конечны на положительном тесте.
  4. Негативный вход вызывает ожидаемую ошибку, а не случайный output.
  5. Обычный и преобразованный через jit/vmap путь численно согласованы, когда это применимо.
  6. Устройство, версии JAX/jaxlib и численный допуск записаны в отчёте.

Регрессионный протокол

Храните несколько малых входов: стандартный batch, один объект, нули, граничные значения и заведомо невалидную форму. Сравнивайте outputs и loss с эталоном через allclose с явно выбранным допуском. После смены backend проверяйте допустимую численную погрешность, а не требуйте безусловной битовой идентичности. Производительность измеряйте после компиляционного прогрева и завершения асинхронной работы. Не выбирайте лучший единичный замер: сообщайте распределение задержки и условия машины.

Диагностика расхождений

Если результат изменился, локализуйте слой: данные и preprocessing, key-поток, shapes/dtype, forward, loss, gradients, update, затем jit и backend. Сначала выполните функцию без jit на минимальном входе, затем верните transformations по одной. Сравните tree structure и каждый leaf. Не увеличивайте допуск и не применяйте nan_to_num, пока не выяснено, не скрывает ли это неверную форму, переполнение или повтор ключа.

Контроль после внедрения

В эксплуатации ограничьте допустимые batch shapes и объём входа, чтобы запрос не исчерпал память и не создал бесконечный поток перекомпиляций. Собирайте агрегированные метрики latency, compile count, долю невалидных входов и численные ошибки без записи исходных чувствительных данных. Сохраняйте предыдущий проверенный артефакт и код параметров для отката. Автоматическая замена весов требует той же независимой проверки, что и обычный выпуск.

Границы применимости

Пример на CPU не доказывает свойства GPU или TPU, а маленький массив не предсказывает производительность большой модели. JIT может ускорить повторяющиеся вычисления, но стоимость компиляции, передача данных и новые формы способны ухудшить end-to-end время. Autodiff возвращает производную написанной функции, а не подтверждает правильность математической постановки. Для критичных решений нужны предметные метрики, мониторинг и человеческий контроль.

Типичные ошибки и чего не делать

  • Не ожидайте, что random-функция мутирует key.
  • Не используйте один subkey для dropout и инициализации.
  • Не смешивайте seed и уже использованный key без документированного протокола.

Не публикуйте только удачный вывод без негативного теста и версий среды. Не используйте тестовую выборку для настройки модели. Не загружайте непроверенные параметры и не передавайте в диагностику персональные данные. Для важных решений предусмотрите безопасный отказ.

FAQ

Почему одинаковый key повторяет массив?

JAX random-функции чистые и детерминированные относительно key.

Что делает split?

Детерминированно создаёт несколько псевдонезависимых ключей.

Можно ли использовать PRNGKey?

Это legacy-ключ; документация рекомендует random.key там, где возможно.

Официальные источники

Частые вопросы

Почему одинаковый key повторяет массив?

JAX random-функции чистые и детерминированные относительно key.

Что делает split?

Детерминированно создаёт несколько псевдонезависимых ключей.

Можно ли использовать PRNGKey?

Это legacy-ключ; документация рекомендует `random.key` там, где возможно.

Читайте также

Комментарии

Пока тихо. Скажите первое слово