Гайд · TNWS AI

Как посчитать cross-entropy через log_softmax в JAX

4 мин—

Стабильная categorical cross-entropy для logits и целочисленных меток: log_softmax, индексация класса, mean loss и точный ручной тест.

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

Актуальный запрос: «как посчитать cross entropy JAX log_softmax». Рассчитать loss классификации из logits без ручного log(softmax(x)). jax.nn.log_softmax использует численно устойчивую формулу. Для меток-классов выбирается log probability правильного столбца, затем берётся отрицательное среднее. Форма logits (batch, classes), меток — (batch,).

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

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

  1. Создайте logits для трёх объектов и двух классов.
  2. Примените log_softmax по последней оси.
  3. Выберите значения правильных классов через индексы batch.
  4. Сравните loss с независимым расчётом через logaddexp.

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

import jax
import jax.numpy as jnp

logits = jnp.array([[2., 0.], [0., 2.], [1., 1.]], dtype=jnp.float32)
labels = jnp.array([0, 1, 1], dtype=jnp.int32)
def cross_entropy(x, y):
    log_probs = jax.nn.log_softmax(x, axis=-1)
    return -jnp.mean(log_probs[jnp.arange(y.shape[0]), y])

loss = cross_entropy(logits, labels)
manual = jnp.mean(jnp.array([
    jnp.logaddexp(2.,0.)-2., jnp.logaddexp(0.,2.)-2., jnp.log(2.)
]))
assert jnp.allclose(loss, manual)
assert jnp.isfinite(loss) and loss > 0
print(float(loss))

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

Первые два объекта уверенно отнесены правильно, третий имеет одинаковые logits и штраф log(2). Итоговый loss положителен, конечен и совпадает с ручной устойчивой формулой.

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

Проверьте диапазон labels от нуля до classes-1, dtype целых чисел и ось классов. Добавьте негативный тест с неверной формой. Для one-hot targets формула выбора индекса заменяется суммой по классам.

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

Для рабочей модели сначала зафиксируйте контракт параметров и 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 возвращает производную написанной функции, а не подтверждает правильность математической постановки. Для критичных решений нужны предметные метрики, мониторинг и человеческий контроль.

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

  • Не вычисляйте log(jax.nn.softmax) вручную для больших logits.
  • Не применяйте softmax дважды.
  • Не передавайте метки 1..K без преобразования к индексам 0..K-1.

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

FAQ

Почему log_softmax стабильнее?

Он объединяет нормализацию и логарифм без промежуточного переполнения.

Какая форма labels?

Один целочисленный индекс класса на объект.

Что усредняется?

Отрицательные log probabilities правильных классов.

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

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

Почему log_softmax стабильнее?

Он объединяет нормализацию и логарифм без промежуточного переполнения.

Какая форма labels?

Один целочисленный индекс класса на объект.

Что усредняется?

Отрицательные log probabilities правильных классов.

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

Комментарии

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