본문 바로가기

Study/Unity

[유니티 ML-Agents] #01. 머신러닝 및 ML-Agents 소개

반응형

본 포스트는 교재 '따라하면서 배우는 유니티 ML-Agents'를 공부하며 작성하였습니다.

이 책은 번역서이기 때문에 번역이 어색한 부분이 많이 있어서 알아서 잘 해석하고 검색해봐야 합니다.

이 책은 유니티에서 ML-Agents 플랫폼을 사용하는 것에 대해 설명한다. 이 책의 목차부터 살펴보면 이렇다.

#01. 머신러닝 및 ML-Agents 소개
#02. 밴딧과 강화학습
#03. 파이썬을 이용한 심층강화학습
#04. 더 깊은 딥러닝 속으로
#05. 게임하기
#06. 다시 만들어 보는 테라리엄 - 다중 에이전트 생태계

먼저 머신러닝과 ML-Agents에 대해 살펴보고 훈련(training)에 대해 공부한다. (이 책에서 훈련은 학습과 같은 의미로 사용되었다.) 그리고 강화학습(reinforcement learning)에 대해 공부하고 Q 학습(Q learning)에 대해 공부한다. keras로 신경망을 구축하는 방법을 알아보고 이를 통해 심층 Q 신경망(deep Q-network)를 구현한다. 그리고 다양한 훈련 전략으로 신경망을 개선해본다. 마지막으로 multi-agent 환경에서 에이전트 간 경쟁을 구현하여 agent가 더 어려운 게임을 할 수 있도록 만든다.

keras는 텐서플로 같은 기반 라이브러리를 사용하기 쉽도록 포장한 wrapper 라이브러리이다. keras는 인공지능 대중화가 목표이기 떄문에 이를 사용하면 쉽게 딥러닝 신경망을 구축할 수 있다.

#1. 머신러닝

#1-1. 머신러닝

머신러닝은 인공지능을 구현하는 여러가지 방식 중에 하나이다. 학습하는 시계, 기계가 학습하는 일, 훈련받는 기계 등으로 이해할 수 있다. 컴퓨터가 데이터(data)/상태(state)를 이해(assimilate)시키며 학습한(learning)한 풀이방법(solution)/응답(response)을 제공하는 방법이다.

#1-2. 학습 모델

머신러닝에서 자주 볼 수 있는 세 가지 훈련 유형이 있다.

1. 비지도 훈련(unsupervised training)

비지도 학습은 자체적으로 데이터셋을 검사하고 분류 작업을 수행한다. 분류는 특정 측정 기준(metrics, 척도, 메트릭)을 기반으로 할 수 있고 학습 자체에서 발견할 수 있다.

2. 지도 훈련(supervised training)

지도 학습은 데이터 과학 분야의 머신러닝 방법 중 대다수가 예측 또는 분류를 수행하는 데 사용하는 일반적인 학습 방법이다. 이는 입력 데이터와 출력 데이터에 레이블(label)을 지정해야 하기 때문에 모델을 제작하기 위해서는 훈련 데이터셋이 필요하다.
* 구글 인셉션(Google Inception): 이미지 분류 머신.

지도학습 기반 모델(supervision-based models)을 구현할 때에는 label이 많아질수록 모델이 커지고 실용적이지 않게 된다. 즉, 지속적으로 데이터에서 표본 재추출(resample)을 하고 레이블 재지정(relabel)을 해서 모델을 재훈련(retrain)해야 하는 문제가 있다. 이런 점에서 강화학습 등에 이점이 있다. 강화학습은 환경에 대한 사전 지식이 없는 자율적인 에이전트, 즉 머신러닝이 성공적으로 탐색할 수 있는 학습 방법을 제공하기 때문이다.

3. 강화훈련(reinforcement training)

