14. PPO Trainer 연결 및 학습 실행

date
3월 8, 2026
status
완료
tags
unrealRL

1. 소개#

이전 단계에서는 BP_SpiderTrainingManagerBeginPlay 안에서 PPO 학습에 필요한 핵심 객체들을 생성하고 연결하였다.

구체적으로는 Make Policy, Make Critic, Make PPOTrainer 노드를 추가하여, Observation을 바탕으로 Action을 출력할 Policy, 현재 상태의 가치를 평가할 Critic, 그리고 이 둘을 PPO 방식으로 학습시킬 Trainer를 준비하였다.

현재까지 구성한 학습 요소는 다음과 같다.

구성 요소역할
SpiderInteractorObservation 수집 및 Action 적용
SpiderTrainingEnvironmentReward, Completion, Reset 처리
SpiderPolicyObservation을 입력받아 Action 출력
SpiderCritic현재 상태의 가치 평가
SpiderPPOTrainerPolicy와 Critic을 PPO 방식으로 학습

하지만 여기까지는 아직 학습이 실제로 실행되는 단계는 아니다.

Make PPOTrainer는 PPOTrainer 객체를 생성하고 필요한 구성 요소를 연결하는 역할을 한다.

즉, 학습을 실행할 준비를 하는 단계이지, 실제로 매 프레임마다 경험을 수집하고 Policy를 업데이트하는 단계는 아니다.

따라서 이번 단계에서는 생성한 SpiderPPOTrainer를 사용하여 실제 학습 루프를 실행하는 과정을 구성한다.

학습 실행 흐름은 다음과 같이 정리할 수 있다.

flowchart TD
    A[Event Tick] --> B[Run Training]
    B --> C[Observation 수집]
    C --> D[Policy Action 출력]
    D --> E[Interactor가 로봇에 Action 적용]
    E --> F[Physics Simulation 진행]
    F --> G[Reward 계산]
    G --> H[Completion 판단]
    H --> I{Episode 종료?}
    I -- 아니오 --> C
    I -- 예 --> J[Reset Agent Episode]
    J --> C

여기서 핵심은 Run Training이다.

Run Training은 PPOTrainer를 대상으로 호출되며, 학습 과정에서 필요한 Observation 수집, Action 추론, Reward 계산, Completion 판단, Episode Reset, 경험 처리 등을 반복적으로 수행하는 역할을 한다.

즉, 지금까지 만든 구성 요소들이 다음과 같이 실제 학습 루프 안에서 사용된다.

단계사용되는 구성 요소
Observation 수집SpiderInteractor
Action 출력SpiderPolicy
Action 적용SpiderInteractor
Reward 계산SpiderTrainingEnvironment
Completion 판단SpiderTrainingEnvironment
Reset 처리SpiderTrainingEnvironment
Policy 업데이트SpiderPPOTrainer
Value 평가SpiderCritic

이번 페이지에서는 SpiderPPOTrainer를 실제 학습 루프에 연결하고, 첫 번째 PPO 학습 실행이 가능한 상태까지 구성하는 것을 목표로 한다.


2. 구현#

2.1. Run Training 노드 추가#

Run Training은 PPOTrainer를 대상으로 호출하는 노드이며, 기본적인 학습 루프를 실행하는 역할을 한다.

공식 문서 기준으로 Run Training은 처음 호출될 때 학습을 시작하고 RunInference를 호출한다.

그 이후부터는 호출될 때마다 GatherRewards, GatherCompletions, ProcessExperience, RunInference를 순서대로 실행한다.

즉, 이 노드가 호출되어야 지금까지 만든 다음 함수들이 실제 학습 과정에서 반복적으로 사용된다.

호출되는 기능역할
RunInference현재 Policy를 사용해 Action 출력
GatherRewardsTraining Environment에서 Reward 수집
GatherCompletionsEpisode 종료 여부 확인
ProcessExperience수집한 경험을 학습 데이터로 처리
RunInference다음 Action 추론

따라서 이번 단계에서는 Event Tick에서 Run Training을 호출하도록 구성해주자


1. Event Tick 사용#

