ML-Agents란?

Machine Learning Agents로 말 그대로 머신러닝을 시키는 API라고 이해하고 있음
Python을 사용, Unity에 접목 가능

진행과정

<시작>

  1. 새로운 Unity3D 프로젝트(RollerBall00)를 만든다.
  2. 유니티 패키지를 열어서 ML-Agents를 추가한다.
    1. Window -> Package Manager -> ML Agents(당시 실험 버전 1.0.6) Install

<오브젝트 환경 설정>

  1. SampleScene의 이름을 RollerBallA로 변경한다.
    1. Scene의 이름이 중요한가 확인 중
  2. 새 GameObject : TrainingArea 추가한다.
  3. TrainingArea 오브젝트 밑에 바닥을 추가한다.
    1. 3D Object > Plane
    2. 이름은 Floor
    3. 한 번 Reset
  4. TrainingArea 오브젝트 밑에 타겟이 될 Cube를 추가한다.
    1. 3D Object > Cube
    2. 이름은 Target
    3. 한 번 Reset하고 Position을 변경 : (3, 0.5, 3)
  5. TrainingArea 오브젝트 밑에 장애물이 될 Cube를 추가한다.
    1. 3D Object > Cube
    2. 이름은 Hurdle
    3. 한 번 Reset하고 Position을 변경 : (1.5, 0.5, 1.5)
    4. 장애물 테스트 중
  6. TrainingArea 오브젝트 밑에 이제 지가 알아서 학습할 녀석인 Sphere를 추가한다.
    1. 3D Object > Sphere
    2. 이름은 RollerAgent
    3. 한번 Reset하고 Position을 변경 : (0, 0.5, 0)
    4. Component 추가 : Rigidbody

<스크립트 설정>

  1. Scripts 폴더를 만들고 RollerAgent 스크립트를 그 속에 만든다.
  2. 이것을 구인 RollerAgent에 부착
  3. RollerAgent 편집
    •  

      using System.Collections;
      using System.Collections.Generic;
      using UnityEngine;
      
      // : MLAgent 사용
      using Unity.MLAgents;
      using Unity.MLAgents.Sensors;
      
      public class RollerAgent : Agent
      {
          // : 1 Start
          Rigidbody rBody;
          void Start()
          {
              rBody = this.GetComponent<Rigidbody>();
          }
      
          // : Episode가 시작할 때마다 상황 변경
          public Transform target;
          public Transform hurdle;
          public override void OnEpisodeBegin()
          {
              // : 떨어졌을 때 속도 및 위치 초기화
              if(this.transform.localPosition.y < 0)
              {
                  this.rBody.angularVelocity = Vector3.zero;
                  this.rBody.velocity = Vector3.zero;
                  this.transform.localPosition = new Vector3(0, 0.5f, 0);
              }
      
              // : 타깃 위치 변경
              target.localPosition = this.GetRandomPosition(this.transform.localPosition);
              // : 장애물 위치 변경
              hurdle.localPosition = this.GetRandomPosition(this.transform.localPosition);
          }
      
          // : 관찰 스테이터스 결정
          public override void CollectObservations(VectorSensor sensor)
          {
              // :: 포지션
              sensor.AddObservation(this.transform.localPosition);
              sensor.AddObservation(this.target.localPosition);
              sensor.AddObservation(this.hurdle.localPosition);
      
              // :: 속도
              sensor.AddObservation(rBody.velocity.x);
              sensor.AddObservation(rBody.velocity.z);
          }
      
          // : 행동 에피소드 결정
          public float forceMultiplier = 10;
          public override void OnActionReceived(float[] vectorAction)
          {
              // :: 행동할 액션은 2가지 x 이동과 z 이동
              Vector3 controlSignal = Vector3.zero;
              controlSignal.x = vectorAction[0];
              controlSignal.z = vectorAction[1];
              rBody.AddForce(controlSignal * this.forceMultiplier);
      
              // :: 거리 측정
              float distanceToTarget = Vector3.Distance(this.transform.localPosition, this.target.localPosition);
              float distanceToHurdle = Vector3.Distance(this.transform.localPosition, this.hurdle.localPosition);
      
              // : 보상
              if(distanceToTarget < 1.42f)
              {
                  Debug.Log("+1");
                  this.SetReward(1.0f);
                  this.EndEpisode();
              }
      
              // : 벌
              else if(distanceToHurdle < 1.42f)
              {
                  Debug.Log("-1");
                  this.SetReward(-0.5f);
                  this.EndEpisode();
              }
      
              // : 떨어졌을 때
              else if(this.transform.localPosition.y < 0)
              {
                  this.EndEpisode();
              }
          }
      
          // : 키보드 조작
          public override void Heuristic(float[] actionsOut)
          {
              actionsOut[0] = Input.GetAxis("Horizontal");
              actionsOut[1] = Input.GetAxis("Vertical");
          }
      
          // : Get
          private Vector3 GetRandomPosition(Vector3 exceptPosition)
          {
              // :: Set
              Vector3 position = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4);
      
              // :: 중복이 발생하지 않도록
              float distance = Vector3.Distance(exceptPosition, position);
              while(distance <= 1f)
              {
                  position = new Vector3(Random.value * 8 - 4, 0.5f, Random.value * 8 - 4);
                  distance = Vector3.Distance(exceptPosition, position);
              }
      
              return position;
          }
      }
  4. RollerAgent 스크립트에 Target과 Hurdle 오브젝트를 연결 
  5. RollerAgent 오브젝트에 Add Component로 Decision Requester 추가
    1. Decision Period는 10으로 설정
  6. RollerAgent 오브젝트에 Add Component로 Behavior Parameter 추가
    1. Behavior Name은 RollerBall
    2. Vector Observation > Space Size 는 11로 변경
    3. Vector Action > Space Type을 Continuous로 변경
    4. Vector Action > Space Size는 2로 변경

<트레이닝 설정>

  1. Python, pip3, MLAgents 등의 설치 : 생략(나중에 기회되면 추가)
  2. MLAgents 클로닝(github.com/Unity-Technologies/ml-agents)
  3. MLAgents 의 config 폴더 밑에 rollerball_config.yaml 생성
    • UTF-8 with BOM으로 되어 있으면 UTF-8로 변경
    • behaviors:
        RollerBall:
          trainer_type: ppo
          hyperparameters:
            batch_size: 10
            buffer_size: 100
            learning_rate: 3.0e-4
            beta: 5.0e-4
            epsilon: 0.2
            lambd: 0.99
            num_epoch: 3
            learning_rate_schedule: linear
          network_settings:
            normalize: false
            hidden_units: 128
            num_layers: 2
          reward_signals:
            extrinsic:
              gamma: 0.99
              strength: 1.0
          max_steps: 500000
          time_horizon: 64
          summary_freq: 10000
  4. 터미널로 해당 config 폴더로 가서 MLAgents 실행
    1. 명령어 : mlagents-learn rollerabll_config.yaml --run-id=firstRollerBall00
    2. 2번째 테스트부터는 ID 변경하면 됨
  5. 배우는 것을 본다
    1. https://youtu.be/bdBM4BFAd0E
    2. ML-Agents 롤러볼 머신러닝 중
  6. 결과물(Result 폴더에 있는 것)을 유니티에 넣는다.
    1. RollerBall.onmx
  7. RollerAgent 오브젝트의 Behavior Parameters의 Model에 해당 RollerBall.onmx를 추가
  8. 결과 확인(30만번 돌렸을 때)
    1. youtu.be/TL0kVnCFEnk

 

블로그 이미지

RIsN

,