Saltar al contenido
coden

Neuroevolución: evolución de los pesos y la forma de las redes neuronales, y el algoritmo NEAT

La neurona y la red en pocas palabras, evolución de un controlador para el péndulo invertido sobre un carro, por qué evolución en lugar de gradiente, XOR y neuronas ocultas, NEAT con marcas históricas y especiación, qué pasa sin especiación y los sucesores, de HyperNEAT a AmoebaNet.

15 minutos Matěj Žalmánek 2026-10-15

Serie Fundamentos de IA Parte 31 de 52
  1. Mapa de la inteligencia artificial: qué es cada cosa y cómo encaja todo
  2. Breve historia de la inteligencia artificial: de Turing a los modelos de lenguaje
  3. Datos, modelo, entrenamiento, inferencia: los conceptos básicos en un solo ejemplo
  4. Cómo leer la notación matemática: símbolos, subíndices, sumatorios y cuantificadores
  5. Conjuntos y relaciones: las piezas con las que se construyen las definiciones en IA
  6. Funciones y aplicaciones: por qué todo modelo de IA es una función
  7. Lógica y demostraciones: las reglas con las que se razona en IA
  8. Grafos y árboles: la estructura sobre la que se apoyan la búsqueda y las redes neuronales
  9. Álgebra lineal para aprendizaje automático: vectores, matrices y por qué la IA sobre todo multiplica
  10. Derivadas, gradiente y regla de la cadena: cómo sabe un modelo en qué dirección aprender
  11. Descenso de gradiente: cómo aprende un modelo
  12. Qué es la probabilidad: del lanzamiento de un dado a los axiomas de Kolmogórov
  13. Probabilidad condicionada y teorema de Bayes: cómo cambiar una estimación cuando te enteras de algo nuevo
  14. Variable aleatoria y función de distribución: una sola función que lo dice todo sobre la distribución
  15. Función de densidad y función de probabilidad: por qué una variable continua tiene probabilidad cero en cada punto
  16. Esperanza, varianza y covarianza: dónde está una distribución, qué anchura tiene y qué se relaciona con qué
  17. Resumen de las distribuciones de probabilidad: Bernoulli, binomial, Poisson, uniforme, normal y exponencial
  18. Ley de los grandes números y teorema central del límite: por qué las medias se comportan de forma tan predecible
  19. Estadística y estimación de parámetros: máxima verosimilitud, MAP e intervalos de confianza
  20. Teoría de la información: entropía, entropía cruzada y divergencia KL, el origen de las funciones de pérdida
  21. Búsqueda en el espacio de estados: BFS, DFS, UCS y A* con animaciones
  22. Juegos y adversarios: minimax, poda alfa-beta y Monte Carlo tree search
  23. Satisfacción de restricciones: backtracking, propagación de restricciones y AC-3 con un sudoku y un mapa de regiones checas
  24. Lógica y sistemas basados en conocimiento: encadenamiento hacia delante y hacia atrás, resolución y sistemas expertos
  25. Planificación: STRIPS, el mundo de bloques, heurísticas a partir de la relajación y la planificación en los agentes de IA
  26. Búsqueda local y recocido simulado: un viajante por las capitales regionales checas
  27. Algoritmos genéticos: población, cruce, mutación y selección en una mochila para la excursión
  28. Estrategias evolutivas y programación genética: de la regla de un quinto a la ley de Kepler
  29. Optimización por colonia de hormigas: cómo un rastro de feromona encuentra un camino corto
  30. Optimización por enjambre de partículas: inercia, experiencia propia y experiencia del enjambre
  31. Neuroevolución: evolución de los pesos y la forma de las redes neuronales, y el algoritmo NEAT
  32. Conjuntos difusos y funciones de pertenencia: cómo escribir «algo cálido»
  33. Lógica difusa y probabilidad: por qué «algo cálido» no significa «probablemente cálido»
  34. Lógica difusa: t-normas, implicaciones y reglas SI–ENTONCES
  35. Control difuso: Mamdani y Sugeno, del ventilador al péndulo invertido sobre un carro
  36. Agrupamiento difuso: el algoritmo fuzzy c-means y los puntos entre clusters
  37. Sistemas neuro-difusos (ANFIS): reglas difusas que aprenden de los datos
  38. Cadenas de Markov: matriz de transición, distribución estacionaria y PageRank
  39. Modelos ocultos de Márkov: el algoritmo de Viterbi y el casino deshonesto
  40. Redes bayesianas: por qué está mojada la hierba y qué significa eso para el aspersor
  41. El filtro de Kalman: cómo estimar a partir de mediciones imprecisas dónde está un coche y a qué velocidad va
  42. Tipos de aprendizaje automático: supervisado, no supervisado, semisupervisado y más
  43. Prompts, contexto y RAG: cómo darle a un modelo la información correcta
  44. Autocodificadores variacionales (VAE): imágenes nuevas a partir de un espacio latente continuo
  45. Redes generativas adversarias (GAN): el falsificador contra el detective
  46. Modelos de difusión: cómo el ruido puro se convierte en una imagen
  47. Procesos de decisión de Markov: estados, acciones, recompensas y ecuaciones de Bellman
  48. Q-learning y DQN: aprender el valor de las acciones, de la tabla a la red neuronal
  49. Gradiente de la política y PPO: aprender directamente la política
  50. Cómo funciona un agente de IA: un modelo de lenguaje en un bucle con herramientas
  51. Programación con agentes de IA: encargo, pruebas y revisión
  52. Evaluación y seguridad de los sistemas de IA: cómo medir y cómo vigilar

