LECCIÓN 11 (β β). APRENDIZAJE EN MÁQUINAS. En esta lección se exploran estrategias de aprendizaje con refuerzo. Con ellas se desarrolla un agente capaz de aprender estrategias para jugar al «conecta-4». "De humanos es errar y de necios permanecer en el error." (Cicerón) Inteligencia Artificial e I.C.. 2003/2004 10.1 Dpto. Leng. C. Comp.(Universidad de Málaga) Inteligencia Artificial e I.C.. 2003/2004 10.2 Dpto. Leng. C. Comp.(Universidad de Málaga) R.11.1. Diferencias temporales: tabla de valores. a) Definir un tipo de datos tabla-valor que guarde un valor para cada estado de un problema Los valores de la tabla estarán comprendidos entre los de dos variables globales *ganar* y *perder*, y podrán modificarse empleando las siguientes funciones: a. (tabla-valor-estado-ganador estado tabla) que inicie el valor de estado en la tabla a *ganar*. b. (tabla-valor-estado-perdedor estado tabla) que inicie el valor de estado en la tabla a *perder*. c. (tabla-valor-estado-empate estado tabla) que inicie el valor de estado en la tabla al de otra variable global llamada *empatar*. d. (tabla-valor-actualiza-dt estado sucesor tabla &key alfa) que actualice el valor de estado en función de su sucesor empleando el método de las diferencias temporales: tabla(estado) tabla(estado) + alfa * (tabla(sucesor) – tabla(estado)) ************************** SOLUCION: Se trata de un conjunto de definiciones bastante sencillas. Comenzaremos definiendo las variables globales necesarias: (defvar *ganar*) (setq *ganar* 100) (defvar *perder*) (setq *perder* -100) (defvar *empatar*) (setq *empatar* -1) (defvar *alfa*) ;tasa de aprendizaje de la regla de diferencias temporales (setq *alfa* 0.1) Cada tabla de valores se implementará como una tabla hash indexada por estados. Los constructores y funciones de lectura y escritura son sencillas: (defun make-tabla-valor (&optional (eq-estado #'equalp)) (make-hash-table :test eq-estado)) (defun tabla-valor-asignar (estado valor tabla) (setf (gethash estado tabla) valor)) "Guarda valor para estado" (defun tabla-valor (e tabla) "El valor del estado en la tabla, o *empatar* si no existe" (or (gethash e tabla) *empatar*)) Definiremos también por conveniencia una función tabla-valor-tam, que nos dirá el número de entradas que hay guardadas en una tabla. El lector interesado puede consultar la sintáxis de la función maphash en la HiperEspecificación del lenguaje. (defun tabla-valor-tam (tabla) "Número de entradas de la tabla" (let ((n 0)) (maphash #'(lambda (e v) (setf n (1+ n))) tabla) n)) Una vez definido el tipo de datos, es sencillo escribir las funciones de actualización de la tabla que necesitaremos para el método de aprendizaje con diferencias temporales: (defun tabla-valor-estado-perdedor (e tabla) (tabla-valor-asignar e *perder* tabla)) Inteligencia Artificial e I.C.. 2003/2004 10.3 Dpto. Leng. C. Comp.(Universidad de Málaga) (defun tabla-valor-estado-ganador (e tabla) (tabla-valor-asignar e *ganar* tabla)) (defun tabla-valor-estado-empate (e tabla) (tabla-valor-asignar e *empatar* tabla)) (defun tabla-valor-actualiza-dt (estado sucesor tabla &key (alfa *alfa*)) "Actualiza el valor de estado según el método de las diferencias temporales." (let ((valor (tabla-valor estado tabla))) (tabla-valor-asignar estado (+ valor (* alfa (- (tabla-valor sucesor tabla) valor))) tabla))) Nótese que estas operaciones son independientes de la implementación de los objetos tabla-valor. Inteligencia Artificial e I.C.. 2003/2004 10.4 Dpto. Leng. C. Comp.(Universidad de Málaga) R.11.2. Diferencias temporales en problemas de juegos. a) Definir una función crea-funcion-evaluacion-tabla que reciba un objeto tabla-valor como los definidos en R11.1 y devuelva una función de evaluación de juegos considerando los valores de la tabla. b) Definir una función (aprende-tabla-valor-2 jug1 jug2 estr-rand &optional (pex 0.1)...), que reciba dos jugadores jug1, jug2, y aprenda una tabla-valor de evaluaciones heurísticas para el jugador jug2. El jugador jug2 realizará movimientos de exploración aleatorios con probabilidad pex empleando una estrategia estr-rand. c) Apender una tabla de valores empleando la función anteriror en 10000 partidas del juego del conecta-3 en un tablero 3x3. Crear un jugador-evaluar adecuado y comprobar su eficacia frente a jugadores heurísticos como los definidos en la lección 10. ************************** SOLUCION: a) La definición es bastante sencilla, y similar a la estudiada en R10.2.b. La función de evaluación actuará del siguiente modo: si la posición es final y ganadora para MAX, devolvemos el valor *ganar*, si es final y perdedora para MAX devolvemos *perder*, y en caso contrario se consulta el valor guardado en la tabla: (defun crea-funcion-evaluacion-tabla (tabla &key fmax fmin) #'(lambda (e) (let ((ganador (finalp e))) (cond ((eql ganador fmax) *ganar*) ((eql ganador fmin) *perder*) (t (tabla-valor e tabla)))))) Nótese que cada función devuelta es un cierre léxico que contiene su propia tabla. b) Para definir la función aprende debemos considerar el uso que un jugador hará posteriormente de la tabla de valores. En principio, la tabla se creará para jugadores del tipo jugador-evaluar, tal como se definieron en R10.2.b. En la tabla, se guardará la evaluación de los estados del jugador contrario al que está aprendiendo (MIN), ya que son esas precisamente las que nuestro jugador (MAX) estará interesado en aprender a evaluar. También se guardarán los valores correspondientes a estados finales y perdedores para MAX, de modo que los valores perdedores también se propaguen adecuadamente por la tabla. Al igual que ocurría con la función de evaluación de R10.2.b, la tabla aprendida será diferente según el turno (o la ficha) de nuestro jugador. En nuestro caso, estamos interesados en aprender una tabla para *jugador-2*, aunque la tabla para *jugador-1* se puede aprender de forma análoga. Definiremos aprende-tabla-valor-2 como una función recursiva. Incialmente tabla tendrá una tabla vacía, y e el estado inicial del juego. El esquema inicial podría ser el siguiente: (defun aprende-tabla-valor-2-incompleta (jug1 jug2 estr-rand &optional (pex 0.1) (tabla (make-tabla-valor)) (e (hacer-estado-inicial))) (cond ((or (agotado e) (finalp e)) tabla) (t ;MOVIMIENTO DE jug1 (let ((e2 (elegir-suc-nth (jugador-elige-movimiento jug1 e) e))) ;MOVIMIENTO DE jug2 (let ((e3 (elegir-suc-nth (jugador-elige-movimiento jug2 e2) e2))) (cond ((finalp e3) (tabla-valor-estado-ganador e3 tabla)) ((agotado e3) (tabla-valor-estado-empate e3 tabla))) (tabla-valor-actualiza-dt e e3 tabla)) (aprende-tabla-valor-2-incompleta jug1 jug2 estr-rand pex tabla e3)))))) Inteligencia Artificial e I.C.. 2003/2004 10.5 Dpto. Leng. C. Comp.(Universidad de Málaga) En cada llamada se realizan dos movimientos a partir del estado e, el primero de MIN (dando lugar al estado e2), y el segundo de MAX (dando lugar al estado e3). Si e3 corresponde a un estado final, será ganador para MAX, y si corresponde a un estado agotado, será un empate. A continuación se actualiza el valor de e en la tabla utilizando el de e3 y el método de diferencias temporales. El entrenamiento termina cuando e corresponde al final del juego. Sin embargo, es necesario tener en cuenta consideraciones adicionales: 1. En primer lugar, existe la posibilidad de que e2 pueda corresponder también a un estado final (perdedor para MAX) o agotado. En tal caso, incluiremos la evaluación correspondiente a e2 en la tabla, y actualizaremos el valor de e utilizando el de e2 y el método de diferencias temporales. 2. En segundo lugar, para garantizar que MAX encuentre una buena estrategia, es necesario realizar movimientos exploratorios. Introduciremos una pequeña componente aleatoria en los movimientos de MAX (jug2). En caso de que el movimiento sea exploratorio no actualizaremos el valor de e. (defun aprende-tabla-valor-2 (jug1 jug2 estr-rand &optional (pex 0.1) (tabla (make-tabla-valor)) (e (hacer-estado-inicial))) (cond ((or (agotado e) (finalp e)) tabla) (t ;MOVIMIENTO DE jug1 (let ((e2 (elegir-suc-nth (jugador-elige-movimiento jug1 e) e))) (when (finalp e2) (tabla-valor-estado-perdedor e2 tabla) (tabla-valor-actualiza-dt e e2 tabla) (return-from aprende-tabla-valor-2 tabla)) ;termina perdiendo (when (agotado e2) (tabla-valor-estado-empate e2 tabla) (tabla-valor-actualiza-dt e e2 tabla) (return-from aprende-tabla-valor-2 tabla)) ;termina empatando ;MOVIMIENTO DE jug2 (let* ((explora? (< (random 1.0) pex)) ;cierto con prob. pex (e3 (elegir-suc-nth (if explora? (funcall estr-rand e2) (jugador-elige-movimiento jug2 e2)) e2))) (cond ((finalp e3) (tabla-valor-estado-ganador e3 tabla)) ((agotado e3) (tabla-valor-estado-empate e3 tabla))) (unless explora? (tabla-valor-actualiza-dt e e3 tabla)) (aprende-tabla-valor-2 jug1 jug2 estr-rand pex tabla e3)))))) c) La función aprende-tabla-valor puede recibir una tabla. En tal caso la modifica destructivamente mientras aprende del transcurso de una partida, y luego la devuelve como resultado. Podemos crear un jugador-evaluar que emplee una tabla-valor, y entrenarlo en 10000 partidas frente a un jugador aleatorio. La siguiente función se encarga de entrenar la tabla: (defun entrena-tabla-2 (npartidas &optional (tabla (make-tabla-valor))) (let* ((feval (crea-funcion-evaluacion-tabla tabla :fmax *jugador-2* :fmin *jugador-1*)) (j1 (make-jugador-aleatorio)) (j2 (make-jugador-evaluar :fmax *jugador-2* :fmin *jugador-1* :feval feval))) (dotimes (i npartidas tabla) (aprende-tabla-valor-2 j1 j2 #'estrategia-random tabla)))) Inteligencia Artificial e I.C.. 2003/2004 10.6 Dpto. Leng. C. Comp.(Universidad de Málaga) A continuación configuramos el juego para un tablero 3x3 y conecta-3, y entrenamos una tabla: (setf *nfilas* 3) (setf *ncolumnas* 3) (setf *long-ganadora* 3) (setf *mi-tabla* (entrena-tabla-2 10000)) Lanzamos una partida para ver qué tal actúa nuestro aprendiz (nótese que en el conecta-3 en un tablero 3x3 no existe estrategia ganadora para el primer jugador, a lo más que puede aspirar es a empatar): (conecta4 (make-jugador-humano) (make-jugador-evaluar :feval (crea-funcion-evaluacion-tabla *mi-tabla* :fmax *jugador-2* :fmin *jugador-1*)) t) ¡Buena suerte! Inteligencia Artificial e I.C.. 2003/2004 10.7 Dpto. Leng. C. Comp.(Universidad de Málaga) EJERCICIOS PROPUESTOS. P.11.1. Escribir una definición más elegante del tipo de datos tabla-valor definido en R.11.1, donde las variables globales *ganar*, *perder*, *empatar*, y *alfa* no sean necesarias, y cada objeto del tipo guarde los valores correspondientes P.11.2. El tipo de datos tabla-valor definido en R.11.1 emplea tablas hash para guardar los datos. Las tablas hash son estructuras dinámicas y eficientes, pero no son objetos que puedan escribirse con prin1 ni leerse posteriormente con read. Ampliar la funcionalidad del nuevo tipo de datos escribiendo dos funciones (guardar-tabla-valor tabla nomf) y (leer-tabla-valor tabla nomf) que permitan guardar el contenido de una tabla-valor en un fichero llamado nomf, y devolver una tabla con los contenidos guardados en el mismo respectivamente. P.11.3. Definir una función (ver-aprendizaje npartidas cadam kpruebas) que realice un total de npartidas de entrenamiento para las variantes del juego del conecta4, y devuelva la tabla aprendida. Cada cadam partidas se hará una pausa en el entrenamiento, se jugarán kpruebas partidas contra una estrategia aleatoria, y se mostrará por pantalla una estadística de los resultados. Esto nos permitirá observar la velocidad con que el programa aprende su estrategia de juego, y la eficacia de la misma. Por ejemplo, para el juego del conecta-3 en un tablero 3x3 se debería obtener un resultado parecido al siguiente si se entrena al segundo jugador (J2): (setf *nfilas* 3) (setf *ncolumnas* 3) (setf *long-ganadora* 3) (ver-aprendizaje 10000 500 1000)) Num. Tam. % % % partidas tabla gana J2 empate pierde J2 ---------------------------------------------------0 0 29.70 12.20 58.10 500 236 58.10 30.10 11.80 1000 295 61.40 20.50 18.10 1500 337 63.30 28.90 7.80 2000 371 65.00 29.90 5.10 2500 384 64.30 27.40 8.30 3000 403 63.00 28.10 8.90 3500 429 74.60 16.70 8.70 4000 443 73.90 19.40 6.70 4500 467 84.30 12.30 3.40 5000 483 80.10 19.90 0.00 5500 492 85.00 12.10 2.90 6000 502 81.50 18.50 0.00 6500 513 82.20 17.80 0.00 7000 521 81.10 18.90 0.00 7500 525 81.50 18.50 0.00 8000 531 83.30 16.70 0.00 8500 536 81.10 18.90 0.00 9000 541 82.20 17.80 0.00 9500 542 81.10 18.90 0.00 10000 545 84.30 15.70 0.00 #<EQUALP Hash Table{545} 20F5C30C> P.11.4. Empleando la función del ejercicio anterior, entrenar un jugador para el juego del conecta-3 en un tablero 4x4 y analizar los resultados. Repetir el proceso para el juego del conecta-4 en un tablero 5x5. P.11.5. Definir funciones análogas a las presentadas en R11.2 para aprender una estrategia de juego para el primer jugador del conecta4. P11.6 Emplear las tablas aprendidas en el ejercicio P11.4 para crear un jugador-minimax. ¿Mejora el rendimiento del jugador a medida que ampliamos la profundidad de la búsqueda? ¿Por qué? ¿Cómo podría mejorarse? __________________________________________________________________________________ Las erratas y comentarios sobre estos apuntes son bienvenidos en: [email protected] Inteligencia Artificial e I.C.. 2003/2004 10.8 Dpto. Leng. C. Comp.(Universidad de Málaga)