Unity/복습

Unity 복습 21.05.25~26. Unity MLAgent 설치/튜토리얼

HappyFrog 2021. 5. 27. 00:55

설치

 

 

Tooltip을 선언해주면 하위 필드에 선언된 요소가 인스펙터창에서 Tooltip의 내용을 띄워준다.

 

new 를 필드에 선언하면 변수를 '재정의'하는 행위.

 

MLAgent의 lifecycle

 

저번에 강의실 컴퓨터의 용량이 없어서 Pytorch를 설치하지 못하는 바람에 ml을 경험하지 못했는데, 오늘은 성공했다.

우선, github에서 mlagent의 최신 release버전을 받아주자. 오늘 날짜로는 17이 최신이다.

 

 

Unity-Technologies/ml-agents

Unity Machine Learning Agents Toolkit. Contribute to Unity-Technologies/ml-agents development by creating an account on GitHub.

github.com

 

여기서 주의해야 할 점은 Unity내에서도 MLAgent를 임포트 할 수 있지만 해당 게시물에 올라온 것처럼 2.0.0버전까지는 지원을 하지 않고 1.0.7버전 밖에 임포트 할 수 없다. 따라서 우리는 해당 17릴리즈버전의 ml에이전트를 이용해야 하며 이를 유니티에 설치하는 방법은 후술하도록 하겠다.

 

파이썬도 받아주자. 3.6이나 3.7버전을 권장한다고 하니 3.6.5버전을 받아주겠다.

Python홈페이지 //  우측처럼 파이선을 경로에 추가해주어야한다.
3.6.5버전이 설치되었다.

 

 

 

 

Unity-Technologies/ml-agents

Unity Machine Learning Agents Toolkit. Contribute to Unity-Technologies/ml-agents development by creating an account on GitHub.

github.com

이건 ML Agent의 설치 안내인데, 이곳에 적힌 파이썬 버전을 설치해 주어야 정상적으로 실행이 가능하다. 해당 페이지에서는 3.6.1이상을 설치하라고 되어있지만, 강의를 들을때는 3.6.5버전을 설치했으며, 결과적으로는 잘 작동했다.

 

* 반드시 해당 가이드를 읽고 설치해주어야 ML Agent를 실행할 수 있다.

 

그리고 아래 사진이 위에서 말했던 ML Agent 2.0.0버전을 새로운 프로젝트 내에서 사용할 수 있는 방법이다.

Package Manager에서 AddPackage from disk를 선택하고, 먼저 받아둔 mlAgent릴리즈 파일에서 com.unity.ml-agents폴더안의 package.json파일을 선택해주면 된다.

 

그러면 간단하고 쉽게 프로젝트가 mlAgent2.0.0버전을 탑재하게 된다.

 

그리고 요구되는 버전 이상의 파이썬과 유니티가 준비되었다면, Pytorch를 깔아보자.

나는 프롬프트 창으로 깔 것이다. 우선 파이썬 버전확인을 위해 python을 입력하여 확인하였고 pip3를 이용할것이기 때문에 pip3가 정상적으로 작동하는지를 확인해보았다.

pip3가 정상작동하면 해당 창처럼 설명이 나온다.

 

그렇다면 이제 설치가이드에 있던 이 챕터를 따라가면 된다. 

 

설치가이드가면 복붙가능

해당 코드를 입력하여 Pytorch를 설치하자.

 

강의들을때도 여기서 멈추더라 꼭 // 기다리다보면 완료됨. 오른쪽 메시지가 떠야 성공적으로 설치된 거임.

 

Pytorch설치가 끝났다면 위 사진을 또다시 입력하여 mlagents를 설치받자.

 

이제 필수적인 조건은 모두 마련되었다.

그리고 Penguin튜토리얼을 실행하기 위해 아래 링크를 들어간다.

 

 

Unity ML Agents | Penguins — Immersive Limit

In this Unity ML Agents tutorial you’ll learn how to use machine learning, specifically reinforcement learning in Unity to train penguins to find fish and feed their babies.

www.immersivelimit.com

그리고 Downloads를 찾아서 링크를 타고 들어가 다운받자.

이런 화면이 나올텐데 price를 마음대로 설정할 수 있으므로 0으로 하면 무료, 후원하고 싶다면 가격을 달면 된다 // 나는 맨 위에꺼 받음

 

펭귄을 다운받고 새로운 유니티 프로젝트를 만들어 위에서 말했던 대로 MLAgent를 release에 배포된 것과 같은 버전으로 만들어주자. 

 

Add package from disk를 한다면 위와 같이 MLAgents가 2.0.0버전으로 잘 적용된다.

 

이제 준비는 끝났다. 튜토리얼을 진행해보자.

 

 

위에서 소개한 펭귄튜토리얼을 다운받는 페이지의 상단에는 튜토리얼의 단계가 4단계로 나뉘어서 소개되고 있고, 유튜브 영상 또한 준비되어 있다. 복습으로 이 튜토리얼을 따라할 예정이다.

 

 


튜토리얼 시작

 

 

1.Asset폴더 하위에 Penguin폴더를 생성하고 그 하위에 다시 Meshes폴더를 생성한 다음, penguin_release의 meshes폴더를 import해준다.

2.모든 메쉬들을 한번에 씬으로 드래그하여 생성한다.

3.언팩해주고 각 객체들의 이름을 3번째 사진처럼 바꿔주자.

 

1.Penguin폴더 하위에 Preafabs폴더를 생성한 뒤, 이름을 바꿔준 오브젝트들을 프리팹화 한다.

2.PenguinArea를 제외한 오브젝트들을 Hierachy에서 모두 지워준다. (나는 언팩도 해주었다.)

3.스크립트를 만든다. 이름은 PenguinArea, PenguinAgent, Fish이다.(이름만 봐도 어디에 할당해줄 스크립트인지 알 수 있다.)

 

 

1.PenguinArea를 열어 위 사진처럼 Start, Update를 삭제하고, Unity.MLAgents, TMPro를 선언해주자.

ㄴ튜토리얼에는 using MLAgents라고 나와있지만, 2020 3.8f버전에서는 Unity.MLAgents라고 선언해야한다.

2.그리고 필드에 변수들을 선언해준다.

ㄴ이 때 쓰이는 [Tooltip("message")]는 3번째 사진과 같이 Inspector에서 마우스를 올리면 나오는 설명들을 작성하는 기능이다.

 

 

1.아래의 코드블럭과 같이 작성해준다.

2.ChooseRandomPosition을 통해 원하는 범위 내에서 오브젝트를 생성할 수 있도록 한다.

3.펭귄, 아기펭귄, 물고기마다 다른 값을 매개변수로 부여하여 생성되는 위치가 제각기 다르도록 한다.

 

(Start랑 Update 사용할건데 왜 지우라고 돼있지..)

 

PenguinArea 스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;
using TMPro;

public class PenguinArea : MonoBehaviour
{
    [Tooltip("The agent inside the area")]
    public PenguinAgent penguinAgent;

    [Tooltip("The baby penguin inside the area")]
    public GameObject penguinBaby;

    [Tooltip("The TextMeshPro text that shows the cumulative reward of the agent")]
    public TextMeshPro cumulativeRewardText;

    [Tooltip("Prefab of a live fish")]
    public Fish fishPrefab;

    private List<GameObject> fishList;
    private void Start()
    {
        ResetArea();
    }

    private void Update()
    {
        // Update the cumulative reward text
        cumulativeRewardText.text = penguinAgent.GetCumulativeReward().ToString("0.00");
    }


    public void ResetArea()
    {
        RemoveAllFish();
        PlacePenguin();
        PlaceBaby();
        SpawnFish(4, 0.5f);
    }

    public void RemoveSpecificFish(GameObject fishObject)
    {
        fishList.Remove(fishObject);
        Destroy(fishObject);
    }

    public int FishRemaining
    {
        get { return fishList.Count; }
    }