강화학습은 제어 이론에 기초한 것으로, 환경에 대한 초기 상태나 모델 없이 학습하는 기법이다. 환경을 모델링하거나 지도 학습을 위해서 필요한 데이터 레이블링 과정이 필요없어서 매우 강력한 학습 방법이다. 라벨링 과정이 없는 대신에, 에이전트는 환경 속에서 모델링 되고 그들의 행동(actions)을 기준으로 보상(rewards)를 받는다. (2장 참조)
* 딥마인드(DeepMind): 고전적인 아타리 게임에 강화학습 기법 적용해 인간보다 더 게임을 잘하는 로봇으로 만들었다.

4. 모방 학습(imitation learning)

바람직한 행동을 보여주면 그것을 에이전트가 모방하는 식으로 훈련하는 기술이다. (4장 참조)

5. 커리큘럼 학습(curriculum learning)

문제를 복잡도에 따라 쪼개서 처리하는 진보한 학습 형태이다. 표본 데이터셋을 무작위로 제공하는 것이 아니라, 일반적인 커리큘럼을 짜듯 쉬운 것부터 어려운 순으로 정리해 제공하여 더 잘 훈련되게 하는 학습 알고리즘이다. 에이전트 또는 머신러닝이 차원 높은 활동으로 이동하기 전에 각 수준의 복잡성을 해결할 수 있게 해준다. 예를 들어보면, 웨이터라는 에이전트는 1) 쟁반의 균형을 잡고 2) 음식이 담긴 접시를 쟁반에 놓고 3) 쟁반과 음식을 지닌 채 걸어서 4) 음식을 식탁에 내려놓아야 한다. 이렇게 행동을 쪼개서 생각하는 것이다. (5장 참조)

6. 딥러닝(deep learning)

학습에 사용되는 신경망이 많아서, 즉 깊어서 딥러닝이라고 부른다. 딥러닝은 다양한 형태의 내부 훈련 메커니즘을 이용하여 다층 신경망을 훈련한다. (3장 참조)

#1-3. 게임에 사용되는 머신러닝

유니티는 머신러닝을 게임 인공지능으로만 사용하는 수준으로 그치지 않고 제품의 모든 측면에 사용되도록 하고 있다. 게임 개발 시에는 다음과 같은 영역에서 잘 사용된다.

1. 맵/레벨 생성(map/level generation)

던전이라는 비현실적 공간부터 현실적인 공간까지 게임 속의 지형을 머신러닝을 이용해 자동으로 생성한다. 이를 통해 게임에 endless replayability를 제공할 수 있지만, 개발하기에는 난해할 수 있다.

2. 텍스처/셰이더(질감/그림자) 생성(texture/shader generation)

고수준의 GAN(generative adversarial network, 생성적 경쟁 신경망)에서 여기에 관심이 많다. 딥페이크(Deep Fake)가 여기에 해당한다.
* GAN?
생성자(Generator)와 식별자(Discriminator)가 서로 경쟁(Adversarial)하는 과정을 거쳐서 데이터를 생성(Generative)하는 모델이다. 생성자와 식별자가 서로 경쟁하여 점차 성능을 개선해나가는 쪽으로 학습이 진행된다. 비지도학습의 생성 모델이다.

3. 모델 생성(model generation)

 

4. 오디오 생성(audio generation)

오디오 효과음이나 음악을 즉석에서 생성한다.

5. 인공 플레이어(artificial player)

게임이 자체적으로 게이머의 수준에 맞춰지게 한다. (5장 참조)

6. NPC 또는 게임 인공지능(NPC or game AI)

행동 패턴을 모델링한다. (6장 참조)

이 책에서는 5. 인공 플레이어와 6. 게임 인공지능에 대해 다룬다.

 

#2. ML-Agents

#2-1. github에서 ML-Agents 패키지 가져오기

https://github.com/Unity-Technologies/ml-agents 이 주소에서 패키지를 가져올 수 있는데, 해당 책에서는 beta 0.3.0 ver을 사용하므로, https://github.com/Unity-Technologies/ml-agents/releases/tag/0.3.0 이 링크에 접속하여 소스코드를 zip으로 다운로드 한 후에 가져온다. C:\Users\유지원\workspace\ML-Agents\ml-agents 경로에 다운로드 된 것들을 모두 복사 붙여넣기 하면 된다. 이러면 ML-Agents 패키지가 설치된 것이다.