Temario completo de la serie 52 de 83 temas publicados

Qué te llevarás
  • Cómo la evolución encuentra los pesos de una red cuando del éxito solo nos enteramos al final.
  • Por qué para XOR no basta con ajustar pesos y cómo NEAT deja crecer la red desde el mínimo.
  • Por qué NEAT sin especiación casi no funciona y hacia dónde lleva hoy la neuroevolución.

Conviene conocer antes: Algoritmos genéticos: población, cruce, mutación y selección en una mochila para la excursión, Estrategias evolutivas y programación genética: de la regla de un quinto a la ley de Kepler

Hoy las redes neuronales se entrenan casi exclusivamente con descenso de gradiente: la red comete un error, se calcula hacia dónde hay que girar cada peso y se gira. Pero ¿y si el error no se puede derivar, porque el éxito solo se conoce al final de la partida, o porque ni siquiera sabemos qué forma debe tener la red? Entonces le toca el turno a la evolución. La neuroevolución deja que los algoritmos evolutivos cultiven los pesos de las redes y, en su versión más interesante, también su forma. Con esta entrega termina el módulo de algoritmos inspirados en la naturaleza y, a la vez, se abre la puerta a las redes neuronales.

Continúa las entregas Algoritmos genéticos y Estrategias evolutivas y programación genética.

1. La red neuronal en pocas palabras

Definición — neurona artificial y red

Una neurona con entradas x1, …, xn, pesos w1, …, wn y sesgo (umbral) b calcula

y = σ(w1x1 + … + wnxn + b),

donde σ es la función de activación — por ejemplo la sigmoide σ(z) = 1 / (1 + e−z), o un simple escalón «positivo → 1, si no 0».

Una red neuronal es un grafo dirigido de neuronas: las entradas de la red llevan a neuronas, y las salidas de las neuronas, a otras neuronas. En una red prealimentada el grafo no tiene ciclos. Las neuronas que no son ni entrada ni salida son ocultas.

Dicho de forma sencilla

La neurona suma sus entradas, cada una multiplicada por su peso, y según la suma «se enciende» o no. Los pesos determinan qué le importa. Una red son muchas neuronas conectadas una tras otra. Todo el comportamiento de la red está en los valores de los pesos y en quién está conectado con quién — y ambas cosas se pueden cultivar con la evolución. A las redes neuronales y a su aprendizaje por gradiente se dedica en el temario un módulo entero aparte.

y = σ( ∑i=1n wi xi + b )

xi
entradas — lo que la neurona «ve» (en el péndulo, posición, velocidad, ángulo); la neurona no las cambia, solo calcula con ellas
wi
pesos — lo único que se aprende o evoluciona; el signo indica si la entrada estimula o inhibe la neurona, y la magnitud, cuánto importa
b
sesgo — desplaza la frontera de decisión; sin él, unas entradas nulas darían siempre el mismo σ(0) y la frontera tendría que pasar por el origen
σ
función de activación — la no linealidad; sin ella, incluso una red de muchas capas calcularía solo una función lineal, porque la composición de funciones lineales vuelve a ser lineal
La suma ∑ wixi + b es una votación ponderada de las entradas; σ la convierte en la salida. La frontera entre «se enciende» y «no se enciende» es el conjunto donde la suma es cero — una recta (en el plano), en general un hiperplano.

2. Evolución de pesos: el péndulo invertido sobre un carro

Un problema clásico de control: sobre un carro hay una barra unida por una articulación, y el carro tiene que mantenerla vertical desplazándose a izquierda y derecha — como cuando se equilibra una escoba sobre la palma de la mano.

Definición — el problema del péndulo invertido sobre un carro

El estado es una cuádrupla (x, v, θ, ω): la posición x y la velocidad v del carro, el ángulo θ de la barra respecto a la vertical y su velocidad angular ω. Cada 0,02 s el controlador elige una fuerza de +10 N o −10 N, y el estado cambia según las ecuaciones del movimiento (carro de 1 kg, barra de 0,1 kg y 1 m de longitud). El intento termina cuando |θ| > 12° o |x| > 2,4 m. El objetivo es aguantar 1 000 pasos (20 s).

El controlador será una sola neurona con activación en escalón: la fuerza es +10 N si w1x + w2v + w3θ + w4ω + b > 0, y −10 N en caso contrario. La aptitud es el número medio de pasos desde tres inicios distintos.

Dicho de forma sencilla

Cinco números deciden cuándo dar un tirón al carro hacia la izquierda y cuándo hacia la derecha. Ningún maestro dice qué fuerza era la correcta en cada momento — solo sabemos cuánto aguantó la barra. Justo una situación así es difícil de resolver con gradiente y fácil con evolución.

Definición — ecuaciones del movimiento del péndulo invertido sobre un carro

El ángulo θ se mide desde la vertical, y una fuerza positiva empuja el carro en el sentido de x positivo. Sea M = mv + mt = 1 + 0,1 = 1,1 kg la masa total del carro y la barra, l = 0,5 m la mitad de la longitud de la barra (la distancia del centro de masas a la articulación) y g = 9,8 m/s². Sin rozamiento (las ecuaciones en la forma en que las dan Barto, Sutton y Anderson, 1983, y en que las usa todavía hoy la mayoría de las implementaciones), la aceleración angular de la barra ε y la aceleración del carro a son:

aF = (F + mt l ω² sin θ) / M

ε = (g sin θ − cos θ · aF) / (l (4/3 − mt cos² θ / M))

a = aF − mt l ε cos θ / M

La simulación avanza con el método de Euler con paso Δt = 0,02 s: la nueva posición es la anterior más Δt por la velocidad anterior, y la nueva velocidad es la anterior más Δt por la aceleración — x ← x + Δt v, v ← v + Δt a, θ ← θ + Δt ω, ω ← ω + Δt ε.

ε = ( g sin θ − cos θ · aF ) / l (4/3 − mt cos² θ / M)

g sin θ
el peso — la razón de que la barra caiga: cuanto más inclinada está, con más fuerza la gravedad la sigue volcando; en la vertical es nulo, así que la posición vertical es un equilibrio, aunque inestable
aF
la aceleración del carro debida a la fuerza del controlador (más una pequeña fuerza centrífuga de la barra) — el único camino por el que el controlador actúa sobre la barra: el carro se mete debajo de la barra y la articulación la «empuja» de vuelta
cos θ
qué parte del empujón horizontal hace girar la barra — con la barra vertical, casi todo; con la barra tumbada, nada; por eso cuesta salvar una barra inclinada más de unos pocos grados
l (4/3 − …)
la inercia de la barra — el 4/3 procede del momento de inercia de una barra homogénea respecto a su extremo, ⅓ m(2l)² = ⁴⁄₃ ml²; el término restado corrige el hecho de que, al girar la barra, también el carro de debajo da un tirón
La aceleración angular de la barra es un duelo entre dos términos: el peso vuelca la barra, la aceleración del carro la devuelve.
Ejemplo — un paso de la simulación

Inicio (0, 0, 0,05, 0), es decir, la barra inclinada 0,05 rad ≈ 2,9°. Denominador: 0,5 · (4/3 − 0,1 · 0,9988² / 1,1) ≈ 0,621.

sin fuerza (F = 0): ε = 9,8 · 0,0500 / 0,621 ≈ +0,79 rad/s² — la barra empieza a caer

fuerza de +10 N: aF = 10 / 1,1 ≈ 9,09 m/s²,   ε = (0,490 − 0,999 · 9,09) / 0,621 ≈ −13,8 rad/s²