    public static Vector3 ChooseRandomPosition(Vector3 center, float minAngle, float maxAngle, float minRadius, float maxRadius)
    {
        float radius = minRadius;
        float angle = minAngle;

        if (maxRadius > minRadius)
        {
            // Pick a random radius
            radius = UnityEngine.Random.Range(minRadius, maxRadius);
        }

        if (maxAngle > minAngle)
        {
            // Pick a random angle
            angle = UnityEngine.Random.Range(minAngle, maxAngle);
        }

        // Center position + forward vector rotated around the Y axis by "angle" degrees, multiplies by "radius"
        return center + Quaternion.Euler(0f, angle, 0f) * Vector3.forward * radius;
    }

    private void RemoveAllFish()
    {
        if (fishList != null)
        {
            for (int i = 0; i < fishList.Count; i++)
            {
                if (fishList[i] != null)
                {
                    Destroy(fishList[i]);
                }
            }
        }

        fishList = new List<GameObject>();
    }

    private void PlacePenguin()
    {
        Rigidbody rigidbody = penguinAgent.GetComponent<Rigidbody>();
        rigidbody.velocity = Vector3.zero;
        rigidbody.angularVelocity = Vector3.zero;
        penguinAgent.transform.position = ChooseRandomPosition(transform.position, 0f, 360f, 0f, 9f) + Vector3.up * .5f;
        penguinAgent.transform.rotation = Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f);
    }
        
    private void PlaceBaby()
    {
        Rigidbody rigidbody = penguinBaby.GetComponent<Rigidbody>();
        rigidbody.velocity = Vector3.zero;
        rigidbody.angularVelocity = Vector3.zero;
        penguinBaby.transform.position = ChooseRandomPosition(transform.position, -45f, 45f, 4f, 9f) + Vector3.up * .5f;
        penguinBaby.transform.rotation = Quaternion.Euler(0f, 180f, 0f);
    }

    private void SpawnFish(int count, float fishSpeed)
    {
        for (int i = 0; i < count; i++)
        {
            // Spawn and place the fish
            GameObject fishObject = Instantiate<GameObject>(fishPrefab.gameObject);
            fishObject.transform.position = ChooseRandomPosition(transform.position, 100f, 260f, 2f, 13f) + Vector3.up * .5f;
            fishObject.transform.rotation = Quaternion.Euler(0f, UnityEngine.Random.Range(0f, 360f), 0f);

            // Set the fish's parent to this area's transform
            fishObject.transform.SetParent(transform);

            // Keep track of the fish
            fishList.Add(fishObject);

            // Set the fish speed
            fishObject.GetComponent<Fish>().fishSpeed = fishSpeed;
        }
    }
}

 

이제 PenguinAgent스크립트를 작성해보자.

 

1.마찬가지로 Update와 Start를 삭제한다.

2.마찬가지로 Unity.MLAgents를 선언한다.

ㄴ추가로 Unity.MLAgents.Sensors, Unity.MLAgents.Actuators도 선언해준다.(TMPro는 선언안함)

3.스크립트에 Agent를 상속한다.

4.필드에 변수들을 선언해준다.

 

1. Agent 클래스의 Initialize를 오버라이딩하고 내용을 넣어준다.

2. Actuator기능으로 추가된 OnActionReceived역시 오버라이딩하고 내용을 넣는다.

ㄴ움직임의 여부와 방향을 정하고 이를 적용하며, 이를 통해 보상을 부여하는 방법이다.(비록 (-)값이지만 보상은 보상이니까) 

ActionBuffer의 DiscreteActions의 0인덱스의 값이 0이라면 자리를 유지하고 있는것이며, 1이라면 최고속도로 전진함을 나타낸다. 1인덱스 값이 0일때는 회전이 없고, 1일때는 -방향회전을 하며 2일때는 +방향 회전을 한다고 한다.

 

1. 직접조작으로 움직일 수 있도록 Heuristic도 만들어주자.

 

1.Agent를 학습시킨 결과를 모델로 만들기 위해서는 데이터를 수집해야한다. 이를 파이썬으로 보내기 위해서는 싸이클을 시작시켜야 하는데 그 기능을 해주는게 OnEpisodeBegin이다.

2.에피소드가 시작되면 관찰값을 기록하기 시작하는데 관찰값은 인수의 갯수를 모두 전달해야 하므로 float은 1가지 값으로 이루어져 1개의 value만 가지지만, Vector3의 경우는 x,y,z 총 3가지 인수로 이루어지므로 value가 3이다.

