강의자료 · 전기공학을 위한 강화학습

Isaac Lab과 Robot Simulation · 학습

실행 조건

이번에 배울 내용

새 Simulator의 예제를 실행하는 데서 멈추지 않고, 내 연구 Task에서 바꿔야 할 관측·행동·물리를 찾습니다.

Simulator의 구성

Task는 관측·행동·Reward·Reset·Termination을 정의합니다. Physics backend는 물리 계산을, Renderer는 영상 생성을, RL library는 정책 학습을 담당합니다.

주기의 대응

물리 Step과 정책의 제어 주기는 같지 않을 수 있습니다. Action scale·Joint 단위·Control decimation을 맞춰야 다른 Simulator나 로봇으로 정책을 옮길 수 있습니다.

장비 경로

기본 CPU 경로에서도 Transition 분석과 Task 구성 대응을 수행합니다. GPU가 준비되면 개인 장비를 우선 활용하고 공용 환경으로 보완합니다.

Jetson은 정책 추론·지연 측정 단계에 활용하되 Simulator 호환성을 별도로 확인합니다.

풀이 예제

CartPole-v1의 관측·행동·Reset·시간 제한을 출발점으로 삼습니다.

"""Small public-environment benchmark; evaluation traces are ordinary numeric arrays."""
import json
from importlib.metadata import version
from pathlib import Path
import numpy as np
import gymnasium as gym

def collect(env_id='CartPole-v1', policy=None, seeds=range(100,103)):
    env=gym.make(env_id); transitions=[]; summary=[]
    for seed in seeds:
        obs,info=env.reset(seed=seed);env.action_space.seed(seed);total=0.;length=0
        while True:
            action=env.action_space.sample() if policy is None else policy(obs)
            nxt,reward,terminated,truncated,info=env.step(action)
            transitions.append((obs.copy(),np.asarray(action).copy(),reward,nxt.copy(),terminated,truncated,seed))
            obs=nxt;total+=reward;length+=1
            if terminated or truncated:break
        summary.append([seed,total,length,int(terminated),int(truncated)])
    env.close()
    columns=list(zip(*transitions))
    data={k:np.asarray(v) for k,v in zip(['observations','actions','rewards','next_observations','terminated','truncated','episode_seed'],columns)}
    return np.asarray(summary),data

def cartpole_rule(obs):return int(obs[2]+.25*obs[3]>0)
def zero_torque(obs):return np.zeros(1,dtype=np.float32)

def save_trace(path, env_id, data, policy_name, seeds):
    # Contains numeric arrays and JSON text only; never requires pickle.
    metadata=dict(env_id=env_id,policy=policy_name,seeds=list(seeds),gymnasium=version('gymnasium'))
    np.savez_compressed(path,**data,metadata_json=np.array(json.dumps(metadata)))
    with np.load(path,allow_pickle=False) as saved:
        assert len(saved['observations'])==len(saved['rewards'])
        print(json.loads(str(saved['metadata_json'])))

def public_model(algorithm='DQN',env_id='CartPole-v1',seed=7,steps=2048,**changes):
    from stable_baselines3 import DQN,PPO,SAC
    options=dict(policy_kwargs=dict(net_arch=[32,32]),seed=seed,verbose=0,device='cpu')
    if algorithm=='DQN':options.update(buffer_size=5000,learning_starts=100,target_update_interval=100,batch_size=32)
    if algorithm=='PPO':options.update(n_steps=128,batch_size=64,n_epochs=3)
    if algorithm=='SAC':options.update(buffer_size=5000,learning_starts=100,batch_size=64)
    options.update(changes)
    env=gym.make(env_id)
    model={'DQN':DQN,'PPO':PPO,'SAC':SAC}[algorithm]('MlpPolicy',env,**options)
    model.learn(total_timesteps=steps)
    env.close()
    return model

print('Gymnasium',version('gymnasium'))
env=gym.make('CartPole-v1')
print('Observation:',env.observation_space,'Action:',env.action_space,'Limit:',env.spec.max_episode_steps)
env.close()
# For visual inspection, create a separate env with render_mode='rgb_array'.
# Rendering requires gymnasium[classic-control]; do not render every training step.

rows,trace=collect(policy=cartpole_rule,seeds=[100]);print(rows)
Gymnasium 1.3.0
Observation: Box([-4.8               -inf -0.41887903        -inf], [4.8               inf 0.41887903        inf], (4,), float32) Action: Discrete(2) Limit: 500
[[100. 500. 500.   0.   1.]]

공식 문서·데이터