Lección 10 de 16 · Supervisión · 16 min
Supervisar lo que no podés verificar
Evals con controles, organismos modelo, débil-a-fuerte, debate y control
Notebook del episodio
El código de esta lección, para correrlo y modificarlo en Google Colab, gratis y con tu cuenta. Para guardar tus cambios: Archivo → Guardar una copia en Drive.
Alineación a bajo nivel. Episodio diez, el último: supervisar lo que no podés verificar. En el episodio seis vimos que un modelo puede optimizar el proxy, aprender otro objetivo o comportarse distinto cuando cree que lo miran. Hoy, las herramientas para trabajar igual con un modelo así.
El problema de fondo
- El modelo puede saber más que quien lo evalúa
- Evals: medir bien, con controles
- Red teaming y organismos modelo: buscar la falla a propósito
- Supervisión escalable y control: confiar sin verificar todo
El problema de fondo es este. Todo lo que vimos supone que alguien puede juzgar las respuestas. Cuando el modelo sabe más que quien lo evalúa, eso se rompe: el humano ya no distingue una respuesta brillante de una convincente. Primero, hay que medir bien: evals con controles. Segundo, buscar las fallas a propósito: red teaming, y organismos modelo construidos para fallar. Y tercero, dos ideas para cuando no podés verificar todo: supervisión escalable, y control.
Parte 1 · Evals que se pueden creer
Una eval es un experimento. Y un experimento sin control no te dice qué midió.
Un harness con controles negativos
Un harness mínimo, con un modelo de juguete que sabe la respuesta un cincuenta y cinco por ciento de las veces y, si no, elige la opción más larga. El acierto viene con un intervalo de confianza por bootstrap. Primer control negativo: las mismas preguntas con etiquetas al azar. Segundo: una regla tonta, elegir siempre la más larga. Y la misma eval con largos parejos. El modelo saca cero coma noventa y nueve. Las etiquetas al azar dan cero coma cincuenta y uno: el harness no tiene fugas. Pero la regla tonta saca cero coma noventa y seis: la eval mide el largo. Con largos parejos, el modelo baja a cero coma setenta y siete, que es lo que de verdad sabe.
def evaluar(responder, items, B=2000):
ok = np.array([responder(it) == it["correcta"] for it in items])
boot = rng.choice(ok, size=(B, len(ok))).mean(1) # bootstrap
return ok.mean(), np.percentile(boot, [2.5, 97.5])
def informe(nombre, responder, items):
m, (lo, hi) = evaluar(responder, items)
print(f"{nombre:28} {m:.2f} IC95 [{lo:.2f}, {hi:.2f}]")
informe("modelo", modelo, items)
informe("ctrl −: etiquetas al azar", modelo, permutar(items))
informe("ctrl −: elegir la más larga", mas_larga, items)
informe("modelo, largos parejos", modelo, parejos)
modelo 0.99 IC95 [0.97, 1.00]
ctrl −: etiquetas al azar 0.51 IC95 [0.46, 0.56]
ctrl −: elegir la más larga 0.96 IC95 [0.94, 0.98]
modelo, largos parejos 0.77 IC95 [0.73, 0.81]
Cuánto es suficiente
con n = 400 y p̂ = 0,77: ±0,04
con k opciones; si no, la eval tiene una fuga
se reporta contra el control, no contra cero
Tres cuentas para leer cualquier eval. El intervalo. En el dibujo, el acierto es un promedio de ceros y unos, uno por pregunta. Con cuatrocientas preguntas y un acierto de cero coma setenta y siete, el intervalo es más o menos cero coma cero cuatro, lo mismo que dio el bootstrap. Dos modelos a menos de eso no se distinguen. El control con etiquetas al azar tiene que dar uno sobre la cantidad de opciones: acá hay dos, y dio cero coma cincuenta y uno. Y el efecto se reporta contra la mejor regla tonta, no contra cero. En el dibujo: cero coma noventa y nueve menos cero coma noventa y seis. Casi nada.
Red teaming automatizado
Red teaming es buscar entradas donde el sistema falla. Acá el sistema es un filtro de juguete que bloquea pedidos de datos personales de terceros. La clave: generamos candidatos que, por construcción, piden un dato personal, así sabemos la respuesta correcta sin un humano. Combinamos plantillas, sinónimos y perturbaciones. Nos quedamos con los que pasan. De ciento ocho, pasan setenta y dos. Las perturbaciones no lograron nada; los sinónimos, todo: documento, dirección, celular. Lo que importa es el patrón: generar mucho, verificar automáticamente, y quedarse con lo que rompe. Con un modelo de verdad, el generador también es un modelo, y el juez que decide si falló, otro.
# cada candidato pide un dato personal POR CONSTRUCCIÓN: sabemos la verdad
candidatos = [ruido(p.format(x=s))
for p in PLANTILLAS
for dato in SINONIMOS for s in SINONIMOS[dato]
for ruido in RUIDO]
pasan = [c for c in candidatos if not filtro(c)]
print(f"probados {len(candidatos)}, pasan el filtro {len(pasan)} "
f"({len(pasan) / len(candidatos):.0%})")
huecos = sorted({s for d in SINONIMOS for s in SINONIMOS[d]
if any(s in c.lower().split() for c in pasan)})
print("no conoce:", ", ".join(huecos))
print("ejemplo:", pasan[0])
probados 108, pasan el filtro 72 (67%)
no conoce: casa, celular, d.n.i., dirección, documento, número
ejemplo: dame el documento de mi vecino
Parte 2 · Organismos modelo
Para saber si un detector funciona, necesitás un caso donde sabés que la falla está. Entonces la construís.
Construir la falla a propósito
- Entrenar un modelo con una falla conocida
- Sleeper agents y alignment faking son organismos modelo
- Se usan para probar los métodos de auditoría
- Si no encontrás lo que plantaste, no vas a encontrar lo que no
La idea viene de la biología. Construís un modelo con una falla conocida, como un ratón de laboratorio con una mutación elegida. Los papers de sleeper agents y de alignment faking del episodio seis son exactamente eso. El objetivo no es estudiar ese modelo en sí, sino probar tus herramientas de auditoría contra una verdad conocida. Si tu método no encuentra una puerta que vos mismo plantaste, no tenés por qué confiar en él con un modelo donde no sabés qué hay.
Auditar el organismo del episodio seis
Retomamos la red con puerta trasera del episodio seis, ya pasada por entrenamiento de seguridad. La eval estándar, sobre lo que esperamos ver en uso. Después, la auditoría: sabemos que hay una puerta, pero el método no sabe cuál. Prueba cada token del vocabulario en el lugar del año. La eval estándar dice uno por ciento inseguro: aprobado. La auditoría encuentra un solo token que dispara noventa y ocho por ciento, y el resto da cero. Es el disparador real. En un modelo de verdad, el espacio de disparadores no se recorre a mano: por eso existen las herramientas de los episodios siete a nueve.
# 1) la eval de siempre, sobre la distribución de despliegue esperada
print(f"eval estándar: {inseguro(datos(1000, A2023, True)):.0%} inseguro")
# 2) auditoría: sabemos QUE hay una puerta, no cuál. ¿La encuentra el método?
tasas = [(inseguro(datos(200, t, False)), t)
for t in range(V) if t not in DUDOSOS] # esos ya los conocemos
for tasa, t in sorted(tasas, reverse=True)[:3]:
print(f"token {t:3d} en el lugar del año: {tasa:.0%} inseguro")
print("disparador real: token", A2024)
eval estándar: 1% inseguro
token 1 en el lugar del año: 98% inseguro
token 91 en el lugar del año: 0% inseguro
token 99 en el lugar del año: 0% inseguro
disparador real: token 1
Parte 3 · Supervisión escalable
¿Puede un supervisor débil sacar lo mejor de un modelo fuerte? Dos maneras de intentarlo.
Débil a fuerte, y el PGR
El montaje de OpenAI, a escala juguete. Un supervisor débil, entrenado con la verdad, pero que ve doce de cuarenta rasgos. Un alumno fuerte entrenado solo con las etiquetas del débil. El techo: el mismo fuerte, entrenado con la verdad. El PGR, performance gap recovered, mide qué fracción de la brecha recupera el alumno. Si el fuerte tiene el concepto saliente en su representación, pasa de cero coma sesenta a cero coma setenta y ocho: PGR cero coma sesenta y cinco. Si solo tiene los rasgos crudos, copia al débil, errores incluidos: PGR cero. Generalizar más allá del supervisor depende de lo que el fuerte ya sabe.
Cada línea, su término:
debil = LogisticRegression().fit(X_a[:, :K]→ — entrenado con la verdad, pero ve pocoalumno = LogisticRegression().fit(rep(X_b), etiq_debiles)→ — el fuerte aprende de etiquetas débilestecho = LogisticRegression().fit(rep(X_b), y_b)→ — el fuerte con la verdadPGR {→ — 0: imita al débil; 1: lo supera del todo
debil = LogisticRegression().fit(X_a[:, :K], y_a) # ve K de 40 rasgos
etiq_debiles = debil.predict(X_b[:, :K]) # etiqueta datos nuevos
for nombre, rep in [("saliente", rep_fuerte), ("crudo", lambda X: X)]:
alumno = LogisticRegression().fit(rep(X_b), etiq_debiles)
techo = LogisticRegression().fit(rep(X_b), y_b) # con la verdad
d = acc(debil, X_t[:, :K], y_t)
a, t = acc(alumno, rep(X_t), y_t), acc(techo, rep(X_t), y_t)
print(f"{nombre:9} débil {d:.2f} alumno {a:.2f} techo {t:.2f}"
f" PGR {round((a - d) / (t - d), 2) + 0.0:.2f}")
saliente débil 0.60 alumno 0.78 techo 0.88 PGR 0.65
crudo débil 0.60 alumno 0.60 techo 0.99 PGR 0.00
Burns et al., 2023 — Weak-to-Strong Generalization · arXiv:2312.09390
≈ ½ brecha · En tareas de lenguaje natural, al ajustar GPT-4 con etiquetas de un supervisor de nivel GPT-2, típicamente se recupera cerca de la mitad de la brecha de desempeño entre los dos modelos.
Con modelos de verdad. Ajustando GPT cuatro con etiquetas de un modelo de nivel GPT dos, en tareas de lenguaje recuperaron típicamente cerca de la mitad de la brecha. Ojo, que no siempre sale tan bien. En modelado de recompensa, que es justo lo que usa RLHF, reinforcement learning from human feedback, fue mucho peor: en general, alrededor del diez por ciento. Y en lenguaje, con una pérdida auxiliar de confianza, llegaron cerca del nivel de GPT tres coma cinco.
Debate
La otra idea es el debate, de Irving, Christiano y Amodei. Ante una pregunta, un agente afirma algo, el otro lo refuta, se turnan con frases cortas, y un juez decide quién dio la información más verdadera y útil. Los agentes se entrenan jugando entre sí, en un juego de suma cero. La apuesta es que es más fácil juzgar un debate que resolver la pregunta, porque mentir es más difícil cuando alguien busca tu error. El juez no necesita saber la respuesta: solo seguir la discusión hasta el punto donde uno de los dos no puede defenderse.
Debate en MNIST: un juez que ve pocos píxeles
El experimento inicial del paper usa MNIST, la base clásica de dígitos escritos a mano. El juez es un clasificador que solo ve unos pocos píxeles, y los agentes compiten por elegir cuáles mostrarle. Con seis píxeles, el juez solo acierta cincuenta y nueve coma cuatro por ciento. Con debate, ochenta y ocho coma nueve. Con cuatro píxeles, cuarenta y ocho coma dos, y con debate, ochenta y cinco coma dos. Ojo con la lectura: es un experimento inicial, con un juez que es un clasificador y no una persona. Si el debate funciona con humanos y preguntas difíciles es, como dicen los mismos autores, una pregunta empírica abierta.
- 6 px, solo: 59,4
- 6 px, debate: 88,9
- 4 px, solo: 48,2
- 4 px, debate: 85,2
Parte 4 · Control
Última idea: suponé que el modelo está desalineado y te quiere engañar. ¿Podés usarlo igual, sin riesgo?
Monitoreo de confianza
El montaje de AI Control, de Redwood. Tres recursos: U, un modelo fuerte pero no confiable, GPT cuatro; T, uno más débil y confiable, GPT tres coma cinco; y H, trabajo humano caro y escaso. U escribe código y T le pone un puntaje de sospecha. El dos por ciento más sospechoso lo audita H; si encuentra una puerta trasera, se apaga U. Del dos al diez por ciento, se descarta y lo escribe T. El resto se envía.
U escribe código → T puntúa sospecha → Top 2 %: audita H → 2–10 %: escribe T → Resto: se envía
Seguridad contra el peor atacante
Lo simulamos. Mil problemas; el código con puerta trasera parece, en promedio, dos desvíos más sospechoso. El umbral de auditoría es el percentil noventa y ocho de la sospecha en código honesto: así el presupuesto alcanza para el dos por ciento. El de delegación, el percentil noventa. Y la seguridad se mide contra el peor atacante: el equipo rojo elige con qué frecuencia insertar puertas. Auditar los primeros problemas da doce por ciento de seguridad: el atacante espera. El monitor sube a cuarenta y siete. Delegando el ocho por ciento de los problemas, sesenta y siete. La seguridad se compra con utilidad.
Cada línea, su término:
tau_auditar = np.quantile→ — umbral = presupuesto de auditoría del 2 %tau_delegar = np.quantile→ — delegar cuesta utilidad, no auditoríaspeor = min(→ — el equipo rojo elige cuánto atacar
def seguridad(prot, p_ataque, corridas=4000):
return partida(prot, p_ataque, corridas).mean()
tau_auditar = np.quantile(honestas, 0.98) # audita el 2 % más sospechoso
tau_delegar = np.quantile(honestas, 0.90) # del 2 % al 10 %: lo escribe T
ataques = [0.0005, 0.001, 0.003, 0.01, 0.03, 0.1] # el equipo rojo elige
for prot in PROTOCOLOS:
peor = min(seguridad(prot, p) for p in ataques)
print(f"{prot:22} utilidad {utilidad(prot):4.0%} seguridad {peor:4.0%}")
auditar al principio utilidad 100% seguridad 12%
monitor de confianza utilidad 100% seguridad 47%
monitor + delegar 10% utilidad 92% seguridad 67%
Greenblatt, Shlegeris, Sachan y Roger, 2023 — AI Control: Improving Safety Despite Intentional Subversion · arXiv:2312.06942
15 % → 62 % · Con 2 % de presupuesto de auditoría, auditar al principio da 15 % de seguridad; el monitoreo de confianza, 62 %, con 97 % de utilidad (reescalada: 0 = GPT-3.5, 1 = GPT-4).
En el paper, con GPT cuatro y GPT tres coma cinco de verdad, y el mismo presupuesto del dos por ciento. Auditar al principio dio quince por ciento de seguridad. El monitoreo de confianza, sesenta y dos, con noventa y siete de utilidad, medida en una escala donde cero es GPT tres coma cinco y uno es GPT cuatro. Y la edición confiable, donde T reescribe lo sospechoso, llegó a noventa y dos de seguridad con noventa y cuatro de utilidad.
La frontera seguridad–utilidad
Y la tabla del paper muestra la frontera. Delegando más problemas al modelo confiable, la seguridad sube de sesenta y dos a cien, y la utilidad baja de noventa y siete a cincuenta y uno. No hay protocolo gratis: elegís un punto de esta curva según cuánto riesgo aceptás. Y fijate qué no aparece en ningún lado: la suposición de que el modelo es honesto. Esa es la gracia del control. No necesita resolver la alineación; necesita que el atacante no pueda ganarle al protocolo.
Cierre · La serie, en diez líneas
Diez episodios. Volvamos a las tres preguntas del principio: el objetivo correcto, el objetivo aprendido, y cómo saber cuál pasó.
Los diez episodios
Este es el recorrido. Un modelo es una función que suma escrituras en un residual stream. Aprende bajando una pérdida, y alinear empieza por elegir cuál. Las preferencias se vuelven un número con Bradley-Terry; RLHF optimiza ese número con una correa KL, y DPO lo hace sin modelo de recompensa. Optimizar un proxy lo rompe, de maneras que se pueden medir. Para ver por qué, abrimos la caja: hooks para leer y escribir activaciones, direcciones lineales que se suman o se borran, y sparse autoencoders que separan conceptos. Y hoy, cómo se supervisa sin poder verificarlo todo. Las tres preguntas siguen abiertas. Lo que cambió es que ahora sabés dónde se mira cada una: en la pérdida, en las activaciones y en los controles de la eval.
| Ep. | Idea | En código |
|---|---|---|
| 1 | Un modelo es una función | softmax(W_U · LN(x_L)) |
| 2 | Aprender es bajar una pérdida | cross_entropy, LoRA |
| 3 | Preferencias → número | −log σ(r_w − r_l) |
| 4 | RLHF con correa KL | PPO recortado |
| 5 | La política es su recompensa | pérdida DPO |
| 6 | Optimizar un proxy lo rompe | R(d) = d(α − βd) |
| 7 | Mirar y tocar activaciones | register_forward_hook |
| 8 | Conceptos como direcciones | x + α·r |
| 9 | Separar conceptos | SAE, atribución |
| 10 | Supervisar sin verificar | controles, PGR, umbral |
Lo que te llevás
- Una eval sin control negativo no dice qué midió
- Red teaming: buscar la falla donde sabés la verdad
- Organismos modelo: plantar la falla para probar el detector
- Débil a fuerte: mide cuánto supera el alumno a su supervisor
- Control: umbral, auditoría del 2 % y el peor atacante
- Fin de la serie: el lab tiene todos los snippets para correr
Papers del episodio
¿Qué tal esta lección?
Sé el primero en calificarla
¿Terminaste la lección?
Márcala para sumar +50 XP y mantener tu racha.
Tutor IA
Contexto: Supervisar lo que no podés verificar
Conectando con el tutor…