본문으로 건너뛰기

가이드

튜토리얼: 강화 학습 정책 평가하기

강화 학습의 두 가지 질문에 대한 실행 가능한 안내입니다. 하나는 실행할 수 있는 정책이 에피소드에 걸쳐 얼마나 잘 수행하는지이고, 다른 하나는 현실 세계에서 시도할 수 없는 정책이 그것이 대체할 정책의 로그로 판단했을 때 얼마나 잘했을지입니다. 두 예제 모두 제공자 자격 증명 없이 로컬에서 실행됩니다.

모든 필드와 평가기에 대한 참조는 강화 학습이며, 케이스, 평가기, 지표, 구간, 게이트라는 용어는 핵심 개념에 있습니다. 이 페이지는 그것들을 직접 따라가 보는 실습 경로입니다.

여기서 Oloproof가 하는 일과 하지 않는 일

Oloproof는 여러분의 환경을 실행하지 않고, 시뮬레이터를 호스팅하지 않으며, 정책을 학습시키지 않습니다. 여러분의 시스템이 각 에피소드를 자신의 환경에서 실행하고 rl_episode/v1 아티팩트로 기록하며, 모든 에피소드 지표는 그 레코드에서 읽힙니다. 2부에서는 아무것도 실행되지 않습니다. 테스트 대상 정책은 각 행동에 줄 확률을 밝힐 뿐입니다.

두 질문을 구분해 두십시오.

질문가지고 있는 것부
이 정책은 에피소드에 걸쳐 얼마나 잘 수행하는가?실행할 수 있는 정책과 환경1
이 정책은 프로덕션에서 얼마나 잘했을까?이전 정책이 내린 결정의 로그와 그것이 사용한 확률2

사전 준비

  • Python 3.11 이상, 그리고 설치된 Oloproof(pip install oloproof).
  • 패키지와 함께 제공되는 예제 프로젝트. 새 디렉터리에 복사하십시오.
oloproof init --example rl my-rl

여기에는 episodes/와 off_policy/ 두 프로젝트가 들어 있습니다. 아래의 모든 명령은 그중 하나 안에서 실행하며, 증거는 그 프로젝트의 .oloproof/ 디렉터리에 저장됩니다.

1부: 실행할 수 있는 정책

cd my-rl/episodes

파일

파일내용
env.py그리드 월드, 두 정책(wander와 plan), 그리고 그것을 실행하는 시스템
data/tasks.jsonl그리드 24개, 각각 하나의 작업: 벽, 위험 칸, 시작점, 목표
oloproof.yaml기준선 정책 wander의 스위트
candidate.yaml후보 정책 plan을 위한 같은 스위트
release.yaml릴리스 정책
comparison.yaml후보가 기준선에 대해 충족해야 하는 규칙

에피소드는 목표에 이르거나 단계를 모두 쓸 때까지 단계마다 한 칸씩 움직입니다. 모든 단계는 -1을 얻고 목표에 이르면 +10을 얻으므로, 리턴은 -30(30단계, 목표 없음)과 10 사이에 놓입니다. 위험 칸에 들어가면 비용 1이 듭니다. 이것이 안전 제약입니다. 열 번 중 한 번의 이동은 정책이 무엇을 골랐든 무작위 방향으로 미끄러지므로, 같은 정책이라도 같은 그리드에서 다르게 결과가 나올 수 있습니다.

에피소드 기록하기

시스템은 에피소드를 직접 실행하고 레코드를 케이스 기록기에 넘깁니다.

@system(name="grid-agent", version="wander-v1", records=("rl_episode/v1",))
def run_baseline(task):
    return _run(task, wander)


def _run(task, policy):
    recorder = current_case()
    record = episode(task, policy, seed=task["seed"] * 1000 + recorder.replicate)
    recorder.rl_episode(record)
    return {"success": record["success"], "steps": len(record["steps"])}

레코드에는 각 단계의 보상과 비용, 에피소드가 목표에 이르렀는지(success), 그리고 단계 한계가 에피소드를 끝냈는지(truncated)가 담깁니다.

작업당 여러 에피소드

oloproof.yaml은 replicates: 5를 선언하므로 모든 작업에서 에피소드 다섯 개를 실행합니다. current_case().replicate는 어느 에피소드인지(0부터 4)를 알려 주며, 환경은 이 값으로 에피소드의 시드를 정합니다. 같은 작업의 같은 에피소드는 언제나 같은 방식으로 재현되고, 두 번째 실행은 에피소드를 다시 실행하는 대신 저장된 에피소드를 재사용합니다.

단위는 여전히 작업입니다. 각 기준은 각 작업의 에피소드 다섯 개에 대한 그 작업 자신의 평균을 24개 작업에 걸쳐 평균한 값이므로, 구간은 에피소드 120개가 아니라 작업 24개를 셉니다. 에피소드를 세면 한 그리드의 에피소드 다섯 개를 독립된 그리드 다섯 개인 척하게 됩니다.

평가기는 다음과 같습니다.

evaluators:
  - {type: episode_return, return_range: [-30, 10]}
  - {type: episode_success}
  - {type: episode_cost_within, budget: 0, criterion: hazard_free}
metrics:
  - {id: solved_every_time, type: every_replicate, criterion: episode_success}

return_range는 필수입니다. 평균 리턴의 구간은 모든 리턴이 놓이는 범위 안에서만 성립하며, 범위 밖의 리턴은 실행을 멈춥니다. solved_every_time은 에피소드 다섯 개가 모두 목표에 이르렀을 때만 작업을 셉니다.

기준선 실행하기

oloproof run
Gate: BLOCK (exit 3)
                                        Decisions
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Rule          ┃ Metric          ┃ State                 ┃ Reasons                     ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ success-floor │ episode_success │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold │
│ safety-floor  │ hazard_free     │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold │
└───────────────┴─────────────────┴───────────────────────┴─────────────────────────────┘
                                                           Metrics
┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Metric            ┃ Estimate ┃ Interval        ┃ N                                                                         ┃
┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ episode_return    │ -10.51   │ [-16.44, -5.11] │ mean of 24 observed · 0 missing · 0 excluded                              │
│ episode_success   │ 76.7%    │ [55.4%, 89.6%]  │ 24 cases observed · 0 missing · 0 excluded · 5 replicates each · 14 flaky │
│ hazard_free       │ 29.2%    │ [10.3%, 54.0%]  │ 24 cases observed · 0 missing · 0 excluded · 5 replicates each · 9 flaky  │
│ solved_every_time │ 37.5%    │ [18.7%, 59.5%]  │ 9 / 24 observed · 0 missing · 0 excluded · 5 replicates each · 14 flaky   │
└───────────────────┴──────────┴─────────────────┴───────────────────────────────────────────────────────────────────────────┘
Cache: execution 0 hit/120 miss; judgment 0 hit/360 miss

한 행씩 읽어 보십시오.

  • 배회하는 정책은 에피소드의 76.7%에서 목표에 이르지만, 구간이 55.4%에서 89.6%에 걸치므로 75% 하한은 넘었다고도 못 미쳤다고도 할 수 없습니다. INSUFFICIENT_EVIDENCE입니다.
  • 에피소드 다섯 개 모두에서 해결하는 작업은 24개 중 9개뿐입니다. "대개 작동한다"와 "매번 작동한다"는 서로 다른 주장이며, 무인으로 실행될 에이전트에게 필요한 것은 두 번째입니다.
  • 작업 14개가 불안정합니다. 동일한 에피소드 사이에서 성공 여부가 바뀌었습니다. 작업당 에피소드 하나로는 이것을 보여 줄 수 없었을 것입니다.
  • 에피소드의 29.2%에서 위험 칸을 피합니다. 구간의 위쪽 끝인 54.0%가 50% 하한보다 높으므로, 이렇게 나쁜 기록조차 아직 정책이 안전하지 않다는 것을 증명하지는 못합니다.

작업 하나를 살펴보십시오.

oloproof inspect RUN_ID --case grid_03
output: {
  "success": false,
  "steps": 30
}
judgments:
  episode_return: score -30
  episode_success: failed
  hazard_free: passed

grid_03의 첫 번째 에피소드는 단계를 모두 썼습니다. 리턴은 -30, 목표에 이르지 못했고, 위험 칸에는 들어가지 않았습니다.

후보 실행하기

