Compartir a través de



Noviembre de 2018

Volumen 33, número 11

Inteligencia artificial: examen más detallado del aprendizaje de refuerzo

Por Frank La La

Frank La VigneEn la columna del mes pasado, exploré algunos conceptos sobre el aprendizaje de refuerzo (RL). Probé un enfoque estrictamente aleatorio para navegar por un entorno simple y, a continuación, implementé una tabla Q para recordar las acciones pasadas y las que conducen a recompensas. En la demostración, un agente que trabaja de forma aleatoria fue capaz de alcanzar el estado objetivo aproximadamente un 1 por ciento del tiempo y casi la mitad del tiempo al usar una tabla Q para recordar acciones anteriores. Sin embargo, este experimento solo arañó la superficie del campo prometedor y en expansión de RL.

Recuerde de la columna anterior (msdn.com/magazine/mt830356) que un espacio de problemas RL consta de un entorno, un agente, acciones, estados y las recompensas. Un agente examina el estado de un entorno y realiza una acción. A continuación, la acción cambia el estado del agente o el entorno. El agente recibe una recompensa y examina el estado actualizado de su entorno. Luego, el ciclo se reinicia y se ejecuta para varias iteraciones hasta que el agente triunfa o fracasa en un objetivo predefinido. Cuando un agente triunfa o fracasa, finaliza la simulación. Con una tabla Q, un agente recuerda las acciones que han producido recompensas positivas y las consulta al tomar decisiones en simulaciones posteriores.

Problema MAB (Multi-Armed Bandit)

Uno de los problemas clásicos de RL es la tensión entre la exploración y la explotación. Las máquinas tragaperras, a menudo conocidas como “one-armed bandits” son la inspiración para este problema. Un conjunto de máquinas tragaperras plantea un problema "Multi-Armed Bandit". Cada una de estas máquinas tragaperras tiene una probabilidad de desembolsar un bote o no. La probabilidad de que cada giro desembolse un bote se puede representar como P y la probabilidad de que no dé ningún premio es 1 - P. Si un equipo tiene una probabilidad de bote (JP) de 0,5, cada tiro de la palanca tiene la misma probabilidad de ganar o perder. Por el contrario, una máquina con una JP de 0,1 produciría un resultado perdedor el 90 por ciento de las veces.

Ahora, imagine un conjunto de cinco máquinas tragaperras y un jugador (o agente) con un objetivo de maximizar las ganancias y minimizar las pérdidas. Con ningún conocimiento previo de ninguna probabilidad de bote (JP) de las máquinas, el agente debe asumir algunos riesgos al principio. Con el primer tiro de la palanca, el agente gana y recibe un premio. Sin embargo, los intentos posteriores revelan que esta máquina da premios aproximadamente la mitad de las veces (el valor de JP es 0,54). Teniendo en cuenta que son máquinas tragaperras, el porcentaje es bastante generoso. El agente debe decidir si debe aprovechar el recurso conocido actual o explorar una nueva máquina. Si la probabilidad de que la primera máquina tragaperras dé premio es así de generosa, ¿vale la pena probar las otras máquinas del conjunto para ver si las posibilidades de premio son mayores?

La mejor manera de explorar aún más este espacio de problemas es usar código de Python en un cuaderno de Jupyter. Cree un cuaderno de Python 3 en su plataforma preferida. Traté los cuadernos de Jupyter en un artículo anterior (msdn.com/magazine/mt829269). Cree una celda vacía, escriba el siguiente código y ejecute la celda.

import numpy as np
import matplotlib.pyplot as plt
number_of_slot_machines = 5
np.random.seed(100)
JPs =  np.random.uniform(0,1, number_of_slot_machines)
print(JPs)
plt.bar(np.arange(len(JPs)),JPs)
plt.show()

La salida debería leer y mostrar un trazado de los valores, como se muestra en la Figura 1.

[0.54340494 0.27836939 0.42451759 0.84477613 0.00471886]

Probabilidades de ganar el bote de las cinco máquinas tragaperras
Figura 1 Probabilidades de ganar el bote de las cinco máquinas tragaperras

El código crea una matriz de valores JP para una serie de cinco máquinas tragaperras comprendidos entre 0,004 y 0,844. Sin embargo, la primera máquina que el agente ha probado, aunque es generosa, no es la mejor. Claramente, la cuarta máquina tragaperras, con un índice de premios del 84,4 por ciento, es la más rentable del entorno. También vale la pena destacar que la última máquina tragaperras ofrece las peores probabilidades de obtener un bote. Recuerde que el agente no tiene ningún conocimiento previo de los índices de premios y que debe descubrirlos por sí mismo. Si el agente se hubiese quedado en la primera máquina y elegido la explotación en vez de la exploración, nunca habría encontrado la máquina más rentable.

Para representar lo que el agente sabe al principio de la simulación, agregue el código siguiente a una nueva celda:

known_JPs = np.zeros(number_of_slot_machines)

