Preferencias y el modelo de recompensa

Preferencias y el modelo de recompensa

35 min de lectura

Con el ajuste supervisado, el mini-GPT contesta en lugar de continuar el documento, y la forma de obedecer queda resuelta. El contenido no: un modelo ajustado llega hasta donde llegan los pares con que se ajustó, ni un punto más arriba. Mejorar lo que responde pide otro tipo de dato, y esta lección trabaja con comparaciones: un par de respuestas a la misma pregunta y la que alguien prefiere de las dos.

Los anotadores de InstructGPT hacían eso a escala. Por cada instrucción ordenaban de cuatro a nueve respuestas del modelo, y aun así dos de ellos coincidían en una comparación algo menos de tres veces de cada cuatro. Esta lección convierte datos así, ruidosos y sin una escala común, en un número por respuesta, la recompensa, y entrena una red que lo calcula. Con ese número, el bloque tendrá por fin algo que maximizar.

Pedir notas parece más directo, y tiene un defecto que ninguna cantidad de notas arregla. Una anotadora generosa le pone un 9 a una explicación de por qué el cielo es azul y un anotador severo le pone un 6 a otra; los dos podrían preferir la segunda. Cada nota se lee en la escala de quien la pone, y esa escala se mueve también a lo largo de una tarde de trabajo. Si una anotadora puntúa unas respuestas y otro anotador otras, juntar sus notas junta sus escalas.

Una comparación tira la escala y se queda con el orden. Entre dos explicaciones, la generosa y el severo dicen cuál prefieren, y lo generosos que sean no entra en la respuesta. Lo que se pierde es el tamaño de la diferencia, y se recupera contando: si tres de cada cuatro anotadores prefieren una, la ventaja es pequeña; si la prefieren todos, grande.

El ajedrez resolvió así el mismo problema. Nadie le pone nota a un jugador: juega partidas, gana o pierde, y su Elo sale de los resultados. El Elo es un número por jugador, y la probabilidad de que uno gane a otro depende sólo de la diferencia entre los dos: con 400 puntos más que su rival, se espera que un jugador gane diez partidas por cada una que pierda. Chatbot Arena clasifica hoy los modelos de lenguaje igual, con millones de votos entre dos respuestas anónimas. Con respuestas en lugar de jugadores, el número es la recompensa.

Mueve las dos recompensas y mira la probabilidad de que el anotador prefiera A, y lo que cuesta la comparación si la eligió. Después mueve c: las dos recompensas se desplazan por la recta y nada de abajo cambia.

Una recompensa que reproduce las comparaciones

Fijemos los datos. Una comparación es una terna (x,yw,yl)(x, y_w, y_l): una instrucción, la respuesta que un anotador prefirió y la que rechazó, y se escribe yw≻yly_w \succ y_l. Los subíndices vienen del inglés, win y lose. Un anotador (labeler) es la persona que compara, y su elección tiene algo de azar: los anotadores no siempre coinciden, y uno solo tampoco consigo mismo de un día a otro.

El modelo de Bradley–Terry (1952) le da a cada respuesta un número, su recompensa r(x,y)r(x, y), y dice cómo salen las comparaciones. Para dos respuestas yAy_A e yBy_B a la misma instrucción, antes de que nadie elija, la probabilidad de que el anotador prefiera yAy_A es la parte de er(x,yA)e^{r(x, y_A)} en la suma de las dos. Dividiendo arriba y abajo por ese término,

P(yA≻yB∣x)=er(x,yA)er(x,yA)+er(x,yB)=11+e−(r(x,yA)−r(x,yB))=σ(r(x,yA)−r(x,yB)).\begin{aligned} P(y_A \succ y_B \mid x) &= \frac{e^{r(x, y_A)}}{e^{r(x, y_A)} + e^{r(x, y_B)}} = \frac{1}{1 + e^{-\left(r(x, y_A) - r(x, y_B)\right)}} \\ &= \sigma\big(r(x, y_A) - r(x, y_B)\big). \end{aligned}

