pub struct MlpBurnPolicy<B: Backend> { /* private fields */ }Expand description
Two- or three-layer MLP actor-critic for discrete action spaces, ported to Burn.
Layout mirrors crate::policy::mlp::MlpBurnPolicy at a high level:
obs → fc1 →act→ fc2 →act→ (fc3 →act→)? policy_head (logits)
└─ value_head (V(s))Both heads share the trunk activations — standard PPO actor-critic.
§Numerical parity
When constructed with use_orthogonal_init = true (the default), the
trunk uses [Initializer::Orthogonal { gain: sqrt(2) }] and the
output heads use gain = 0.01. These match the tch policy’s init
gains exactly (see crate::policy::mlp::MlpBurnPolicy::with_config),
which is the necessary precondition for the phase-4 numerical-parity
check called out on issue #81.
Implementations§
Source§impl<B: Backend> MlpBurnPolicy<B>
impl<B: Backend> MlpBurnPolicy<B>
Sourcepub fn new(
obs_dim: usize,
action_dim: usize,
hidden_dim: usize,
device: &B::Device,
) -> Self
pub fn new( obs_dim: usize, action_dim: usize, hidden_dim: usize, device: &B::Device, ) -> Self
Backward-compatible 2-layer constructor (the phase 1 scout signature). Uses Burn’s default Kaiming-uniform init — kept so the existing bandit trainer and parity tests are not perturbed.
New call sites that want PPO-style orthogonal init should call
MlpBurnPolicy::with_config instead.
Sourcepub fn new_seeded(
obs_dim: usize,
action_dim: usize,
hidden_dim: usize,
seed: u64,
device: &B::Device,
) -> Self
pub fn new_seeded( obs_dim: usize, action_dim: usize, hidden_dim: usize, seed: u64, device: &B::Device, ) -> Self
Seeded variant of new: same 2-layer Kaiming
architecture, but constructed deterministically from seed so
two calls with the same seed produce bit-identical weights.
Convenience wrapper for callers (and the PSRO/NFSP policy
factories) that want reproducible policies without assembling a
full MlpBurnConfig. Equivalent to
with_config(.., MlpBurnConfig { use_orthogonal_init: false, .., seed: Some(seed) }, ..).
Sourcepub fn with_config(
obs_dim: usize,
action_dim: usize,
config: MlpBurnConfig,
device: &B::Device,
) -> Self
pub fn with_config( obs_dim: usize, action_dim: usize, config: MlpBurnConfig, device: &B::Device, ) -> Self
Build a fresh policy on device with the given configuration.
This is the production constructor for phase 4 onwards. Mirrors
crate::policy::mlp::MlpBurnPolicy::with_config.
Sourcepub fn forward(&self, obs: Tensor<B, 2>) -> (Tensor<B, 2>, Tensor<B, 1>)
pub fn forward(&self, obs: Tensor<B, 2>) -> (Tensor<B, 2>, Tensor<B, 1>)
Forward pass: returns (logits, value).
obsis shape[batch, obs_dim].logitsis shape[batch, action_dim](pre-softmax).valueis shape[batch](squeezed from[batch, 1]).
Sourcepub fn encoder_features(&self, obs: Tensor<B, 2>) -> Tensor<B, 2>
pub fn encoder_features(&self, obs: Tensor<B, 2>) -> Tensor<B, 2>
Compute the shared-trunk feature representation for obs.
Mirrors crate::policy::mlp::MlpBurnPolicy::encoder_features —
auxiliary regularizers (cross-agent redundancy penalties,
behavioural-diversity bonuses) tap this directly.
Gradients flow back into the trunk.
Sourcepub fn policy_head_action_dim(&self) -> usize
pub fn policy_head_action_dim(&self) -> usize
Action-head output dimensionality (number of discrete actions).
Reads the policy_head weight tensor’s shape — Burn’s
burn::nn::Linear stores weight: Param<Tensor<B, 2>> with
shape [d_input, d_output], so d_output is the action
cardinality. Used by the multi-agent joint trainer’s
crate::multi_agent::joint::JointPolicy::action_dims_joint impl
to size the rollout action buffer without consuming RNG draws.
Sourcepub fn policy_head(&self) -> &Linear<B>
pub fn policy_head(&self) -> &Linear<B>
Borrow the policy (action-logits) head.
Sourcepub fn value_head(&self) -> &Linear<B>
pub fn value_head(&self) -> &Linear<B>
Borrow the value (V(s)) head.
Sourcepub fn get_action_host(
&self,
obs: Tensor<B, 2>,
) -> (Vec<i64>, Vec<f32>, Vec<f32>)
pub fn get_action_host( &self, obs: Tensor<B, 2>, ) -> (Vec<i64>, Vec<f32>, Vec<f32>)
Sample one action per row from the policy’s categorical
distribution and return (actions_host, log_probs_host, values_host) as plain Vecs.
Thin backwards-compat wrapper around
MlpBurnPolicy::get_action_host_seeded that constructs a
thread-local RNG. Not deterministic across calls — use
get_action_host_seeded and pass
a seeded rand::rngs::StdRng when reproducibility is required
(PSRO/NFSP/joint trainer rollouts call the seeded form via the
crate::multi_agent::joint::JointPolicy trait so that
PsroConfig::seed / NfspConfig::seed produce bit-identical
rollouts; see issue #114).
Retained for example-driver convenience where the caller does
not need bit-exact reproducibility and would otherwise have to
thread an &mut StdRng through bespoke rollout loops.
Sourcepub fn get_action_host_seeded(
&self,
obs: Tensor<B, 2>,
rng: &mut StdRng,
) -> (Vec<i64>, Vec<f32>, Vec<f32>)
pub fn get_action_host_seeded( &self, obs: Tensor<B, 2>, rng: &mut StdRng, ) -> (Vec<i64>, Vec<f32>, Vec<f32>)
Same contract as get_action_host but
the host-side categorical draws consume rng instead of the
thread-local generator.
The trainer-side rollout loop does not need gradient flow
through the sampled action (only the eventual
MlpBurnPolicy::evaluate_actions call on the stored
transitions matters for the PPO surrogate). We therefore do the
categorical draw on the host with rand, sidestepping Burn
0.21’s lack of a first-class multinomial op.
Bit-exactness contract: two calls with the same obs, same
policy state, and same-seeded rng (StdRng::seed_from_u64)
must produce element-wise identical
(actions, log_probs, values). This is the load-bearing
guarantee PsroConfig::seed / NfspConfig::seed rely on after
issue #114.
Sourcepub fn get_actions_host_seeded_batched(
&self,
obs: Tensor<B, 2>,
rng: &mut StdRng,
) -> (Vec<i64>, Vec<f32>, Vec<f32>)
pub fn get_actions_host_seeded_batched( &self, obs: Tensor<B, 2>, rng: &mut StdRng, ) -> (Vec<i64>, Vec<f32>, Vec<f32>)
Batched seeded sampler: one forward over [N, obs_dim], then N
host-side categorical draws in row-major order.
Bit-identical to calling Self::get_action_host_seeded once per row
on [1, obs_dim] slices provided the rows are drawn from the same
policy — the forward is a single matmul over all N rows (same
weights), and the RNG is consumed one draw per row, ascending. This
is the crate::multi_agent::joint::JointPolicy-trait batched
entry point that eliminates per-call batch-1 overhead on the
NdArray backend wherever many observations are scored through the
same model in one step (issue #235).
Sourcepub fn evaluate_actions(
&self,
obs: Tensor<B, 2>,
actions: Tensor<B, 1, Int>,
) -> (Tensor<B, 1>, Tensor<B, 1>, Tensor<B, 1>)
pub fn evaluate_actions( &self, obs: Tensor<B, 2>, actions: Tensor<B, 1, Int>, ) -> (Tensor<B, 1>, Tensor<B, 1>, Tensor<B, 1>)
Evaluate a batch of (obs, actions) pairs.
Returns (action_log_probs, entropy_per_row, values) — the
quantities the PPO surrogate loss needs. Entropy is per-row here
(not the mean): the caller decides how to aggregate. This
matches the tch policy’s contract (the tch
evaluate_actions returns a scalar mean; the trainer reduces
per-row entropy on the Burn path inside
crate::train::ppo::trainer::PPOTrainerBurn::train_step).
Trait Implementations§
Source§impl<B> AutodiffModule<B> for MlpBurnPolicy<B>
impl<B> AutodiffModule<B> for MlpBurnPolicy<B>
Source§type InnerModule = MlpBurnPolicy<<B as AutodiffBackend>::InnerBackend>
type InnerModule = MlpBurnPolicy<<B as AutodiffBackend>::InnerBackend>
Source§fn valid(&self) -> Self::InnerModule
fn valid(&self) -> Self::InnerModule
Source§fn from_inner(module: Self::InnerModule) -> Self
fn from_inner(module: Self::InnerModule) -> Self
Source§impl<B: Backend> Clone for MlpBurnPolicy<B>
impl<B: Backend> Clone for MlpBurnPolicy<B>
Source§impl<B: Backend> Display for MlpBurnPolicy<B>
impl<B: Backend> Display for MlpBurnPolicy<B>
Source§impl<B> HasAutodiffModule<B> for MlpBurnPolicy<B::InnerBackend>
impl<B> HasAutodiffModule<B> for MlpBurnPolicy<B::InnerBackend>
Source§type TrainModule = MlpBurnPolicy<B>
type TrainModule = MlpBurnPolicy<B>
Source§impl<B: AutodiffBackend> JointPolicy<B> for MlpBurnPolicy<B>where
Self: AutodiffModule<B> + Clone,
impl<B: AutodiffBackend> JointPolicy<B> for MlpBurnPolicy<B>where
Self: AutodiffModule<B> + Clone,
Source§fn get_action_host_seeded(
&self,
obs: Tensor<B, 2>,
rng: &mut StdRng,
) -> (Vec<i64>, Vec<f32>, Vec<f32>)
fn get_action_host_seeded( &self, obs: Tensor<B, 2>, rng: &mut StdRng, ) -> (Vec<i64>, Vec<f32>, Vec<f32>)
Source§fn get_actions_host_seeded_batched(
&self,
obs: Tensor<B, 2>,
rng: &mut StdRng,
) -> (Vec<i64>, Vec<f32>, Vec<f32>)
fn get_actions_host_seeded_batched( &self, obs: Tensor<B, 2>, rng: &mut StdRng, ) -> (Vec<i64>, Vec<f32>, Vec<f32>)
obs carries N rows scored through this
one policy in a single forward, returning N actions. Read moreSource§fn evaluate_actions_joint(
&self,
obs: Tensor<B, 2>,
actions: Tensor<B, 2, Int>,
) -> (Tensor<B, 1>, Tensor<B, 1>, Tensor<B, 1>)
fn evaluate_actions_joint( &self, obs: Tensor<B, 2>, actions: Tensor<B, 2, Int>, ) -> (Tensor<B, 1>, Tensor<B, 1>, Tensor<B, 1>)
Source§impl<B: Backend> Module<B> for MlpBurnPolicy<B>
impl<B: Backend> Module<B> for MlpBurnPolicy<B>
Source§type Record = MlpBurnPolicyRecord<B>
type Record = MlpBurnPolicyRecord<B>
Source§fn load_record(self, record: Self::Record) -> Self
fn load_record(self, record: Self::Record) -> Self
Source§fn into_record(self) -> Self::Record
fn into_record(self) -> Self::Record
Source§fn num_params(&self) -> usize
fn num_params(&self) -> usize
Source§fn visit<Visitor: ModuleVisitor<B>>(&self, visitor: &mut Visitor)
fn visit<Visitor: ModuleVisitor<B>>(&self, visitor: &mut Visitor)
Source§fn map<Mapper: ModuleMapper<B>>(self, mapper: &mut Mapper) -> Self
fn map<Mapper: ModuleMapper<B>>(self, mapper: &mut Mapper) -> Self
Source§fn collect_devices(&self, devices: Devices<B>) -> Devices<B>
fn collect_devices(&self, devices: Devices<B>) -> Devices<B>
Source§fn to_device(self, device: &B::Device) -> Self
fn to_device(self, device: &B::Device) -> Self
Source§fn fork(self, device: &B::Device) -> Self
fn fork(self, device: &B::Device) -> Self
Source§fn devices(&self) -> Vec<<B as BackendTypes>::Device>
fn devices(&self) -> Vec<<B as BackendTypes>::Device>
Source§fn train<AB>(self) -> Self::TrainModulewhere
AB: AutodiffBackend<InnerBackend = B>,
Self: HasAutodiffModule<AB>,
fn train<AB>(self) -> Self::TrainModulewhere
AB: AutodiffBackend<InnerBackend = B>,
Self: HasAutodiffModule<AB>,
Source§fn save_file<FR, PB>(
self,
file_path: PB,
recorder: &FR,
) -> Result<(), RecorderError>
fn save_file<FR, PB>( self, file_path: PB, recorder: &FR, ) -> Result<(), RecorderError>
Source§fn load_file<FR, PB>(
self,
file_path: PB,
recorder: &FR,
device: &<B as BackendTypes>::Device,
) -> Result<Self, RecorderError>
fn load_file<FR, PB>( self, file_path: PB, recorder: &FR, device: &<B as BackendTypes>::Device, ) -> Result<Self, RecorderError>
Source§fn quantize_weights(self, quantizer: &mut Quantizer) -> Self
fn quantize_weights(self, quantizer: &mut Quantizer) -> Self
Source§impl<B: Backend> ModuleDisplay for MlpBurnPolicy<B>
impl<B: Backend> ModuleDisplay for MlpBurnPolicy<B>
Source§fn format(&self, passed_settings: DisplaySettings) -> String
fn format(&self, passed_settings: DisplaySettings) -> String
Source§fn custom_settings(&self) -> Option<DisplaySettings>
fn custom_settings(&self) -> Option<DisplaySettings>
Auto Trait Implementations§
impl<B> !Freeze for MlpBurnPolicy<B>
impl<B> !RefUnwindSafe for MlpBurnPolicy<B>
impl<B> !UnwindSafe for MlpBurnPolicy<B>
impl<B> Send for MlpBurnPolicy<B>
impl<B> Sync for MlpBurnPolicy<B>
impl<B> Unpin for MlpBurnPolicy<B>where
<B as BackendTypes>::FloatTensorPrimitive: Unpin,
<B as BackendTypes>::QuantizedTensorPrimitive: Unpin,
<B as BackendTypes>::Device: Unpin,
impl<B> UnsafeUnpin for MlpBurnPolicy<B>where
<B as BackendTypes>::Device: UnsafeUnpin,
<B as BackendTypes>::FloatTensorPrimitive: UnsafeUnpin,
<B as BackendTypes>::QuantizedTensorPrimitive: UnsafeUnpin,
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
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