#3. 예제 실행

유니티는 다양한 학습 및 훈련 시나리오를 보여줄 수 있게 미리 준비해 둔 예제를 ML-Agents 패키지에 담아서 제공한다. 이 예제 프로젝트를 유니티에서 로드해보자.

ML-Agents를 사용하려고 했는데 이 패키지는 기존에 사용하던 2020.3.25f1과 버전이 맞지 않아 사용할 수가 없었다.

사용하려면 2018.1.0b6 버전을 설치하라고 에러가 떠서 해당 버전으로 설치를 다시 했다. 몰랐는데, 별도의 작업 없이 새 버전을 까니까 2020.3.25 버전에 2018 버전이 덮여쓰여 설치가 된 것 같았다. 때문에 다른 버전을 설치하고 둘 다 쓰기 위해서는 다른 작업이 필요한 듯하다. 이런 작업을 하려고 unity hub를 쓰는 걸 텐데... 나중에 2020 버전 써야할 때 다시 시도해봐야겠다.

unity 2018 버전을 실행해서 Project > Open > ML-Agents/ml-agents/unity-environment 폴더를 선택한다. 그러면 unity-environment 프로젝트가 유니티 에디터에 로드된다. Project 창의 Assets/ML-Agents/Examples/3DBall 폴더에서 '3DBall' 씬 파일을 더블클릭하면 에디터에서 씬이 열린다.

#3-1. 에이전트 브레인 설정

에이전트가 사용하는 브레인 유형을 변경해보자. 브레인은 에이전트의 두뇌로, 에이전트의 머신러닝 모델을 말한다.

씬은 위와 같이 구성되어 있다. 하이어라키 창 > Ball3DAcademy 오브젝트를 선택한다.

Ball3DBrain 오브젝트의 인스펙터 창을 보면 위와 같다. Brain (Script) 컴포넌트의 Brain Type을 설정하면 되는데, 기본값은 Player다. 말 그대로 player인 인간이 키보드로 직접 조종하는 것이다. 그리고 Heuristic 브레인 설정을 통해 유니티가 자체적으로 내장하고 있는, 휴리스틱 방식으로 코딩된 ML-Agents를 이용할 수 있다.

* 휴리스틱 프로그래밍(Heuristic programming)?

고전적인 알고리즘에서는 상대적으로 간단한 해법 중 하나로, 시행착오를 거쳐 최적해를 찾아 가는 방식이다. 경험적 방식 또는 시행착오적 방식이라고도 부른다. 현재 게임 인공지능의 대부분은 이 알고리즘을 사용하는 범주에 속한다.

휴리스틱 방식을 사용하면 player가 조작하지 않는 상태에서 스스로 판을 움직여 균형을 맞추는 것을 보여준다. 이때 Rotation Speed를 0.4 정도로 조정하면 더 잘 기능하는 것을 확인할 수 있다.

Internal 브레인이라는 것도 볼 수 있는데, 이것은 6장에서 다룰 것이다.

이제 휴리스틱 브레인을 사용하는 스크립트를 열고 일부 코드를 살펴보자.

스크립트는 이렇다. 이 중에 'Ball3DDecision'(3D 볼 의사결정) 스크립트를 선택해서 보자.

전체 코드는 이렇다. 보다시피 꽤나 간단하다.