Es el softmax de las dos recompensas, el de la lección sobre funciones de pérdida del curso anterior, y con dos entradas el softmax es una sigmoide de la diferencia. Llamemos margen a esa diferencia, margen=r(x,yA)−r(x,yB)\text{margen} = r(x, y_A) - r(x, y_B). Despejando, P/(1−P)=emargenP/(1 - P) = e^{\text{margen}}: el margen es el logaritmo de la ventaja. Uno de ln⁡3≈1.1\ln 3 \approx 1.1 quiere decir que tres de cada cuatro anotadores prefieren yAy_A; uno de ln⁡9≈2.2\ln 9 \approx 2.2, nueve de cada diez. El Elo es esta misma curva con otra unidad, y sus 400 puntos son un margen de ln⁡10\ln 10.

Un número por respuesta es una afirmación fuerte, y tiene consecuencias que se pueden poner a prueba. Los márgenes se suman a lo largo de una cadena: si yAy_A gana a yBy_B tres a uno y yBy_B a yCy_C tres a uno, el modelo dice que yAy_A gana a yCy_C nueve a uno, sin que nadie las haya comparado. Y no admite ciclos. Si los anotadores prefieren yAy_A a yBy_B, yBy_B a yCy_C e yCy_C a yAy_A, ninguna recompensa lo reproduce, y con las tres ventajas iguales el mejor ajuste es un empate. Es la concesión de Bradley–Terry: supone que detrás de cada elección hay un único eje de «calidad».

Lo que las comparaciones no fijan

Sumemos a todas las recompensas de una instrucción un mismo número, que puede ser distinto para cada instrucción, y llamémoslo κ(x)\kappa(x). Ninguna probabilidad cambia, porque el margen lo resta:

σ((r(x,yA)+κ(x))−(r(x,yB)+κ(x)))=σ(r(x,yA)−r(x,yB)).\sigma\Big(\big(r(x, y_A) + \kappa(x)\big) - \big(r(x, y_B) + \kappa(x)\big)\Big) = \sigma\big(r(x, y_A) - r(x, y_B)\big).

Las comparaciones enfrentan siempre dos respuestas a la misma instrucción, así que fijan los márgenes dentro de cada instrucción y nada más. La recompensa queda definida salvo una constante por instrucción, y eso tiene dos consecuencias. Comparar recompensas de instrucciones distintas no significa nada: que una respuesta sobre la nieve tenga más recompensa que otra sobre el mar no lo ha dicho ninguna comparación. Y quien aprende una recompensa de comparaciones tiene que fijar el nivel por su cuenta, o dejarlo donde caiga. InstructGPT, antes de usar su modelo de recompensa, le ajustaba a mano un sesgo para que las respuestas escritas por sus anotadores tuvieran media cero, y daba esta misma razón.

Lo que las comparaciones sí fijan es la escala. Multiplicar las recompensas por 2 dobla cada margen y cambia cada probabilidad. La unidad de la recompensa no es la de ningún anotador: es la frecuencia con que coinciden. Esta libertad de una constante por instrucción parece un defecto del modelo, y más adelante el bloque la aprovechará.

Aprender la recompensa de las comparaciones

Un modelo de recompensa (reward model) es una red rϕ(x,y)r_\phi(x, y), con sus parámetros ϕ\phi, que lee una instrucción y una respuesta y devuelve un número. Se entrena como todo en este bloque, maximizando la verosimilitud de sus datos. Llamemos pprefp_{\text{pref}} a la distribución que saca una comparación al azar del conjunto. Lo que el modelo dice de una comparación es la probabilidad de que el anotador eligiera la que eligió, y la pérdida es menos su logaritmo, en media:

LR(ϕ)=E(x,yw,yl)∼ppref[−log⁡σ(rϕ(x,yw)−rϕ(x,yl))].\mathcal{L}_{\text{R}}(\phi) = \mathbb{E}_{(x, y_w, y_l) \sim p_{\text{pref}}}\left[-\log \sigma\big(r_\phi(x, y_w) - r_\phi(x, y_l)\big)\right].

Es la entropía cruzada binaria de aquella lección sobre funciones de pérdida, con el margen en el lugar de zz y la etiqueta siempre 1, porque cada comparación se escribe con la preferida delante. Su óptimo sale con el argumento de siempre. Si la red puede dar cualquier recompensa, agrupemos las comparaciones de un mismo par de respuestas: cada grupo es una entropía cruzada entre la proporción de veces que ganó cada una y la sigmoide del margen, y la desigualdad de la lección sobre la perplejidad la hace mínima cuando son iguales. Un margen aprendido es una proporción de acuerdo escrita como logaritmo de una ventaja: tres anotadores de cuatro, ln⁡3\ln 3.