tras el paso: ω = 0 + 0,02 · (−13,8) ≈ −0,28 rad/s,   v ≈ 0 + 0,02 · 9,72 ≈ 0,19 m/s

Una fuerza de ±10 N es enorme frente al peso — un solo tirón invierte el sentido de la caída. El problema, por tanto, no está en la fuerza, sino en el momento oportuno: cuándo dejar de empujar para que la barra no se pase al otro lado.

¿Cuánto da el azar? De mil controladores con pesos aleatorios, solo uno aguantó los 20 segundos completos; la mediana es de 9 pasos — la barra cae en menos de una quinta parte de segundo. Un controlador directo que solo se mueve hacia donde se inclina la barra aguanta 39 pasos: atrapa la barra, sí, pero la pone a oscilar. La estrategia evolutiva (5, 20) de la entrega sobre estrategias evolutivas encontró un controlador que aguanta los 20 segundos completos desde los tres inicios en la generación 15 — tras probar unos trescientos controladores:

solo según el ángulo 0,8 s evolución de pesos 20,0 s+
Péndulo invertido sobre un carro: los primeros 8 segundos de simulación

El controlador evolucionado da el mayor peso a la velocidad angular — no atrapa la barra cuando ya está cayendo, sino cuando apenas empieza a caer. También el ángulo y la velocidad del carro tienen pesos nada despreciables, de modo que el carro no oscila ni se sale de la pista. Nadie escribió esa «regla»; salió de la evolución.

Definición — aptitud del controlador y evolución de pesos

Para los pesos w = (w1, …, w4, b), Tk(w) ∈ {1, …, 1 000} es el número de pasos hasta que, desde el inicio k, la barra cae o el carro se sale (como mucho 1 000). La aptitud es

Z(w) = ⅓ (T1(w) + T2(w) + T3(w)),

con los inicios (0, 0, 0,05, 0), (0, 0, −0,08, 0) y (0,5, 0, 0,02, 0,1). Tres inicios en lugar de uno impiden que la evolución encuentre un controlador que solo sepa manejar una posición de partida. Z es constante a trozos — un pequeño cambio de los pesos casi nunca cambia el número de pasos, así que el gradiente es cero casi en todas partes. Por eso, evolución.

Estrategia evolutiva (5, 20): cinco padres con pesos aleatorios en [−1, 1]; en cada generación, veinte descendientes, cada uno obtenido de un padre al azar sumando 0,5 · N(0, 1) a cada peso; los siguientes padres son los cinco mejores descendientes.

import random

def regulator(w, s):                 # s = (x, v, θ, ω)
    u = w[0]*s[0] + w[1]*s[1] + w[2]*s[2] + w[3]*s[3] + w[4]
    return 10 if u > 0 else -10       # activación en escalón: fuerza ±10 N

def zdatnost(w):                     # simuluj(): pasos hasta la caída, como mucho 1000
    return sum(simuluj(regulator, w, start) for start in STARTY) / 3

rodice = [[random.uniform(-1, 1) for _ in range(5)] for _ in range(5)]
for generace in range(30):
    deti = [[wi + 0.5 * random.gauss(0, 1) for wi in random.choice(rodice)]
            for _ in range(20)]
    deti.sort(key=zdatnost, reverse=True)
    rodice = deti[:5]                # (5, 20): solo sobreviven los descendientes
Ejemplo — cómo decide el controlador evolucionado

Pesos encontrados por la evolución (redondeados): w = (0,05; 1,01; 1,37; 4,23), b = 0,09 para (x, v, θ, ω).

barra inclinada y quieta: (0, 0, 0,05, 0) → u = 1,37 · 0,05 + 0,09 ≈ +0,16 → +10 N, el carro se mete debajo de la barra

barra inclinada, pero ya volviendo: (0, 0, 0,05, −0,1) → u = 0,07 − 0,42 + 0,09 ≈ −0,26 → −10 N, el carro frena

En el segundo caso la barra está igual de inclinada, pero el controlador empuja en sentido contrario: la velocidad angular −0,1 rad/s con peso 4,23 pesa más que el ángulo 0,05 rad con peso 1,37. La barra vuelve por sí sola, y si el carro siguiera empujando, se pasaría al otro lado. El controlador directo «solo según el ángulo» empujaría igual en ambos estados — por eso pone la barra a oscilar.

