앎을 경계하기

Machine Learning/Unity ML-Agent

텐서플로와 유니티 ML-Agent로 배우는 강화학습(1-1) ML-Agents 개요

양갱맨 2019. 12. 27. 22:58

참고 도서 - 텐서플로와 유니티 ML-Agent로 배우는 강화학습
포스팅은 해당 도서를 공부 하면서 정리 목적으로 작성되었습니다.
문제 시 삭제하도록 하겠습니다.


유니티 ML-Agents

유니티 ML-Agents를 사용하는 방법

  1. 유니티 ML-Agents의 내장 알고리즘 사용하기

    • ML-Agents를 이용해 환경을 제작하고 빌드한다.
    • 해당 환경의 에이전트를 기본적으로 제공하고 있는 알고리즘을 이용해 학습시킨다.
    • 학습이 완료된 딥러닝 모델이 nn 확장자를 가진 파일로 저장된다.
    • nn 파일을 유니티 환경 내 에이전트에게 적용한다.
  2. 파이썬으로 구성한 에이전트를 사용하기

    • 파이썬으로 구성된 강화학습 알고리즘을 이용해서 상태에 맞는 행동을 선택한다.
    • 선택한 행동을 유니티 환경의 에이전트에게 전달한다.
    • 에이전트는 전달받은 행동을 취하고 이로 인해 변화된 환경 상태와 보상에 대한 정보를 파이썬에 전달한다.

    ML-Agents 구성요소

    Agent
    public class TemplateAgent : Agent{
     public override void CollectObservations(){}
     pulbic override void AgentAction(float[] vectorAction, string textAction){}
     public override void AgentReset(){}
     public override void AgentOnDone(){}
    }
  3. 에이전트는 환경 내 행동을 취하는 주인공에게 할당해주는 스크립트

CollectObservations

public override void CollectObservations()는 에이전트의 Vector Observation에 값을 추가하는 함수이다.
AddVectorObs()함수를 사용해서 추가할 수 있다.

public override void CollectObservations(){
    AddVectorObs(transform.position.x);
    AddVectorObs(transform.position.z);
}

transform.position.x와 transoform.position.z 값을 AddVectorObs() 함수를 사용해 Vector Observation에 추가한다.

transform.position.x 는 해당 스크립트가 적용된 오브젝트의 위치 정보 중 x의 값을 말한다.

AgentAction

public override void AgentAction(float[] vectorAction, string textAction)은 에이전트의 행동을 받아서 어떻게 명령을 수행할지 결정하는 함수이다.

행동의 종류에 따라 코드 구성이 달라진다.

  1. Discrete Action

    • 이산적인 행동의 경우 행동 종류를 나누는 기준인 브랜치를 0, 1, 2와 같은 정수로 구성할 수 있다.
      example code

      public override void AgentAction(float[] vectorAction){
        int movement_x = Mathf.FloorToInt(vectorAction[0]);
        int movement_y = Mathf.FloorToInt(vectorAction[1]);
        int movement_z = Mathf.FloorToInt(vectorAction[2]);
      
        if (movement_x == 0) { directionX = -1; }
        if (movement_x == 1) { directionX = 0; }
        if (movement_x == 2) { directionX = 1; }
      
        if (movement_y == 0) { directionY = -1; }
        if (movement_y == 1) { directionY = 0; }
        if (movement_y == 2) { directionY = 1; }
      
        if (movement_z == 0) { directionZ = -1; }
        if (movement_z == 1) { directionZ = 0; }
        if (movement_z == 2) { directionZ = 1; }
      
        gameObject.GetComponent<Rigidbody>().AddForce(new Vector3(directionX, directionY, directionZ));
      }

      먼저 AgentAction함수는 파라미터로 float형 배열 vectorAction을 받는다.

      첫 번째 브랜치의 값은 vectorAction[0]에 들어있다.

      두 번째는 vectorAction[1], 세 번째는 vectorAction[2]에 들어있다.

      각 값들이 0이면 directionX,Y,Z 변수에 -1을 넣고 1이면 0, 2이면 1을 넣는다.

      마지막 AddForce함수를 사용해서 축 방향을 정해 힘을 가한다.

  2. Continuous Action

    • 연속적인 행동의 경우 행동이 이산적으로 0,1,2 이런식으로 표현되는 것이 아니라 구간 내 모든 수를 값으로 가질 수 있다.

      example code

      public override void AgentAction(float[] vectorAction){
        float force_x = Mathf.Clamp(vectorAction[0], -1, 1);
        float force_y = Mathf.Clamp(vectorAction[1], -1, 1);
        float force_z = Mathf.Clamp(vectorAction[2], -1, 1);
      
        gameObject.GetComponent<Rigidbody>().AddForce(new Vector3(force_x, force_y, force_z));
      }

      연속적 행동은 브랜치라는 개념이 적용되지 않는다.

      vectorAction의 각 실수값을 Clamp함수를 사용해서 (-1,1)로 제한한다.

      크기가 제한된 값을 각각 force_x,y,z에 저장하고 AddForce함수를 사용해서 게임오브젝트에 힘을 가한다.