El gradiente es una línea de aquella lección y la regla de la cadena. La derivada de la entropía cruzada binaria respecto de zz era y^−y\hat{y} - y; con y^=σ(margen)\hat{y} = \sigma(\text{margen}) e y=1y = 1, es σ(margen)−1=−σ(−margen)\sigma(\text{margen}) - 1 = -\sigma(-\text{margen}). Así que

∇ϕ[−log⁡σ(rϕ(x,yw)−rϕ(x,yl))]=−σ(rϕ(x,yl)−rϕ(x,yw))(∇ϕrϕ(x,yw)−∇ϕrϕ(x,yl)).\begin{aligned} &\nabla_\phi\left[-\log \sigma\big(r_\phi(x, y_w) - r_\phi(x, y_l)\big)\right] \\ &\qquad = -\sigma\big(r_\phi(x, y_l) - r_\phi(x, y_w)\big)\left(\nabla_\phi r_\phi(x, y_w) - \nabla_\phi r_\phi(x, y_l)\right). \end{aligned}

Un paso de descenso sube la recompensa de la preferida y baja la de la rechazada, cada una en la dirección de su gradiente. El factor que lo multiplica, σ(rϕ(x,yl)−rϕ(x,yw))\sigma(r_\phi(x, y_l) - r_\phi(x, y_w)), es la probabilidad que el modelo le da todavía al orden contrario. Una comparación que ya ordena con un margen de 4 pesa 0.0180.018; una que tiene al revés por 1, 0.7310.731. El modelo aprende de lo que aún tiene mal, y lo que tiene bien sigue empujando, cada vez menos.

En la práctica, rϕr_\phi es el modelo ajustado con su última capa cambiada: en lugar de la que da un logit por entrada del vocabulario, una capa lineal que da un solo número. InstructGPT lo hizo con 6 000 millones de parámetros. Aquí lo haremos con el mini-GPT congelado y una capa lineal encima. Sea hˉ(x,y)\bar{\mathbf{h}}(x, y) la media de los vectores h\mathbf{h} que el último bloque deja en las posiciones de los tokens de yy:

hˉ(x,y)=Ej[h(x,y≤j)],rϕ(x,y)=u⊤hˉ(x,y)+b,\bar{\mathbf{h}}(x, y) = \mathbb{E}_j\left[\mathbf{h}(x, y_{\le j})\right], \qquad r_\phi(x, y) = \mathbf{u}^{\top}\bar{\mathbf{h}}(x, y) + b,

con jj por igual sobre los tokens de yy, <|fin|>\texttt{<|fin|>} incluido, y ϕ=(u,b)\phi = (\mathbf{u}, b): 65 números. Es la neurona del curso anterior sin activación, con u\mathbf{u} para el peso porque ww ya marca la preferida.

El gradiente de rϕr_\phi es hˉ(x,y)\bar{\mathbf{h}}(x, y) respecto de u\mathbf{u} y 1 respecto de bb, el mismo 1 en las dos respuestas. En la ecuación del gradiente, lo que las dos tienen en común se va en la resta, y el de bb es 1−1=01 - 1 = 0. El sesgo no aprende nunca: es un κ(x)\kappa(x) como el de antes, el mismo para todas las instrucciones, hecho parámetro.

Un modelo de recompensa sobre el mini-GPT

Las dos celdas corren sobre el mini-GPT, tu mini-GPT del bloque 1 cargado desde el checkpoint con las cuatro filas de la plantilla, y no lo entrenan: lo congelan y entrenan encima los 65 números de ϕ\phi. He partido del modelo preentrenado y no del ajustado de la lección anterior, que olvidó la novela por aprender diez frases.

El anotador es un programa que sabe de qué color es cada cosa. Hay 36 preguntas como las del ajuste, seis cosas de cada color, y cada una tiene seis respuestas con la forma de los pares, una por color. El anotador prefiere la correcta, y cada pregunta da cinco comparaciones. En 24 de las preguntas, tres de sus comparaciones entran en el entrenamiento y las otras dos se guardan: son los rivales nuevos, respuestas que el modelo nunca ha visto enfrentadas a la correcta. Las 12 preguntas restantes, dos por color, son de cosas que la novela no nombra nunca, y ninguna de sus comparaciones entra. La primera celda calcula hˉ\bar{\mathbf{h}} de las 216 respuestas en una sola ida.