public float[] Decide(
	List<float> vectorObs,
    List<Texture2D> visualObs, 
    float reward, 
    bool done, 
    List<float> memory)
 { 
 	if (gameObject.GetComponent<Brain>().brainParameters.vectorActionSpaceType == SpaceType.continuous) 
    { 
    	List<float> act = new List<float>(); 
    	// state[5] is the velocity of the ball in the x orientation. 
    	// We use this number to control the Platform's z axis rotation speed, 
    	// so that the Platform is tilted in the x orientation correspondingly. 
    	act.Add(vectorObs[5] * rotationSpeed); 
    
    	// state[7] is the velocity of the ball in the z orientation. 
    	// We use this number to control the Platform's x axis rotation speed, 
    	// so that the Platform is tilted in the z orientation correspondingly. 
    	act.Add(-vectorObs[7] * rotationSpeed); 
    
    	return act.ToArray(); 
 	} 
 
 	// If the vector action space type is discrete, then we don't do anything. 
 	return new float[1] { 1f }; 
 }

스크립트 내의 Decide 메서드의 코드만 가져오면 이렇다. 이 코드는 플랫폼 상의 공들을 균형 잡게 하는 휴리스틱 브레인인데, 코드가 정말 간단하다.
하지만 3D Ball 문제는 매우 간단하게 8개(0~7)의 state(상태)만 사용하면 되기 때문에 쉽게 모델링될 수 있으나 실제로는 수십억~수백만 개에 해당하는 state가 있을 수 있기 때문에 휴리스틱 방식을 사용해서 쉽게 해결할 수 있는 일은 거의 없다.

 

여기까지 활동한 폴더의 파일 트리 구조를 살펴보면 아래와 같다.

C:.
├─ML-Agents
│  ├─Editor
│  ├─Examples
│  │  ├─3DBall
│  │  │  ├─Materials
│  │  │  │  └─Materials
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─BananaCollectors
│  │  │  ├─Materials
│  │  │  ├─Models
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Basic
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Bouncer
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Crawler
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─GridWorld
│  │  │  ├─Materials
│  │  │  ├─Resources
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Hallway
│  │  │  ├─Material
│  │  │  ├─Prefabs
│  │  │  ├─Scenes
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─PushBlock
│  │  │  ├─Prefabs
│  │  │  ├─Scenes
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Reacher
│  │  │  ├─Materials
│  │  │  │  └─Materials
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─SharedAssets
│  │  │  ├─Materials
│  │  │  └─Scripts
│  │  ├─Soccer
│  │  │  ├─Materials
│  │  │  ├─Prefabs
│  │  │  │  └─SoccerBall
│  │  │  │      ├─Materials
│  │  │  │      ├─Meshes
│  │  │  │      ├─Prefabs
│  │  │  │      └─Textures
│  │  │  ├─Scenes
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Template
│  │  │  └─Scripts
│  │  ├─Tennis
│  │  │  ├─Materials
│  │  │  ├─Prefabs
│  │  │  ├─Racket
│  │  │  │  └─Materials
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  └─WallJump
│  │      ├─Material
│  │      ├─Prefabs
│  │      ├─Scenes
│  │      ├─Scripts
│  │      └─TFModels
│  ├─Plugins
│  │  └─JSON
│  └─Scripts

#4. 새로운 머신러닝 환경 만들기

위에서 brain을 조정하는 등 약간의 사용자 설정이 필요했다. 유니티 문서에서는 관련 스크립트들이 엮여 있는 Academy, Agent, Brain 오브젝트를 사용해서 머신러닝 환경을 구성할 것을 권장한다.
ML-Agents 프로젝트에는 간단한 환경을 구성하고 설정하는 데 사용할 템플릿 폴더가 있다. 첫 번째 머신러닝 환경을 설정해보자.
Assets/ML-Agents/Examples/Template 폴더를 복사해서 Assets 폴더에 복사 붙여넣기 한 후, 이름을 'Simple'로 바꿔준다. 그런 다음에 스크립트 이름에 있는 Template 단어를 모두 Simple로 바꿔주면 된다. 그리고 각 스크립트 코드 속 클래스 명의 Template 단어를 모두 Simple로 바꿔준다. 그리고 Academy 오브젝트의 Template 관련 컴포넌트를 모두 지우고, Simple 이름을 가진 컴포넌트를 추가해주면 된다.
이렇게 우리만의 Academy, Agent, Decision(브레인) 스크립트를 구현하기 위한 새로운 머신러닝 환경을 세팅했다.

 