이러한 액션을 취하면 에이전트는 그에 상응하는 보상을 받게된다.

보상은 AddReward()함수를 사용하고 게임 한 판이 끝나는 경우 Done()함수를 사용해 게임 종료를 하면 된다.

if(transform.position.x == 1f){
    AddReward(1.0f);
    Done();
}

if(transform.position.x == -1f){
    AddReward(-1f);
    Done();
}

스크립트가 적용된 오브젝트의 x축 위치가 1이면 positive reward 1을 받고 게임이 종료된다.

반대로 x축 위치가 -1이 되면 negative reward -1을 받고 게임이 종료된다.

이러한 보상형태가 주어진다면 오브젝트는 positive reward를 받기 위한 쪽으로 액션을 하게 될 것이다.

AgentReset

AgentReset()Done()함수로 게임이 종료되었을 때 호출되는 함수이며 에이전트의 상태를 초기화시키는 것에 대한 설정을 하는 함수이다.

public override void AgentReset(){
    transform.position = new Vector3(0f, 0f, 0f);
}

Done함수가 실행되고나면 AgentReset함수에서는 오브젝트의 위치를 (0,0,0)으로 설정한다.

AgentOnDone

AgentOnDone()은 에이전트를 더 이상 사용하지않고 없애기 직전에 호출되는 함수이다.
이 함수를 호출하면 brain에게 이 에이전트를 이제 사용하지 않는다는 것을 알려준다.

public override void AgentOnDone(){
    Destroy(gameObject);
}

Destroy()는 전달 게임오브젝트를 게임 씬에서 파괴한다.


실제로 Agent script를 적용하면 유니티 인스펙터뷰에서 나타나는 속성들은 다음과 같다.

  • Brain
  • Agent Cameras, Agent Render Textures
  • Max Step
  • Reset On Done
  • Decision Frequency

Brain

에이전트에 연결할 브레인을 설정한다.

브레인 종류에 따라 직접 사람이 컨트롤 하거나, 코딩한 규칙에 따라 행동하거나, 파이썬과 통신하며 학습할 수 있다.

Agent Cameras, Agent Render Textures

시각적 관측에 대한 설정을 할 수 있다.

Agent Cameras에 있는 Add Camera 버튼을 클릭하면 visual observations로 사용할 카메라를 추가할 수 있다.

Render Texture는 이미지 전체가 들어오는게 아니라 텍스쳐만 들어오기 때문에 이미지보다 단순한 형태로 표현된다.

Max Step

1 step은 에이전트가 현재의 상태를 기반으로 액션을 선택하고 보상 또는 게임 종료 여부를 받는 과정이다.

이러한 step들이 쭉 진행되어서 게임이 종료되면 1episode를 진행했다고 한다.

즉, Max Step은 한 에피소드에서 진행되는 최대의 스텝 수를 의미한다.

게임 한 판이 너무 길어지면 학습 효율성이 떨어지기 때문에 최대 스텝 수를 설정해 max step만큼 게임 step이 진행되면 Done함수를 호출시켜 1에피소드를 종료한다.

Reset On Done

Reset On Done이 체크되어있어야 Done() 호출이 되는 경우나 Max Step이 되는 경우에 AgentReset()함수를 호출하게 된다.

On Demand Decision

특정 이벤트가 발생했을 때 액션을 취하게 하거나 가변적인 주기로 액션을 취할 수 있도록 한다.

만약 On Demand Decision를 체크하지 않으면 Decision Interval 항목에 값을 설정할 수 있다.

Decision Interval

값을 1보다 더 높이 주면 해당 값의 step마다 한 번씩 행동을 결정하게 된다.

예를 들어서 Decision Interval이 10인 경우,

먼저 observation을 토대로 action을 하나 결정한다.

그 후 이 action을 10step동안 반복하고 새로운 action을 결정한다.

이런 과정을 반복해서 행동을 결정하는 것이다.

같은 행동을 여러 스텝동안 반복하는 이유는 빠른 주기로 행동이 변하는 것을 방지하기 위해서 설정하는 것이다.