Curso de Matemáticas para IA · Lección 25 de 180

Resolución numérica para IA: usa solve sin inversas explícitas

Resuelve sistemas de recuperación de parámetros de IA con NumPy y usa después residuos, números de condición y comprobaciones de singularidad para juzgar si la respuesta es fiable.

Comparte este artículo

Un paso de calibración de IA puede necesitar recuperar dos parámetros desconocidos a partir de dos respuestas medidas. Las ecuaciones son lo bastante pequeñas para escribirlas en una pizarra, pero el código de producción aún tiene que decidir cómo resolverlas y cómo comprobar la respuesta. Un vector que parece plausible no demuestra que los datos lo hayan determinado de forma fiable.

Esta lección desarrolla esa decisión con NumPy. Resolverás un sistema lineal cuadrado, compararás numpy.linalg.solve con la ruta de la inversa explícita, calcularás un residuo, medirás el condicionamiento y reconocerás el límite singular en el que no existe una estimación única de los parámetros.

Resultado de aprendizaje: Usa numpy.linalg.solve y explica por qué normalmente se evita la inversión explícita.

La lección 22: Identidad y transformaciones inversas mostró qué significa una inversa desde el punto de vista matemático. La lección 24: La forma escalonada por filas revela la estructura mostró cómo los pivotes y las variables libres exponen lo que un sistema puede determinar. Aquí conectamos ese álgebra exacta con la computación de precisión finita. El sitio web oficial de apoyo de Mathematics for Machine Learning sitúa este trabajo en la sección 2.3 del PDF del libro; el escenario de calibración, los números, el código, la visualización y las evaluaciones que siguen son originales.

Un sistema lineal es un contrato de recuperación de parámetros

Escribe el vector de parámetros desconocidos como

x=[x1x2]∈R2.x = \begin{bmatrix}x_1\\x_2\end{bmatrix}\in\mathbb{R}^2.

El vector tiene dos coordenadas, por lo que cada fila de una matriz de coeficientes AA debe contener dos coeficientes. Si dos observaciones producen el vector de términos independientes bb, un sistema de recuperación de parámetros tiene la forma

Ax=b,A∈R2×2,b∈R2,x∈R2.A x=b, \qquad A\in\mathbb{R}^{2\times 2}, \quad b\in\mathbb{R}^{2}, \quad x\in\mathbb{R}^{2}.

En una pequeña cabeza de calibración, x1x_1 podría ser una escala aplicada a una señal y x2x_2 una corrección parecida a un desplazamiento aplicada a otra. De forma más general, la misma notación describe una capa lineal pequeña, una corrección de sensor o un subproblema de recuperación de parámetros dentro de una canalización de IA más grande. Las filas de AA son los patrones de coeficientes observados; bb contiene las respuestas que esos patrones deberían producir.

Si AA es cuadrada e invertible, el álgebra de la lección anterior da

x=A−1b.x=A^{-1}b.

Esa identidad es útil para razonar. No significa que un programa deba construir primero A−1A^{-1} cada vez que necesita xx.

Ejemplo trabajado: recuperar dos parámetros de calibración

Considera el sistema deliberadamente pequeño

A=[3112],b=[81].A=\begin{bmatrix}3&1\\1&2\end{bmatrix}, \qquad b=\begin{bmatrix}8\\1\end{bmatrix}.

Las dos ecuaciones son

3x1+x2=8,x1+2x2=1.3x_1+x_2=8, \qquad x_1+2x_2=1.

Resuélvelo por sustitución antes de pedirle a NumPy que haga el mismo trabajo. La primera ecuación da x2=8−3x1x_2=8-3x_1. Sustituye esa expresión en la segunda:

x1+2(8−3x1)=1⟹−5x1=−15⟹x1=3.x_1+2(8-3x_1)=1 \Longrightarrow -5x_1=-15 \Longrightarrow x_1=3.

Después x2=8−3(3)=−1x_2=8-3(3)=-1, así que

x=[3−1].x=\begin{bmatrix}3\\-1\end{bmatrix}.

Comprueba las dos ecuaciones originales, no solo la que has reordenado:

Ax=[3112][3−1]=[81]=b.A x = \begin{bmatrix}3&1\\1&2\end{bmatrix} \begin{bmatrix}3\\-1\end{bmatrix} = \begin{bmatrix}8\\1\end{bmatrix}=b.