BP_SpiderTrainingManager의 Event Graph에는 기본적으로 Event Tick 노드가 존재한다.

현재 Event Tick이 회색으로 비활성화되어 보일 수 있는데, 이는 실행 핀이 아무 노드에도 연결되어 있지 않기 때문이다.

Event Tick의 실행 핀을 Run Training 노드에 연결하면 활성화된다.

Run Training은 한 번만 실행하고 끝나는 노드가 아니라, 학습 중 매 프레임 반복 호출되어야 한다.

따라서 BeginPlay가 아니라 Event Tick에서 호출하는 방식으로 구성한다.

flowchart LR
    A[Event Tick] --> B[Run Training]

2. Run Training 노드 추가#

  • 변수 목록에서 SpiderPPOTrainer 변수를 Event Graph로 드래그(Get)

  • Get SpiderPPOTrainer의 파란 출력 핀에서 드래그 → Run Training 노드 추가

  • Event Tick/실행핀 → Run Training 실행 입력핀 연결

    Run Training의 Target은 어떤 PPOTrainer를 실행할지를 지정하는 입력이다.

    앞 단계에서 Make PPOTrainer로 생성한 Trainer를 SpiderPPOTrainer 변수에 저장했으므로, 이 변수를 Run Training의 Target에 연결해주자


3. Run Training 입력값 확인#

  • Run Training 노드에는 다음 입력값이 존재한다

    Run Training 핀설정
    TargetSpiderPPOTrainer
    Trainer Training Settings우선 기본값 사용
    Training Game Settings우선 기본값 사용
    Reset Agents on Begin체크
    Reset Agents on Update체크

    Trainer Training SettingsTraining Game Settings는 학습 실행 방식과 게임 시뮬레이션에 영향을 주는 설정값이다.

  • 컴파일 후 실행


2.2. 첫 실행 및 유효성 검사 로직 추가#

  • Run Training 노드까지 연결한 뒤 컴파일을 진행하였고, 컴파일 자체는 정상적으로 완료되었다.

  • 이후 Play를 실행하여 PPO 학습 루프가 실제로 호출되는지 확인하였다.

  • 하지만 실행 직후 Output Log에서 다음과 같은 런타임 오류가 반복적으로 발생하였다.

  • 첫 실행 출력 로그 확인

    PIE: Error: 블루프린트 런타임 오류: "BP_SpiderTrainingManager_C의 (real) 프로퍼티 SpiderPPOTrainer을(를) 읽으려고 시도하는 동안 None에 액세스했습니다.". 노드:  Run Training 그래프:  EventGraph 함수:  Execute Ubergraph BP Spider Training Manager 블루프린트:  BP_SpiderTrainingManager
    PIE: Error: 블루프린트 런타임 오류: "BP_SpiderTrainingManager_C의 (real) 프로퍼티 SpiderPPOTrainer을(를) 읽으려고 시도하는 동안 None에 액세스했습니다.". 노드:  Run Training 그래프:  EventGraph 함수:  Execute Ubergraph BP Spider Training Manager 블루프린트:  BP_SpiderTrainingManager
  • 이 오류는 Run TrainingEvent Tick에서 매 프레임 호출되는데, 그 시점에 SpiderPPOTrainer 변수가 아직 유효한 객체를 가지고 있지 않기 때문에 발생한 것이다.

  • 즉, Run Training 자체가 잘못된 것이 아니라, Target으로 전달한 SpiderPPOTrainerNone인 상태에서 호출된 것이 문제였다.


1. 문제 원인#

  • 현재 Run Training은 다음과 같이 연결되어 있었다.

    Event Tick
    → Run Training

    그리고 Run TrainingTarget에는 SpiderPPOTrainer 변수를 연결하였다.

    SpiderPPOTrainer
    → Run Training / Target
  • 하지만 SpiderPPOTrainerBeginPlay에서 Make PPOTrainer를 통해 생성된 뒤 변수에 저장된다. 따라서 다음과 같은 상황에서는 SpiderPPOTrainer가 아직 유효하지 않을 수 있다.

    가능성설명
    Make PPOTrainer 생성이 실패한 경우Communicator, Trainer Settings 등 필수 설정 문제로 Trainer가 생성되지 않을 수 있음
    BeginPlay 흐름이 끝나기 전에 Tick이 먼저 실행된 경우Tick에서 아직 설정되지 않은 변수를 읽을 수 있음
    BeginPlay 실행선이 중간에서 끊긴 경우Set SpiderPPOTrainer까지 도달하지 못함

    이 상태에서 Event Tick이 계속 Run Training을 호출하면, 매 프레임마다 같은 None 오류가 반복된다.