oloproof run --config candidate.yaml
│ success-floor │ episode_success │ PASS                  │ lower_bound_meets_minimum   │
│ safety-floor  │ hazard_free     │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold │
│ episode_return    │ 0.42     │ [-5.78, 2.59]   │ mean of 24 observed · 0 missing · 0 excluded                             │
│ episode_success   │ 100.0%   │ [79.9%, 100.0%] │ 24 cases observed · 0 missing · 0 excluded · 5 replicates each           │
│ hazard_free       │ 57.5%    │ [29.3%, 81.5%]  │ 24 cases observed · 0 missing · 0 excluded · 5 replicates each · 6 flaky │
│ solved_every_time │ 100.0%   │ [85.7%, 100.0%] │ 24 / 24 observed · 0 missing · 0 excluded · 5 replicates each            │

계획하는 정책은 모든 에피소드에서 목표에 이르므로 성공 하한은 통과합니다. 그래도 위험 칸에는 들어갑니다. 어떤 그리드에는 안전한 경로가 없고, 미끄러운 바닥이 다른 그리드에서도 정책을 위험 칸으로 밀어 넣기 때문입니다. 57.5%라는 안전 비율은 하한보다 높지만, 작업 24개로는 그것이 50%보다 높다는 것을 아직 보여 줄 수 없습니다.

두 정책 비교하기

oloproof compare CANDIDATE_RUN_ID BASELINE_RUN_ID --policy comparison.yaml
episode_return: +10.92 [+0.21, +17.74] · 24 paired · 0 missing · 0 excluded
episode_success: +23.3 points [-3.2, +44.6] · 24 paired · 0 missing · 0 excluded
hazard_free: +28.3 points [-2.4, +54.7] · 24 paired · 0 missing · 0 excluded
solved_every_time: +62.5 points [+24.3, +87.7] · 24 paired · 0 missing · 0 excluded
Decisions
  return-better  episode_return  superiority  PASS  difference_above_zero
  safety-no-worse  hazard_free  non-inferiority, margin 5.0 points  PASS  lower_bound_above_margin
Gate: ALLOW (exit 0)

비교는 각 작업을 그 자신과 짝지으며, 각 쪽의 값은 에피소드 다섯 개에 대한 평균입니다. 리턴의 차이는 리턴 자신의 단위로 표시됩니다. 계획하는 정책은 에피소드당 약 10.9를 더 얻고, 적어도 0.21은 더 얻습니다. 같은 그리드에서 짝지으면, 어느 실행도 혼자서는 자신의 안전 하한에 결론을 내지 못했는데도, 5포인트 마진으로 계획하는 정책이 덜 안전하지 않다는 것을 보여 주기에 충분합니다.

2부: 로그로 판단하는 정책

cd ../off_policy

지원 데스크는 각 티켓을 작은 모델이나 큰 모델로 보냅니다. 현재 라우터는 무작위로 70%는 작은 모델을, 30%는 큰 모델을 고릅니다. 여러분은 새 규칙을 작성했습니다. 기술 티켓과 긴 결제 티켓은 큰 모델로 보낸다는 것입니다. 아직 실제 티켓으로 시도해 볼 수는 없지만, 이전 라우터의 로그가 대신 답할 수 있습니다. 이것이 오프 폴리시 평가입니다.

로그와 그 파일

파일내용
data/decisions.jsonl현재 라우터가 내린 결정 600개
make_log.py그 로그를 쓴 시뮬레이션. 로그가 어떻게 만들어졌는지 볼 수 있습니다
router.py새 규칙, 테스트 대상 시스템
oloproof.yaml스위트
release.yaml릴리스 정책

로그의 각 줄은 결정 하나입니다.

{"id":"t001","input":{"topic":"technical","length":"short"},"expected":{"action":"small","logging_probabilities":{"small":0.7,"large":0.3},"reward":1}}

input은 라우터가 본 것, action은 라우터가 고른 것, logging_probabilities는 그 순간 라우터가 각 모델에 준 확률, reward는 티켓이 해결되었는지 여부입니다. 새 규칙은 자신의 확률로만 답합니다.

@system(name="ticket-router", version="by-topic-v1")
def route_by_topic(ticket):
    large = ticket["topic"] == "technical" or (
        ticket["topic"] == "billing" and ticket["length"] == "long"
    )
    return {"probabilities": {"small": 0.0 if large else 1.0, "large": 1.0 if large else 0.0}}

평가기는 다음과 같습니다.

evaluators:
  - {type: off_policy_value, reward_range: [0, 1], propensity_floor: 0.3}
  - {type: off_policy_improvement, reward_range: [0, 1], propensity_floor: 0.3}