그러면 아래와 같은 파일 트리 구조를 갖게 된다.

C:.
├─ML-Agents
│  ├─Editor
│  ├─Examples
│  │  ├─3DBall
│  │  │  ├─Materials
│  │  │  │  └─Materials
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─BananaCollectors
│  │  │  ├─Materials
│  │  │  ├─Models
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Basic
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Bouncer
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Crawler
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─GridWorld
│  │  │  ├─Materials
│  │  │  ├─Resources
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Hallway
│  │  │  ├─Material
│  │  │  ├─Prefabs
│  │  │  ├─Scenes
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─PushBlock
│  │  │  ├─Prefabs
│  │  │  ├─Scenes
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Reacher
│  │  │  ├─Materials
│  │  │  │  └─Materials
│  │  │  ├─Prefabs
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─SharedAssets
│  │  │  ├─Materials
│  │  │  └─Scripts
│  │  ├─Soccer
│  │  │  ├─Materials
│  │  │  ├─Prefabs
│  │  │  │  └─SoccerBall
│  │  │  │      ├─Materials
│  │  │  │      ├─Meshes
│  │  │  │      ├─Prefabs
│  │  │  │      └─Textures
│  │  │  ├─Scenes
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  ├─Template
│  │  │  └─Scripts
│  │  ├─Tennis
│  │  │  ├─Materials
│  │  │  ├─Prefabs
│  │  │  ├─Racket
│  │  │  │  └─Materials
│  │  │  ├─Scripts
│  │  │  └─TFModels
│  │  └─WallJump
│  │      ├─Material
│  │      ├─Prefabs
│  │      ├─Scenes
│  │      ├─Scripts
│  │      └─TFModels
│  ├─Plugins
│  │  └─JSON
│  └─Scripts
└─Simple
    └─Scripts

 

#5. Academy, Agent, Brain 컴포넌트

주요 컴포넌트는 Academy, Agent, Brain(Decision) 이 세 가지이고 이 개념을 설명하기 위해 멀티암드 밴딧(multi-armed bandit) 문제를 기반으로 간단한 예를 구성해보자.

* 멀티암드 밴딧(multi-armed bandit)

슬롯머신

'팔이 여러 개인 산적'이라는 뜻이다. 미국 카지노에서는 레버가 하나 달린 슬롯머신을 도둑놈 마냥 돈을 가져간다고 해서 밴딧이라 부르고 다르게는 외팔이 산적(one-armed bandit)이라고 부르는데, 이러한 슬롯머신을 여러 대 쓰는 건 마치 팔이 여러 개인 도둑처럼 볼 수 있다고 해서 이렇게 부른다.

기존 슬롯머신(원암드 밴딧)은 팔이 하나지만, 멀티암드 밴딧은 플레이어가 사용할 수 있는 활동이 네 가지가 제공된다. 그리고 각 활동에 대해서 플레이어는 보상을 받는다.

방금 편집한 Simple 프로젝트를 열어보자.
메뉴>GameObject>3D Object>Cube를 선택하고 이름을 'Bandit'으로 수정한다. 그리고 인스펙터>Transform>톱니바퀴>Reset 을 눌러서 오브젝트의 Position을 (0,0,0)으로 설정한다. 이 오브젝트가 우리 씬의 중심이 된다. Mesh Renderer 컴포넌트의 Materials을 NetMat 머티리얼로 선택하면 아래와 같이 된다.

이제 Project 창에서 Assets/Simple/Scripts 폴더에서 새로운 C# Script를 만들고 이름을 Bandit으로 변경한다. 그리고 아래와 같은 코드를 입력한다.

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

// 클래스를 MonoBehaviour에서 확장된 Bandit이라고 선언
// 유니티의 모든 게임 오브젝트는 MonoBehaviour에서 확장된 것이다.
public class Bandit : MonoBehaviour
{