Por qué solve suele ser el paso intermedio adecuado

La expresión matemática directa A−1bA^{-1}b oculta dos tareas computacionales diferentes:

RutaQué calculaPor qué importa para un término independiente
np.linalg.solve(A, b)Factoriza AA y aplica los factores a bbCalcula solo el vector solicitado.
np.linalg.inv(A) @ bConstruye cada columna de A−1A^{-1} y después la multiplica por bbCalcula mucha más información de la que necesita esta única resolución.

Para un solo término independiente, solve evita materializar una inversa completa. Para varios términos independientes almacenados como columnas de BB, usa np.linalg.solve(A, B) para que la misma matriz de coeficientes se factorice una vez mientras se calculan todas las soluciones solicitadas. Conserva una inversa solo cuando la aplicación realmente necesita la inversa; no es un sustituto predeterminado de una resolución.

La documentación actual de NumPy para solve dice que la matriz de coeficientes debe ser cuadrada y de rango completo, y documenta que la rutina usa una implementación LAPACK _gesv. La documentación de inv también advierte que una matriz mal condicionada puede producir resultados inexactos aunque la inversión no genere un error. Por eso la elección de implementación y los diagnósticos deben formar parte del mismo modelo mental.

La diferencia de tiempo de ejecución depende del hardware y de las bibliotecas, así que no es un benchmark portable. Como ilustración, la siguiente ejecución en el host de autoría usó una matriz aleatoria fija de 64×6464\times64, cinco repeticiones de medición y veinte llamadas por repetición:

from timeit import repeat

rng = np.random.default_rng(7)
A_timing = rng.normal(size=(64, 64)) + 64 * np.eye(64)
b_timing = rng.normal(size=64)

solve_time = min(
    repeat(lambda: np.linalg.solve(A_timing, b_timing), repeat=5, number=20)
) / 20
inverse_time = min(
    repeat(lambda: np.linalg.inv(A_timing) @ b_timing, repeat=5, number=20)
) / 20

print(solve_time * 1e6, inverse_time * 1e6, inverse_time / solve_time)

La ejecución verificada imprimió aproximadamente 15.2 µs, 52.2 µs y 3.43× para el tiempo de resolución, el tiempo de la ruta de la inversa y la proporción. Considera esas cifras como una forma reproducible de la comparación, no como una promesa de rendimiento: la razón algorítmica para preferir solve es que evita calcular una matriz que no se usa, y una biblioteca BLAS o un tamaño de matriz diferente pueden cambiar la proporción.

Un residuo es una comprobación de ajuste, no un certificado de confianza

Para el ejemplo trabajado, calcula el residuo de la ruta directa:

r=b−Ax^=[81]−[81]=[00].r=b-A\hat{x} = \begin{bmatrix}8\\1\end{bmatrix} - \begin{bmatrix}8\\1\end{bmatrix} = \begin{bmatrix}0\\0\end{bmatrix}.

El programa de punto flotante informa de una norma cercana a 10−1510^{-15} en vez de exactamente cero. Es una buena evidencia de que el vector devuelto ajusta este bb. Sin embargo, imagina que los coeficientes o las respuestas proceden de mediciones de sensores redondeadas. Un solucionador puede encontrar un vector que ajuste muy bien esos valores redondeados y, aun así, cambiar sustancialmente cuando las mediciones varían dentro de su incertidumbre.

El condicionamiento mide la sensibilidad

El número de condición compara cuánto puede amplificar una matriz los cambios relativos de entrada. Para una matriz invertible y la norma 2,

κ2(A)=∥A∥2,∥A−1∥2=σmax⁡(A)σmin⁡(A),\kappa_2(A)=\lVert A\rVert_2,\lVert A^{-1}\rVert_2 =\frac{\sigma_{\max}(A)}{\sigma_{\min}(A)},

donde σmax⁡\sigma_{\max} y σmin⁡\sigma_{\min} son los valores singulares mayor y menor. Un número de condición cercano a 11 indica direcciones equilibradas. Un valor grande significa que algún cambio pequeño en las entradas puede provocar un cambio relativo mucho mayor en la solución. Si el valor singular menor es cero, la matriz es singular y el número de condición es infinito.

Para un término independiente perturbado, una cota útil tiene la forma

∥δx∥∥x∥≲κ(A)∥δb∥∥b∥,\frac{\lVert\delta x\rVert}{\lVert x\rVert} \lesssim \kappa(A)\frac{\lVert\delta b\rVert}{\lVert b\rVert},