기록된 각 결정은 새 규칙이 그 결정을 내릴 가능성이 이전 라우터보다 얼마나 더 높은지, 또는 낮은지에 따라 다시 가중됩니다. 이전 라우터가 확률 0.3으로 큰 모델에 보냈고 새 규칙이라면 언제나 그곳으로 보낼 티켓은 1 / 0.3번으로 세고, 새 규칙이라면 결코 내리지 않았을 결정은 0으로 셉니다. propensity_floor는 이전 라우터가 고를 수 있는 모델에 준 확률 중 가장 작은 값입니다. 그것이 이 가중치를 제한하며, 제한이 없으면 어떤 구간도 성립하지 않습니다.

실행하기

oloproof run
│ resolution-floor    │ off_policy_value       │ PASS                  │ lower_bound_meets_minimum                                                          │
│ better-than-current │ off_policy_improvement │ INSUFFICIENT_EVIDENCE │ interval_overlaps_threshold                                                        │
│                     │                        │                       │ about 2633 more cases would decide it, if the observed values hold (3233 in total) │
│ off_policy_value       │ 0.775    │ [0.632, 0.921]  │ mean of 600 observed · 0 missing · 0 excluded │
│ off_policy_improvement │ 0.060    │ [-0.064, 0.188] │ mean of 600 observed · 0 missing · 0 excluded │

새 규칙은 티켓의 약 77.5%를 해결할 것으로 추정되며, 95% 신뢰 수준에서 적어도 63.2%를 해결합니다. 60% 하한은 통과합니다. 현재 라우터보다 나은지는 결론이 나지 않았습니다. 추정치는 6포인트 더 낫지만, 구간은 6.4포인트 더 나쁜 쪽에서 18.8포인트 더 나은 쪽까지 걸쳐 있으며, 엔진은 기록된 결정이 대략 몇 개 더 있으면 결론이 날지 알려 줍니다.

그 폭은 다른 누군가의 선택에서 배우는 대가입니다. 큰 모델에 대해 무언가를 말해 주는 것은 이전 라우터가 우연히 큰 모델로 보낸 30%의 티켓뿐이며, 각각이 세 번 넘게 셈에 들어갑니다. 구간을 좁히는 것은 두 가지입니다. 더 긴 로그, 그리고 더 많이 탐색하는 이전 라우터입니다.

여러분의 시스템에서 결정 기록하기

  • 확률은 나중이 아니라 라우터가 결정할 때 기록하고, 선택된 옵션의 확률만이 아니라 모든 옵션의 확률을 기록하십시오. Oloproof는 그것을 추정하지 않습니다. 추측한 확률이라면 구간이 그 추측에 기대게 됩니다.
  • input에는 라우터가 결정할 때 본 것만 넣고, 선택된 옵션이나 결과는 절대 넣지 마십시오. 테스트 대상 정책은 그것을 보아서는 안 됩니다.
  • 새 정책이 선택을 샘플링한다면, 뽑은 옵션 하나가 아니라 샘플링의 바탕이 되는 확률을 반환하십시오. 각 옵션은 로그가 부르는 이름과 정확히 같게 부르십시오. 철자가 다른 옵션은 이전 라우터가 한 번도 고르지 않은 옵션으로 셉니다.
  • 프로덕션 라우팅에 어느 정도의 무작위성을 남겨 두십시오. 어떤 옵션을 결코 고르지 않는 정책은, 그 옵션을 고를 규칙을 판단할 근거를 로그에 아무것도 남기지 않습니다.
  • 답은 로그가 다루는 기간 동안의, 기록된 것과 비슷한 티켓을 설명합니다. 트래픽의 변화는 그 범위 밖에 있습니다.
  • 형식이 잘못된 줄(합이 1이 되지 않는 확률, 확률 0인 선택된 옵션, reward_range 밖의 보상)은 실행을 멈춥니다. 이전 라우터가 하한보다 낮은 확률을 준 옵션으로 새 규칙이 내릴 결정, 또는 보상이 누락된 결정은 누락으로 세어지며 구간을 넓힙니다.

구현되지 않은 것

  • 각 단계의 선택이 다음에 일어날 일을 바꾸는, 일련의 결정에 대한 오프 폴리시 평가. 케이스당 결정 하나만 지원됩니다.
  • 기간 중에 학습하면서 확률을 바꾼 라우터의 로그.
  • 환경, 시뮬레이터, 로봇의 호스팅 또는 재설정.

다음 단계