    // Material를 public 속성으로 정의
    // 보상 값을 표시하는 데 사용한다.
    public Material Gold;
    public Material Silver;
    public Material Bronze;
    // mesh라는 MeshRenderer의 자리표시자(placeholder)를 private 속성으로 정의
    // rest(재설정)이라고 부르는 원래의 material을 private 속성으로 정의
    private MeshRenderer mesh;
    private Material reset;


    // Use this for initialization
    // 오브젝트가 시작될 때 실행되는 기본 유니티 메서드
    void Start()
    {
        mesh = GetComponent<MeshRenderer>();
        reset = mesh.material;

    }

    // Arm(레버)를 당길 때
    // 적절한 머터리얼과 보상 설정하는 switch 문인 PullArm 메서드
    public int PullArm(int arm)
    {
        // reward 변수 선언 및 초기화
        var reward = 0;
        // arm = 1,2,3,4 에 따라 switch 문. material과 reward가 다름.
        switch (arm)
        {
            case 1:
                mesh.material = Gold;
                reward = 3;
                break;
            case 2:
                mesh.material = Bronze;
                reward = 1;
                break;
            case 3:
                mesh.material = Bronze;
                reward = 1;
                break;
            case 4:
                mesh.material = Silver;
                reward = 2;
                break;
        }
        // reward 반환
        return reward;
    }
    
    // 원래의 속성을 재설장하는 Reset 메서드
    public void Reset()
    {
        mesh.material = reset;
    }
}

이 코드는 switch 문을 이용하여 포암드 밴딧(four armed bandit)을 구현한다.

public class Bandit : MonoBehaviour {}

이 클래스가 'MonoBehaviour'에서 확장된 'Bandit'이라고 선언한다. 유니티의 모든 게임 오브젝트는 MonoBehaviour에서 확장된 것이다.

// Material 설정
public Material Gold;
public Material Silver;
public Material Bronze;

그리고 보상 값을 표시하는 데 사용되는 material들을 public 속성으로 정의한다. Gold, Silver, Bronze 이 세 가지가 있다.

 private MeshRenderer mesh;
 private Material reset;

'mesh'라는 MeshRenderer의 placeholder를 private 속성으로 정의한다. 그리고 reset이라고 부르는 원래의 Material도 private 속성으로 정의한다.
* placeholder는 별 게 아니라, 아무것도 입력하지 않았을 때에 채워져 있는 값이라고 보면 된다.

void Start () { 
	mesh = GetComponent<MeshRenderer>(); reset = mesh.material; 
}

그 다음으로 Start 메서드는 오브젝트가 시작될 때 실행되는 기본 유니티 메서드다. 우리는 여기서 오브젝트의 MeshRenderer를 기반으로 두 개의 private 필드 값을 정한다. GetComponent<>()를 이용해 MeshRenderer 컴퍼넌트를 mesh에 가져온다.

// Arm(레버)를 당길 때
public int PullArm(int arm) 
{ 
	// reward 변수 선언 및 초기화
	var reward = 0; 
    // arm = 1,2,3,4 에 따라 switch 문. material과 reward가 다름. 
    // arm의 개수가 4개 이므로 포암드 밴딧(four armed bandit)
    switch (arm) 
    { 
    	case 1:
        	mesh.material = Gold;
            reward = 3; 
            break; 
        case 2: 
        	mesh.material = Bronze;
        	reward = 1;
        	break;
        case 3:
        	mesh.material = Bronze; 
            reward = 1;
            break;
        case 4:
        mesh.material = Silver;
        reward = 2;
        break; 
   } 
   
   // reward 반환
   return reward; 
 }

그리고 arm의 값에 따라 적절한 Material과 reward를 설정하는 switch 문인 PullArm 메서드를 작성한다.

public void Reset()
{
	mesh.material = reset;
}

마지막으로 원래의 속성을 재설정 해주는 Reset 메서드로 마무리한다. 게임을 반복하려면 Reset을 해줘야 한다.