3.그리고 Agent의 행동으로 인한 오브젝트들과의 충돌결과를 만들어주기 위해서 OnCollisionEnter을 생성해주고

4.그 행동을 결정하는 EatFish와 RegurgitateFish를 만들어준다.

5.EatFish는 물고기와 충돌했을 때, 해당 물고기를 없애고 펭귄이 물고기를 먹었다고 상태를 바꾸고 보상을 준다.

6.RegurgitateFish는 펭귄이 물고기를 먹었을때, 아기펭귄과 충돌하면 보상을 주며 그 이후에 만약 PenguinArea에 물고기가 존재하지 않는다면 에피소드(Agent의 한 사이클)이 끝난다.

 

PenguinAgent스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.MLAgents;
using Unity.MLAgents.Sensors;
using Unity.MLAgents.Actuators;

public class PenguinAgent : Agent
{
    [Tooltip("How fast the agent moves forward")]
    public float moveSpeed = 5f;

    [Tooltip("How fast the agent turns")]
    public float turnSpeed = 180f;

    [Tooltip("Prefab of the heart that appears when the baby is fed")]
    public GameObject heartPrefab;

    [Tooltip("Prefab of the regurgitated fish that appears when the baby is fed")]
    public GameObject regurgitatedFishPrefab;

    private PenguinArea penguinArea;
    new private Rigidbody rigidbody;
    private GameObject baby;
    private bool isFull; // If true, penguin has a full stomach

    public override void Initialize()
    {
        base.Initialize();
        penguinArea = GetComponentInParent<PenguinArea>();
        baby = penguinArea.penguinBaby;
        rigidbody = GetComponent<Rigidbody>();
    }

    public override void OnActionReceived(ActionBuffers actionBuffers)
    {
        // Convert the first action to forward movement
        float forwardAmount = actionBuffers.DiscreteActions[0];

        // Convert the second action to turning left or right
        float turnAmount = 0f;
        if (actionBuffers.DiscreteActions[1] == 1f)
        {
            turnAmount = -1f;
        }
        else if (actionBuffers.DiscreteActions[1] == 2f)
        {
            turnAmount = 1f;
        }

        // Apply movement
        rigidbody.MovePosition(transform.position + transform.forward * forwardAmount * moveSpeed * Time.fixedDeltaTime);
        transform.Rotate(transform.up * turnAmount * turnSpeed * Time.fixedDeltaTime);

        // Apply a tiny negative reward every step to encourage action
        if (MaxStep > 0) AddReward(-1f / MaxStep);
    }

    public override void Heuristic(in ActionBuffers actionsOut)
    {
        int forwardAction = 0;
        int turnAction = 0;
        if (Input.GetKey(KeyCode.W))
        {
            // move forward
            forwardAction = 1;
        }
        if (Input.GetKey(KeyCode.A))
        {
            // turn left
            turnAction = 1;
        }
        else if (Input.GetKey(KeyCode.D))
        {
            // turn right
            turnAction = 2;
        }

        // Put the actions into the array
        actionsOut.DiscreteActions.Array[0] = forwardAction;
        actionsOut.DiscreteActions.Array[1] = turnAction;
    }

    public override void OnEpisodeBegin()
    {
        isFull = false;
        penguinArea.ResetArea();
    }