import numpy as np
from pyodide.http import open_url
exec(open_url("/courses/llm-agents/modelo.py").read()) # red, F, codificar

# La plantilla de chat, con sus cuatro filas nuevas: la media de E.
ID = {e: 512 + i for i, e in enumerate(["<|sistema|>", "<|usuario|>", "<|asistente|>", "<|fin|>"])}
red.p["E"] = np.vstack([red.p["E"], np.tile(red.p["E"].mean(axis=0), (4, 1))])
red.cfg["n_v"] = 516

# Seis cosas de cada color. Las dos últimas de cada uno no entran en el entrenamiento.
CASOS = {"blanco": "la nieve, la leche, la nube, el azúcar, la sal, el algodón",
"negro": "el carbón, la noche, la tinta, la pizarra, el cuervo, el petróleo",
"rojo": "la sangre, el fuego, la rosa, la fresa, el tomate, la cereza",
"verde": "la hierba, la hoja, el pino, la esmeralda, la lechuga, el pepino",
"azul": "el cielo, el mar, el río, el lago, el zafiro, el arándano",
"amarillo": "el sol, el oro, el limón, el trigo, el plátano, el maíz"}
COLORES, FEM = list(CASOS), {"blanco": "blanca", "negro": "negra", "rojo": "roja", "amarillo": "amarilla"}
cosas = [(cosa, color, i >= 4) for color in COLORES for i, cosa in enumerate(CASOS[color].split(", "))]

def frase(cosa, color): # «La nieve es blanca.»
art, nombre = cosa.split(" ")
return "%s %s es %s." % (art.capitalize(), nombre, FEM.get(color, color) if art == "la" else color)

# Las 36 preguntas con sus seis respuestas: 216 conversaciones en un solo batch.
convs, tramos = [], []
for cosa, _, _ in cosas:
x = [ID["<|usuario|>"]] + codificar("¿De qué color es %s?" % cosa, F) + [ID["<|fin|>"], ID["<|asistente|>"]]
for color in COLORES:
y = codificar(frase(cosa, color), F) + [ID["<|fin|>"]]
convs.append(x + y)
tramos.append((len(x), len(x) + len(y))) # las posiciones de los tokens de y
T = max(map(len, convs))
X = np.array([ids + [0] * (T - len(ids)) for ids in convs]) # relleno detrás: la máscara causal lo ignora
Hn = red.adelante(X)[1][3] # el vector h de cada posición
H = np.array([Hn[b, i:j].mean(axis=0) for b, (i, j) in enumerate(tramos)]).reshape(36, 6, 64)

# Las comparaciones (pregunta, preferida, rechazada): la correcta contra cada una de las otras cinco.
entreno, rivales_nuevos, preguntas_nuevas = [], [], []
for q, (cosa, color, reservada) in enumerate(cosas):
w = COLORES.index(color)
for k, l in enumerate([l for l in range(6) if l != w]):
(preguntas_nuevas if reservada else entreno if (k + q) % 5 < 3 else rivales_nuevos).append((q, w, l))
print("h̄ de cada respuesta:", H.shape)
print("comparaciones: %d de entrenamiento, %d con rivales nuevos, %d de preguntas nuevas"
% (len(entreno), len(rivales_nuevos), len(preguntas_nuevas)))
numpy

La primera ejecución descarga el intérprete de Python (~15 MB). Después queda en la caché del navegador y se reutiliza en todas las lecciones.

Cada una de las 216 respuestas queda en un vector de 64 números, la media de los h\mathbf{h} en sus posiciones, y nada más del mini-GPT se usa en adelante. Las comparaciones son 72 de entrenamiento, 48 con rivales nuevos y 60 de preguntas nuevas. La segunda celda entrena ϕ\phi con trescientos pasos de descenso por gradiente sobre LR\mathcal{L}_{\text{R}} y mide el acierto en los tres grupos: la proporción de comparaciones en que la preferida recibe más recompensa. Después enseña las seis recompensas de una pregunta del entrenamiento y de una nueva.

