En, el campeón mundial de Go, Lee Sedol, se enfrentó a un oponente que no estaba hecho de carne y sangre, sino de líneas de código.
Pronto quedó claro que el humano había perdido.
Al final, Lee Sedol perdió 4: 1.
La semana pasada vi el documental Alphago nuevamente, y lo encontré fascinante una vez más.
¿Lo aterrador de ello? Alphago no obtuvo su estilo de juego de bases de datos, reglas o libros de estrategia.
En cambio, había jugado contra sí mismo millones de veces, y aprendió a ganar en el proceso.
Move 37 en el Juego 2 fue el momento en que todo el mundo entendió: esta IA no juega como un humano, juega mejor.
Alphago combinó el aprendizaje supervisado, el aprendizaje de refuerzo y la búsqueda. Una parte fascinante es que su estrategia surgió del aprendizaje jugando contra sí mismo, utilizando el aprendizaje de refuerzo para mejorar con el tiempo.
Ahora utilizamos el aprendizaje de refuerzo no solo en los juegos, sino también en la robótica, como los brazos de purgador o los robots domésticos, en la optimización de la energía, por ejemplo, para reducir el consumo de energía de los centros de datos o para el control del tráfico, por ejemplo, a través de la optimización de la luz del tráfico.
Y también en los agentes modernos, ahora usamos modelos de idiomas grandes junto con el aprendizaje de refuerzo (por ejemplo, el aprendizaje de refuerzo de la retroalimentación humana) para hacer que las respuestas de ChatGPT, Claude o Gemini sean más humanos, por ejemplo.
En este artículo, te mostraré exactamente cómo funciona esto y cómo podemos entender mejor el mecanismo usando un juego simple: Tic Tac Toe.
¿Qué es el aprendizaje de refuerzo?
Cuando observamos que un bebé aprende a caminar, vemos: se pone de pie, se cae, lo intenta nuevamente, y en algún momento da sus primeros pasos.
Ningún maestro muestra al bebé cómo hacerlo. En cambio, el bebé intenta diferentes acciones por prueba y error para caminar.
Cuando puede pararse o caminar unos pasos, esta es una recompensa para el bebé. Después de todo, su objetivo es poder caminar. Si se cae, no hay recompensa.
Este proceso de aprendizaje de prueba, error y recompensa es la idea básica detrás del aprendizaje de refuerzo (RL).
El aprendizaje de refuerzo es un enfoque de aprendizaje en el que un agente aprende a través de la interacción con su entorno, que las acciones conducen a recompensas.
Su objetivo: obtener tantas recompensas como sea posible a largo plazo.
- A diferencia del aprendizaje supervisado, no hay “respuestas correctas” o etiquetas. El agente tiene que averiguar por sí mismo qué decisiones son buenas.
- A diferencia del aprendizaje no supervisado, el objetivo no es encontrar patrones ocultos en los datos, sino llevar a cabo aquellas acciones que maximizan la recompensa.
Cómo piensa un agente de RL, decide y aprende
Para que un agente de RL aprenda, necesita cuatro cosas: una idea de dónde está actualmente (estado), qué puede hacer (acciones), qué quiere lograr (recompensa) y qué tan bien se ha hecho con una estrategia en el pasado (valor).
Un agente actúa, recibe comentarios y mejora.
Para que esto funcione, se necesitan cuatro cosas:
1) Política / estrategia
Esta es la regla o estrategia según la cual un agente decide qué acción realizar en un determinado estado. En casos simples, esta es una tabla de búsqueda. En aplicaciones más complejas (por ejemplo, con redes neuronales), es una función.
2) Señal de recompensa
La recompensa es la retroalimentación del medio ambiente. Por ejemplo, esto puede ser +1 para una victoria, 0 para un empate y -1 para una pérdida. El objetivo del agente es recolectar tantas recompensas como sea posible en tantos pasos como sea posible.
3) Función de valor
Esta función estima la recompensa futura esperada de un estado. La recompensa muestra al agente si la acción fue “buena” o “mala”. La función de valor estima qué tan bueno es un estado, no solo de inmediato, sino que, considerando las recompensas futuras, el agente puede esperar de ese estado en adelante. Por lo tanto, la función de valor estima el beneficio a largo plazo de un estado.
4) Modelo del entorno
Un modelo le dice al agente: “Si hago la acción A en el estado S, probablemente terminaré en el estado S ‘y obtendré recompensa R”.
Sin embargo, en métodos sin modelos como Q-Learning, esto no es necesario.
Explotación versus exploración: Move 37, y lo que podemos aprender de él
Quizás recuerdes Move 37 del Juego 2 entre Alphago y Lee Sedol:
Un movimiento inusual que parecía un error para nosotros los humanos, pero luego fue aclamado como genio.
¿Por qué el algoritmo hizo eso?
El programa de computadora estaba probando algo nuevo. Esto se llama exploración.
El aprendizaje de refuerzo necesita ambos: un agente debe encontrar un equilibrio entre la explotación y la exploración.
- La explotación significa que el agente usa las acciones que ya conoce.
- La exploración, por otro lado, son acciones que el agente intenta por primera vez. Los intenta porque podrían ser mejores que las acciones que ya conoce.
El agente intenta encontrar la estrategia óptima a través de prueba y error.
Tic-tac-toe con aprendizaje de refuerzo
Echemos un vistazo al aprendizaje de refuerzo con un juego súper conocido.
Probablemente también lo hayas jugado cuando era niño: Tic Tac Toe.
El juego es perfecto como ejemplo introductorio, ya que no requiere una red neuronal, las reglas son claras y podemos implementar el juego con solo un poco de Python:
- Nuestro agente comienza con cero conocimiento del juego. Comienza como un humano ver el juego por primera vez.
- El agente evalúa gradualmente cada situación del juego: un puntaje de 0.5 significa “Todavía no sé si voy a ganar aquí”. Un 1.0 significa: “Esta situación seguramente conducirá a la victoria.
- Al interpretar a muchas fiestas, el agente observa lo que funciona y adapta su estrategia.
El objetivo? Para cada turno, el agente debe elegir la acción que conduce a la más alta recompensa a largo plazo.
En esta sección, construiremos dicho sistema RL paso a paso y crearemos el archivo tictactoerl.py.
→ Puede encontrar todo el código en este Repositorio de Github.
1. Construyendo el entorno del juego
En el aprendizaje de refuerzo, un agente aprende a través de interacciones con un entorno. Determina qué es un estado (por ejemplo, el tablero actual), qué acciones están permitidas (por ejemplo, donde puede hacer una apuesta) y qué comentarios hay sobre una acción (por ejemplo, una recompensa de +1 si gana).
En teoría, nos referimos a esta configuración como el proceso de decisión de Markov: un modelo consiste en estados, acciones y recompensas.
Primero, creamos una clase Tictactoe. Esto administra el tablero de juego, que creamos como una matriz Numpy 3 × 3, y administra la lógica del juego:
- La función de reinicio (self) comienza un nuevo juego.
- La función disponible_acciones () devuelve todos los campos gratuitos.
- El paso de función (self, acción, jugador) ejecuta un movimiento del juego. Aquí devolvemos el nuevo estado, una recompensa (1 = ganancia, 0.5 = sorteo, -10 = movimiento no válido) y el estado del juego. Penalizamos los movimientos no válidos en este ejemplo con -10 en gran medida para que el agente aprenda a evitarlos rápidamente, una técnica común en entornos RL pequeños.
- La función check_winner () verifica si un jugador tiene tres X u O seguidos y, por lo tanto, ha ganado.
- Con render_gui () mostramos la placa actual con matplotlib como gráficos X y O.
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
import random
from collections import defaultdict
# Tic Tac Toe Spielumgebung
class TicTacToe:
def __init__(self):
self.board = np.zeros((3, 3), dtype=int)
self.done = False
self.winner = None
def reset(self):
self.board[:] = 0
self.done = False
self.winner = None
return self.get_state()
def get_state(self):
return tuple(self.board.flatten())
def available_actions(self):
return [(i, j) for i in range(3) for j in range(3) if self.board[i, j] == 0]
def step(self, action, player):
if self.done:
raise ValueError("Spiel ist vorbei")
i, j = action
if self.board[i, j] != 0:
return self.get_state(), -10, True
self.board[i, j] = player
if self.check_winner(player):
self.done = True
self.winner = player
return self.get_state(), 1, True
elif not self.available_actions():
self.done = True
return self.get_state(), 0.5, True
return self.get_state(), 0, False
def check_winner(self, player):
for i in range(3):
if all(self.board[i, :] == player) or all(self.board[:, i] == player):
return True
if all(np.diag(self.board) == player) or all(np.diag(np.fliplr(self.board)) == player):
return True
return False
def render_gui(self):
fig, ax = plt.subplots()
ax.set_xticks([0.5, 1.5], minor=False)
ax.set_yticks([0.5, 1.5], minor=False)
ax.set_xticks([], minor=True)
ax.set_yticks([], minor=True)
ax.set_xlim(-0.5, 2.5)
ax.set_ylim(-0.5, 2.5)
ax.grid(True, which='major', color='black', linewidth=2)
for i in range(3):
for j in range(3):
value = self.board[i, j]
if value == 1:
ax.plot(j, 2 - i, 'x', markersize=20, markeredgewidth=2, color='blue')
elif value == -1:
circle = plt.Circle((j, 2 - i), 0.3, fill=False, color='red', linewidth=2)
ax.add_patch(circle)
ax.set_aspect('equal')
plt.axis('off')
plt.show()
2. Programa el agente Q-Learning
A continuación, definimos la parte de aprendizaje: nuestro agente
Decide qué acción realizar en cierto estado obtener tanta recompensa como sea posible.
El agente utiliza el método RL clásico Q-learning. Se almacena un valor Q para cada combinación de estado y acción, el beneficio estimado a largo plazo de esta acción.
Los métodos más importantes son:
- Usando el
choose_action(self, state, actions)función, el agente decide en cada situación del juego si elegir una acción que ya conoce bien (explotación) o si probar una nueva acción que aún no se ha probado suficientemente (exploración).Esta decisión se basa en el llamado enfoque de ε-grisio:
Con una probabilidad de ε = 0.1, el agente elige una acción aleatoria (exploración), con una probabilidad del 90 % (1-ε) elige la acción actualmente más conocida basada en su tabla Q (explotación).
- Con la función
update(state, action, reward, next_state, next_actions)Ajustamos el valor Q dependiendo de cuán buena fue la acción y qué sucede después. Este es el paso de aprendizaje central para el agente.
# Q-Learning-Agent
class QLearningAgent:
def __init__(self, alpha=0.1, gamma=0.9, epsilon=0.1):
self.q_table = defaultdict(float)
self.alpha = alpha
self.gamma = gamma
self.epsilon = epsilon
def get_q(self, state, action):
return self.q_table[(state, action)]
def choose_action(self, state, actions):
if random.random() < self.epsilon:
return random.choice(actions)
else:
q_values = [self.get_q(state, a) for a in actions]
max_q = max(q_values)
best_actions = [a for a, q in zip(actions, q_values) if q == max_q]
return random.choice(best_actions)
def update(self, state, action, reward, next_state, next_actions):
max_q_next = max([self.get_q(next_state, a) for a in next_actions], default=0)
old_value = self.q_table[(state, action)]
new_value = old_value + self.alpha * (reward + self.gamma * max_q_next - old_value)
self.q_table[(state, action)] = new_value
En mi SustituciónRegularmente escribo resúmenes sobre los artículos publicados en los campos de la tecnología, Python, Ciencia de datosAprendizaje automático y IA. Si está interesado, eche un vistazo o suscríbase.
3. Entrena al agente
El proceso de aprendizaje real comienza en este paso. Durante la capacitación, el agente aprende a través de prueba y error. El agente juega muchos juegos, memoriza qué acciones han funcionado bien y adapta su estrategia.
Durante la capacitación, el agente aprende cómo se recompensan sus acciones, cómo su comportamiento afecta a los estados posteriores y cómo se desarrollan mejores estrategias a largo plazo.
- Con la función
train(agent, episodes=10000)Definimos que el agente juega 10,000 juegos contra un oponente aleatorio simple. En cada episodio, el agente (Jugador 1) hace un movimiento, seguido del oponente (Jugador 2). Después de cada movimiento, el agente aprende a través deupdate(). - Cada 1000 juegos ahorramos cuántas victorias, dibujos y derrotas ha habido.
- Finalmente, trazamos la curva de aprendizaje con matplotlib. Muestra cómo el agente mejora con el tiempo.
# Training mit Lernkurve
def train(agent, episodes=10000):
env = TicTacToe()
results = {"win": 0, "draw": 0, "loss": 0}
win_rates = []
draw_rates = []
loss_rates = []
for episode in range(episodes):
state = env.reset()
done = False
while not done:
actions = env.available_actions()
action = agent.choose_action(state, actions)
next_state, reward, done = env.step(action, player=1)
if done:
agent.update(state, action, reward, next_state, [])
if reward == 1:
results["win"] += 1
elif reward == 0.5:
results["draw"] += 1
else:
results["loss"] += 1
break
opp_actions = env.available_actions()
opp_action = random.choice(opp_actions)
next_state2, reward2, done = env.step(opp_action, player=-1)
if done:
agent.update(state, action, -1 * reward2, next_state2, [])
if reward2 == 1:
results["loss"] += 1
elif reward2 == 0.5:
results["draw"] += 1
else:
results["win"] += 1
break
next_actions = env.available_actions()
agent.update(state, action, reward, next_state2, next_actions)
state = next_state2
if (episode + 1) % 1000 == 0:
total = sum(results.values())
win_rates.append(results["win"] / total)
draw_rates.append(results["draw"] / total)
loss_rates.append(results["loss"] / total)
print(f"Episode {episode+1}: Wins {results['win']}, Draws {results['draw']}, Losses {results['loss']}")
results = {"win": 0, "draw": 0, "loss": 0}
x = [i * 1000 for i in range(1, len(win_rates) + 1)]
plt.plot(x, win_rates, label="Win Rate")
plt.plot(x, draw_rates, label="Draw Rate")
plt.plot(x, loss_rates, label="Loss Rate")
plt.xlabel("Episodes")
plt.ylabel("Rate")
plt.title("Lernkurve des Q-Learning-Agenten")
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
4. Visualización del tablero
Con el programa principal “if name ==” principal “:” Definimos el punto de partida del programa. Asegura que la capacitación del agente se ejecute automáticamente cuando ejecutamos el script. Y usamos el render_gui() Método para mostrar la placa Tictactoe como un gráfico.
# Hauptprogramm
if __name__ == "__main__":
agent = QLearningAgent()
train(agent, episodes=10000)
# Visualisierung eines Beispielbretts
env = TicTacToe()
env.board[0, 0] = 1
env.board[1, 1] = -1
env.render_gui()
Ejecución en la terminal
Guardamos el código en el archivo Tictactoerl.py.
En el terminal, ahora navegamos al directorio correspondiente donde nuestro Tictactoerl.py se almacena y ejecuta el archivo con el comando “Pitón Tictactoerl.py “.
En la terminal, podemos ver cuántos juegos ha ganado nuestro agente después de cada 1000 episodio:
Y en la visualización vemos la curva de aprendizaje:
Pensamientos finales
Con Tictactoe, usamos un juego simple y algo de pitón, pero podemos ver fácilmente cómo Aprendizaje de refuerzo obras:
- El agente comienza sin ningún conocimiento previo.
- Desarrolla una estrategia a través de comentarios y experiencia.
- Sus decisiones mejoran gradualmente como resultado, no porque conozca las reglas, sino porque aprende.
En nuestro ejemplo, el oponente era un agente aleatorio. Luego, pudimos ver cómo nuestro agente Q-Learning se desempeña contra otro agente de aprendizaje o en contra de nosotros mismos.
El aprendizaje de refuerzo nos muestra que la inteligencia de máquinas no solo se crea a través del conocimiento o la información, sino a través de la experiencia, la retroalimentación y la adaptación.