    public override void CollectObservations(VectorSensor sensor)
    {
        // Whether the penguin has eaten a fish (1 float = 1 value)
        sensor.AddObservation(isFull);

        // Distance to the baby (1 float = 1 value)
        sensor.AddObservation(Vector3.Distance(baby.transform.position, transform.position));

        // Direction to baby (1 Vector3 = 3 values)
        sensor.AddObservation((baby.transform.position - transform.position).normalized);

        // Direction penguin is facing (1 Vector3 = 3 values)
        sensor.AddObservation(transform.forward);

        // 1 + 1 + 3 + 3 = 8 total values
    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.transform.CompareTag("fish"))
        {
            // Try to eat the fish
            EatFish(collision.gameObject);
        }
        else if (collision.transform.CompareTag("baby"))
        {
            // Try to feed the baby
            RegurgitateFish();
        }
    }

    private void EatFish(GameObject fishObject)
    {
        if (isFull) return; // Can't eat another fish while full
        isFull = true;

        penguinArea.RemoveSpecificFish(fishObject);

        AddReward(1f);
    }

    private void RegurgitateFish()
    {
        if (!isFull) return; // Nothing to regurgitate
        isFull = false;

        // Spawn regurgitated fish
        GameObject regurgitatedFish = Instantiate<GameObject>(regurgitatedFishPrefab);
        regurgitatedFish.transform.parent = transform.parent;
        regurgitatedFish.transform.position = baby.transform.position;
        Destroy(regurgitatedFish, 4f);

        // Spawn heart
        GameObject heart = Instantiate<GameObject>(heartPrefab);
        heart.transform.parent = transform.parent;
        heart.transform.position = baby.transform.position + Vector3.up;
        Destroy(heart, 4f);

        AddReward(1f);

        if (penguinArea.FishRemaining <= 0)
        {
            EndEpisode();
        }
    }
}

 

마지막으로Fish스크립트를 작성해보자.

 

1.Start와 Update를 지운다.

2.필드에 변수를 선언한다.

(Fish는 MLAgent를 선언할 필요가 없다.)

 

 

1.Fish의 움직임을 제어할 Swim메서드를 작성하고 FixedUpdate에서 Swim을 사용한다.

2.Swim메서드는 Fish의 속도, 갈 방향, 갈 방향으로 회전, 그곳까지 갈 시간을 무작위로 계산해주며 주기적으로 움직이고 멈추는 행동을 구현해준다.

 

이로써 모든 스크립트의 작성이 끝났다.

 

FIsh스크립트

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Fish : MonoBehaviour
{
    [Tooltip("The swim speed")]
    public float fishSpeed;

    private float randomizedSpeed = 0f;
    private float nextActionTime = -1f;
    private Vector3 targetPosition;

    private void FixedUpdate()
    {
        if (fishSpeed > 0f)
        {
            Swim();
        }
    }

    private void Swim()
    {
        // If it's time for the next action, pick a new speed and destination
        // Else, swim toward the destination
        if (Time.fixedTime >= nextActionTime)
        {
            // Randomize the speed
            randomizedSpeed = fishSpeed * UnityEngine.Random.Range(0.5f, 1.5f);

            // Pick a random target
            targetPosition = PenguinArea.ChooseRandomPosition(transform.parent.position, 100f, 260f, 2f, 13f);

            // Rotate toward the target
            transform.rotation = Quaternion.LookRotation(targetPosition - transform.position, Vector3.up);

            // Calculate the time to get there
            float timeToGetThere = Vector3.Distance(transform.position, targetPosition) / randomizedSpeed;
            nextActionTime = Time.fixedTime + timeToGetThere;
        }
        else
        {
            // Make sure that the fish does not swim past the target
            Vector3 moveVector = randomizedSpeed * transform.forward * Time.fixedDeltaTime;
            if (moveVector.magnitude <= Vector3.Distance(transform.position, targetPosition))
            {
                transform.position += moveVector;
            }
            else
            {
                transform.position = targetPosition;
                nextActionTime = Time.fixedTime;
            }
        }
    }
}

 

이제 Unity에서 컴포넌트들을 추가하며 값을 조정해 주고 스크립트에 선언된 public변수들을 할당해줄것이다.

 

BabyPenguin Prefab

1.아기펭귄프리팹을 열어 Rigidbody와 SphereCollider를 추가하고 사진과같이 설정해준다.

2.태그에 baby를 추가하고 아기펭귄의 태그를 baby로 바꿔준다.

*주의 대/소문자 구분 잘할것. baby와 후술할 fish는 전부 소문자.

 

FishPrefab

1.태그에 fish를 추가하고 Fish프리팹의 태그를 fish로 설정한다.

2.Rigidbody와 Capsule Collider를 추가하여 사진과같이 설정해준다.

Capsule Collider의 Dircetion이 Z-Axis이다. 

3.Fish스크립트를 추가해준다.

 

