Tabla de contenidos

Introducción

A menudo oímos en las noticias de esta cosa llamada “aprendizaje automático” y cómo las computadoras están “aprendiendo” para realizar ciertas tareas. A partir de los ejemplos que vemos, casi parece como magia cuando un equipo crea paisajes perfectos desde la nada o hace una charla pintura. Pero lo que a menudo se pasa por alto, y lo que queremos cubrir en este tutorial, es que el aprendizaje de la máquina se puede utilizar en la creación de juegos de vídeo también.

En otras palabras, podemos utilizar el aprendizaje de máquina para hacer videojuegos más interesantes y mejor mediante la formación de nuestra IA para realizar ciertas tareas de forma automática con algoritmos de aprendizaje automático.

Este tutorial le mostrará cómo podemos utilizar agentes de la Unidad de LD para hacer un objetivo AI y encontrar un objeto de juego. Más específicamente, vamos a estar buscando la manera de personalizar el proceso de entrenamiento para crear una IA con un dominio muy específico en esta tarea. A través de este, se llega a ver cuánto tiene el potencial de aprendizaje de la máquina cuando se trata de hacer IA para juegos de video.

Así que, sin más preámbulos, vamos a empezar y aprender a código IA de gran alcance con el poder de la unidad y la máquina de aprendizaje combinan!
No se pierda! extremos de la oferta en

  • Accede a los más de 200 cursos
  • Nuevos cursos añadió mensual
  • Cancelar en cualquier momento
  • Los certificados de terminación

    ACCESO ahora

    Descripción del proyecto y el código fuente

    Este proyecto se basa en un ejemplo de paquete de la unidad de LD-Agentes de demostración. Puede descargar este paquete en GitHub (https://github.com/Unity-Technologies/ml-agents) o simplemente puede descargar este proyecto terminado haciendo clic aquí (código fuente). La descripción básica de nuestro proyecto es que vamos a tener un cubo rebotando en un plano buscar el cubo “objetivo”.

    visualización previa para el proyecto Agentes ML

    (pre-visualización)

    Este es un gran proyecto para personalizar el nivel de competencia en una IA. ¿Queremos que esta AI sea adecuada, competente, o una bestia completa en este objetivo? Vamos a determinar esta medida que avanzamos en nuestro proyecto. Otra cosa importante a destacar es que este tutorial no pretende aprendizaje automático cubierta en general, ni tiene la intención de ser una introducción a ML-Agents. Para una explicación más profunda de ML-Agentes y lo que hacen los componentes, echar un vistazo a otro tutorial ML-Agentes de la Academia Dev Juego (https://gamedevacademy.org/unity-ml-agents-tutorial/). Con este panorama, vamos a empezar a formular un plan para recompensar el agente

    premios y castigos

    Algunas sanciones obvias que podríamos dar este agente son para caerse del avión o por ir demasiado lejos del borde. Lo que puede no ser tan obvio es qué otras sanciones que podemos dar el agente. Por ejemplo, se podría sancionar al agente si se tarda demasiado tiempo para alcanzar el objetivo o si se utiliza demasiados saltos para llegar allí. Si se va a desarrollar este proyecto desde cero, es posible empezar con un enfoque totalmente diferente a la asignación de sanciones. Es posible pasar por varios planes diferentes para la asignación de las sanciones antes de encontrar uno que funcione. Afortunadamente, usted está siguiendo, junto con un tutorial que ya sabe cuál es el mejor castigo y recompensas plan son. Por lo tanto, en términos de sanciones, se le dará nuestro agente de tres. Uno de caerse del avión, uno para tomar demasiado tiempo para alcanzar el objetivo, y una penalización más pequeña para el uso de una acción. Esto animará el agente a buscar la forma más eficiente para alcanzar el objetivo.

    Ahora vamos a hablar acerca de las recompensas. La recompensa más evidente que el agente se obtiene es cuando llega al cubo de destino. Y lo creas o no, esto es en realidad la única manera en que vamos a ser muy satisfactorio el agente. Este sistema rígido de muchas penalidades, un menor número de recompensas será lo que hace que el agente de bueno en este objetivo. Porque conseguir recompensas es tan estrecho, el agente se verá obligado a encontrar la manera más eficiente para alcanzar el objetivo. También le dará la oportunidad de ser una bestia absoluta en el objetivo. Solo debe estar preparado para algunas veces larga y digna de formación.

    Observaciones

    ¿Qué tipo de cosas hace la necesidad agente de conocer, a fin de tomar decisiones? Lo que podemos hacer aquí es dejar que el agente se salta un paso y simplemente le dan la posición del objetivo. Podríamos tratar de dar al agente de algún tipo de mecanismo de “ver” donde se busca alrededor y encuentra el objetivo de esa manera, o simplemente puede dar la posición en la salida. Esta es la mejor manera de hacer observaciones con un proyecto que no tiene por qué ser demasiado terriblemente complicado. Incluso con este “atajo”, todavía nos encontramos con que lo hace tomar una buena cantidad de tiempo para entrenar.

    Así que vamos a dar al agente de la posición del objetivo, lo que más hace la necesidad agente para saber? Bueno, ya que no se añade automáticamente, vamos a dar al agente de su propia posición como una observación. De esta manera, lo que se espera que suceda es que la red neuronal reconocerá la conexión entre las proximidades de la posición de destino y altas recompensas. Las observaciones de este proyecto son bastante simple y directo.

    Acciones

    Así que tenemos nuestras observaciones de que vamos a enviar a la red neuronal y va a evaluar las observaciones y enviar de vuelta algunas acciones (una simplificación masiva de aprendizaje automático pero sirve a nuestros propósitos). ¿Qué queremos que el agente que ver con esas acciones? Además, ¿cuántos debemos exigir de la red neuronal? Una vez más, si estuviera haciendo este proyecto desde cero, es posible que tenga que pasar por varias iteraciones de un plan antes de llegar a la correcta. Ya tengo el plan que funcione mejor con este proyecto así que vamos a empezar por ahí. Necesitamos tres acciones de flotación de la red neuronal. Esto será para la x, y, z y la rotación de nuestro agente. Si el agente está saltando alrededor, puede ser tentador para tener el control de la red neuronal la fuerza del salto también. Como regla general, usted quiere tener el control de redes neuronales como pocas cosas como sea posible, especialmente cosas que involucran la interacción física. Por lo tanto, el mejor enfoque es tener el control de la red neuronal de la rotación del objeto mientras se utiliza una fuerza de salto fijo a rebotar.

    Configuración del Proyecto

    Instalación ML-Agentes

    Ir a la ventana -.> Gestor de paquetes y descargar el paquete de ML-Agentes

    Navegando al gestor de paquetes

    Importar el paquete Agentes ML

    Si no puede verlo, asegúrese de que está viendo “paquetes de previsualización.” A continuación, vamos a necesitar Python 3.6 x 64 bits instalado. A continuación, puede ejecutar el siguiente comando de la consola para instalar Agentes ML
    PIP3 instalar mlagents

    Para más detalles sobre la instalación de ML-Agents, echa un vistazo al tutorial de introducción en la Academia juego Dev (https://gamedevacademy.org/unity-ml-agents-tutorial/).

    Configuración de la escena

    Nada es complicado acerca de nuestra escena. Necesitamos un avión y dos cubos, pero estos objetos deben ser hijos de un objeto del juego vacío llamado “medio ambiente”. Como regla general, es mejor tener sus agentes sean hijos de algún otro objeto. De esta manera, es más fácil de duplicar el objeto primario y la red neuronal está tratando con la misma transformación general en todos los agentes.

    Objeto de Padres del Agente en la unidad

    Crear una nueva carpeta llamada “Materiales” y crear algunos nuevos materiales para hacer que todo sea más fácil ver.

    Una carpeta para nuestros materiales

    Creación de nuevos materiales y asignarlos a los objetos de la escena

    Hagamos un poco de cambio de nombre. El cubo de color no será el “agente” y el cubo verde será el “blanco”.

    Cambiar el nombre de los objetos

    El objetivo necesitará un conjunto de cuerpo rígido “cinemático” y su colisionador tendrá que ser “gatillo”.

    Adición de un cuerpo rígido y un colisionador que es gatillo a la diana

    Ahora el agente se necesita un cuerpo rígido también, pero éste no será cinemática ni será el colisionador “Trigger”.

    El componente de cuerpo rígido en el agente

    Mientras estamos aquí, vamos a seguir adelante y darle el agente y el objetivo de algunos scripts. Crear una nueva carpeta “Scripts” y hacer dos secuencias de comandos de C # llamados “BouncerAgent” y “BouncerTarget.”

    New

    Dos nuevas secuencias de comandos de C #

    Asignar éstos a sus respectivos objetos del juego.

    El

    La

    El agente se va a necesitar un componente más. Haga clic en “Agregar componente” y encontrar la secuencia de comandos “parámetros de comportamiento”. Esto, unido al agente.

    Búsqueda de los

    Esto se comunicará con la Academia (la Academia es el componente que envía observaciones a la red neuronal y obtiene las acciones de espalda) durante el proceso de entrenamiento para generar una política neuronal. Y con eso, todo está configurado en la escena y podemos empezar a crear scripts!

    Scripting

    The Script Agente

    Lo primero es lo primero, tenemos que estar heredando de “agente” en lugar de “Monobehavior”, que requiere que se emplea “Unity.MLAgents”.
    usando System.Collections; usando System.Collections.Generic; usando UnityEngine; usando Unity.MLAgents; // nueva clase BouncerAgent linepublic: Agente // nueva línea {// inicio se llama antes de la primera actualización del marco vacío Inicio () {} // actualización se llama una vez por cuadro vacío Update () {}} 12345678910111213141516171819usingSystem.Collections; usingSystem. Collections.Generic; usingUnityEngine; usingUnity.MLAgents; // nueva linepublicclassBouncerAgent: Agente // nueva línea {// inicio se llama antes de que el primer cuadro updatevoidStart () {} // actualización se llama una vez por framevoidUpdate () {}}

    a continuación, vamos a seguir adelante y añadir en los cinco métodos contenidos en el agente abstracto. Son “CollectObservations”, “Inicializar”, “OnActionReceived”, “heurística”, y “OnEpisodeBegin.” La implementación de “CollectObservations” requiere que estamos utilizando “Unity.MLAgents.Sensors”.
    usando System.Collections; usando System.Collections.Generic; usando UnityEngine; usando Unity.MLAgents; usando Unity.MLAgents.Sensors; // nueva clase BouncerAgent linepublic: Agente {public override void Initialize () {base.Initialize (); } Public override void CollectObservations (VectorSensor sensor) {base.CollectObservations (sensor); } Void public override OnActionReceived (float [] vectorAction) {base.OnActionReceived (vectorAction); } Public override void heurístico (float [] actionsOut) {base.Heuristic (actionsOut); } Public override OnEpisodeBegin void () {base.OnEpisodeBegin (); }} 123456789101112131415161718192021222324252627282930313233usingSystem.Collections; usingSystem.Collections.Generic; usingUnityEngine; usingUnity.MLAgents; usingUnity.MLAgents.Sensors; // nuevo linepublicclassBouncerAgent: Agent {publicoverridevoidInitialize () {base.Initialize ();} publicoverridevoidCollectObservations (sensor VectorSensor) {base. CollectObservations (sensor);} publicoverridevoidOnActionReceived (float [] vectorAction) {base.OnActionReceived (vectorAction);} publicoverridevoidHeuristic (float [] actionsOut) {base.Heuristic (actionsOut);} publicoverridevoidOnEpisodeBegin () {base.OnEpisodeBegin ();}}

    en la actualidad, para completar el esqueleto de nuestro script, agregue en los métodos “Fixedupdate” “Actualizar” y.
    utilizando System.Collections; usando System.Collections.Generic; usando UnityEngine; usando Unity.MLAgents; utilizando Unity.MLAgents.Sensors; BouncerAgent clase pública: Agente {public override void Initialize () {base.Initialize (); } Public override void CollectObservations (VectorSensor sensor) {base.CollectObservations (sensor); } Void public override OnActionReceived (float [] vectorAction) {base.OnActionReceived (vectorAction); } Public override void heurístico (float [] actionsOut) {base.Heuristic (actionsOut); FixedUpdate} private void () {// nuevo método} private void Update () {// nuevo método de anulación} public void OnEpisodeBegin () {base.OnEpisodeBegin (); }} 1234567891011121314151617181920212223242526272829303132333435363738394041424344usingSystem.Collections; usingSystem.Collections.Generic; usingUnityEngine; usingUnity.MLAgents; usingUnity.MLAgents.Sensors; publicclassBouncerAgent: Agent {publicoverridevoidInitialize () {base.Initialize ();} publicoverridevoidCollectObservations (sensor VectorSensor) {base.CollectObservations (sensor );} publicoverridevoidOnActionReceived (float [] vectorAction) {base.OnActionReceived (vectorAction);} publicoverridevoidHeuristic (float [] actionsOut) {base.Heuristic (actionsOut);} privatevoidFixedUpdate () {// nuevo método} privatevoidUpdate () {// nuevo método} publicoverridevoidOnEpisodeBegin () {base.OnEpisodeBegin ();}}

    Así que ahora que tenemos la mayoría de los métodos que vamos a utilizar, vamos a añadir en algunas variables. ¿Qué tipos de variables que necesitamos? Obviamente necesitamos la posición del objetivo y vamos a necesitar la posición del jugador. Pero pensemos por un minuto, las variables si estamos tratando de tener este agente de rebote en torno a alcanzar el objetivo de la manera más rápida posible, no sólo necesitamos para saltar (como el cuerpo rígido del jugador y la fuerza de salto), pero también necesitamos una manera de llevar la cuenta del número de veces que el agente ha saltado. Estas son las variables que vamos a necesitar:
    utilizando System.Collections; usando System.Collections.Generic; usando UnityEngine; usando Unity.MLAgents; utilizando Unity.MLAgents.Sensors; BouncerAgent public class: agente de destino {GameObject pública; GameObject agentObject pública; la fuerza de flotación pública = 350f; agentRigidbody cuerpo rígido; orientación Vector3; flotar jumpCoolDown; int totalJumps = 20; int jumpsLeft = 20; EnvironmentParameters defaultParams; 12345678910111213141516171819usingSystem.Collections; usingSystem.Collections.Generic; usingUnityEngine; usingUnity.MLAgents; usingUnity.MLAgents.Sensors; publicclassBouncerAgent: Agent {target publicGameObject; publicGameObject agentObject; publicfloatstrength = 350f; cuerpo rígido agentRigidbody; orientación Vector3; floatjumpCoolDown; inttotalJumps = 20 ; intjumpsLeft = 20; EnvironmentParameters defaultParams;

    tenemos la posición del objetivo y el agente. Estos vamos a asignar en el inspector junto con la fuerza del salto. El cuerpo rígido agente vamos a asignar usando un getComponent y el vector “orientación” es lo que vamos a utilizar para hacer girar el agente. “JumpCoolDown” es lo que el agente no mantiene saltando como locos. “TotalJumps” y “jumpsLeft” son para realizar un seguimiento del número de veces que el agente ha saltado. Lo que podemos hacer es si “jumpsLeft” es igual a 0, podemos terminar el episodio y asignamos un castigo. Y, por último, los “EnvironmentParameters” solo nos permite para restablecer todo a su valor por defecto cuando un episodio extremos.

    Ahora que tenemos todas las variables que necesitamos, podemos empezar a rellenar todos aquellos métodos que hemos creado. El lugar obvio para comenzar es el método Initialize. Aquí, podemos asignar la variable de cuerpo rígido, cero el vector de orientación, y asignar los “DefaultParameters.”
    override public void Initialize () {agentRigidbody = gameObject.GetComponent (); orientación = Vector3.zero; defaultParams = Academy.Instance.EnvironmentParameters; } 123456publicoverridevoidInitialize () {agentRigidbody = gameObject.GetComponent (); orientación = Vector3.zero; defaultParams = Academy.Instance.EnvironmentParameters;}

    Esto es sólo para que todo comienza con una pizarra fresca. Cambiando de tema, hay que rellenar el método “CollectObservations”. Esto es súper sencilla ya que las únicas observaciones que estamos tomando en son la posición del agente y el objetivo.
    public override void CollectObservations (VectorSensor sensor) {sensor.AddObservation (target.transform.position); sensor.AddObservation (agentObject.transform.position); } 12345publicoverridevoidCollectObservations (sensor VectorSensor) {sensor.AddObservation (target.transform.position); sensor.AddObservation (agentObject.transform.position);}

    Super simple y directo. Tenga en cuenta que estamos tomando en un total de 6 flotadores aquí ya que cada vector de posición tiene 3 flotadores.

    Ahora tenemos que especificar lo que el agente va a hacer cuando volvamos algunas acciones de la Academia. El código de este método (y, en cierto sentido, para toda esta secuencia de comandos) puede no parecer muy intuitiva. Eso es simplemente porque, como he mencionado antes, este método de secuencias de comandos es el resultado de una gran cantidad de ensayo y error y por lo que, naturalmente, puede parecer diferente a la forma en que probablemente se acerca a esto. Dada esta naturaleza poco intuitivo, aquí está el código que entra en “OnActionRecieved” y espero que pueda explicarlo todo de una manera que tenga sentido:
    override public void OnActionReceived (float [] vectorAction) {for (var i = 0; i En primer lugar, tenemos que sujetar todas las acciones que obtenemos atrás, así que no obtenemos ningún súper valores extraños. A continuación, asignamos esas acciones a algunas variables locales. Estas variables son luego van a determinar la dirección del rebote y la orientación del agente. Por último, estamos añadiendo un pequeño castigo (-0.05) cada vez que el agente utiliza a una acción. Vale la pena señalar que “AddReward” es diferente en una gran forma de “SetReward.” Mediante el uso de “AddReward” Le estamos diciendo que añadir (o restar) un valor de la compensación total acumulado. Si utilizamos “SetReward” que establece todos los premios acumulados a cualquier valor que especifique. Ambos sonido similar pero son muy diferentes cuando se trata de la asignación de recompensas.

    El método “heurístico” es muy sencillo ya que sólo en el mapa los acciones a las pulsaciones de teclado.
    override public void heurístico (float [] actionsOut) {actionsOut [0] = Input.GetAxis ( «horizontal»); actionsOut [1] = Input.GetKey (KeyCode.Space)? 1.0f: 0.0f; actionsOut [2] = Input.GetAxis ( «vertical»); } 123456publicoverridevoidHeuristic (float [] actionsOut) {actionsOut [0] = Input.GetAxis ( «horizontal»); actionsOut [1] = Input.GetKey (KeyCode.Space) 1.0f:? 0.0f; actionsOut [2] = Entrada. GetAxis ( «vertical»);}

    Cambiando de tema, necesitamos poblar “FixedUpdate.” Aquí es donde vamos a hacer un raycast simple que determina cuando el agente está en contacto con el suelo. Usaremos esto para terminar episodios y realizar un seguimiento de la cantidad de saltos que el agente ha dejado. El aspecto del método completado de esta manera:
    FixedUpdate vacío () {if (Physics.Raycast (transform.position, nuevo Vector3 (0f, -1f, 0f), 0.51f) && jumpCoolDown <= 0F) {// Fuerzas una decisión, ceros fuera de velocidad, y jumpsLeft decrementos' 'RequestDecision (); jumpsLeft - = 1; jumpCoolDown = 0.1f; agentRigidbody.velocity = por defecto (Vector3); } JumpCoolDown - = Time.fixedDeltaTime; si (gameObject.transform.position.y <-1) {// Cuando el agente se cae del plano AddReward (-1); EndEpisode (); regreso; } If (gameObject.transform.localPosition.x <-17 || gameObject.transform.localPosition.x> 17 || gameObject.transform.localPosition.z <-17 || gameObject.transform.localPosition.z> 17) {/ / Cuando el agente va más allá de la AddReward plano (-1); EndEpisode (); regreso; } If (jumpsLeft == 0) {EndEpisode (); }} 12345678910111213141516171819202122232425262728293031323334353637383940voidFixedUpdate () {if (Physics.Raycast (transform.position, newVector3 (0f, -1f, 0f), 0.51f) && jumpCoolDown <= 0f) {// Fuerzas decisión, ceros fuera de velocidad, y decrementos 'jumpsLeft 'RequestDecision (); jumpsLeft- = 1; jumpCoolDown = 0.1f; agentRigidbody.velocity = por defecto (Vector3);} jumpCoolDown- = Time.fixedDeltaTime; si (gameObject.transform.position.y <-1) {// Cuando el agente cae de la planeAddReward (-1); EndEpisode (); return;} if (gameObject.transform.localPosition.x <-17 || gameObject.transform.localPosition.x> 17 || gameObject.transform.localPosition.z < -17 || gameObject.transform.localPosition.z> 17) {// Cuando el agente va más allá de la planeAddReward (-1); EndEpisode (); return;} if (jumpsLeft == 0) {EndEpisode ();}}

    Tenga en cuenta que este es el único lugar donde realmente terminamos episodios. Además, nota que la declaración lógica que usamos para determinar si el agente se había ido a los valores de los usos del plano (es decir, 17 y -17) que podemos obtener de la escena.

    La posición del agente donde cae off

    En el método de “actualización”, que sólo tiene que asegurarse de que la rotación del agente coincide con el vector de orientación. Podemos utilizar “Vector3.Lerp” para girar el agente.
    private void Update () {if (orientation.magnitude> float.Epsilon) {agentObject.transform.rotation = Quaternion.Lerp (agentObject.transform.rotation, Quaternion.LookRotation (orientación), Time.deltaTime * 10f); }} 123456789privatevoidUpdate () {if (orientation.magnitude> float.Epsilon) {agentObject.transform.rotation = Quaternion.Lerp (agentObject.transform.rotation, Quaternion.LookRotation (orientación), Time.deltaTime * 10f);}} < p> Tenga en cuenta que hacemos una comprobación para asegurarse de que la magnitud es mayor que un valor muy pequeño. “Float.Epsilon” es el valor más pequeño de un número de coma flotante puede tener. Esto es importante porque si utilizamos simplemente cero, siempre sería verdad.

    Sólo tenemos un método más para poner en práctica y que es el método “OnEpisodeBegin”. ¿Qué queremos hacer cuando comienza un episodio? La elección obvia sería tener el agente y el respawn objetivo en un punto aleatorio. Vamos a ser volver a visitar este método, una vez que hayamos terminado el guión “BouncerTarget”. Por ahora, esto es lo que debe ser similar:
    public override OnEpisodeBegin void () {gameObject.transform.localPosition = new Vector3 ((1 – 2 * Random.value) * 5, 2, (1 – 2 * Random.value) * 5); agentRigidbody.velocity = Vector3.zero; } 123456publicoverridevoidOnEpisodeBegin () {gameObject.transform.localPosition = newVector3 ((1-2 * Random.value) * 5,2, (1-2 * Random.value) * 5); agentRigidbody.velocity = Vector3.zero;} < p> Y antes de salir de la secuencia de comandos “BouncerAgent”, vamos a añadir un método más que será otro nivel de reposición.
    ResetParamters public void () {var = TargetScale defaultParams.GetWithDefault ( «target_scale», 1.0f); target.transform.localScale = nuevo Vector3 (TargetScale, TargetScale, TargetScale); } 12345publicvoidResetParamters () {vartargetScale = defaultParams.GetWithDefault ( «target_scale», 1.0f); target.transform.localScale = newVector3 (TargetScale, TargetScale, TargetScale);}

    Y podemos llamar a esto en el “OnEpisodeBegin” y “ métodos Inicializar”.
    utilizando System.Collections; usando System.Collections.Generic; usando UnityEngine; usando Unity.MLAgents; utilizando Unity.MLAgents.Sensors; BouncerAgent public class: agente de destino {GameObject pública; GameObject agentObject pública; la fuerza de flotación pública = 350f; agentRigidbody cuerpo rígido; orientación Vector3; flotar jumpCoolDown; int totalJumps = 20; int jumpsLeft = 20; EnvironmentParameters defaultParams; override public void Initialize () {agentRigidbody = gameObject.GetComponent (); orientación = Vector3.zero; defaultParams = Academy.Instance.EnvironmentParameters; ResetParamters (); // nueva línea} public override void CollectObservations (VectorSensor sensor) {sensor.AddObservation (target.transform.position); sensor.AddObservation (agentObject.transform.position); } Override public void OnActionReceived (float [] vectorAction) {for (var i = 0; i 17 || gameObject.transform.localPosition.z <-17 || gameObject.transform.localPosition.z> 17) {AddReward (-1); EndEpisode (); regreso; } If (jumpsLeft == 0) {EndEpisode (); }} Actualización de private void () {if (orientation.magnitude> float.Epsilon) {agentObject.transform.rotation = Quaternion.Lerp (agentObject.transform.rotation, Quaternion.LookRotation (orientación), Time.deltaTime * 10f); }} Public override OnEpisodeBegin void () {gameObject.transform.localPosition = new Vector3 ((1 – 2 * Random.value) * 5, 2, (1 – 2 * Random.value) * 5); agentRigidbody.velocity = Vector3.zero; ResetParamters (); // nueva línea ResetParamters} public void () {var = TargetScale defaultParams.GetWithDefault ( «target_scale», 1.0f); target.transform.localScale = nuevo Vector3 (TargetScale, TargetScale, TargetScale); }} 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118usingSystem.Collections; usingSystem.Collections.Generic; usingUnityEngine; usingUnity.MLAgents; usingUnity.MLAgents.Sensors; publicclassBouncerAgent: Agent {target publicGameObject; publicGameObject agentObject; publicfloatstrength = 350f; cuerpo rígido agentRigidbody; orientación Vector3; floatjumpCoolDown; inttotalJumps = 20; intjumpsLeft = 20; EnvironmentParameters defaultParams; publicoverridevoidInitialize () {agentRigidbody = gameObject.GetComponent (); de orientación = Vector3.zero; defaultParams = Academy.Instance.EnvironmentParameters; ResetParamters (); // nueva línea} publicoverridevoidCollectObservations (VectorSensor sensores ) {sensor.AddObservation (target.transform.position); sensor.AddObservation (agentObject.transform.position);} publicoverridevoidOnActionReceived (flo en [] vectorAction) {for (vari = 0; i 17 || gameObject.transform.loca lPosition.z <-17 || gameObject.transform.localPosition.z> 17) {AddReward (-1); EndEpisode (); return;} if (jumpsLeft == 0) {EndEpisode ();}} privatevoidUpdate () { si (orientation.magnitude> float.Epsilon) {agentObject.transform.rotation = Quaternion.Lerp (agentObject.transform.rotation, Quaternion.LookRotation (orientación), Time.deltaTime * 10f);}} publicoverridevoidOnEpisodeBegin () {gameObject.transform .localPosition = newVector3 ((1-2 * Random.value) * 5,2, (1-2 * Random.value) * 5); agentRigidbody.velocity = Vector3.zero; ResetParamters (); // nueva línea} publicvoidResetParamters () {vartargetScale = defaultParams.GetWithDefault ( «target_scale», 1.0f); target.transform.localScale = newVector3 (TargetScale, TargetScale, TargetScale);}}

    The script Target

    El script de destino no es tan implicado como agente de la secuencia de comandos. Sólo tenemos que comprobar si el agente ha colisionado con el objetivo y reaparecer en una posición aleatoria.
    utilizando UnityEngine; utilizando Unity.MLAgents; public class BouncerTarget: MonoBehaviour {void FixedUpdate () {gameObject.transform.Rotate (nueva Vector3 (1, 0, 0), 0.5f); } Void OnTriggerEnter (colisión Colisionador) {var = agente collision.gameObject.GetComponent (); si (agente! = null) {agent.AddReward (1f); Respawn (); }} Public void Respawn () {gameObject.transform.localPosition = new Vector3 ((1 – 2 * Random.value) * 5f, 2f + Random.value * 5f, (1 – 2 * Random.value) * 5f); }} 1234567891011121314151617181920212223242526272829usingUnityEngine; usingUnity.MLAgents; publicclassBouncerTarget: MonoBehaviour {voidFixedUpdate () {gameObject.transform.Rotate (newVector3 (1,0,0), 0.5f);} voidOnTriggerEnter (Colisionador de colisión) {varagent = collision.gameObject.GetComponent < agente> (); si {agent.AddReward (1f); Respawn ();} (agente! = null)} publicvoidRespawn () {gameObject.transform.localPosition = newVector3 ((1-2 * Random.value) * 5f, 2f + Random.value * 5f, (1-2 * Random.value) * 5f);}}

    Tenga en cuenta que tenemos un método “Respawn”. Podemos llamar a este método en la parte posterior “OnEpisodeBegin” en el guión “BouncerAgent”
    public override OnEpisodeBegin void () {gameObject.transform.localPosition = new Vector3 ((1 – 2 * Random.value) * 5, 2, (1 – 2 * Random.value) * 5); agentRigidbody.velocity = Vector3.zero; ambiente var = gameObject.transform.parent.gameObject; objetivos var = environment.GetComponentsInChildren (); foreach (var t en los objetivos) {t.Respawn (); } JumpsLeft = totalJumps; ResetParamters (); } 12345678910111213141516publicoverridevoidOnEpisodeBegin () {gameObject.transform.localPosition = newVector3 ((1-2 * Random.value) * 5,2, (1-2 * Random.value) * 5); agentRigidbody.velocity = Vector3.zero; varenvironment = gameObject.transform.parent.gameObject; vartargets = environment.GetComponentsInChildren (); foreach (vartintargets) {t.Respawn ();} = jumpsLeft totalJumps; ResetParamters ();}

    Se ve un poco ocupado, pero todos esto es decir es llamar al método “Respawn” cada vez que un episodio comienza en cualquier objetivos están en la escena.

    El entrenamiento de la EA

    Ahora tenemos que configurar todo en el inspector. The “BouncerAgent” needs itself and the target while the “Behaviour Paramters” component needs to have a observation space set to 6 and an action space set to “Continous” and 3. Also, go ahead give our behavior a unique name.

    Configuring the Behaviour Paramters on the agent

    Now, go ahead and duplicate the environment several times.

    Duplicating the environment to begin training

    Then open up a command line and run the following command:

    mlagents-learn –run-id=AIBouncer1mlagents-learn–run-id=AIBouncer

    The agents will then start training. It may take a while so just make yourself a pot of coffee and sit tight.

    After a couple of hours, it should reach the maximum number of steps and the training will cease. However, if you notice they console log, you’ll see that the total number of rewards is a negative number.

    This is usually not a good sign. It means that even after all that time, the agent still wouldn’t behave properly. You can check this out by dragging in the neural network saved in “C:Users*your Username*resultsAIBouncer.”


    So how do we fix this? Well, since we did see the rewards increasing over time, the best strategy is to increase the training time. We can do this by grabbing the config file we found in the results folder and modifying it a bit. Open it up in notepad and let’s have a look.

    This config file is where all the training settings live. We can configure quite a lot and there’s too much here to cover just in this tutorial but the main thing we want to focus on is the “Max_Steps.”

    Right now, it’s set to 500,000 which, in this case, is much too little. The agent doesn’t accumulate enough rewards in that number of steps. So what should we set it too? This is where we can determine the level of proficiency this AI can have. If we set it to 4,000,000, the AI will train for much longer and become very proficient at the task. If we set it to a value a little bit lower, like 900,000, it will have a level of proficiency slightly better than you or I would. For safety sake, I decided to set mine to 4,000,000 and decided I would stop it if I felt it had trained enough.

    Also, at the time of writing, there was a slight bug in version 1.0.3 of ML-Agents that requires you to delete this line

    in order for the changes to be read. So delete that line and then save your config file. I chose to save it in my Documents folder as “bouncerAIconfig” since we’re going to be referencing it in our new training command. Make sure to include “.yaml” when you save the file. With our config file sufficiently modified, we can run a new command in the command line.

    mlagents-learn DocumentsbouncerAIconfig.yaml –run-id=AIBouncer –resume1mlagents-learn DocumentsbouncerAIconfig.yaml–run-id=AIBouncer–resume

    Of course, you would put the path to your config file if you didn’t save it to your documents. Now, you should notice that ML-Agents recognized our changes to the config file and has resumed training!

    This will take a bit longer so go ahead and make another pot of coffee.

    I let my agent train overnight and I think the results were worth it! Drag the neural network from the results folder and assign it to your agent.


    Conclusión

    With all our training done, we officially have our AI targetting objects – once again all thanks to Unity’s ML Agents! So congratulations for following along and learning how to code an interesting AI for your game projects.

    While we’ve chosen to demonstrate with simple primitives, the skills learned here can be applied to a number of different games projects. Though we can’t say the coding principles will apply in all cases, we can say that through persistence and sticktoitiveness, you will be creating a number of different machine learning networks in no time to suit your own project. What we hope we’ve taught you here, more than anything else, is how to modify the AI training process and how that in turn affects your ML agent. Where you take these skills, though, is up to you!

    We hope you’ve found this useful and relevant, and as always…

    Seguir haciendo grandes juegos!

    Mensajes relacionados

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *