Unity ML Agent를 사용한 강화된 학습 환경 구축

본문은 시리즈 문장''의 두 번째 부분이다.Unity에 관심이 있는 ML 에이전트를 자신의 강화 학습 프로젝트에 사용하는 초보자에게도 적용됩니다.

검토 및 개요


제 수업에서 ML 에이전트와 교육 에이전트를 설정하는 법을 배웠습니다.
본고에서 나는 어떻게 Unity에서 3D 물리를 바탕으로 하는 배구 환경을 구축하는지 소개할 것이다.잠시 후, 우리는 이 환경을 이용하여 배구에 성공한 대리인을 깊이 있게 강화할 수 있도록 훈련할 것이다.

법정을 세우다

  • 이것repo에서 초보자 프로젝트를 다운로드하거나 복제합니다.
  • Unity Hub을 열고 프로젝트 > 추가를 시작합니다.
  • '궁극 배구 초보자'프로젝트 폴더를 선택합니다.콘솔에서 경고 메시지를 볼 수 있지만, 지금은 안전하게 무시할 수 있습니다.
  • Unity의 프로젝트 탭에서 에셋 > 장면으로 이동합니다.
  • 마운트Volleyball.unity 장면.
  • [프로젝트] 탭에서 [에셋 > 사전 제작]으로 이동하고 VolleyballArea.prefab 객체를 장면으로 드래그합니다.
  • 프로젝트를 저장합니다.

  • 하면, 만약, 만약...▶️ 장면 뷰어 위에서, 게임 대상이 어떻게 상호작용해야 하는지를 정의하기 위해 물리나 논리를 추가하지 않았기 때문에, 이상한 일이 일어났다는 것을 알게 될 것이다.우리는 다음 절에서 소개할 것이다.

    환경을 조성하다


    ⚠ 시작하기 전에 배구 영역 프리셋(프로젝트 패널 > 에셋 > 프리셋)을 엽니다.기본 사전 설정이 사전 설정의 모든 인스턴스에 반영되도록 편집합니다.우리가 여러 차례 환경을 복제하여 병행 훈련을 할 때, 이것은 쓸모가 있을 것이다.

    배구


    우리의 배구는 Unity의 물리적 엔진에 의해 제어된다.
  • 차원 패널에서 배구 구역의 대상을 펼치고 배구를 선택한다.
  • Inspector 패널에서 레이블을 ball로 설정합니다.
  • 어셈블리 추가 > 강체 를 클릭합니다.
  • 설정질량=3, 저항=1, 각저항=1.기본값은 원하는 대로 사용할 수 있습니다.더 무거운 공 하나가 환경을 더욱 어렵게 할 것이다.
  • 우리의 공에'탄력성'을 추가하다.
  • 구체 충돌기 부품을 추가합니다.
  • 반지름을 0.15로 설정합니다.
  • [프로젝트] 패널에서 [에셋 > 재료 > 물리적 재료]로 이동합니다.
  • 재료 슬롯으로 Bouncy.physicMaterial을 드래그합니다.
  • "탄력성"을 변경하려면 Bouncy.physicMaterial을 두 번 클릭합니다.

  • 파란색과 보라색의 대리 입방체는 배구와 비슷한 방식으로 설정되어 있습니다.

    땅바닥

  • 지상 게임 대상 선택
  • Inspector 패널에서 레이블을 walkableSurface로 설정합니다.이것은 나중에 에이전트가 점프 작업으로 인해 '고정' 되었는지 확인하는 데 사용됩니다.
  • 장방체 충돌기 부품을 추가합니다.이것은 강체 구성 요소를 포함하는 다른 게임 대상과의 충돌을 등록하는 데 사용됩니다.그것이 없으면 그것들은 땅에서 떨어질 것이다.
  • 목표


    목표는 지면의 얇은 층으로 표시된다.
  • BluePlayArea 및 PurplePlayArea 상위 객체를 확장합니다.
  • BlueGoal과PurpleGoal 게임 대상에 테두리 충돌기를 추가한다.
  • 두 대상의'예 트리거'상자를 선택합니다.

  • 게임 대상이 트리거로 설정되었을 때, 물리적 충돌을 기록하지 않습니다.비록 목표는 지면층 위에 있지만 기술적으로 대리인은 우리가 이전에 창설한 지면층 충돌기에서 이동한 것이다.
    트리거를 설정하면 우리가 잠시 후에 OnTriggerEnter 방법을 사용할 수 있습니다. 이 방법은 공이 언제 충돌기에 맞았는지 측정할 수 있습니다.

    그물

  • 배구망의 온라인 게임 대상을 선택한다.
  • 장방체 충돌기를 추가합니다.
  • 충돌기 편집 아이콘 을 클릭합니다.
  • 녹색 충돌기의 하단 노드를 클릭하고 드래그하여 전체 네트워크 높이를 덮어씁니다.두께는 마음대로 사용할 수 있습니다.이곳의 의도는 공이 네트 밑이나 네트 주위에 들어가는 것을 방지하기 위해 물리적 블로킹기를 만드는 것이다.

  • 💡 Some shortcuts: Alt+click to rotate, middle-click to pan, middle mouse wheel to zoom in/out.


    경계


    보이지 않는 세 가지 경계가 있다.

  • 외곽 베이스(볼 아웃 여부 확인)

  • 블루 사이드볼(블루 사이드 코트 입장 여부 확인)

  • 보라색 경계(공이 보라색 구역에 들어갔는지 검사)
  • 이 경계의 충돌기, 표시기, 트리거를 설정했습니다.

    환경 스크립트 작성


    이 절에서는 환경 동작을 정의하는 스크립트를 추가합니다. 예를 들어 공이 바닥에 떨어지거나 드라마가 시작될 때 어떤 일이 일어날지.

    커트 설정.대테러 엘리트


    우리의 첫 번째 스크립트는 간단하게 상수를 저장할 것입니다. 프로젝트 전체에 상수를 다시 사용할 것입니다.
  • 배구 장면으로 돌아가 배구 설정 게임 대상을 선택한다.
  • Inspector에서 추가 스크립트 구성 요소를 볼 수 있습니다.슬라이더 설정 스크립트를 두 번 클릭하여 선택한 IDE에서 엽니다.
  • 다음을 확인하십시오.
  • public float agentRunSpeed = 1.5f;
    public float agentJumpHeight = 2.75f;
    public float agentJumpVelocity = 777;
    public float agentJumpVelocityMaxChange = 10;
    
    // Slows down strafe & backward movement
    public float speedReductionFactor = 0.75f;
    
    public Material blueGoalMaterial;
    public Material purpleGoalMaterial;
    public Material defaultMaterial;
    
    // This is a downward force applied when falling to make jumps look less floaty
    public float fallingForce = 150;
    
    참고: ProjectSettingsOverride.cs 스크립트도 제공됩니다.이것은 시간 보조 및 해석 물리와 관련된 다른 기본 설정을 포함합니다.
    Unity 편집기로 돌아가 배구 설정 게임 객체를 선택합니다.이러한 변수는 Inspector 패널에서 사용할 수 있습니다.

    커트 컨트롤러.대테러 엘리트


    이 스크립트는 배구 경기 대상에 추가되어 공이 언제 경계나 목표 트리거에 명중했는지 측정할 수 있습니다.
  • 배구에 첨부된VolleyballController.cs 스크립트를 펼친다.
  • 류의 시작VolleyballController : MonoBehaviour(Start()방법 위), 성명 변수:
  • [HideInInspector]
    public VolleyballEnvController envController;
    
    public GameObject purpleGoal;
    public GameObject blueGoal;
    Collider purpleGoalCollider;
    Collider blueGoalCollider;
    
  • 스크립트를 저장합니다.
  • Unity 편집기에서 배구 경기 상대를 클릭합니다.
  • 퍼플고얼 게임 대상을 인스펙터의 보라색 골대 안으로 드래그했다.
  • BlueGoal 게임 대상을 Inspector의 Blue Goal 슬롯으로 드래그합니다.

  • 이것은 우리가 나중에 그들의 하위 대상을 방문할 수 있도록 허락할 것이다.Start()
    이 메서드는 처음 렌더링 환경에서 사용됩니다.다음을 수행합니다.
  • 방법을 사용하여 PurpleGoal과 BlueGoal 충돌기 자체(물리적 충돌을 바탕으로 하는 구성 요소를 기록):
  • purpleGoalCollider = purpleGoal.GetComponent<Collider>();
    blueGoalCollider = blueGoal.GetComponent<Collider>();
    
  • Ballarea 게임 대상을 변수'envController'에 할당하여 나중에 참고할 수 있도록 합니다.
  • envController = GetComponentInParent<VolleyballEnvController>();
    
    다음 명령문을 GetComponent<Collider> 메서드에 복사합니다.
    void Start()
    {
        envController = GetComponentInParent<VolleyballEnvController>();
        purpleGoalCollider = purpleGoal.GetComponent<Collider>();
        blueGoalCollider = blueGoal.GetComponent<Collider>();
    }
    
    Start()공이 충돌기에 부딪혔을 때 이 방법을 사용하세요.
    체크해야 하는 장면은 다음과 같습니다.
  • 공 착지/골
  • 아웃
  • 공을 네트에 던졌다
  • 이 방법은 모든 장면을 검측하고 이 정보를 OnTriggerEnter(Collider other)에 전달한다(다음 절에 추가할 것이다).다음 블록을 이 메서드에 복사합니다.
    if (other.gameObject.CompareTag("boundary"))
    {
        // ball went out of bounds
        envController.ResolveEvent(Event.HitOutOfBounds);
    }
    else if (other.gameObject.CompareTag("blueBoundary"))
    {
        // ball hit into blue side
        envController.ResolveEvent(Event.HitIntoBlueArea);
    }
    else if (other.gameObject.CompareTag("purpleBoundary"))
    {
        // ball hit into purple side
        envController.ResolveEvent(Event.HitIntoPurpleArea);
    }
    else if (other.gameObject.CompareTag("purpleGoal"))
    {
        // ball hit purple goal (blue side court)
        envController.ResolveEvent(Event.HitPurpleGoal);
    }
    else if (other.gameObject.CompareTag("blueGoal"))
    {
        // ball hit blue goal (purple side court)
        envController.ResolveEvent(Event.HitBlueGoal);
    }
    

    환경 컨트롤러


    이 스크립트는 환경의 모든 주요 논리를 포함한다. 그것이 실행되어야 할 최대 걸음, 공과 에이전트가 어떻게 생성되어야 하는지, 줄거리가 언제 끝나야 하는지, 보상을 어떻게 분배해야 하는지 등이다.
    샘플 뼈대 스크립트에서는 몇 가지 변수 및 액세스 방법이 제공됩니다.
  • VolleyballEnvController.cs - 나중에 필요한 구성 요소와 개체를 가져옵니다
  • .
  • Start() - 어떤 에이전트가 마지막에 공을 잡았는지 추적
  • UpdateLastHitter() - 지면의 색깔을 바꾸는 것
  • GoalScoredSwapGroundMaterial()Unity 엔진은 프레임 업데이트 FixedUpdate() 에서 초 간격으로 설정될 때마다 호출됩니다.
    이것은 에피소드를 중단하기 전에 (예를 들어 공이 어디에 끼면) 환경이 가장 많이 업데이트되는 횟수 (즉 '단계') 를 제어할 것이다.
    다음을 FixedDeltaTime=0.02에 추가합니다.
    /// <summary>
    /// Called every step. Control max env steps.
    /// </summary>
    void FixedUpdate()
    {
        resetTimer += 1;
        if (resetTimer >= MaxEnvironmentSteps && MaxEnvironmentSteps > 0)
        {
            blueAgent.EpisodeInterrupted();
            purpleAgent.EpisodeInterrupted();
            ResetScene();
        }
    }
    
    ProjectSettingsOverride.cs이것은 시작된 번식 행위를 통제할 것이다.
    우리의 목표는 매니저가 공이 어디로 보내든지 경기장 한쪽에서 공을 되돌릴 수 있는 모델을 배우는 것이다.훈련에 도움이 되도록 우리는 합리적인 범위 내에서 대리와 공의 시작 조건을 무작위로 배정할 것이다.
    /// <summary>
    /// Reset agent and ball spawn conditions.
    /// </summary>
    public void ResetScene()
    {
        resetTimer = 0;
    
        lastHitter = Team.Default; // reset last hitter
    
        foreach (var agent in AgentsList)
        {
            // randomise starting positions and rotations
            var randomPosX = Random.Range(-2f, 2f);
            var randomPosZ = Random.Range(-2f, 2f);
            var randomPosY = Random.Range(0.5f, 3.75f); // depends on jump height
            var randomRot = Random.Range(-45f, 45f);
    
            agent.transform.localPosition = new Vector3(randomPosX, randomPosY, randomPosZ);
            agent.transform.eulerAngles = new Vector3(0, randomRot, 0);
    
            agent.GetComponent<Rigidbody>().velocity = default(Vector3);
        }
    
        // reset ball to starting conditions
        ResetBall();
    }
    
    /// <summary>
    /// Reset ball spawn conditions
    /// </summary>
    void ResetBall()
    {
        var randomPosX = Random.Range(-2f, 2f);
        var randomPosZ = Random.Range(6f, 10f);
        var randomPosY = Random.Range(6f, 8f);
    
        // alternate ball spawn side
        // -1 = spawn blue side, 1 = spawn purple side
        ballSpawnSide = -1 * ballSpawnSide;
    
        if (ballSpawnSide == -1)
        {
            ball.transform.localPosition = new Vector3(randomPosX, randomPosY, randomPosZ);
        }
        else if (ballSpawnSide == 1)
        {
            ball.transform.localPosition = new Vector3(randomPosX, randomPosY, -1 * randomPosZ);
        }
    
        ballRb.angularVelocity = Vector3.zero;
        ballRb.velocity = Vector3.zero;
    }
    
    void FixedUpdate()이 방법은 우리가 이전에 ResetScene()에서 정의한 장면을 해결할 것이다.
    우리는 이런 방법을 사용하여 서로 다른 방식으로 보상을 분배하여 서로 다른 유형의 행위를 장려할 수 있다.일반적으로 보상을 [-1,1] 이내로 유지하는 것이 좋습니다.
    간단하게 말하자면, 우리의 현재 목표는 공을 이리저리 튕기고 경기에서 공을 유지할 수 있는 매니저를 훈련시키는 것이다.상응하는 장면에서 우리는 ResolveEvent() 방법을 사용하여 매번 대리가 공을 네트에 칠 때마다 +1의 보상을 분배할 것이다.
    case Event.HitIntoBlueArea:
        if (lastHitter == Team.Purple)
        {
            purpleAgent.AddReward(1);
        }
        break;
    
    case Event.HitIntoPurpleArea:
        if (lastHitter == Team.Blue)
        {
            blueAgent.AddReward(1);
        }
        break;
    
    만약 골이나 공이 아웃된다면 우리는 당분간 어떤 보상도 주지 않을 것이다.만약 이 두 가지 상황이 모두 발생한다면, 우리는 이 회를 끝낼 것이다.다음 코드 블록을 VolleyballController.cs 주석 지시 부분에 추가합니다.
    blueAgent.EndEpisode();
    purpleAgent.EndEpisode();
    ResetScene();
    
    다음은 AddReward(1f)의 모양새입니다.
    /// <summary>
    /// Resolves scenarios when ball enters a trigger and assigns rewards
    /// </summary>
    public void ResolveEvent(Event triggerEvent)
    {
        switch (triggerEvent)
        {
            case Event.HitOutOfBounds:
                if (lastHitter == Team.Blue)
                {
                    // apply penalty to blue agent
                }
                else if (lastHitter == Team.Purple)
                {
                    // apply penalty to purple agent
                }
    
                // end episode
                blueAgent.EndEpisode();
                purpleAgent.EndEpisode();
                ResetScene();
                break;
    
            case Event.HitBlueGoal:
                // blue wins
    
                // turn floor blue
                StartCoroutine(GoalScoredSwapGroundMaterial(volleyballSettings.blueGoalMaterial, RenderersList, .5f));
    
                // end episode
                blueAgent.EndEpisode();
                purpleAgent.EndEpisode();
                ResetScene();
                break;
    
            case Event.HitPurpleGoal:
                // purple wins
    
                // turn floor purple
                StartCoroutine(GoalScoredSwapGroundMaterial(volleyballSettings.purpleGoalMaterial, RenderersList, .5f));
    
                // end episode
                blueAgent.EndEpisode();
                purpleAgent.EndEpisode();
                ResetScene();
                break;
    
                    case Event.HitIntoBlueArea:
                        if (lastHitter == Team.Purple)
                        {
                            purpleAgent.AddReward(1);
                        }
                        break;
    
                    case Event.HitIntoPurpleArea:
                        if (lastHitter == Team.Blue)
                        {
                            blueAgent.AddReward(1);
                        }
                        break;
                        }
    }
    
    지금 재생을 클릭하면▶️ 너는 환경이 정상적으로 작동하는 것을 보아야 한다. 공이 중력의 영향을 받아 스파이가 바닥에 서 있을 수 있고, 공이 땅에 떨어질 때 줄거리가 리셋된다.

    마무리


    당신들은 지금 배구 환경을 가지고 우리 매니저에게 훈련을 제공해야 합니다.그것은 특정 유형의 행위 (인터럽트) 를 격려하기 위해 우리 매니저들에게 보상을 분배할 것이다.
    다음 절에서는 에이전트를 설계하고 선택할 수 있는 조작과 환경을 관찰할 수 있는 방법을 제공할 것입니다.
    만약 어떤 피드백이나 문제가 있으면 저에게 알려주세요!

    좋은 웹페이지 즐겨찾기