PenguinPrefab

1.펭귄도 Rigidbody와 Capsule Collider를 추가하여 사진과 같이 설정해준다.

ㄴ* 이때도 Capsule Collider의 Direction은 Z-Axis이다. (태그는 안바꿔도 된다.)

2. 그리고 Behavior Parameters와 Penguin Agent, Ray Perception Sensor 3D, Decision Requester를 모두 추가해준다.

3.사진과 같이 설정을 모두 바꿔준다.

4.Behavior Parameters(행동 매개변수)의 설정중 Vector Observation의 Space Size는 PenguinObserVation의 CollectObservations메서드에서 전달하는 value의 갯수와 동일하다.

 

5.Actions의 Branch n Size(n > 0, n = 정수)는 PenguinAgent스크립트의 OnActionReceived메서드 내의 actionBuffers.DiscreteActions의 n인덱스에 해당하는 값의 갯수를 말한다.

ㄴ스크립트를 작성할 때 설명했듯이, actionBuffers.DiscreteActions[0]은 움직임의 여부를 정하며 값은 0과 1로 2개라서 BranchSize가 2개이고

ㄴactionBuffers.DiscreteActions[1]은 회전여부를 정하며 회전없음/-방향회전/+방향회전으로 0,1,2 총 3개의 값으 가지므로 BranchSize가 3인것이다.

 

6.Ray Perception Sensor 스크립트(이하 Ray스크립트)는 Agent가 Ray를 출력하여 오브젝트의 태그를 가려내는데 도움을 준다.

ㄴRay 스크립트에서 Detectable Tags(감지가능한 태그)의 크기를 3으로 설정한 뒤, 해당 Element(요소)들에 baby, fish, Untagged를 입력해준다.

*주의 Tag의 이름을 적는것이기 때문에 반드시 설정해둔 태그들과 이름이 같아야한다. baby와 fish는 소문자로 시작한다.

ㄴ그 아래는 Ray의 갯수, 각도등을 설정해주는 부분이다.

7.데이터를 보고하고 수집할 Agent에게는 파이썬 트레이너에게서 행동을 받을 Decision Requester가 반드시 할당되어야 한다.

 

PenguinAreaPrefab

Mesh Renderer삭제 // Material 적용 후

1.Area하위의 해당 오브젝트들을 다중선택 한 뒤 Mesh Renderer 컴포넌트를 삭제하고 Mesh Collider를 추가한다.

2.Penguin폴더 하위에 Materials폴더를 생성하여 Snow Material을 만든 뒤, Albedo를 (255,255,255,255) 또는 FFFFFF로 만들고 Smoothness는 0으로 바꿔준다.

3.Water Material도 생성한 뒤 Albedo를 (0,200,255,165) 또는 00C8FF로 만들어 준 뒤, RenderType = TransParent, Smoothness는 0으로 설정해준다.

4.Snow Material을 iceberg와 rock들에 적용시킨다.

5.Water Material을 Water에 적용시킨다.

 

TMP를 처음 만들면 해당 창이 뜨는데, Import TMP Essentials를 누르면 된다 // 적용된 모습 // TMP 설정

1.Area의 하위에 Create 3D Object -> Text - TextMeshPro 를 생성한다.

2.해당 TMP를 Cumulative Reward (TMP)로 이름을 바꿔준다.

3.TMP의 Position을 (7,2,11), 크기를 20(Width)x5(Height), Rotation을 (0,30,0)으로 바꿔준다.

4.TMP의 DefaultText를 0.00으로 입력하고 FontSize를 30으로 설정, Vertex Color를 Black(0,0,0, 상관x) 또는 000000으로 바꿔주고 수평, 수직정렬을 중앙정렬로 바꿔준다.

 

1.Penguin과 BabyPenguin을 PenguinArea Prefab의 Hierachy에 생성한 뒤, Area프리팹에 Area스크립트를 할당한다.

2.BabyPenguin, Penguin Agent, Fish, TMP를 모두 Area스크립트에 할당해준다.

 

Area도 이걸로 끝났다.

 

Scene

(Heuristic)

Game화면은 용량이 너무 커질까봐 Scene화면을 녹화했다.