bajo las hipótesis habituales para un sistema no singular. La desigualdad advierte de una posible amplificación; no promete que toda perturbación alcance el peor caso.

Ahora usa filas casi dependientes:

B=[1111.0001],xtrue=[2−1],b=Bxtrue=[10.9999].B=\begin{bmatrix}1&1\\1&1.0001\end{bmatrix}, \qquad x_{\text{true}}=\begin{bmatrix}2\\-1\end{bmatrix}, \qquad b=B x_{\text{true}}=\begin{bmatrix}1\\0.9999\end{bmatrix}.

La segunda fila es casi una copia de la primera. Con el bb exacto que se muestra, la resolución recupera [2,−1][2,-1]. Cambia solo la segunda respuesta en 10−610^{-6} y vuelve a resolver. NumPy informa de lo siguiente:

condition number: 40002.000074915224
original solution: [ 2. -1.]
perturbed solution: [ 1.99 -0.99]
relative input change: 7.071421374297804e-07
relative solution change: 0.006324555320519327
perturbed residual norm: 0.0

La entrada cambió aproximadamente 7.1×10−77.1\times10^{-7} de forma relativa, mientras que el vector de parámetros cambió aproximadamente 6.3×10−36.3\times10^{-3} de forma relativa. Es aproximadamente una amplificación de cuatro órdenes de magnitud expresada por el número de condición. La solución perturbada sigue teniendo residuo cero para los datos perturbados: resolvió correctamente las nuevas ecuaciones, pero los datos no identificaron un vector de parámetros estable.

Mapa estático de estabilidad

Un residuo pequeño puede ocultar una solución sensible

El residuo comprueba la ecuación resuelta. El número de condición avisa cuánto puede moverse la solución cuando cambian los datos de entrada.

Comparación entre residuo y condicionamientoTres casos comparan un sistema bien condicionado, uno casi dependiente y uno singular. Los dos primeros ajustan sus segundos miembros, pero un pequeño cambio de entrada mueve mucho más la solución sensible. El caso singular no tiene una solución única.A x = bsolveruta de la inversaresiduo pequeño‖b − A x̂‖₂Bien condicionadoκ₂(A) = 2.62Δb pequeño: 1.2 × 10⁻⁷Δx pequeño: 2.0 × 10⁻⁷‖r‖₂ ≈ 10⁻¹⁵Mal condicionadoκ₂(A) ≈ 4.0 × 10⁴Δb pequeño: 7.1 × 10⁻⁷Δx: 6.3 × 10⁻³‖r‖₂ = 0 for perturbed bSingularκ₂(A) = ∞solve: LinAlgErrorruta de la inversa: LinAlgErrorno hay x única
Los tres casos pueden producir un residuo pequeño para su segundo miembro. El condicionamiento determina si ese ajuste también es una estimación de parámetros fiable.
Cantidades exactas representadas en el mapa de estabilidad
CasoNúmero de condiciónCambio relativo de entrada → soluciónResiduo e interpretación
Bien condicionado2.621.2 × 10⁻⁷ → 2.0 × 10⁻⁷Residuos de alrededor de 10⁻¹⁵; ambas rutas coinciden en este ejemplo bien condicionado.
Mal condicionado4.0002 × 10⁴7.1 × 10⁻⁷ → 6.3 × 10⁻³Residuo 0 para los datos perturbados, pero un cambio de entrada de 7,1 × 10⁻⁷ mueve x en 6,3 × 10⁻³.
Singular∞No aplicableκ₂(A) es infinito; solve e inverse generan un error de matriz singular en lugar de devolver una respuesta única.

Lee ambos diagnósticos juntos: el residuo pregunta “¿este x ajusta b?”; el condicionamiento pregunta “¿cuánto cambiaría x si b o A fueran ligeramente distintos?”

La visualización separa las dos preguntas. El residuo pregunta si el candidato ajusta las ecuaciones que están actualmente en memoria. El número de condición pregunta si un pequeño cambio en las ecuaciones podría mover ese candidato. Un sistema de calibración de IA necesita ambas respuestas.

Caso límite: singular significa “no hay una solución única”

Considera

C=[1224].C=\begin{bmatrix}1&2\\2&4\end{bmatrix}.