2. Branch와 Is Valid 추가#

  • 이를 방지하기 위해 Run Training 앞에 유효성 검사 로직을 추가해주자

  • 처음에는 Event Tick이 바로 Run Training을 호출하고 있었지만, 이를 다음과 같이 수정

    Event Tick
    → Branch
    → Run Training
  • 그리고 SpiderPPOTrainer 변수를 Is Valid 노드에 연결

    SpiderPPOTrainer
    → Is Valid / Object
  • Is Valid의 반환값은 Boolean이므로, 이 값을 BranchCondition에 연결

    Is Valid / Return Value
    → Branch / Condition
  • 마지막으로 BranchTrue 실행 핀만 Run Training에 연결

    Branch / True
    → Run Training / 입력 실행핀
  • 최종 연결

    flowchart LR
        A[Event Tick] --> B[Branch]
        C[SpiderPPOTrainer] --> D[Is Valid]
        D --> B
        B -- True --> E[Run Training]
        C --> E


3. 이 수정의 의미#

  • 이 수정은 SpiderPPOTrainer가 정상적으로 생성된 경우에만 Run Training을 실행하도록 만드는 안전장치이다.

    조건동작
    SpiderPPOTrainer가 유효함Run Training 실행
    SpiderPPOTrainer가 NoneRun Training 실행하지 않음
  • 따라서 BeginPlay에서 PPOTrainer 생성이 실패했거나 아직 생성되지 않은 상태에서는 Run Training이 호출되지 않는다.

    이렇게 하면 None 상태의 SpiderPPOTrainer를 대상으로 Run Training을 실행하면서 발생하던 런타임 오류를 막을 수 있다.

  • 컴파일 후 실행


2.3. 실제 학습 실행 설정 연결#

Run Training이 정상적으로 호출되는 구조까지 만들었으므로, 이제 실제 PPO 학습을 실행하기 위한 설정값을 연결해보자

1. Run Training의 빈 Settings 핀 채우기#

  • Run Training 노드에는 학습 실행과 관련된 입력값이 존재한다.

    입력역할
    Trainer Training SettingsPPO 학습이 어떤 방식으로 진행될지 설정
    Training Game Settings학습 중 게임 시뮬레이션이 어떻게 동작할지 설정
    Reset Agents on Begin학습 시작 시 Agent를 초기화할지 여부
    Reset Agents on Update학습 업데이트 시 Agent Reset을 사용할지 여부
  • 이 중,

    Trainer Training Settings
    Training Game Settings

    이 두 개를 채워야 “그냥 호출되는 상태”에서 “학습 실행 설정을 가진 상태”로 넘어간다.

  • Run Training 노드의 Trainer Training Settings 핀에서 드래그해서 검색 → Make Learning Agents Training Game Settings 노드 추가

  • Run Training 노드의 Trainer Training Settings 핀에서 드래그해서 검색 →Make Learning Agents PPO Training Settings 노드 추가

  • 연결 구조

  • 컴파일 후 실행


2.4. 실행 결과 영상#

  • 영상

  • 학습 실행을 종료한 뒤에도 Unreal Editor는 개발 환경과 렌더링 리소스를 유지하기 위해 일정량의 VRAM을 계속 점유한다. VRAM을 완전히 해제하려면 Unreal Editor를 종료한 뒤 다시 실행하면 된다.


3. 후기#

  • 이번 단계에서는 SpiderPPOTrainer를 실제 학습 루프에 연결하고, Run Training을 통해 PPO 학습 실행이 가능한 상태까지 구성하였다.

    이전 단계까지는 Make Policy, Make Critic, Make PPOTrainer를 통해 PPO 학습에 필요한 구성 요소를 생성하는 것까지만 진행하였다. 하지만 이것만으로는 학습이 자동으로 실행되지 않기 때문에, 이번 단계에서는 Event Tick에서 Run Training을 호출하도록 구성하였다.

  • 처음에는 Run TrainingTarget에 연결한 SpiderPPOTrainerNone 상태로 남아 런타임 오류가 발생하였다.

    SpiderPPOTrainer를 읽으려고 시도하는 동안 None에 액세스했습니다.

    이 문제를 해결하기 위해 Is ValidBranch를 추가하여, SpiderPPOTrainer가 정상적으로 생성된 경우에만 Run Training이 실행되도록 구성하였다.

    또한 Make PPOTrainerClass 값이 비어 있으면 PPOTrainer 객체가 정상적으로 생성되지 않을 수 있다는 점을 확인하고, LearningAgentsPPOTrainer 클래스를 명시적으로 지정하였다.

  • 이후에는 Communicator’s Trainer is nullptr 오류가 발생하였다.

    이는 PPOTrainer가 외부 학습 프로세스와 통신할 Trainer Process를 찾지 못한다는 의미였다.

    처음에는 Make Shared Memory Communicator를 사용하려고 했지만, 실제 연결 과정에서 타입이 맞지 않는 문제가 있었다.

    최종적으로는 Make Shared Memory Training ProcessReturn ValueMake PPOTrainerCommunicator 핀에 직접 연결하는 방식으로 수정하였다.

  • 마지막으로 Run TrainingTrainer Training SettingsTraining Game Settings를 연결하여 실제 학습 실행에 필요한 설정값을 전달하였다.

  • 최종적으로 구성된 학습 실행 흐름은 다음과 같다.

    flowchart TD
        A[BeginPlay] --> B[Make Policy]
        B --> C[Make Critic]
        C --> D[Make Shared Memory Training Process]
        D --> E[Make PPOTrainer]
        E --> F[Set SpiderPPOTrainer]
    
        G[Event Tick] --> H[Is Valid: SpiderPPOTrainer]
        H --> I{Valid?}
        I -- True --> J[Run Training]
        I -- False --> K[Skip]

    이후 Play를 실행하자 로봇의 관절이 실제로 움직이는 것을 확인하였다.

    이는 다음 흐름이 실제로 연결되었음을 의미한다.

    Run Training 실행
    → Policy Action 출력
    → Interactor가 Action 적용
    → SpiderJointController가 관절 제어
    → 로봇 물리 움직임 발생
  • 현재 실행 결과에서 로봇은 안정적으로 걷기보다는 몸체가 흔들리고 다리가 불규칙하게 움직이는 모습을 보였다. 이는 아직 Policy가 충분히 학습되지 않은 초기 상태이기 때문에 자연스러운 결과이다.

    이번 단계에서 중요한 것은 로봇이 바로 걷는 것이 아니라, PPO 학습 실행 구조가 실제 로봇 제어까지 연결되었는지를 확인하는 것이었기 때문이다.

  • 다음 단계에서는 학습을 더 오래 실행하면서 Reward 값이 제대로 작동하는지 확인하고, 로봇이 단순히 버둥거리는 상태에서 벗어나 전방으로 이동하는 방향으로 학습되는지 확인해야 한다.

  • 이후 조정해야 할 주요 항목은 다음과 같다.

    조정 항목목적
    ForwardRewardScale전방 이동 보상을 얼마나 강하게 줄지 조정
    TiltPenaltyScale몸체 기울기 패널티 강도 조정
    ActionScale관절 움직임의 크기 조정
    MaxTiltAngleForCompletion넘어짐 판정 기준 조정
    ResetLocation, ResetRotationEpisode 시작 자세 안정화
    Episode 길이너무 빨리 끝나거나 너무 오래 실패 상태가 유지되는 문제 조정
    학습 시간 / IterationPolicy가 개선될 만큼 충분한 경험 수집
  • 다음 단계에서는 첫 학습 결과를 바탕으로 Reward와 Action Scale을 조정하면서, 평지에서 안정적인 보행을 유도하는 방향으로 학습을 개선해볼 예정이다.

Be Your Own Lamp