Se crea una matriz de ceros, que significa que el agente supone que el valor de JP de cada máquina tragaperras es cero. Aunque quizás no sea el mejor valor inicial en todos los casos, bastará para nuestros fines. Para crear una simulación de una máquina tragaperras, agregue el código siguiente a una nueva celda y ejecútelo:

def play_machine(slot_machine):
  x = np.random.uniform(0, 1)
  if (x <= JPs[slot_machine]):
    return(10)
  else:
    return(-1)

Este fragmento de código simula una máquina tragaperras que proporciona una recompensa de 10 si da premio y una recompensa negativa de -1 si no lo da. Las probabilidades de premio se basan en la probabilidad definida en la matriz numpy de JP. Para probar el código, escriba el código de Python siguiente en una nueva celda y ejecútelo:

# Test Slot Machine 4
for machines in range(10):
  print(play_machine(3))
print ("------")      
# Test Slot Machine 5
for machines in range(10):
  print(play_machine(4))

Este código marca la máquina de mejor rendimiento frente a la que ofrece el peor rendimiento. Puesto que todo se basa en el azar, no hay ninguna garantía de los resultados de salida. Los resultados deben reflejarlo, con una mayoría de valores de 10 para la máquina 4 y casi todos los valores de -1 para la máquina 5. Con el comportamiento previsto del código de la máquina tragaperras simulado, ha llegado el momento de examinar un algoritmo común en RL: Epsilon-greedy.

Algoritmo epsilon-greedy

El dilema más importante al que aquí se enfrenta el agente es si priorizar la codicia, el deseo de aprovechar un recurso conocido, o la curiosidad, deseo explorar otras máquinas tragaperras con la esperanza de optar a más premios. Uno de los algoritmos más sencillos para resolver este dilema se conoce como el algoritmo epsilon-greedy, donde el agente elige al azar entre usar la máquina tragaperras con más probabilidades de premio según lo observado hasta el momento o probar otra máquina con la esperanza de que dé más premios. Con un valor bajo de epsilon, este algoritmo sigue el algoritmo greedy, pero en ocasiones probará otra máquina tragaperras. Por ejemplo, si el valor de epsilon es 0,1, el algoritmo optará por aprovechar el 90 por ciento del tiempo y explorar solo el 10 por ciento. Por lo general, los valores predeterminados de epsilon tienden a estar comprendidos entre 0,05 y 0,1. En resumen, el agente jugará principalmente a la mejor máquina tragaperras que descubra y, en ocasiones, probará otra. Recuerde que cada tiro de la palanca tiene un costo y que el agente no sabe lo que nosotros sabemos: la máquina 4 es la que da más premios.

Esto enfatiza la noción de RL. El agente no sabe nada sobre el entorno inicialmente, por lo que debe explorarlo primero y explotarlo después. El aprendizaje continúa durante todo el proceso. En esencia, es la noción de una recompensa retrasada, que, en beneficio del agente, no será “greedy” totalmente y dejará algo de espacio para la exploración.

Prueba de la hipótesis de epsilon-greedy

Para probar esta hipótesis, agregue el código de la Figura 2 a una nueva celda y ejecútelo. Este código crea la función multi_armed_bandit, que simula una serie de ejecuciones en una colección de máquinas tragaperras. La función almacena las probabilidades observadas de desembolso de premios. En cada iteración, el agente jugará al azar a la máquina tragaperras que ha observado que tiene más probabilidades de dar premio hasta el momento, o bien probará otra máquina de manera arbitraria. La función argmax devuelve el valor más alto de la matriz numpy. En este caso, hace referencia a la máquina tragaperras con las probabilidades más altas de dar el bote. Los parámetros de la función permiten controlar el número de máquinas tragaperras, la cantidad de iteraciones que se ejecutan y el valor de epsilon. 

Figura 2 Código de aprendizaje de refuerzo

def multi_armed_bandit(arms, iterations, epsilon):
  total_reward, optimal_action = [], []
  estimated_payout_odds = np.zeros(arms)
  count = np.zeros(arms)
  for i in range(0, iterations):
    epsilon_random = np.random.uniform(0, 1)
    if epsilon_random > epsilon :
      # exploit
      action = np.argmax(estimated_payout_odds)
    else :
      # explore
      action = np.random.choice(np.arange(arms))
    reward = play_machine(action)
    estimated_payout_odds[action] = estimated_payout_odds[action] +
      (1/(count[action]+1)) *
      (reward - estimated_payout_odds[action])
    total_reward.append(reward)
    optimal_action.append(action == np.argmax(estimated_payout_odds))
    count[action] += 1
  return(estimated_payout_odds, total_reward)

Con el código RL implementado, ha llegado el momento de probar el algoritmo epsilon-greedy. Escriba el código de la Figura 3 en una celda vacía y ejecútelo. Los resultados muestran el gráfico de la Figura 1, que se consulta fácilmente, seguido de las probabilidades que ha observado el código RL.

Figura 3 Código para comparar las probabilidades reales de una máquina tragaperras con las observaciones del agente

print ("Actual Odds")
plt.bar(np.arange(len(JPs)),JPs)
plt.show()
print (JPs)
print("----------------------------------")
iterations = 1000
print("\n----------------------------------")
print ("Learned Odds with epsilon of .1")
print("----------------------------------")
learned_payout_odds, reward = multi_armed_bandit(number_of_slot_machines, iterations, .1)
plt.bar(np.arange(len(learned_payout_odds)),learned_payout_odds)
plt.show()
print (learned_payout_odds)
print ("Reward: ", sum(reward))

Como puede ver en la Figura 4, el algoritmo realizó un excelente trabajo, no solo al determinar la máquina tragaperras con las probabilidades más favorables, sino también al generar probabilidades de premio bastante precisas para las otras cuatro máquinas tragaperras. Los gráficos se alinean bastante bien. La excepción es la quinta máquina tragaperras, que tiene pocas probabilidades de premio y ha obtenido una puntuación negativa en las observaciones del agente.

Resultados con un valor de epsilon de 0,1
Figura 4 Resultados con un valor de epsilon de 0,1

Ahora, con la línea base establecida, es el momento de experimentar un poco más. ¿Qué ocurre si epsilon se establece en cero, lo que significa que el algoritmo nunca explorará? Escriba el código siguiente en una nueva celda y ejecútelo para llevar a cabo ese experimento:

print("\n----------------------------------")
print ("Learned Odds with epsilon of 0")
print("----------------------------------")
learned_payout_odds, reward =
  multi_armed_bandit(number_of_slot_machines, iterations, 0)
plt.bar(np.arange(len(learned_payout_odds)),learned_payout_odds)
plt.show()
print (learned_payout_odds)
print ("Reward: ", sum(reward))

El gráfico resultante se muestra con un valor mayor que cero. Una máquina prevalece sobre las demás, lo que deja claro que el agente encontró una máquina y se quedó enganchado a ella. Sin embargo, ejecute el código varias veces y observará que, en ocasiones, se desarrolla un patrón interesante. Habrá una o varias máquinas con valores negativos y una máquina con un valor mayor que cero. En estos casos, el agente perdió en una máquina determinada y luego ganó en otra. Una vez que el agente detecta una máquina ganadora, se engancha a ella, ya que será la máquina elegida por la función argmax. Si epsilon se establece en cero, el agente aún puede explorar, pero no será intencionado. Por lo tanto, las probabilidades de la máquina tragaperras observada no se acercarán nada a las probabilidades reales. También vale la pena tener en cuenta que el método "greedy" genera una puntuación de recompensa menor que cuando epsilon estaba establecido en 0,1. La codicia, como mínimo la codicia absoluta, parecería contraproducente.

¿Qué sucede si epsilon se establece en 1 y provoca que el agente explore cada vez y no aproveche nada? Escriba el código siguiente en una nueva celda y ejecútelo:

print("\n----------------------------------")
print ("Learned Odds with epsilon of 1")
print("----------------------------------")
learned_payout_odds, reward  = multi_armed_bandit(number_of_slot_machines, iterations, 1)
plt.bar(np.arange(len(learned_payout_odds)),learned_payout_odds)
plt.show()
print (learned_payout_odds)
print ("Reward: ", sum(reward))

Los resultados mostrarán que el agente hizo un excelente trabajo al observar probabilidades similares a las reales, y el gráfico se alinea muy estrechamente con la Figura 1. De hecho, los resultados de establecer epsilon en 1 se parecen mucho a los obtenidos con el valor 0,1. Sin embargo, tome nota del valor de Reward, que presenta una diferencia notable. El valor de reward con epsilon establecido en 0,1 casi siempre será mayor que cuando se establece en 1. Si el agente está configurado para explorar solamente, probará una máquina al azar en cada iteración. Aunque puede aprender de la observación, no actúa sobre estas observaciones.

Resumen

El aprendizaje de refuerzo sigue siendo uno de los espacios más emocionantes de la inteligencia artificial. En este artículo, exploré el algoritmo epsilon-greedy con el clásico problema "Multi-Armed Bandit", y me centré específicamente en el dilema de exploración o explotación al que se enfrentan los agentes. Le animo a explorar aún más las compensaciones. Para ello, experimente con los distintos valores de epsilon y con cantidades mayores de máquinas tragaperras.


Frank La Vigne trabaja en Microsoft como profesional de soluciones de tecnología de inteligencia artificial, donde ayuda a las empresas a llegar más lejos aprovechando al máximo sus datos con inteligencia artificial y análisis. También hospeda en colaboración el podcast DataDriven. Escribe publicaciones con regularidad en FranksWorld.com y puede verlo en su canal de YouTube, "Frank’s World TV" (FranksWorld.TV).

Gracias al siguiente experto técnico por su ayuda en la revisión de este artículo: Andy Leonard


Comente este artículo en el foro de MSDN Magazine