8 votos

log(1 - softmax(X))?

Sea $\vec X$ sea un vector. La dirección $\vec V = \mathrm{logsoftmax}(\vec{X})$ se define como:

$$v_i = \ln\left(\frac{e^{x_i}}{\sum_i e^{x_i}}\right)$$

Esto se proporciona en los paquetes numéricos de aprendizaje automático para la estabilidad numérica.

¿Existe una implementación numéricamente estable de:

$$\ln\left(1 - \frac{e^{x_i}}{\sum_i e^{x_i}}\right)$$

proporcionados en paquetes estándar (por ejemplo, PyTorch, o scipy, etc.)? ¿Cuál es una buena manera de calcular esto?

Por ejemplo, si $e^{x_i}$ representa la probabilidad (no normalizada) de una etiqueta, entonces es el logaritmo de la probabilidad de una etiqueta incorrecta.

6voto

jldugger Puntos 7490

Normalmente estos valores no se calculan solos: toda la colección de $v_i$ y $\log(1 - \exp(v_i))$ es necesario. Eso cambia el análisis del esfuerzo computacional.

Para ello

$$\bar x = \log\left(\sum_{j} e^{x_j}\right) = x_k + \log\left(1 + \sum_{j\ne k} e^{x_j-x_k}\right)$$

para cualquier índice $k.$ La expresión de la derecha muestra cómo $\bar x - x_k$ puede calcularse de forma numéricamente estable cuando $k$ es el índice del argumento mayor, pues entonces el argumento del logaritmo está entre $1$ y $n$ (el número del $x_i$ ) y la suma puede calcularse con precisión utilizando exp (especialmente cuando el $x_j$ se ordenan de menor a mayor en la suma).

La relación

$$\eqalign{ \log\left(1 - \frac{e^{x_i}}{\sum_{j} e^{x_j}}\right) &= \log\left(\frac{\sum_{j\ne i} e^{x_j}}{\sum_{j} e^{x_j}}\right) \\ &= \log\left(\sum_{j\ne i} e^{x_j}\right) - x_k + \log\left(\frac{e^{x_k}}{\sum_{j} e^{x_j}}\right) \\ &= \log\left(-e^{x_i} + \sum_{j} e^{x_j}\right) - x_k + v_k \\ &= \log\left(1 - e^{x_i - \bar x}\right) + (\bar x - x_k) + v_k }$$

reduce el problema a encontrar ese último logaritmo, lo que se consigue aplicando un log1mexp a la diferencia $x_i - \bar x.$

Para $n$ argumentos $x_i,$ $i=1,2,\ldots, n,$ el esfuerzo total para calcular todos $2n$ es

  • $n$ cálculos del $v_i$ utilizando logsoftmax .

  • Un cálculo de $\bar x - x_k$ (utilizando $n-1$ exponenciales y un logaritmo).

  • $n$ invocaciones de log1mexp .

4voto

Björn Puntos 457

Una opción es utilizar la implementación log-softmax numéricamente estable en combinación con un $\text{log1m_exp}(x):=\log(1-\exp(x))$ función.

Creo que lo siguiente es bastante bueno para $\text{log1m_exp}$ :

  • si x > -0,693147 se utiliza $\log(-\text{expm1}(x))$ ,
  • de lo contrario $\text{log1m}(\exp(x))$ ,

donde $\text{log1m}(x):= \text{log1p}(-x)$ . $\text{log1p}(x):=\log(1+x)$ se implementa normalmente (por ejemplo, en numpy o en base R, de forma similar la función inversa para $\text{log1p}$ es decir $\text{expm1}(x) = \text{log1p}^{-1}(x)$ ).

0voto

Paul Stephenson Puntos 17507

He aquí una posible manera de hacerlo, en código Julia (que creo que es bastante legible incluso si uno no sabe Julia):

function log1msoftmax(x::AbstractArray; dims=1)
  m = maximum(x; dims=dims)
  e = exp.(x .- m)
  s = sum(e; dims=dims)
  return log.((s .- e) ./ s)
end

Tiene la misma complejidad que un logsoftmax (hace una exp y una log llamada por entrada).

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X