Usar una red neuronal multicapa para evitar obstáculos en los juegos.

Encontrar formas de evitar obstáculos en los juegos es una tarea clásica con la que todos los desarrolladores de juegos tienen que lidiar. Existen varios algoritmos bien conocidos de diversos grados de eficiencia. Todos ellos, en un grado u otro, analizan la posición relativa del obstáculo y el jugador, y en función de los resultados, se toma una u otra decisión de movimiento. Traté de usar una red neuronal entrenada para resolver el problema de evitar obstáculos. Quiero compartir mi experiencia en la implementación de este enfoque en Unity3D en este breve artículo.


Concepto


El terreno basado en el terreno estándar se utiliza como espacio de juego. Las colisiones con la superficie no se consideran en este artículo. Cada modelo está equipado con un conjunto de colisionadores, que describe con la mayor precisión posible la geometría de los obstáculos. El modelo, que debe sortear obstáculos, tiene cuatro



sensor de colisión (en la captura de pantalla, la ubicación y la distancia de los sensores se indican con líneas turquesas). En esencia, los sensores son reykast, cada uno de los cuales pasa la distancia al objeto de colisión en el algoritmo de análisis. La distancia varía de 0 (el objeto se encuentra lo más cerca posible) a 1 (sin colisión, esta dirección está libre de obstáculos).
En general, el trabajo del algoritmo para evitar obstáculos es el siguiente:


  1. Se alimentan cuatro valores de sensores de colisión a las cuatro entradas de una red neuronal entrenada
  2. Se calcula el estado de la red neuronal. En la salida, obtenemos tres valores:
    a. La potencia de rotación del modelo en sentido antihorario (toma un valor de 0 a 1)
    b. La potencia de rotación del modelo en sentido horario (toma un valor de 0 a 1)
    c. Aceleración de frenado (toma un valor de 0 a 1)
  3. Se aplican esfuerzos al modelo con coeficientes apropiados.

Implementación


Honestamente, no tenía idea de si algo saldría de esta aventura. En primer lugar, implementé la clase neuroNet en Unity. No me detendré en el código de clase, ya que es un clásico perceptrón multicapa. En el proceso, surgió de inmediato la cuestión del número de capas de red. ¿Cuántos de ellos se requieren para proporcionar la capacidad requerida por un lado y una velocidad de cálculo aceptable por el otro? Después de una serie de experimentos, me decidí por doce capas (tres condiciones básicas para cuatro entradas).


Luego, fue necesario implementar el proceso de entrenamiento de una red neuronal. Para hacer esto, tuve que crear una aplicación separada que usara la misma clase neuroNet. Y ahora el problema de los datos para la capacitación ha alcanzado su punto máximo. Inicialmente, quería usar valores obtenidos directamente de la aplicación del juego. Para hacer esto, organicé el registro de datos de los sensores, para que en el futuro cada conjunto de valores de los cuatro sensores indique al programa de entrenamiento los valores de salida correctos. Pero, mirando el resultado, me desanimé. El hecho es que no es suficiente indicar un valor adecuado para cada conjunto de cuatro valores de sensor; estos valores deben ser consistentes. Esto es muy importante para el entrenamiento exitoso de la red neuronal. Además, no había garantía de que la muestra resultante representara todas las situaciones posibles.


Una solución alternativa era una tabla compilada manualmente de opciones básicas para los valores de los sensores y las salidas. Las opciones básicas fueron valores tomados: 0.01 - el obstáculo está cerca, 0.5 - el obstáculo está a medio camino, 1 - la dirección está libre. Esto ha reducido el tamaño de la muestra de entrenamiento.


  Sensor 1 
  Sensor 2 
  Sensor 3 
  Sensor 4 
Rotación en sentido horarioRotación antihorariaFrenado
0,010,010,010,010,010,010,01
0,010,010,010.5 0.50,010,010,01
0,010,010,010,9990,010,010,01
0,010,010.5 0.50,010,9990,010,01
0,010,010.5 0.50.5 0.50,9990,010,01
0,010,010.5 0.50,9990,9990,010.5 0.5
0,010,010,9990,010,9990,010.5 0.5
0,010,010,9990.5 0.50,9990,010,999
0,010,010,9990,9990,9990,010,999

La tabla muestra un pequeño fragmento de la muestra de entrenamiento (total en la tabla 81-una fila). El resultado final del programa de capacitación fue una tabla de ponderación, que se guardó en un archivo separado.


Resultados


Anticipándome a frotarme las manos, organicé la carga de las probabilidades en un juego de demostración y comencé el proceso. Pero, como resultó, claramente no hice lo suficiente para el caso. Desde el principio, el modelo probado giró y se topó con todos los obstáculos seguidos, como un gatito ciego. En general, el resultado fue muy regular. Tuve que profundizar en el estudio del problema. Una fuente de comportamiento indefenso se descubrió con bastante rapidez. Con las respuestas generalmente correctas de la red neuronal a las lecturas del sensor, las acciones de control transmitidas resultaron ser demasiado fuertes.


Después de resolver este problema, me encontré con una nueva dificultad: la distancia del sensor reykast. Con una larga distancia de detección de interferencia, el modelo realizó maniobras prematuras, lo que resultó en una distorsión significativa de la ruta (e incluso en colisiones imprevistas en obstáculos aparentemente ya superados). Una pequeña distancia condujo a una cosa: un "pegado" indefenso del modelo en todos los obstáculos con una clara falta de tiempo para responder.


Mientras más jugueteaba con el modelo de juego de demostración, tratando de enseñarlo para evitar obstáculos, más me parecía que no estaba programando, sino que trataba de enseñarle a mi hijo a caminar. ¡Y fue una sensación inusual! Fue aún más alegre ver que mis esfuerzos trajeron resultados tangibles. Al final, el desafortunado bote flotante sobrevolando la superficie comenzó a rodear con confianza las estructuras que surgían en la ruta. Las pruebas reales para el algoritmo comenzaron cuando conscientemente intenté llevar el modelo a un callejón sin salida. Aquí se requería cambiar la lógica de trabajo con aceleración de frenado, para hacer algunas correcciones a la muestra de entrenamiento. Veamos ejemplos prácticos de lo que sucedió como resultado.


1. Derivación simple de un obstáculo



Como puede ver, el bypass no causó ninguna dificultad.


2. Dos obstáculos (opción 1)



El modelo encontró fácilmente un pasaje entre los dos edificios. Tarea fácil


3. Dos obstáculos (opción 2)



Los edificios están más cerca, pero el modelo encuentra un pasaje.


4. Dos obstáculos (opción 3)



La opción es más complicada, pero aún está resuelta.


5. Tres obstáculos



El problema se resolvió con bastante rapidez.


6. Callejón sin salida



Aquí el modelo tuvo problemas. Los primeros 30 segundos del video muestran que el modelo se tambalea impotente en una configuración de construcción simple. Lo más probable es que el problema aquí radique no tanto en el modelo de red neuronal como en el algoritmo principal para moverse a lo largo de la ruta: intenta persistentemente hacer que la nave vuelva a su curso, a pesar de los intentos desesperados de evitar una colisión.


Después de varias ejecuciones fallidas de esta situación con diferentes parámetros, logré obtener un resultado positivo. Desde el trigésimo segundo del video, puede observar cómo se selecciona un modelo con una mayor distancia de sensores y con una fuerza de frenado más potente desde el callejón sin salida. Para esto, necesitó casi cinco minutos de tiempo (corté el tormento y dejé solo los últimos 30 segundos del video). Es poco probable que en un juego real esto se considere un buen resultado, por lo que obviamente hay margen para mejoras en el algoritmo.


Conclusión


En general, el problema fue resuelto. La efectividad de esta solución es una pregunta abierta, y se requiere más investigación. Por ejemplo, no se sabe cómo se comportará el modelo cuando aparezcan obstáculos dinámicos (otros objetos en movimiento). Otro problema es la falta de sensores de colisión que apuntan hacia atrás, lo que genera dificultades para evitar obstáculos complejos.


El obvio desarrollo adicional de la idea de un algoritmo para evitar obstáculos en la red neuronal se ve en la introducción del entrenamiento. Para hacer esto, debe introducirse una evaluación del resultado de la decisión tomada, y con correcciones posteriores sin cambios significativos en la posición del objeto, la evaluación debe deteriorarse. Al alcanzar un cierto valor, el modelo debe pasar al modo de entrenamiento y, por ejemplo, cambiar aleatoriamente las decisiones tomadas para encontrar una salida.


Otra característica del modelo me parece la variabilidad del entrenamiento inicial. Esto hace posible, por ejemplo, tener varios comportamientos para diferentes modelos sin la necesidad de programar cada uno de ellos por separado. En otras palabras, si tenemos, por ejemplo, un tanque pesado y un reconocimiento ligero, su manera de evitar obstáculos puede variar significativamente. Para lograr este efecto, utilizamos el mismo perceptrón, pero entrenado en diferentes muestras.

Source: https://habr.com/ru/post/es419265/


All Articles