marla.learning
The recurrent PPO policy, its sub-modules, rollout collection, and the PPO update itself.
Policy and its components
Ties the graph encoder, action encoder, GRU, base scorer, and critic together into a single live rollout-collection step.
This module handles exactly one environment instance at a time (MARLA does
not vectorize environments – see spec section 25 non-goals), so all
“batch” dimensions here are size 1. Fixed-size, padded multi-sequence
batching for PPO minibatch replay is built on the same components in
Milestone 4’s learning/ppo.py.
- class marla.learning.recurrent_policy.PolicyStepOutput(z: 'Tensor', base_logits: 'Tensor', base_probs: 'Tensor', action_embeddings: 'Tensor', value: 'Tensor')[source]
Bases:
object- Parameters:
z (torch.Tensor)
base_logits (torch.Tensor)
base_probs (torch.Tensor)
action_embeddings (torch.Tensor)
value (torch.Tensor)
- action_embeddings: torch.Tensor
- base_logits: torch.Tensor
- base_probs: torch.Tensor
- value: torch.Tensor
- z: torch.Tensor
- class marla.learning.recurrent_policy.RecurrentPolicy(*args, **kwargs)[source]
Bases:
ModuleThe trainable RL Orchestrator policy (spec section 11).
Only this module’s parameters are optimized by PPO – the Plan Maker is frozen and lives entirely outside this class.
- Parameters:
policy_config (PolicyConfig)
node_feature_dim (int)
consultation_enabled (bool)
- advance_recurrent_state(step_output, selected_action_index, training_reward, query)[source]
Build the next step’s
RecurrentStateafter an action is selected.- Parameters:
step_output (PolicyStepOutput)
selected_action_index (int)
training_reward (float)
query (bool)
- Return type:
- apply_advice(z, base_logits, confidence)[source]
Accepted-advice residual adjustment (spec section 15).
confidencemust already be in the same order asbase_logits(i.e. the legal-action order), reconstructed by stable action ID – never by raw vector position.- Parameters:
z (torch.Tensor)
base_logits (torch.Tensor)
confidence (torch.Tensor)
- Return type:
- property device: torch.device
- initial_recurrent_state()[source]
The recurrent state at the start of a new episode.
Must be used at every episode boundary – hidden state is never propagated across episodes (spec section 17).
- Return type:
- step(graph_observation, legal_actions, recurrent_state)[source]
- Parameters:
graph_observation (GraphObservation)
legal_actions (list[ActionDescriptor])
recurrent_state (RecurrentState)
- Return type:
- class marla.learning.recurrent_policy.RecurrentState(z, previous_action_embedding, previous_reward=0.0, previous_query=0.0)[source]
Bases:
objectThe GRU hidden state plus everything needed to build the next
x_t.- Parameters:
- previous_action_embedding: torch.Tensor
- z: torch.Tensor
Torch Geometric GraphSAGE encoder (spec section 12).
Produces per-node embeddings (used as target-host embeddings for the action encoder) and a global mean-pooled graph embedding (fed into the GRU).
- class marla.learning.graph_encoder.GraphEncoder(*args, **kwargs)[source]
Bases:
Module- forward(data)[source]
Returns
(node_embeddings, graph_embeddings).data.batchis required whendataholds more than one graph (aBatch); for a single graph it may be omitted (global_mean_pooltreats all nodes as one graph).- Parameters:
data (torch_geometric.data.Batch)
- Return type:
tuple[torch.Tensor, torch.Tensor]
Per-action embedding \(e_{t,i} = f_{action}(E_{type}, h_{target}, E_{parameters})\).
Non-target actions (finish) use a learned no-target embedding in place
of a target-host embedding (spec section 12). Action-specific parameters
(exploit/privesc service/os/process names) are summarized as a
small fixed-size presence indicator rather than embedded by name, so the
model does not bake in a per-scenario service/OS vocabulary – scenarios can
introduce new service/OS/process names without changing the model shape.
- class marla.learning.action_encoder.ActionEncoder(*args, **kwargs)[source]
Bases:
Module- encode_descriptors(descriptors, node_embeddings, node_key_to_index, device)[source]
Convenience wrapper: build encoder inputs directly from descriptors.
- Parameters:
descriptors (list[ActionDescriptor])
node_embeddings (torch.Tensor)
device (torch.device)
- Return type:
torch.Tensor
- forward(type_ids, target_embeddings, has_target_mask, parameter_feats)[source]
All inputs are batched over actions: shapes
(N, ...).target_embeddingsrows are ignored (replaced by the learned no-target embedding) whereverhas_target_maskisFalse.- Parameters:
type_ids (torch.Tensor)
target_embeddings (torch.Tensor)
has_target_mask (torch.Tensor)
parameter_feats (torch.Tensor)
- Return type:
torch.Tensor
GRU recurrent state (spec section 13).
z_t = GRUCell(x_t, z_{t-1}) with x_t = [g_t, E(a_{t-1}), r~_{t-1}, q_{t-1}].
At episode start, z is zero, the previous action is a learned start
token, and the previous reward/query are zero. All tensors are batch-first
(B = 1 for single-instance live rollout collection, B > 1 for PPO
minibatch replay in Milestone 4) so the same module serves both.
- class marla.learning.recurrent_core.RecurrentCore(*args, **kwargs)[source]
Bases:
Module- forward(graph_embedding, previous_action_embedding, previous_reward, previous_query, previous_hidden)[source]
- Parameters:
graph_embedding (torch.Tensor)
previous_action_embedding (torch.Tensor)
previous_reward (torch.Tensor)
previous_query (torch.Tensor)
previous_hidden (torch.Tensor)
- Return type:
torch.Tensor
- Parameters:
batch_size (int)
device (torch.device)
- Return type:
torch.Tensor
Dynamic candidate-action scorer (spec section 13).
b_{t,i} = w^T tanh(W_z z_t + W_e e_{t,i}). Candidate sets vary in size
per sample, so actions are passed flattened across the batch together with
an action_to_sample index vector – the same pattern Torch Geometric
uses for variable-size graphs in a Batch (see data.batch).
- class marla.learning.base_scorer.BaseActionScorer(*args, **kwargs)[source]
Bases:
Module- forward(z, action_embeddings, action_to_sample)[source]
Returns raw (unnormalized) logits, one per action row.
z:(B, recurrent_hidden_size).action_embeddings:(N_total, action_hidden_size).action_to_sample:(N_total,)int64, values in[0, B).- Parameters:
z (torch.Tensor)
action_embeddings (torch.Tensor)
action_to_sample (torch.Tensor)
- Return type:
torch.Tensor
Value critic: a linear head over the GRU recurrent state.
- class marla.learning.critic.Critic(*args, **kwargs)[source]
Bases:
Module- Parameters:
hidden_size (int)
Learned binary query gate (spec section 14).
The query decision happens before the Plan Maker is consulted: it is a function of the base policy alone (recurrent state, base entropy, top-two margin, candidate-set size, and the configured consultation cost).
- class marla.learning.query_gate.QueryGate(*args, **kwargs)[source]
Bases:
Modulep_t^q = sigma(f_q[z_t, H_t^0, Delta_t^0, N_t, kappa]).
- marla.learning.query_gate.compute_base_entropy(base_probs)[source]
H_t^0 = -sum_i pi^0(a_i) log pi^0(a_i).
- Parameters:
base_probs (torch.Tensor)
- Return type:
torch.Tensor
- marla.learning.query_gate.compute_top_two_margin(base_logits)[source]
Delta_t^0 = b_(1) - b_(2); zero when only one legal action exists.
- Parameters:
base_logits (torch.Tensor)
- Return type:
torch.Tensor
Advice processing and learned trust (spec section 15).
Confidence scores from the Plan Maker are not assumed calibrated probabilities: they are clipped, converted to log-odds, and z-score normalized before being used as a residual adjustment to the base logits, scaled by a learned per-step trust coefficient and a single learned global scale.
- class marla.learning.advice.AdviceScale(*args, **kwargs)[source]
Bases:
Modulealpha = softplus(alpha_bar); a single learned global scalar (not per-step).
- class marla.learning.advice.AdviceSummary(mean: 'Tensor', std: 'Tensor', max: 'Tensor', top1_minus_top2: 'Tensor', entropy: 'Tensor')[source]
Bases:
object- Parameters:
mean (torch.Tensor)
std (torch.Tensor)
max (torch.Tensor)
top1_minus_top2 (torch.Tensor)
entropy (torch.Tensor)
- entropy: torch.Tensor
- max: torch.Tensor
- mean: torch.Tensor
- std: torch.Tensor
- top1_minus_top2: torch.Tensor
- class marla.learning.advice.AdvisedOutput(final_logits: 'Tensor', beta: 'Tensor', alpha: 'Tensor', normalized_advice: 'Tensor')[source]
Bases:
object- Parameters:
final_logits (torch.Tensor)
beta (torch.Tensor)
alpha (torch.Tensor)
normalized_advice (torch.Tensor)
- alpha: torch.Tensor
- beta: torch.Tensor
- final_logits: torch.Tensor
- normalized_advice: torch.Tensor
- class marla.learning.advice.TrustHead(*args, **kwargs)[source]
Bases:
Modulebeta_t = sigma(f_beta[z_t, S(c_t), A_t]).
- AGREEMENT_DIM = 2
- SUMMARY_DIM = 5
- marla.learning.advice.clip_and_logit(confidence)[source]
c_i -> u_i = logit(clip(c_i, eps, 1-eps)).
- Parameters:
confidence (torch.Tensor)
- Return type:
torch.Tensor
- marla.learning.advice.compute_advice_summary(log_odds)[source]
S(c) = [mean, std, max, top1-top2, H(softmax(u))].
- Parameters:
log_odds (torch.Tensor)
- Return type:
- marla.learning.advice.compute_agreement_features(base_logits, advice_log_odds)[source]
[top-action agreement (0/1), correlation between base logits and PM evidence].
Correlation is 0 when undefined (zero variance in either vector) – spec section 15: “If correlation is undefined, use zero.”
Fixed, non-differentiable features for the trust head: the Plan Maker’s output is external data, not a trainable parameter, so there is no gradient PPO could usefully take through this comparison –
base_logitskeeps its own graph connection for the outer residual sum inRecurrentPolicy.apply_advice(), this is a separate detached copy.- Parameters:
base_logits (torch.Tensor)
advice_log_odds (torch.Tensor)
- Return type:
torch.Tensor
- marla.learning.advice.normalize_advice(log_odds)[source]
z-score normalize log-odds; all-zero when variance is ~0 (spec section 15).
- Parameters:
log_odds (torch.Tensor)
- Return type:
torch.Tensor
- marla.learning.advice.summary_to_tensor(summary)[source]
- Parameters:
summary (AdviceSummary)
- Return type:
torch.Tensor
Compound-decision math shared by live rollout collection and PPO replay.
Both call sites need exactly the same computation: at collection time to record the “old” probabilities, and at replay time to recompute “new” probabilities under updated parameters for the PPO ratio. Sharing this module is what makes that guarantee structural rather than a matter of remembering to keep two implementations in sync.
Replay never samples: it reuses the stored sampled_query flag, the
stored selected_action_index, and (critically) the exact stored Plan
Maker confidence vector – never recomputing or re-fetching any of them.
- class marla.learning.decision.FinalDecision(final_logits: 'Tensor', beta: 'Tensor | None', alpha: 'Tensor | None', normalized_advice: 'Tensor | None')[source]
Bases:
object- Parameters:
final_logits (Tensor)
beta (Tensor | None)
alpha (Tensor | None)
normalized_advice (Tensor | None)
- final_logits: Tensor
- class marla.learning.decision.JointLogProbability(joint_log_prob: 'Tensor', query_log_prob: 'Tensor', action_log_prob: 'Tensor')[source]
Bases:
object- Parameters:
joint_log_prob (torch.Tensor)
query_log_prob (torch.Tensor)
action_log_prob (torch.Tensor)
- action_log_prob: torch.Tensor
- joint_log_prob: torch.Tensor
- query_log_prob: torch.Tensor
- marla.learning.decision.compute_final_decision(policy, step_output, sampled_query, plan_maker_confidence)[source]
Base logits, or the advised residual adjustment when queried and accepted.
Rejected advice forces beta=0 (spec section 15), which makes the resulting distribution numerically identical to the base policy while still reporting a real (if unused) alpha for metrics.
- Parameters:
policy (RecurrentPolicy)
step_output (PolicyStepOutput)
sampled_query (bool)
plan_maker_confidence (Tensor | None)
- Return type:
- marla.learning.decision.compute_joint_log_probability(query_probability, sampled_query, final_logits, selected_action_index)[source]
log p_t = log pi^q(q_t|z_t) + (1-q_t) log pi^0(a_t) + q_t log pi^PM(a_t) (spec section 16).
The single
final_logitssoftmax already is pi^0 when not queried (or when advice was rejected, since beta=0) and pi^PM when queried and accepted, so one formula covers both branches of the spec’s piecewise definition without a special case.- Parameters:
- Return type:
- marla.learning.decision.compute_query_probability(policy, step_output, num_actions, kappa)[source]
p_t^q, before sampling (spec section 14).
- Parameters:
policy (RecurrentPolicy)
step_output (PolicyStepOutput)
num_actions (int)
kappa (float)
- Return type:
torch.Tensor
Rollout, training, and optimization
Recurrent rollout collection (spec sections 16-17).
Runs the compound-decision loop against a live NasimEmuAdapter and
records everything PPO needs to replay each transition without ever calling
the environment or the Plan Maker again. Baseline instances are constructed
with consultation_enabled=False and never touch the query-gate/advice
machinery at all; assisted instances receive a consult_fn callback that
performs the actual Gatekeeper round-trip (kept out of this module so it
stays decoupled from SPADE – see marla.agents.advisory_client).
- class marla.learning.rollout.ConsultationResult(status, scores, request_id, latency_ms=None)[source]
Bases:
objectWhat a
consult_fncallback returns; decoupled from SPADE/Gatekeeper types.- Parameters:
- class marla.learning.rollout.EpisodeSummary(run_id: 'str', episode_id: 'int', seed: 'int', goal_success: 'bool', nasimemu_return: 'float', training_return: 'float', environment_steps: 'int', steps_to_goal: 'int | None', episode_seconds: 'float', finish_reason: 'str', consultation_count: 'int' = 0, consultation_cost: 'float' = 0.0, schema_rejection_count: 'int' = 0, rollout: 'int | None' = None, is_eval: 'bool' = False)[source]
Bases:
object- Parameters:
run_id (str)
episode_id (int)
seed (int)
goal_success (bool)
nasimemu_return (float)
training_return (float)
environment_steps (int)
steps_to_goal (int | None)
episode_seconds (float)
finish_reason (str)
consultation_count (int)
consultation_cost (float)
schema_rejection_count (int)
rollout (int | None)
is_eval (bool)
- class marla.learning.rollout.RolloutCollector(adapter, policy, run_id, base_seed, consultation_enabled=False, consultation_cost=0.0, consult_fn=None, stop_event=None, deterministic=False)[source]
Bases:
objectCollects fixed-length rollout windows, resuming across calls.
One
NasimEmuAdapter/RecurrentPolicypair per instance, matching MARLA’s non-vectorized, single-environment design.- Parameters:
adapter (NasimEmuAdapter)
policy (RecurrentPolicy)
run_id (str)
base_seed (int)
consultation_enabled (bool)
consultation_cost (float)
consult_fn (ConsultFn | None)
stop_event (asyncio.Event | None)
deterministic (bool)
- class marla.learning.rollout.StepRecord(run_id, episode_id, environment_step, observation_id, graph_data, node_key_to_index, legal_action_descriptors, initial_gru_hidden_state, previous_action_embedding, previous_training_reward, previous_query, base_logits, final_logits, selected_action_index, old_action_log_probability, old_joint_log_probability, critic_value, nasimemu_reward, consultation_cost, training_reward, terminated, truncated, bootstrap_value=None, sampled_query=False, old_query_probability=None, old_query_log_probability=None, plan_maker_scores_in_action_order=None, plan_maker_validation_status=None, plan_maker_response_status=None, plan_maker_request_id=None, plan_maker_latency_ms=None, plan_maker_artifact_path=None, normalized_advice=None, beta=None, alpha=None)[source]
Bases:
objectOne compound decision, with everything needed to replay it under PPO.
- Parameters:
run_id (str)
episode_id (int)
environment_step (int)
observation_id (str)
graph_data (torch_geometric.data.Data)
legal_action_descriptors (list[ActionDescriptor])
initial_gru_hidden_state (torch.Tensor)
previous_action_embedding (torch.Tensor)
previous_training_reward (float)
previous_query (bool)
base_logits (torch.Tensor)
final_logits (torch.Tensor)
selected_action_index (int)
old_action_log_probability (float)
old_joint_log_probability (float)
critic_value (float)
nasimemu_reward (float)
consultation_cost (float)
training_reward (float)
terminated (bool)
truncated (bool)
bootstrap_value (float | None)
sampled_query (bool)
old_query_probability (float | None)
old_query_log_probability (float | None)
plan_maker_validation_status (str | None)
plan_maker_response_status (str | None)
plan_maker_request_id (str | None)
plan_maker_latency_ms (float | None)
plan_maker_artifact_path (str | None)
beta (float | None)
alpha (float | None)
- base_logits: torch.Tensor
- final_logits: torch.Tensor
- graph_data: torch_geometric.data.Data
- legal_action_descriptors: list[ActionDescriptor]
- previous_action_embedding: torch.Tensor
- async marla.learning.rollout.run_evaluation_episodes(policy, adapter, run_id, num_episodes, seed_start, consultation_enabled=False, consultation_cost=0.0, consult_fn=None)[source]
Runs
num_episodesdeterministic (greedy) episodes with the current policy weights and reports their returns, contributing nothing to the PPO buffer – anEvalCallback-style periodic evaluation pass (see e.g. stable-baselines3), not a genuine held-out generalization test: MARLA’s config has a singleenvironment.scenario, not a train/test scenario split, so this measures the current policy’s performance without exploration noise on the same scenario training uses, not generalization to unseen scenarios.Reuses
adapterrather than building a second instance: training and evaluation never run concurrently (this is awaited strictly between rollout-collection phases inrun_training_loop), andNasimEmuAdapterholds no state of its own betweenreset()calls.- Parameters:
policy (RecurrentPolicy)
adapter (NasimEmuAdapter)
run_id (str)
num_episodes (int)
seed_start (int)
consultation_enabled (bool)
consultation_cost (float)
consult_fn (Callable[[list[ActionDescriptor], int, int, str, dict], Awaitable[ConsultationResult]] | None)
- Return type:
Recurrent PPO training loop, shared by the baseline and assisted variants.
Ties together RolloutCollector, compute_gae(), and
optimize() into repeated rollout-collect/PPO-update cycles. Native
async def throughout: the assisted variant’s per-step consultation is a
real await on the Gatekeeper round-trip, and running natively on the
event loop (rather than in a background thread) is what lets other
local-mode agents’ behaviours keep being serviced during training. The
SPADE RL Orchestrator (Milestone 5) awaits this directly; this module is
also directly usable standalone for the baseline variant and for tests.
- class marla.learning.trainer.TrainingResult(policy: 'RecurrentPolicy', optimizer: 'torch.optim.Optimizer', episode_summaries: 'list[EpisodeSummary]' = <factory>, update_metrics: 'list[dict[str, float]]' = <factory>, environment_steps: 'int' = 0, all_records: 'list[StepRecord]' = <factory>, stopped_by_user: 'bool' = False, eval_episode_summaries: 'list[EpisodeSummary]' = <factory>)[source]
Bases:
object- Parameters:
policy (RecurrentPolicy)
optimizer (torch.optim.Optimizer)
episode_summaries (list[EpisodeSummary])
environment_steps (int)
all_records (list[StepRecord])
stopped_by_user (bool)
eval_episode_summaries (list[EpisodeSummary])
- all_records: list[StepRecord]
- episode_summaries: list[EpisodeSummary]
- eval_episode_summaries: list[EpisodeSummary]
- optimizer: torch.optim.Optimizer
- policy: RecurrentPolicy
- marla.learning.trainer.build_policy_and_optimizer(config, device, consultation_enabled=False)[source]
- Parameters:
- Return type:
tuple[RecurrentPolicy, torch.optim.Optimizer]
- async marla.learning.trainer.run_baseline_training(config, scenario_path, num_rollouts, device=None, seed=None)[source]
Run
num_rolloutscollect/optimize cycles of baseline recurrent PPO.- Parameters:
- Return type:
- async marla.learning.trainer.run_training_loop(policy, optimizer, adapter, run_id, ppo_config, sequence_length, num_rollouts, device, seed, consultation_enabled=False, consultation_cost=0.0, consult_fn=None, stop_event=None, eval_episodes=0, eval_every_rollouts=1)[source]
Repeated rollout-collect/PPO-update cycles over pre-built components.
Used both by
run_baseline_training()(which builds everything itself, for standalone use and tests) and by the SPADE RL Orchestrator, which resolves the device and constructs the policy before connecting to XMPP – a local-model failure must prevent the agent from ever reporting itself ready (spec section 18).- Parameters:
policy (RecurrentPolicy)
optimizer (torch.optim.Optimizer)
adapter (NasimEmuAdapter)
run_id (str)
sequence_length (int)
num_rollouts (int)
device (torch.device)
seed (int)
consultation_enabled (bool)
consultation_cost (float)
consult_fn (Callable[[list[ActionDescriptor], int, int, str, dict], Awaitable[ConsultationResult]] | None)
stop_event (Event | None)
eval_episodes (int)
eval_every_rollouts (int)
- Return type:
Generalized Advantage Estimation with correct episode-boundary handling.
Three cases determine the “next value” used at each step:
terminated: a true terminal transition (FINISH). The next value is 0 – there is no future return to bootstrap.truncated: the episode was cut short (max_episode_steps). The caller must supply abootstrap_values[t]estimate of the state that followed, since the next buffer row (if any) belongs to a fresh episode with a reset GRU state and is not a valid continuation.Neither, but
tis the last row of the rollout window: the PPO horizon ended mid-episode. The caller must again supplybootstrap_values[t](the value of continuing under the current policy).
In every other case, the next value is simply values[t + 1] – the same
episode continues into the next buffer row.
- marla.learning.gae.compute_gae(rewards, values, terminated, truncated, bootstrap_values, gamma, gae_lambda)[source]
Returns
(advantages, returns), both lengthlen(rewards).
Recurrent PPO optimization (spec sections 16-17).
Sequences are chunked per-episode (never spanning an episode boundary) and
replayed by re-running RecurrentPolicy.step() forward through the
chunk with gradients enabled, seeded by each chunk’s stored initial hidden
state and previous-action embedding (a “stored state” truncated-BPTT
scheme: the chunk boundary is a fixed input, not backpropagated through).
Because NASimEmu observations are already fixed in the buffer, this
recomputes only the encoding of each transition under the current
parameters – it never touches the environment or the Plan Maker again. For
the assisted variant, the exact stored Plan Maker confidence vector is
reused verbatim; the Plan Maker itself is never re-invoked during replay.
Sequences are batched and shuffled as whole units (never individual transitions), and each chunk stays within one episode by construction, so there is no cross-episode hidden-state leakage to mask out. Because MARLA does not vectorize environments, chunks are replayed one at a time rather than as a single padded tensor – correctness first, matching the project’s “NASimEmu simulation correctness is the priority” scoping for v0.1.
- class marla.learning.ppo.ReplayOutputs(new_joint_log_probs: 'Tensor', new_values: 'Tensor', action_entropies: 'Tensor', query_entropies: 'Tensor | None')[source]
Bases:
object- Parameters:
new_joint_log_probs (Tensor)
new_values (Tensor)
action_entropies (Tensor)
query_entropies (Tensor | None)
- action_entropies: Tensor
- new_joint_log_probs: Tensor
- new_values: Tensor
- class marla.learning.ppo.SequenceChunk(records: 'list[StepRecord]', advantages: 'list[float]', returns: 'list[float]')[source]
Bases:
object- records: list[StepRecord]
- marla.learning.ppo.build_sequence_chunks(records, advantages, returns, sequence_length)[source]
Group consecutive same-episode records into chunks of at most
sequence_length.A chunk never spans two episodes: whenever
episode_idchanges, a new chunk starts, which is exactly what prevents hidden-state leakage across episode boundaries during replay.- Parameters:
- Return type:
- marla.learning.ppo.optimize(policy, optimizer, records, advantages, returns, ppo_config, sequence_length, minibatch_sequences, device, rng, consultation_cost=0.0)[source]
Runs
ppo_config.epochspasses of shuffled-minibatch updates over the rollout.- Parameters:
- Return type:
- marla.learning.ppo.ppo_update(policy, optimizer, chunks, ppo_config, device, consultation_cost=0.0)[source]
One gradient step over a minibatch of sequence chunks.
- Parameters:
policy (RecurrentPolicy)
optimizer (torch.optim.Optimizer)
chunks (list[SequenceChunk])
ppo_config (PPOConfig)
device (torch.device)
consultation_cost (float)
- Return type:
Masked softmax/entropy utilities for padded, fixed-size PPO minibatches.
Live rollout collection scores a single instance’s legal actions directly (no padding needed). PPO replay (Milestone 4) batches multiple timesteps with different candidate-action counts into fixed-size tensors, padding short rows; padded entries must be masked out of softmax, log-probability, and entropy computations (spec section 13).
- marla.learning.masking.masked_entropy(log_probs, mask, dim=-1)[source]
- Parameters:
log_probs (Tensor)
mask (Tensor)
dim (int)
- Return type:
Tensor
- marla.learning.masking.masked_log_softmax(logits, mask, dim=-1)[source]
mask:True= valid/real entry,False= padding.- Parameters:
logits (Tensor)
mask (Tensor)
dim (int)
- Return type:
Tensor
- marla.learning.masking.masked_softmax(logits, mask, dim=-1)[source]
- Parameters:
logits (Tensor)
mask (Tensor)
dim (int)
- Return type:
Tensor
Checkpoint save/load for the recurrent PPO policy + optimizer.
- class marla.learning.checkpoint.CheckpointMetadata(update_count: 'int', environment_steps: 'int', config_hash: 'str')[source]
Bases:
object
- marla.learning.checkpoint.load_checkpoint(path, policy, optimizer=None, map_location='cpu')[source]
- Parameters:
policy (RecurrentPolicy)
optimizer (Optimizer | None)
map_location (str | device)
- Return type: