유니티 머신러닝 개발 ML Agents 8편, 목표 찾기 예제 개선. 2 floor 확장, 복잡한 바닥 형태 테스트와 학습의 한계점
저번 글에서는, 이쁘게 꾸며보고, 에이전트가 타겟을 바라보며 갈 수 있게 구성하였습니다.
그래서 모델이 회전을하지 못하는 제한을 설정했고요
그로 인해 변경된 환경 때문에 세팅을 바꾸고 다시 교육을 시키는 내용을 진행했었죠.
이번에도 환경에 대한 변화를 줘 보도록 하겠습니다
이번에는 floor를 확장시켜 봅시다.
floor의 Transform의 Scale를 2,1,2로 수정합니다. 위의 자료 참고하여서
이후 플레이해봅니다.
넓어진 플로어에서 활동하는 에이전트를 보실 수 있습니다.
하지만 타깃이 한정적으로 설치되기 때문에 에이전트가 활동하는 반경은, 기존 floor 사이즈로 제한되어 보입니다.
타겟이 설치되는 소스를 변경해봅시다.
gRollerAgent.cs 의 다음 함수를 수정할 것입니다.
public override void OnEpisodeBegin()
{
//새로운 애피소드 시작시, 다시 에이전트의 포지션의 초기화
// If the Agent fell, zero its momentum
if (this.transform.localPosition.y < 0) //에이전트가 floor 아래로 떨어진 경우 추가 초기화
{
this.rBody.angularVelocity = Vector3.zero;
this.rBody.velocity = Vector3.zero;
this.transform.localPosition = new Vector3(0, 0.5f, 0);
}
//타겟의 위치는 에피소드 시작시 랜덤하게 변경된다.
// Move the target to a new spot
Target.localPosition = new Vector3(Random.value * 8 - 4,
0.5f,
Random.value * 8 - 4);
}
Target.localPosition = new Vector3(Random.value * 8 - 4,
0.5f,
Random.value * 8 - 4);
//위 해당 코드를 아래 코드로 변경합니다.
//수치만 조절하였습니다.
Target.localPosition = new Vector3(Random.value * 18 - 9,
0.5f,
Random.value * 18 - 9);
변경 후 코드 전체
public override void OnEpisodeBegin()
{
//새로운 애피소드 시작시, 다시 에이전트의 포지션의 초기화
// If the Agent fell, zero its momentum
if (this.transform.localPosition.y < 0) //에이전트가 floor 아래로 떨어진 경우 추가 초기화
{
this.rBody.angularVelocity = Vector3.zero;
this.rBody.velocity = Vector3.zero;
this.transform.localPosition = new Vector3(0, 0.5f, 0);
}
//타겟의 위치는 에피소드 시작시 랜덤하게 변경된다.
// Move the target to a new spot
Target.localPosition = new Vector3(Random.value * 18 - 9,
0.5f,
Random.value * 18 - 9);
}
이후 다시 실행해 봅니다.
우리 타깃을 잘 찾아오던 에이전트가 뭔가 이상해졌습니다.
타깃이 외각으로 배치되면 망설이는 모습을 보여주는 에이전트...
이 또한 환경의 변화입니다.
에이전트가 이전 floor 크기에서 학습을 했기 때문에, 현재 floor 크기에서는 정상 작동하지 않는 것입니다.
이전 플로어에서 떨어지는 경험을 하면 에피소드가 리셋되고 보상을 못 받았기 때문에, 그 경험을 하지 않으려 하는 것으로 해석됩니다.
현재 플로어를 기준으로 재교육을 시켜야 할 듯하네요, 그럼 이전의 교육된 상태 가지는 기대하실 수 있을 겁니다.
추가적으로 교육에 소요되는 시간은 늘어날 것입니다.
조금 복잡한 플로어를 제작하고, 에이전트를 다시 교육시켜 보겠습니다.
FloorGroup이라는 빈 오브젝트를 만들고
9장을 복사하여 깔고, 가운데를 비활성화시켜서 비 줬습니다.
포지션은 -10,0,-10 ~ 10,0,10 (중점, transform Position)입니다.
에이전트의 초기 위치를 수정해 주겠습니다.
에이전트가 낙하 이후 부활하는 위치도 수정하겠습니다.
gRollerAgent.cs
public override void OnEpisodeBegin()
{
//새로운 애피소드 시작시, 다시 에이전트의 포지션의 초기화
// If the Agent fell, zero its momentum
if (this.transform.localPosition.y < 0) //에이전트가 floor 아래로 떨어진 경우 추가 초기화
{
this.rBody.angularVelocity = Vector3.zero;
this.rBody.velocity = Vector3.zero;
this.transform.localPosition = new Vector3(10, 0.5f, 0);
}
//타겟의 위치는 에피소드 시작시 랜덤하게 변경된다.
// Move the target to a new spot
Target.localPosition = new Vector3(Random.value * 18 - 9,
0.5f,
Random.value * 18 - 9);
}
this.transform.localPosition = new Vector3(0, 0.5f, 0);
에서
this.transform.localPosition = new Vector3(10, 0.5f, 0);
으로 수정합니다.
플레이해보면 가운데 구멍에서 에이전 트까 빠져서 에피소드가 다시 시작되는 것 보실 수 있습니다.
이번에는 적당히 타깃이 구멍 위에 설치되지 않도록 코딩해 보겠습니다.
위의 함수입니다.
변경 후 함수 가져다 두겠습니다.
public override void OnEpisodeBegin()
{
//새로운 애피소드 시작시, 다시 에이전트의 포지션의 초기화
// If the Agent fell, zero its momentum
if (this.transform.localPosition.y < 0) //에이전트가 floor 아래로 떨어진 경우 추가 초기화
{
this.rBody.angularVelocity = Vector3.zero;
this.rBody.velocity = Vector3.zero;
this.transform.localPosition = new Vector3(10, 0.5f, 0);
}
//타겟의 위치는 에피소드 시작시 랜덤하게 변경된다.
// Move the target to a new spot
float rx = 0;
float rz = 0;
while (true)
{
rx = Random.value * 18 - 9;
if (rx > 6 || rx < -6)
break;
}
while (true)
{
rz = Random.value * 18 - 9;
if (rz > 6 || rz < -6)
break;
}
Target.localPosition = new Vector3(rx,
0.5f,
rz);
}
6이라는 수치는 눈 대충으로 넣은 것입니다.
여러분의 프로젝트에 맞추시면 좋을듯합니다.
판 아래로 떨어지는 것에 대한 확실한 마이너스 보상 또한 주었습니다.
public override void OnActionReceived(ActionBuffers actionBuffers)
{
//학습을 위한, 학습된 정보를 해석하여 이동을 시킨다.
// Actions, size = 2
Vector3 controlSignal = Vector3.zero;
controlSignal.x = actionBuffers.ContinuousActions[0];
controlSignal.z = actionBuffers.ContinuousActions[1];
rBody.AddForce(controlSignal * forceMultiplier);
viewModel.transform.LookAt(Target);
// Rewards
float distanceToTarget = Vector3.Distance(this.transform.localPosition, Target.localPosition);
//타겟을 찻을시 리워드점수를 주고, 에피소드를 종료시킨다.
// Reached target
if (distanceToTarget < 1.42f)
{
SetReward(1.0f);
EndEpisode();
}
//판 아래로 떨어지면 학습이 종료된다.
// Fell off platform
else if (this.transform.localPosition.y < 0)
{
SetReward(-0.1f);
EndEpisode();
}
}
SetReward(-0.1f);
추가된 코드
교육을 해봅니다.
50만 스텝을 수행하여 보았습니다.
아래 참조
보상수치가 0.4 정도 가지 올라온 모습을 보여줍니다.
여러 벌의 수행장을 만드는 것 또한 이후 설명드릴게요
에이전트는 중앙을 돌파하지 못하는 능력을 보여주며, 우측 자기 주변에 목표가 있을 때만 비교적 정상 독작하는 모습을 보여주었습니다. 보상 수치가 0.4라는 것이 이해가 가는 모습
강화 학습이 만능이 아닙니다.
지금 우리가 제공하고 있는 관측치는 다음의 소스입니다.
public override void CollectObservations(VectorSensor sensor)
{
//타겟과 에이전트의 포지션을 전달한다.
// Target and Agent positions
sensor.AddObservation(Target.localPosition);
sensor.AddObservation(this.transform.localPosition);
//현재 에이전트의 이동량을 전달한다.
// Agent velocity
sensor.AddObservation(rBody.velocity.x);
sensor.AddObservation(rBody.velocity.z);
}
타깃과 에이전트의 위치와
현제 에이전트의 이 동량입니다.
제대로 된 학습이 이루어지기 위해선 더 많은 정보를 학습 프로그램에 알려줄 필요가 있습니다.
이와 같은 경우에는 지형의 정보가 넘어갈 수 있으면 좋겠네요.
추가적인 정보를 제공하는 방법은 다양하게 존재합니다.
이후로도 이어 나가 보도록 하겠습니다.
댓글