편집한 script를 Bandit 오브젝트에 드래그 앤 드롭하면 inspector에 Bandit (script)가 추가된다. 각각의 Material에 해당하는 머터리얼을 넣어주면 된다.

 

#5-1. Academy 설정

Academy 오브젝트/컴포넌트는 우리가 에이전트를 위한 훈련 환경구성을 정의하는 데 사용하는 훈련 환경을 나타낸다. 에이전트가 훈련받을 학원이라고 생각하면 된다. 그렇다. 한 마디로 에이전트의 학원이다.

하이어라키 창에서 Academy 오브젝트를 선택하면 inspector 창에서 아래의 사진과 같이 보인다.

Academy 컴포넌트의 각 속성을 한 번 보면 아래와 같다.

1. Max Steps(최대 단계)

이 속성으로 Academy는 각 agent가 실행되기 전에 자신을 재설정하는 행동의 횟수를 제한할 수 있다. 우리가 사용하는 예제에서는 우리가 하나의 step만 수행 중이므로 이 값을 0으로 둘 수 있다. max steps를 0으로 두면, Done이 호출될 때까지 에이전트가 무한히 행동을 반복한다.

2. Training Configuration(훈련 환경설정)

모든 머신러닝 문제는 훈련 세트(training set)과 테스트 세트(test set)로 나누어진다. 때문에 우리는 training 환경이나 training 데이터셋에서 머신러닝(에이전트) 모델을 구축할 수 있다. 모델을 구축한 후에 훈련된 머신러닝을 가져와서 추론을 사용해 실제 데이터셋에서 연습할 수 있다. Training Configuration 부분에서는 training 환경을 구성한다.

3. Inference Configuration(추론 환경설정)

추론 부분에서는 기존에 알지 못했던 환경이나 데이터셋에 대해 모델을 추론하거나 사용한다. 이 환경 설정 영역에서는 머신러닝이 이 유형의 환경에서 실행될 때 파라미터를 설정한다.

#5-2. Agent 설정

에이전트(agents)는 일부 보상에서 일부 태스크 또는 태스크 기반 명령 집합을 수행하는 방법을 배우도록 우리가 훈련하고 있는 연기자(actors)를 나타낸다. 행위자/대리자로도 불린다. 가상 세계나 인공지능 사용 환경 속에서 행위하는 주체, 또는 사람이나 그 외의 것을 대리하는 주체라는 뜻이다.
강화학습 분야에서는 이런 행위자를 행위의 유형에 따라 연기자(actors)와 비평가(critics)로 나누기도 하는데, 강화학습에 대한 2장에서 연기자, 행동, 상태 및 보상에 대해 더 자세히 다룰 것이다.

우선 이번에는 에이전트가 사용할 Brain(두뇌)을 설정해보자.

에이전트 스크립트는 우리가 환경을 관찰하고 관측한 내용을 수집하는 데 사용하는 스크립트이다. 지금 사용하는 예제에서 우리는 항상 이전에 관측한 내용이 없다고 가정한다.


SimpleAgent script에 아래의 코드를 입력한다.

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

public class SimpleAgent : Agent
{
    // Agent가 환경을 관측(observe)하는 대상을 설정하기 위해 호출하는 메서드
    // 모든 에이전트 단계 또는 에이전트 활동에서 호출됨
    public override void CollectObservations()
    {
        AddVectorObs(0); // float 값 0을 에이전트의 관측 컬렉션에 추가함
        // 이 시점에서 현재 우리는 어떤 관측도 하지 않고 있고, 밴딧도 시각적 정보를 제공하지 않는다고 가정한다.
    }