# Necesita la celda anterior. La red sigue congelada: sólo se entrenan u y b, 65 números.
sigma = lambda z: 1 / (1 + np.exp(-z))
H1 = np.concatenate([H, np.ones((36, 6, 1))], axis=2) # (h̄, 1): la última coordenada es la de b
r = lambda phi, q, k: H1[q, k] @ phi # r(x, y) = u·h̄(x, y) + b

def perdida(phi, comparaciones):
"""La pérdida de Bradley-Terry y su gradiente respecto de phi = (u, b)."""
q, w, l = np.array(comparaciones).T
margen = r(phi, q, w) - r(phi, q, l)
peso = sigma(-margen) # la probabilidad del orden contrario
L = np.logaddexp(0, -margen).mean() # -log sigma(margen), sin desbordar
return L, (peso[:, None] * (H1[q, l] - H1[q, w])).mean(axis=0)

phi = np.zeros(65)
for s in range(1, 301):
L, g = perdida(phi, entreno)
phi -= 2.0 * g # descenso por gradiente
if s in (1, 10, 100, 300):
print("paso %3d pérdida %.3f gradiente respecto de b: %.1f" % (s, L, g[-1]))

acierto = lambda comps: np.mean([r(phi, q, w) > r(phi, q, l) for q, w, l in comps])
print("\nacierto: %.2f en entrenamiento, %.2f con rivales nuevos, %.2f en preguntas nuevas"
% (acierto(entreno), acierto(rivales_nuevos), acierto(preguntas_nuevas)))

for q in (0, 34): # la nieve, entrenada; el plátano, nueva
rq = r(phi, q, np.arange(6))
print("\n¿De qué color es %s?" % cosas[q][0])
print(" ".join("%s %.1f" % (COLORES[k], rq[k]) for k in np.argsort(-rq)))
numpy

La primera ejecución descarga el intérprete de Python (~15 MB). Después queda en la caché del navegador y se reutiliza en todas las lecciones.

La pérdida arranca en 0.693=ln⁡20.693 = \ln 2: con ϕ=0\phi = 0 todas las recompensas son iguales y cada comparación es una moneda al aire. Baja a 0.1610.161 en trescientos pasos, y el gradiente respecto de bb es cero en todos ellos, como decía la derivación. El modelo acierta 71 de sus 72 comparaciones de entrenamiento y el 85 % de las de rivales nuevos. Nunca vio La nieve es blanca. frente a La nieve es amarilla. y las ordena bien, porque no ha aprendido comparaciones sueltas sino un número por respuesta, y el de la correcta subió con cada comparación que ganó.

En las preguntas nuevas acierta el 52 %, lo que acertaría una moneda. A ¿De qué color es el plátano?, la respuesta El plátano es amarillo. recibe la menor recompensa de las seis. La capa lineal sólo puede pesar lo que hˉ\bar{\mathbf{h}} trae, y el mini-GPT ha leído una novela en la que no sale ningún plátano: las comparaciones le enseñaron el color de 24 cosas, una a una. Un modelo de recompensa juzga con lo que su red sabe, y por eso los de verdad parten de un modelo grande. El de InstructGPT acertaba un 70 % de las comparaciones de anotadores que no había visto, cerca del 73 % en que los anotadores coincidían entre sí.

Mira también los niveles. La peor respuesta sobre la nieve tiene más recompensa, 18.1, que la mejor sobre el plátano, 14.2, y eso no significa nada: ninguna comparación ha puesto nunca una frente a la otra. Es la constante por instrucción, que aquí pone u⊤\mathbf{u}^{\top} aplicado a lo que las seis respuestas de cada pregunta tienen en común.

Comprueba tu intuición

Cinco preguntas y un desafío: las recompensas de Bradley–Terry a partir de una tabla de votos, sin red.

Dos anotadores puntúan de 1 a 10 respuestas a la misma instrucción. Lucía le pone un 8 a la respuesta P y Andrés un 5 a la respuesta Q; ninguno ha visto la del otro. ¿Qué se puede concluir de P frente a Q?

Tres de cada cuatro anotadores prefieren la respuesta A a la B, y tres de cada cuatro prefieren la B a la C. Si las comparaciones siguen el modelo de Bradley–Terry, ¿con qué probabilidad prefiere un anotador A a C?

Se acepta un margen de ±0.002.

Un modelo de recompensa da r(x,y)r(x, y) a cada respuesta. Marca los cambios que dejan intacta la probabilidad que asigna a cada comparación.