La segunda fila es el doble de la primera, así que CC tiene rango 11, no 22. Con b=[3,6]Tb=[3,6]^\mathsf{T}, las ecuaciones son compatibles pero tienen infinitas soluciones: sirve cualquier (x1,x2)(x_1,x_2) que satisfaga x1+2x2=3x_1+2x_2=3. Con b=[3,7]Tb=[3,7]^\mathsf{T}, son incompatibles porque la segunda ecuación exige el doble del primer miembro izquierdo, pero proporciona un término independiente diferente.

Ninguna de las dos situaciones tiene un vector único que np.linalg.solve pueda devolver. En el entorno incluido, tanto np.linalg.solve(C, [3, 6]) como np.linalg.inv(C) generan numpy.linalg.LinAlgError: Singular matrix. La documentación de NumPy para solve especifica el requisito de rango completo y remite a numpy.linalg.lstsq cuando una solución de mínimos cuadrados es adecuada para un problema no cuadrado o deficiente en rango. Esa es una cuestión distinta de resolver un sistema cuadrado invertible, así que no sustituyas silenciosamente un método por el otro.

Un flujo de trabajo disciplinado de NumPy para sistemas de IA

Para un pequeño subproblema de recuperación de parámetros, un flujo de trabajo defendible es:

  1. Comprueba el contrato. Confirma que coinciden las dimensiones de AA, bb y el vector de parámetros previsto.
  2. Resuelve directamente. Usa np.linalg.solve(A, b) para un sistema cuadrado de rango completo; usa un método diseñado para mínimos cuadrados cuando el problema no esté bien determinado.
  3. Mide el residuo. Calcula np.linalg.norm(A @ x - b) y compáralo con la escala de bb, no solo con un umbral absoluto arbitrario.
  4. Inspecciona el condicionamiento. Calcula np.linalg.cond(A) y compara la posible sensibilidad con la precisión de las mediciones y con el número de dígitos que piensas usar después.
  5. Trata el fallo como información. Un error de singularidad, un número de condición enorme o un residuo grande con respecto a bb debería activar una investigación de los datos, las características, el escalado o el diseño del modelo.

En una tarea de calibración o recuperación de parámetros, este flujo convierte un vector de pesos en un resultado auditable. Un residuo pequeño puede respaldar la afirmación de que la implementación resolvió las ecuaciones suministradas. Un número de condición moderado y una comprobación de perturbaciones aportan evidencia de que esas ecuaciones restringen los parámetros con suficiente fuerza para el uso previsto. Ningún diagnóstico demuestra que el sistema de IA más amplio sea exacto; responden a preguntas de implementación más concretas que se pueden comprobar.

La próxima lección se aparta de los algoritmos numéricos y pregunta qué operaciones algebraicas son válidas sobre el sistema numérico que utilizan los tensores de IA habituales. Por ahora, conserva esta regla práctica: resuelve el sistema que tienes, comprueba el residuo que obtienes y pregunta al condicionamiento si un sistema cercano contaría una historia de parámetros diferente.

Comprueba tu comprensión

Pregunta 1

Para A en R^(m×n), x en R^n y b en R^m, ¿qué le pide Ax = b al programa que encuentre?

Mostrar la solución paso a paso

Le pide un vector xx con nn coordenadas cuya multiplicación por la matriz AA de tamaño m×nm\times n produzca el vector bb de mm coordenadas. La comprobación de las dimensiones va primero: cada fila de AA debe tener nn entradas para que su producto escalar con xx esté definido, y debe haber una ecuación resultante por cada entrada de bb.

Pregunta 2

Resuelve a mano 3x_1 + x_2 = 8 y x_1 + 2x_2 = 1.

Mostrar la solución paso a paso

De la primera ecuación, x2=8−3x1x_2=8-3x_1. Sustituye en la segunda: x1+2(8−3x1)=1x_1+2(8-3x_1)=1, así que −5x1=−15-5x_1=-15 y x1=3x_1=3. Después x2=8−3(3)=−1x_2=8-3(3)=-1. La solución es (3,−1)(3,-1), que se puede comprobar en las dos ecuaciones originales: 3(3)+(−1)=83(3)+(-1)=8 y 3+2(−1)=13+2(-1)=1.

Pregunta 3

Un vector calculado tiene el residuo r = [0.0001, -0.0002]. ¿Qué te dice la norma del residuo y qué no te dice?

