pub struct NfspTrainer<B, P, O, E, FP, FO, FE>where
B: AutodiffBackend,
P: JointPolicy<B>,
O: Optimizer<P, B>,
E: JointEnv,
FP: Fn(&B::Device, u64) -> P,
FO: Fn() -> BurnOptimizer<B, P, O>,
FE: Fn() -> E,{ /* private fields */ }Expand description
NFSP outer-loop trainer.
Generic over the Burn backend B, policy module P, optimizer
type O, env E, and the user-supplied policy/optimizer/env
factories. The trainer owns:
- A
JointMultiAgentTrainerholding theNbest-response (BR) policies. BR updates go throughJointMultiAgentTrainer::update_with_active_agents— the freeze-N-1 primitive PSRO also uses. Naverage-policy (AP) Burn modules and their independent optimizers. AP updates are plain supervised cross-entropy on reservoir samples.Nreservoir buffers (one per agent) carrying(obs, action)pairs harvested from BR-sampled rollout steps.- An internal
StdRng(seeded fromNfspConfig::seed) used for η-anticipatory coin flips, reservoir eviction, and AP minibatch sampling.
As of #119, joint_config.num_agents may be any value ≥ 2. The
formal ε-Nash convergence guarantee from Heinrich & Silver 2016 §3
holds only for N = 2 zero-sum games; for N > 2 this trainer ships
the same per-agent BR/AP/reservoir machinery as an “approximate
NFSP” — see the module docstring for the caveat.
§Single-policy-class assumption
All 2N policies (N BR + N AP) share the same module type
P. For symmetric matching-pennies-style games this is what we
want.
§See also
crate::multi_agent::psro::PsroTrainer— sibling meta-game trainer with the same JointMultiAgentTrainer-based freeze-N-1 plumbing.
Implementations§
Source§impl<B, P, O, E, FP, FO, FE> NfspTrainer<B, P, O, E, FP, FO, FE>where
B: AutodiffBackend,
P: JointPolicy<B>,
O: Optimizer<P, B>,
E: JointEnv,
FP: Fn(&B::Device, u64) -> P,
FO: Fn() -> BurnOptimizer<B, P, O>,
FE: Fn() -> E,
impl<B, P, O, E, FP, FO, FE> NfspTrainer<B, P, O, E, FP, FO, FE>where
B: AutodiffBackend,
P: JointPolicy<B>,
O: Optimizer<P, B>,
E: JointEnv,
FP: Fn(&B::Device, u64) -> P,
FO: Fn() -> BurnOptimizer<B, P, O>,
FE: Fn() -> E,
Sourcepub fn new(
config: NfspConfig,
joint_config: JointTrainerConfig,
device: B::Device,
policy_factory: FP,
optimizer_factory: FO,
env_factory: FE,
) -> Result<Self>
pub fn new( config: NfspConfig, joint_config: JointTrainerConfig, device: B::Device, policy_factory: FP, optimizer_factory: FO, env_factory: FE, ) -> Result<Self>
Construct an NFSP trainer with fresh BR and AP policies.
joint_config.num_agents must be ≥ 2. For N = 2 the trainer
retains Heinrich & Silver §3’s ε-Nash convergence guarantee on
zero-sum games; for N > 2 it ships as “approximate NFSP” with
no formal guarantee beyond per-agent reservoir uniformity (see
the module docstring).
Sourcepub fn avg_policy(&self, i: usize) -> &P
pub fn avg_policy(&self, i: usize) -> &P
Borrow agent i’s average (AP) policy.
Sourcepub fn reservoir(&self, i: usize) -> &ReservoirBuffer<(Vec<f32>, Vec<i64>)>
pub fn reservoir(&self, i: usize) -> &ReservoirBuffer<(Vec<f32>, Vec<i64>)>
Borrow agent i’s reservoir buffer.
Sourcepub fn cumulative_br_pushes(&self) -> usize
pub fn cumulative_br_pushes(&self) -> usize
Cumulative BR-sampled push count across all reservoirs.
Sourcepub fn cumulative_rollout_steps(&self) -> usize
pub fn cumulative_rollout_steps(&self) -> usize
Cumulative rollout-step count across all agents.
Sourcepub fn config(&self) -> &NfspConfig
pub fn config(&self) -> &NfspConfig
Trainer configuration.
Sourcepub fn run<F>(&mut self, on_iteration: F) -> Result<NfspStats>
pub fn run<F>(&mut self, on_iteration: F) -> Result<NfspStats>
Run the NFSP outer loop and return the per-iteration history.
Sourcepub fn run_silent(&mut self) -> Result<NfspStats>
pub fn run_silent(&mut self) -> Result<NfspStats>
Convenience entry point: drives Self::run with a no-op
iteration callback.
Sourcepub fn action_marginal_for(&mut self, policy: &P) -> Option<Vec<f32>>
pub fn action_marginal_for(&mut self, policy: &P) -> Option<Vec<f32>>
Average-policy action distribution under a constant observation
[0.0; obs_dim]. Returns None if the policy’s action_dims
is unsupported (e.g. multi-dim multi-discrete). Used as a
diagnostic on matching-pennies and as the load-bearing
convergence assertion in tests/test_nfsp_matching_pennies.rs.
Takes &mut self because the 128-probe sampling loop consumes
the trainer-owned StdRng via
JointPolicy::get_action_host_seeded. This makes the
diagnostic reproducible under NfspConfig::seed (issue #114).
Callers that hold a &P from Self::avg_policy / Self::br_policy
must .clone() the policy before calling this method to avoid a
&self / &mut self aliasing conflict — the policy clone is
cheap (Burn modules are Clone by design).
Auto Trait Implementations§
impl<B, P, O, E, FP, FO, FE> Freeze for NfspTrainer<B, P, O, E, FP, FO, FE>
impl<B, P, O, E, FP, FO, FE> RefUnwindSafe for NfspTrainer<B, P, O, E, FP, FO, FE>where
<B as BackendTypes>::Device: RefUnwindSafe,
FP: RefUnwindSafe,
FO: RefUnwindSafe,
FE: RefUnwindSafe,
P: RefUnwindSafe,
O: RefUnwindSafe,
B: RefUnwindSafe,
impl<B, P, O, E, FP, FO, FE> Send for NfspTrainer<B, P, O, E, FP, FO, FE>
impl<B, P, O, E, FP, FO, FE> Sync for NfspTrainer<B, P, O, E, FP, FO, FE>
impl<B, P, O, E, FP, FO, FE> Unpin for NfspTrainer<B, P, O, E, FP, FO, FE>
impl<B, P, O, E, FP, FO, FE> UnsafeUnpin for NfspTrainer<B, P, O, E, FP, FO, FE>
impl<B, P, O, E, FP, FO, FE> UnwindSafe for NfspTrainer<B, P, O, E, FP, FO, FE>where
<B as BackendTypes>::Device: UnwindSafe,
FP: UnwindSafe,
FO: UnwindSafe,
FE: UnwindSafe,
P: UnwindSafe,
O: UnwindSafe,
B: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more