3. Por qué evolución y no gradiente

  • Recompensa escasa. En el péndulo, un juego o un robot, la calidad solo se aprecia tras el episodio completo. A la evolución le basta un único número al final.
  • Partes no derivables. La activación en escalón, un simulador físico, las reglas de un juego — la evolución no necesita derivarlos.
  • Paralelismo. Cada individuo se puede evaluar de forma independiente en otro ordenador.
  • Estructura. El gradiente sabe ajustar pesos, pero no añadir una neurona. La evolución puede cambiar también la forma de la red.

La desventaja es su voracidad: en lugar de un solo gradiente que indica la dirección para todos los pesos a la vez, la evolución prueba cambios aleatorios. Para redes con millones de pesos, el gradiente suele ser mucho más económico, si es que se puede calcular.

4. Cuando los pesos no bastan: XOR

La función XOR devuelve 1 cuando exactamente una de sus dos entradas es 1. Como mostró la entrega Lógica y demostraciones, una sola neurona no puede calcularla: su salida divide el plano de entradas con una recta, y ninguna recta separa los puntos (0, 1), (1, 0) de (0, 0), (1, 1). Para XOR hace falta al menos una neurona oculta. Y con eso surge una pregunta que la evolución de pesos por sí sola no resuelve: ¿cuántas neuronas y cómo conectarlas?

Teorema — XOR no es linealmente separable

No existen números w1, w2, b tales que w1x1 + w2x2 + b > 0 se cumpla exactamente en los puntos donde XOR vale 1.

Demostración. Si tales números existieran, se cumpliría

(0, 0): b ≤ 0    (1, 1): w1 + w2 + b ≤ 0

(1, 0): w1 + b > 0    (0, 1): w2 + b > 0

Sumando la primera fila obtenemos w1 + w2 + 2b ≤ 0, y sumando la segunda, w1 + w2 + 2b > 0. Contradicción. ∎

La demostración no usa la forma de la función de activación — vale para cualquier neurona aislada cuya salida dependa solo del signo de la suma ponderada (el escalón, o la sigmoide con umbral 0,5).

Se puede responder a mano — diseñar la arquitectura y ajustar con evolución solo los pesos. Pero en problemas más complejos no sabemos qué arquitectura es la correcta. ¿Por qué no dejar que también ella evolucione?

5. NEAT: evolución de redes que crecen

Los intentos de evolucionar la estructura de las redes chocaban con tres problemas. ¿Cómo cruzar dos redes de forma distinta? ¿Cómo dar una oportunidad a una estructura nueva que al principio es peor, porque sus pesos nuevos aún no están ajustados? ¿Y cómo evitar que las redes se hinchen sin necesidad? Kenneth Stanley y Risto Miikkulainen respondieron en 2002 con el algoritmo NEAT (NeuroEvolution of Augmenting Topologies), basado en tres ideas.

Definición — genoma de NEAT y marcas históricas

El genoma es una lista de genes de conexión; cada gen tiene una neurona de origen y otra de destino, un peso, un indicador activado/desactivado y un número de innovación. Cada vez que una mutación crea por primera vez en la población una conexión nueva, esta recibe el siguiente número de innovación libre; el mismo cambio estructural en otro individuo recibe el mismo número.

Mutaciones: cambio de pesos; añadir una conexión entre dos neuronas aún no conectadas; añadir una neurona — una conexión existente a → b con peso w se desactiva y se sustituye por el par a → h con peso 1 y h → b con peso w.

El cruce alinea los genes de los padres según los números de innovación: los genes coincidentes se heredan al azar de uno de los padres, y los demás, del más apto.

Dicho de forma sencilla

El número de innovación es la partida de nacimiento de una conexión. Si dos redes tienen una conexión con el número 7, se trata de «la misma» conexión, aunque cada una haya llegado a ella por un camino distinto — y en el cruce se pueden emparejar como el mismo gen en dos padres. Una neurona nueva se inserta de modo que, al principio, la red calcule de forma parecida a como lo hacía antes; no se rompe nada esencial, solo se añade una posibilidad.

Ejemplo — añadir una neurona en una conexión con peso 2

Nuestro NEAT usa, igual que el artículo original, una sigmoide más empinada σ(z) = 1 / (1 + e−4,9z). La conexión x1 → y con peso 2 aportaba a la salida 2x1. Tras dividirla, hay x1 → h con peso 1 y h → y con peso 2:

x1 = 1:   2 · σ(1) = 2 · 0,993 ≈ 1,985   (antes 2)

x1 = 0:   2 · σ(0) = 2 · 0,5 = 1   (antes 0)

Así que «de forma parecida» aquí solo es cierto en parte: para la entrada 1 el cambio es despreciable, pero para la entrada 0 se añade un uno a la suma, porque la sigmoide en cero devuelve la mitad. La red empeora un poco — y precisamente por eso la nueva estructura necesita la protección de la que hablamos a continuación.

Definición — especiación y aptitud compartida

La distancia de compatibilidad entre dos genomas es

δ = c1 E / N + c2 D / N + c3 W̄,

donde E es el número de genes en exceso (con números más allá del final del genoma más corto), D el número de genes disjuntos (los que faltan en medio), W̄ la diferencia media de pesos de los genes coincidentes y N el tamaño del genoma mayor (1 para genomas pequeños). Los genomas con δ por debajo de un umbral pertenecen a la misma especie. La aptitud de cada individuo se divide por el tamaño de su especie, y los descendientes se reparten entre las especies según su aptitud media.

Dicho de forma sencilla

Las redes de estructura parecida compiten sobre todo entre sí, no con toda la población. Así una neurona nueva dispone de unas cuantas generaciones para que se ajusten sus pesos, en lugar de que la barran enseguida las redes ya establecidas. Y como la aptitud se reparte dentro de la especie, ninguna especie puede adueñarse de toda la población.

δ = c1 E / N + c2 D / N + c3 W̄

c1 E
genes en exceso — estructura que uno de los genomas adquirió después del último «invento» común; indica una rama de la evolución más joven y distinta
c2 D
genes disjuntos — inventos de la época en que ya existían ambos, pero que solo tiene uno de ellos; otra medida de la diferencia de estructura
N
tamaño del genoma mayor — para que dos genomas grandes que se diferencian en unos pocos genes de muchos no resulten tan distantes como dos pequeños que se diferencian en casi todo; para genomas de menos de 20 genes se toma N = 1
c3 W̄
diferencia media de pesos de los genes coincidentes — redes conectadas igual pero con pesos muy distintos calculan funciones distintas; el peso c3 es menor porque la estructura cambia con menos frecuencia y significa más
Las constantes c1 = c2 = 1, c3 = 0,4 y el umbral δt = 3 son los valores que usaron para XOR Stanley y Miikkulainen (2002); nuestro programa usa los mismos.
Ejemplo — la distancia tras añadir una neurona

El genoma A tiene los genes 1–5. El genoma B procede de un antepasado parecido: también tiene los genes 1–5 (el gen 3 desactivado, porque lo dividió una neurona nueva) y, además, los genes 6 y 7 de la adición de la neurona. Los pesos de los genes coincidentes difieren en 0,2; 0,6; 0; 0,9 y 0,8.

coincidentes: 1–5 → W̄ = (0,2 + 0,6 + 0 + 0,9 + 0,8) / 5 = 0,5

en exceso: 6, 7 (más allá del final del genoma más corto, que termina en el gen 5) → E = 2;   disjuntos: ninguno → D = 0

δ = 1 · 2 / 1 + 1 · 0 / 1 + 0,4 · 0,5 = 2,2 < 3 → la misma especie

Si B adquiriera una conexión más (gen 8), saldría E = 3 y δ = 3,2 ≥ 3 — B fundaría una especie nueva. Una sola neurona nueva, por tanto, no expulsa a la red de su especie, pero una neurona nueva con una conexión nueva, sí.

nk = P · F̄k / ∑j F̄j,   F̄k = ∑i ∈ Sk fi / |Sk|

nk
número de descendientes de la especie k en la siguiente generación — así es como NEAT premia el éxito, y no seleccionando individuos de toda la población
P
tamaño de la población (150) — los descendientes se reparten como una tarta; la población ni crece ni se reduce
|Sk|
número de miembros de la especie — aptitud compartida: la aptitud de cada miembro se divide por el tamaño de su especie, f′i = fi / |Sk|; así una especie grande no puede conseguir más solo por ser grande
F̄k
suma de las aptitudes compartidas de la especie, es decir, su aptitud media — la porción de la tarta la decide la calidad, no el número
∑j F̄j
suma sobre todas las especies — al dividir se obtiene una proporción que suma 1, de modo que se reparten exactamente P descendientes (tras redondear hacia abajo, el resto se lo lleva la mejor especie)
Ejemplo — por qué la aptitud compartida protege a una especie nueva