    // 에이전트는 보상(rewards)을 수집할 때, 해당 보상을 평가한다.
    // 팔을 당길 때 보상을 나타내기 위해 에이전트에게 각 팔 당 하나씩, 총 네 개의 슬롯을 추가해야 한다.
    public Bandit bandit;
    public override void AgentAction(float[] vectorAction, string textAction)
    {
        // 현재 행동을 취해 PullArm 메서드가 있는 Bandit에 적용해, 팔을 당기도록 전달한다.
        var action = (int)vectorAction[0];
        // 밴딧으로부터 반환된 보상은 AddReward를 사용해 추가된다.
        AddReward(bandit.PullArm(action));
        Done();
    }
    // 각 단계 후에 Done 메서드를 호출하는 것은 밴딧이 단일 state 또는 행동이기 때문이다.

    // 밴딧을 다시 시작 상태로 재설정함
    // 에이전트가 행동을 마치거나, 완성하거나, 단계를 벗어날 때 호출됨
    public override void AgentReset()
    {
        bandit.Reset();
    }

    public override void AgentOnDone()
    {

    }

    public Academy academy;
    public float timeBetweenDecisionsAtInference;
    private float timeSinceDecision;

    // brain이 플레이어의 결정을 받아들일 수 있을 만큼 오래 기다리게 하려면 아래의 코드가 필요함
    // 플레이어의 입력을 허용하기 위해서 아래의 코드가 필요
    // 나중에 에이전트의 brain을 개발할 때는 지연시키지 않아도 되니까 필요 없음
    // 이 예제에서는 플레이어가 입력한 것 사용함
    public void FixedUpdate()
    {
        WaitTimeInference();
    }

    private void WaitTimeInference()
    {
        if (!academy.GetIsInference())
        {
            RequestDecision();
        }
        else
        {
            if (timeSinceDecision >= timeBetweenDecisionsAtInference)
            {
                timeSinceDecision = 0f;
                RequestDecision();
            }
            else
            {
                timeSinceDecision += Time.fixedDeltaTime;
            }
        }
    }
}

AddVectorObs(0)에서 알파벳 O를 숫자 0으로 쓰는 바람에 디버깅에 한참 걸렸다. visual studio에서는 대체 왜 대문자 o와 0을 똑같이 만든 것일까? 

에이전트의 속성을 이렇게 바꿔준다.

에이전트는 이제 우리의 행동을 해석하고 Bandit에서 그것을 수행할 수 있다. 행동은 Brain으로부터 에이전트에게 보내진다. Brain이 의사결정을 담당하는데, 이제 그것을 설정하는 것을 배울 예정이다.

#5-3. Brain 설정

brain은 에이전트의 두뇌 역할을 하는 인공지능 알고리즘 혹은 인공지능 모델을 말한다. 앞서 봤듯이, brain의 종류는 Player, Heurisitc, Internal, External이 있다. player 브레인을 설정해보자. 플레이어가 입력하는 내역을 받아들이도록 brain 오브젝트를 설정한다.


brain 설정을 다음과 같이 해준다.


Play를 눌러 씬을 실행하면, A,S,D,F 키를 누를 때 Bandit은 보상에 따라 색깔을 바꾼다. 여기까지가 Player 브레인을 사용해 간단한 포암드 밴딧을 테스트해본 것이다.

 

순서대로 A, S, D, F 키를 눌렀을 때 잘 작동하는 것이 보인다.


#6. 연습문제

연습문제는 Heurisitc 브레인을 구현해보는 것이다. 휴리스틱 알고리즘을 사용해 항상 최고의 솔루션을 선택하는 SimpleDecision 스크립트를 구현해 보라.

 

이 문제를 풀기 위해서는 앞서서 휴리스틱 브레인을 사용해보았던 3DBall 예제에서 SimpleDecision 스크립트를 가져와야 한다.

 

사실 c# 언어를 몰라서 어떻게 풀어야할 지 모르겠다. 해답도 책에 없고 어떻게 나타나야 정답인 것인지 알 수 없어서 스킵한다. 

반응형

'Study > Unity' 카테고리의 다른 글

[유니티] #1. C# 프로그래밍 기초  (3) 2022.01.04
[유니티] #0. unity 준비 운동  (2) 2022.01.01