Marca todas las opciones correctas. Se corrige todo o nada: no hay puntuación parcial.

En un paso de descenso hay dos comparaciones. En la primera, el modelo de recompensa ya da a la preferida 4 puntos más que a la rechazada; en la segunda, le da 1 punto menos. ¿Cómo se comparan los factores que multiplican la dirección de cada una en el gradiente?

En la lección, el modelo de recompensa acierta el 99 % de sus comparaciones de entrenamiento y el 52 % de las de preguntas nuevas. ¿Qué lo explica?

Escribe recompensas(votos): las recompensas de Bradley–Terry de varias respuestas a una misma instrucción, sin red, una recompensa libre por respuesta. votos[i][j] es cuántas veces un anotador prefirió la respuesta i a la j. Devuelve un array con una recompensa por respuesta, que maximice la verosimilitud de los votos y tenga media cero: los votos no deciden el nivel, y alguien tiene que fijarlo. Un ascenso por gradiente con la derivada de la lección converge en todas las pruebas si da unos miles de pasos, cada uno dividido entre las comparaciones de su respuesta.

La primera comprobación descarga el intérprete de Python (~15 MB); después queda en la caché del navegador. Este desafío se resuelve mejor con un teclado físico: en el móvil puedes leerlo y volver luego.


Un modelo de recompensa da un número a cualquier respuesta, también a las que nadie ha comparado, y eso es lo que hacía falta para mejorar la política: cambiar πθ\pi_\theta para que sus respuestas reciban más. La celda dice también dónde se puede confiar en ese número. Cerca de lo que el modelo aprendió, ordena bien; lejos, adivina, y una política que lo maximice sin freno irá a buscar justo las respuestas en que se equivoca.

La lección siguiente, sobre el aprendizaje por refuerzo con retroalimentación humana (reinforcement learning from human feedback, RLHF), escribe ese freno. Maximiza la recompensa media de las respuestas de la política, menos lo que ésta se aleja del modelo ajustado, y deriva cómo se sube esa media con un gradiente aunque las respuestas salgan de un sorteo.

¿Te ha sido útil?
Para profundizar5 fuentes · 5 papers

De dónde sale lo de esta lección, y dónde seguir si quieres más. Nada de aquí hace falta para continuar el curso.

  • Rank Analysis of Incomplete Block Designs: I. The Method of Paired Comparisons
    paperBradley y Terry, 1952Biometrika 39EN

    El artículo que da nombre al modelo: un número por cada cosa comparada y la verosimilitud de los resultados, setenta años antes de que las cosas comparadas fueran respuestas de un modelo de lenguaje.

  • Deep reinforcement learning from human preferences
    paperChristiano, Leike, Brown, Martic, Legg y Amodei, 2017NeurIPS 2017 · arXiv:1706.03741EN

    Donde empieza la idea: personas que comparan dos vídeos cortos de un agente, una recompensa ajustada con la pérdida de esta lección y un robot simulado que aprende una voltereta que nadie sabría escribir como fórmula.

  • Learning to summarize from human feedback
    paperStiennon, Ouyang, Wu, Ziegler, Lowe y otros, 2020NeurIPS 2020 · arXiv:2009.01325EN

    Un modelo de recompensa entrenado con comparaciones de resúmenes, y un modelo optimizado contra él cuyos resúmenes gustan más que los escritos por personas: lo que el ajuste supervisado, que imita, no puede dar.

  • Training language models to follow instructions with human feedback
    paperOuyang, Wu, Jiang, Almeida, Wainwright, Mishkin y otros, 2022NeurIPS 2022 · arXiv:2203.02155EN

    Su sección 3.5 es esta lección a escala: de cuatro a nueve respuestas ordenadas por instrucción, un modelo de recompensa de 6 000 millones de parámetros y un sesgo fijado a mano porque la pérdida no lo fija.

  • Chatbot Arena: An Open Platform for Evaluating LLMs by Human Preference
    paperChiang, Zheng, Sheng, Angelopoulos, Li y otros, 2024ICML 2024 · arXiv:2403.04132EN

    Bradley–Terry para clasificar modelos en lugar de respuestas: votos de usuarios entre dos respuestas anónimas, y una recompensa por modelo con su intervalo de confianza.