Población de 150: la especie establecida A tiene 120 redes con aptitud media 9,0; la nueva especie B, con una neurona oculta, tiene 30 redes con aptitud media 7,5.

con aptitud compartida: nA = 150 · 9,0 / 16,5 ≈ 81,8 → 81 (+1 del resto) = 82,   nB = 150 · 7,5 / 16,5 ≈ 68,2 → 68

sin aptitud compartida (según la suma de aptitudes, 1 080 y 225): A ≈ 150 · 1 080 / 1 305 ≈ 124,   B ≈ 26

Sin aptitud compartida, la especie nueva se extinguiría en unas pocas generaciones, porque es peor y más pequeña. Con ella, recibe más descendientes de los miembros que tiene, y gana tiempo para ajustar sus pesos.

La tercera idea es la más sencilla: empezar por lo mínimo. Al principio, ninguna red tiene neuronas ocultas — las entradas van directamente a la salida. La estructura solo crece cuando compensa. Por eso las redes resultantes suelen ser pequeñas.

Todo junto — una generación de nuestro NEAT simplificado (las probabilidades son las que usa el programa para XOR):

población ← 150 redes mínimas (x₁, x₂ y el sesgo directamente a y,
    pesos aleatorios en [−2, 2])
para la generación g = 0, 1, …, 100:
    evalúa cada red con la aptitud f
    si alguna red resuelve el problema: fin
    reparte las redes en especies: una red pertenece a la primera especie con cuyo
                                   representante tiene δ < 3,
                                   si no, funda una nueva
    elimina las especies que no han mejorado en 15 generaciones (salvo la especie con la
        mejor red)
    asigna a la especie k n_k = 150 · F̄_k / ∑ F̄_j descendientes
    en cada especie:
        padres ← el 20 % mejor de los miembros
        si la especie tiene más de 5 miembros, su mejor red pasa sin cambios
        cada descendiente restante:
            con probabilidad 0,75 cruce de dos padres, si no, copia de uno
            con probabilidad 0,8 cambia los pesos
                (90 %: w ← w + N(0, 1), 10 %: uno nuevo aleatorio)
            con probabilidad 0,1 añade una conexión
            con probabilidad 0,03 añade una neurona (divide una conexión activa al azar)

6. NEAT sobre XOR

Nuestro NEAT simplificado tiene una población de 150 redes y como mucho 100 generaciones. En la ejecución de la figura resolvió XOR en la generación 27 con una red de una sola neurona oculta y siete conexiones — que es la solución más pequeña posible:

f = ( 4 − ∑ |y − t| )2

∑ |y − t|
el error — la suma de las desviaciones de la salida y respecto al valor correcto t en las cuatro entradas; en valor absoluto, para que los errores por arriba y por abajo no se anulen
4
el mayor error posible (cuatro entradas, cada desviación como mucho 1) — al restar, el error, que queremos reducir, se convierte en una aptitud, que la evolución aumenta, y que es siempre no negativa
2
el cuadrado — amplifica las diferencias cerca de la solución: una red con error 0,5 tiene aptitud 12,25, una con error 1, solo 9, así que la selección premia más los últimos puntos porcentuales
Aptitud para XOR según el artículo original de NEAT (Stanley y Miikkulainen, 2002); como mucho 16. Una red que responde 0,5 a todo tiene aptitud (4 − 2)² = 4. Una red cuenta como solución cuando, tras redondear la salida, responde correctamente a las cuatro entradas.
−1,4 −3,0 3,3 −3,4 −5,7 −3,7 0,9 x₁ x₂ 1 y h x₁x₂y 00 0,00 01 0,86 10 1,00 11 0,01
Red para XOR cultivada por NEAT; a la derecha, sus salidas

La red se puede leer. La neurona oculta h solo se enciende cuando ambas entradas son 0 (las dos tienen un peso negativo grande y el sesgo es positivo). Las conexiones directas a la salida calcularían por sí solas «no las dos a la vez» — salida 1 para todo salvo (1, 1) —, pero el peso fuertemente negativo desde h la apaga para (0, 0). Las salidas 0,000; 0,855; 1,000 y 0,005 son, tras redondear, exactamente XOR. Mientras tanto, el número de especies creció de una a una veintena.

Ejemplo — cálculo de la red para las cuatro entradas