Mostrar la solución paso a paso

La norma del residuo es

∥r∥2=0.00012+(−0.0002)2≈0.0002236.\lVert r\rVert_2 =\sqrt{0.0001^2+(-0.0002)^2} \approx 0.0002236.

Te dice hasta qué punto el candidato satisface las ecuaciones suministradas. No te dice si los parámetros verdaderos están cerca, si la matriz está bien condicionada o si las mediciones son exactas. Esas cuestiones requieren comprobaciones del condicionamiento, la escala de los datos y el modelo.

Pregunta 4

¿Por qué pueden coincidir solve(A, b) e inv(A) @ b matemáticamente mientras solve(A, b) sigue siendo la ruta de código preferida?

Mostrar la solución paso a paso

Si AA es invertible, la identidad x=A−1bx=A^{-1}b demuestra que ambas rutas apuntan al mismo vector matemático. Las rutas de implementación difieren: solve factoriza AA y aplica los factores al término independiente solicitado, mientras que inv construye primero cada columna de la inversa y después multiplica. Por tanto, la ruta de la inversa hace trabajo adicional y crea una matriz intermedia que una única resolución no necesita.

Pregunta 5

Un sistema tiene un número de condición de aproximadamente 40.000. ¿Debería un residuo cero darte confianza para informar de muchos dígitos de x?

Mostrar la solución paso a paso

No. Un residuo cero solo dice que la xx comunicada ajusta el bb suministrado en la aritmética actual. Un número de condición cercano a 4×1044\times10^4 dice que pequeños cambios relativos en AA o bb pueden amplificarse aproximadamente a esa escala en una dirección del peor caso. Informa de una precisión coherente con la incertidumbre de las mediciones, inspecciona los valores singulares o el condicionamiento y prueba perturbaciones antes de considerar significativos muchos dígitos.

Pregunta 6

¿Cuál es la diferencia entre un sistema singular con infinitas soluciones y uno sin soluciones?

Mostrar la solución paso a paso

Ambos tienen filas dependientes, por lo que la matriz de coeficientes no puede determinar un vector único. Si el término independiente tiene la misma dependencia, como b=[3,6]Tb=[3,6]^\mathsf{T} para C=[[1,2],[2,4]]C=[[1,2],[2,4]], las ecuaciones son compatibles y hay infinitas soluciones. Si el término independiente rompe esa dependencia, como b=[3,7]Tb=[3,7]^\mathsf{T}, la reducción por filas produce una contradicción como 0=10=1, así que no hay soluciones. Ninguno de los dos casos es una entrada válida para un resultado único de solve.

Pregunta 7

En una cabeza de calibración de IA, ¿qué evidencia registrarías después de llamar a np.linalg.solve(A, b)?

Mostrar la solución paso a paso

Registra las dimensiones de la matriz y el vector, el vector de parámetros devuelto, la norma del residuo ∥Ax^−b∥\lVert A\hat{x}-b\rVert y un diagnóstico de condicionamiento como np.linalg.cond(A). Registra también las unidades, la escala o la incertidumbre de las mediciones si esos detalles afectan a la interpretación. El residuo respalda una afirmación sobre el ajuste de las ecuaciones suministradas; el condicionamiento y las comprobaciones de perturbación respaldan una afirmación distinta sobre la sensibilidad de los parámetros.

Pregunta 8

Una revisión de código propone np.linalg.inv(A) @ b para cada solicitud, incluso con matrices que pueden ser deficientes en rango. ¿Qué deberías cambiar?

Mostrar la solución paso a paso

Sustituye la ruta predeterminada por np.linalg.solve(A, b) después de comprobar que el problema está pensado para ser cuadrado y de rango completo. Captura o muestra LinAlgError en vez de ocultarlo y calcula un residuo después de resolver. Añade np.linalg.cond(A) o una comprobación de condicionamiento equivalente cuando importe la sensibilidad de entrada. Si los datos son rectangulares o deficientes en rango, elige y documenta una formulación de mínimos cuadrados o regularizada, en vez de fingir que existe una inversa.

Fuentes

  1. Mathematics for Machine Learning companion website
  2. Mathematics for Machine Learning book PDF
  3. NumPy documentation: numpy.linalg.solve
  4. NumPy documentation: numpy.linalg.inv
  5. NumPy documentation: numpy.linalg.cond
  6. NumPy documentation: numpy.linalg.norm