1.메인카메라의 위치를 사진과 같이 조정해준다.(생성한 Area프리팹의 위치가 기본값(reset하면 기본값으로 이동됨)이어야 해당 카메라의 위치가 잘 보인다.)

2.PenguinAgent의 Behavior Parameters 스크립트에서 BehaviorType을 Heuristic Only로 설정한다.

ㄴ이러면 수동조작이 가능함

3.오른쪽 영상에서 볼 수 있듯이 물고기는 한번에 한마리밖에 저장을 못하며, 물고기를 먹을때와 아기에게 먹이를 전달할 때 1점씩 획득한다.

ㄴ시간이 지날때마다 점수가 조금씩 깎이며, 탐지 가능한 태그에 Ray가 부딪히면 빨간색으로 보이는 모습이다.

ㄴ그리고 바다에 존재하는 모든 물고기를 아기펭귄에게 먹이면 에피소드가 끝나며 새로운 에피소드가 시작되는 모습을 보여준다.

 

(MLAgent)

공장같네

1.Behavior Type을 다시 Default로 바꿔준다.

2.빠른 학습결과를 얻기위해 프리팹을 여러개 배치해준다.

 

behaviors:
    Penguin:
        trainer_type: ppo
        hyperparameters:
            batch_size: 128
            buffer_size: 2048
            learning_rate: 0.0003
            beta: 0.01
            epsilon: 0.2
            lambd: 0.95
            num_epoch: 3
            learning_rate_schedule: linear
        network_settings:
            normalize: false
            hidden_units: 256
            num_layers: 2
            vis_encode_type: simple
        reward_signals:
            extrinsic:
                gamma: 0.99
                strength: 1.0
        keep_checkpoints: 5
        max_steps: 1000000
        time_horizon: 128
        summary_freq: 5000
        threaded: true

1.프로젝트폴더 하위에 config폴더를 생성 후, 메모장을 하나 켜서 위 스크립트를 적은 뒤, Penguin.yaml로 저장해준다.

ㄴ* 주의 파일형식은 '모든파일'로 저장해야한다.

2.프롬프트 창을 켜서 mlagents-learn config/ppo/Penguin.yaml --run-id Penguin_01를 실행해준다.

ㄴ나는 에러가 나면서 실행이 안됐다 그래서 직접 경로를 지정해 준 뒤 실행시켰다.

ㄴ아래사진 참고

ㄴ'cd 경로'를 쳐서 config상위폴더로 향한 뒤 ppo에서도 에러가 나길래 ppo부분을 지우고 실행했다.

 

ㄴmlAgent실행에 성공하면 Unity로고와 함께 버전들이 나오며 유니티 내에서 Play를 누르라고 한다.

3.Unity에서 Play를 누르면 실행된다.

프롬프트 창에 기록되는 결과가 나오는 모습 // 처음 시작하자마자 // 28만회~ 29.5만회까지 녹화 

위 영상을 보다시피 ML은 같은 코드를 입력했더라도 객체마다 다른 행동을 보이며 그에 따른 학습효과의 차이도 있다.

그리고 이렇게 학습된 데이터들은 모두 파이썬으로 전달되며 기록된다.

ㄴ실제로 위의 두 영상을 보면 학습된 오른쪽 영상은 평균적으로 점수가 높은것을 확인할 수 있다.

 

80~82만번까지의 녹화

학습하면 할 수록 랜덤생성되어 움직이는 물고기를 잘 잡고 랜덤생성되는 아기펭귄의 위치도 잘 찾아간다.

 

 

완료되면 사진과 같이 results폴더가 생성되며 이곳에 결과들로 생성된 모델, 데이터들이 저장된다.


** 이로서 MLAgent Penguin튜토리얼을 마친다

 

이번 복습은 철저히 아래 링크의 Tutorial을 따라하며 학습했습니다.

 

Unity ML Agents | Penguins — Immersive Limit

 

Unity ML Agents | Penguins — Immersive Limit

In this Unity ML Agents tutorial you’ll learn how to use machine learning, specifically reinforcement learning in Unity to train penguins to find fish and feed their babies.

www.immersivelimit.com