Pesos (redondeados): hacia h desde x1, x2 y el sesgo, −3,37; −3,67; 0,95; hacia y desde x1, x2, el sesgo y h, −1,42; −2,96; 3,32; −5,69. La activación es σ(z) = 1 / (1 + e−4,9z). Primero se calcula h y luego y (la tabla usa los pesos sin redondear, así que un cálculo a mano puede diferir en la última cifra):

(x1, x2)zhhzyy|y − t|
(0, 0)0,950,9903,32 − 5,69 · 0,990 = −2,320,0000,000
(0, 1)−2,720,000−2,96 + 3,32 = 0,360,8550,145
(1, 0)−2,430,000−1,42 + 3,32 = 1,891,0000,000
(1, 1)−6,090,000−1,42 − 2,96 + 3,32 = −1,060,0050,005

El error es 0,150 y la aptitud, (4 − 0,150)² ≈ 14,82 de 16. Donde peor responde la red es en (0, 1): la salida 0,855 está correctamente por encima de la mitad, pero no cerca de uno — para contar como solución basta, aunque seguir ajustando los pesos aumentaría todavía la aptitud.

De cincuenta ejecuciones con semillas distintas, NEAT resolvió XOR en 47, de media en 31 generaciones, con 2,6 neuronas ocultas que realmente hacen algo. El artículo original da 32 generaciones y 2,35 neuronas ocultas — así que nuestro NEAT simplificado se acerca bastante.

7. En qué se apoya NEAT

Las mismas 50 ejecuciones con una parte del algoritmo desactivada:

VarianteResolvió XORGeneración media
NEAT47 de 5031,1
sin especiación (una sola especie)1 de 50—
sin cruce50 de 5047,3

Sin especiación, NEAT casi no funciona. Una red con una neurona oculta es, al nacer, peor que las redes establecidas que no la tienen, porque sus pesos nuevos son aleatorios — y en una única competición común la selección la elimina de inmediato. La especiación la protege hasta que madura. Sin cruce, XOR también se resuelve, solo que más despacio y con redes mayores (3,1 neuronas ocultas activas): el cruce ayuda a combinar los hallazgos parciales de distintos individuos.

8. Los sucesores de NEAT

  • HyperNEAT (Stanley et al., 2009) evoluciona una red pequeña que es la que genera los pesos de una red grande según la geometría del problema — como un genoma que no describe cada célula, sino las reglas de crecimiento.
  • La búsqueda de novedad (Lehman y Stanley, 2011) no premia la aptitud, sino el comportamiento nuevo. En un laberinto con callejones sin salida engañosos encontró la meta con más frecuencia que la búsqueda guiada por la aptitud.
  • Neuroevolución profunda. En 2017, el equipo de Uber AI mostró que un simple algoritmo genético puede entrenar redes con millones de pesos en juegos de Atari de forma comparable al aprendizaje por refuerzo.
  • Búsqueda evolutiva de arquitecturas neuronales. La red AmoebaNet (Google, 2019) surgió de la evolución de bloques de construcción y en su momento estaba entre las mejores en reconocimiento de imágenes en ImageNet. Hoy las arquitecturas las diseñan con más frecuencia personas u otros métodos, pero la evolución sigue siendo una de las opciones.

9. Resumen

  • La neuroevolución cultiva redes neuronales con algoritmos evolutivos — es útil donde el gradiente no se puede calcular o donde la recompensa llega solo al final.
  • La evolución de los pesos de una sola neurona mantiene el péndulo invertido sobre un carro durante 20 segundos tras unos trescientos intentos; los pesos aleatorios dan una mediana de 9 pasos.
  • Para XOR no basta una neurona — hay que cambiar la estructura de la red.
  • NEAT evoluciona pesos y estructura: las marcas históricas hacen posible el cruce, la especiación protege las estructuras nuevas y las redes crecen desde lo mínimo.
  • Sin especiación, NEAT resolvió XOR en 1 de 50 ejecuciones; con especiación, en 47 — y la mejor solución tenía una sola neurona oculta.

¿Quieres probarlo por tu cuenta? Pide a un agente de IA que programe el péndulo invertido sobre un carro con evolución del controlador y luego prueba con dos barras de distinta longitud en un mismo carro — la famosa versión más difícil en la que NEAT destacó en su día.

¿Lo ves de otra manera? Escribe a support@coden-app.com.

Un Agente en tu ordenador, controlado desde el móvil