ZoRRo Train API Reference

Overview

Complete API reference for ZoRRo Train's core classes and methods for prompt deduplication in RL training. Covers DeduplicatedActor, ZoRRoTrain, and supporting utilities.

ZoRRo Train API Reference

Overview

ZoRRo Train provides transparent prompt deduplication for reinforcement learning training. The main entry points are:

  • DeduplicatedActor — High-level reference harness for running deduplicated forward and backward passes
  • ZoRRoTrain — Static utility class implementing core deduplication logic
  • Qwen3ModelOncePatcher — Production patcher installed onto models (installed automatically by DeduplicatedActor)

DeduplicatedActor

Reference harness around Qwen3ModelOncePatcher for running deduplicated forward and backward passes.

Constructor

DeduplicatedActor(
    model_name_or_path: str,
    device: str = "cuda",
    logits_optimization: str = "none",
    use_split_attention: bool = True,
    attn_implementation: str = "eager",
    world_size: int = 1,
    max_token_len: int = 4096,
    dtype: torch.dtype = torch.bfloat16,
)

Parameters:

ParameterTypeDefaultDescription
model_name_or_pathstrHugging Face model identifier or local path (Qwen3 family checkpoint)
devicestr"cuda"Device to load the model on
logits_optimizationstr"none"logprob/entropy dispatch: "none" | "memory" | "compute". "memory" requires initialized torch.distributed process group; "none" / "compute" do not
use_split_attentionboolTrueUse split attention (prompt-to-prompt + response-to-full) vs. single reconstructed attention call
attn_implementationstr"eager"Attention implementation: "eager", "flash_attention_2", "flash_attention_3". Flash variants require GPU + flash-attn
world_sizeint1Data-parallel world size; used to sync shard counts in "memory" mode
max_token_lenint4096Reserved; forwarded to patcher (currently unused)
dtypetorch.dtypetorch.bfloat16Model dtype

Methods

forward()

Run deduplicated forward pass.

forward(
    micro_batch: Dict[str, torch.Tensor],
    temperature: float = 1.0,
    calculate_entropy: bool = False,
) -> ModelOutput

Parameters:

ParameterTypeDefaultDescription
micro_batchDict[str, torch.Tensor]Dict with input_ids, position_ids, attention_mask (all [batch_size, seq_len]) and responses ([batch_size, response_len])
temperaturefloat1.0Temperature for scaling logits
calculate_entropyboolFalseWhether to compute per-token entropy

Returns:

ModelOutput with:

  • logprobs: 1D tensor of shape [num_valid_response_tokens], packed in original sample order with padding removed
  • entropy: 1D tensor (if calculate_entropy=True), same shape as logprobs

Example:

actor = DeduplicatedActor(
    model_name_or_path="Qwen/Qwen3-0.6B",
    device="cuda",
    use_split_attention=True,
)

batch = create_dummy_batch(
    batch_size=8,
    num_unique_prompts=2,
    prompt_len=4096,
    response_len=512,
    device="cuda",
    include_training_fields=True,
)

output = actor.forward(batch, temperature=1.0, calculate_entropy=True)
log_probs = output.logprobs  # [num_valid_response_tokens]
entropy = output.entropy     # [num_valid_response_tokens]

compute_policy_loss_and_backward()

Run PPO training step (forward + backward).

compute_policy_loss_and_backward(
    micro_batch: Dict[str, torch.Tensor],
    temperature: float = 1.0,
    gradient_accumulation: int = 1,
) -> Dict[str, float]

Parameters:

ParameterTypeDefaultDescription
micro_batchDict[str, torch.Tensor]Same as forward()
temperaturefloat1.0Temperature for scaling logits
gradient_accumulationint1Gradient accumulation steps

Returns:

Dict with metrics:

  • actor/policy_loss: PPO clipped policy loss
  • actor/pg_loss: Policy gradient loss
  • actor/pg_clipfrac: Clipping fraction
  • actor/ppo_kl: Approximate KL divergence

Example:

actor.model.train()
metrics = actor.compute_policy_loss_and_backward(
    batch,
    temperature=1.0,
    gradient_accumulation=1
)
print(f"Policy loss: {metrics['actor/policy_loss']:.4f}")

patch()

(Re)install Qwen3ModelOncePatcher onto the model.

patch(
    response_len: int,
    rollout_n: int,
    temperature: float,
) -> Qwen3ModelOncePatcher

Parameters:

ParameterTypeDescription
response_lenintLength of response section
rollout_nintNumber of responses sharing a prompt
temperaturefloatTemperature for scaling logits

Returns:

Qwen3ModelOncePatcher instance (patcher is permanently applied to the model).

Note: The patcher is applied "once" in the sense that it mutates the model's forward methods. Re-patching swaps the forward closures without re-installing the patcher, allowing efficient model reuse across different configurations.

train() / eval()

Set model to training/eval mode.

train() -> None
eval() -> None

ZoRRoTrain

Static utility class implementing core (model-free) deduplication tensor logic.

Methods

find_prompt_groups()

Identify which samples share the same prompt.

@staticmethod
find_prompt_groups(
    input_ids: torch.Tensor,
    response_length: int,
) -> Tuple[List[List[int]], torch.Tensor]

Parameters:

ParameterTypeDescription
input_idstorch.Tensor[batch_size, seq_len] concatenated prompt + response
response_lengthintLength of response portion

Returns:

  • prompt_groups: List of lists; each inner list contains sample indices sharing a prompt
  • unique_prompts: [num_unique, prompt_len] tensor of unique prompt sequences

Example:

from arctic_platform.rl.zorro_train import ZoRRoTrain

input_ids = torch.tensor([
    [1, 2, 3, 4, 5, 6],  # Prompt A + Response 1
    [1, 2, 3, 7, 8, 9],  # Prompt A + Response 2
    [10, 11, 12, 13, 14, 15],  # Prompt B + Response 3
])

prompt_groups, unique_prompts = ZoRRoTrain.find_prompt_groups(
    input_ids, response_length=3
)
# prompt_groups: [[0, 1], [2]]
# unique_prompts: [[1, 2, 3], [10, 11, 12]]

create_deduplicated_batch()

Create deduplicated batch by concatenating tokens into a single sequence.

@staticmethod
create_deduplicated_batch(
    input_ids: torch.Tensor,
    position_ids: torch.Tensor,
    response_length: int,
    prompt_groups: List[List[int]],
    unique_prompts: torch.Tensor,
    attention_mask: Optional[torch.Tensor] = None,
    use_unpad: bool = False,
) -> Tuple[torch.Tensor, torch.Tensor, Dict]

Parameters:

ParameterTypeDefaultDescription
input_idstorch.Tensor[batch_size, seq_len] input token IDs (may contain padding)
position_idstorch.Tensor[batch_size, seq_len] position IDs
response_lengthintLength of response section (including padding)
prompt_groupsList[List[int]]Indices of samples sharing same prompt
unique_promptstorch.TensorTensor of unique prompts
attention_maskOptional[torch.Tensor]None[batch_size, seq_len] (1 for valid, 0 for padding)
use_unpadboolFalseIf True, remove padding to produce packed format

Returns:

  • dedup_input_ids: [1, total_tokens] deduplicated (packed if use_unpad=True)
  • position_ids: Original structure or unpadded/packed if use_unpad=True
  • reconstruction_info: Dict with metadata to reconstruct original batch

Example:

prompt_groups, unique_prompts = ZoRRoTrain.find_prompt_groups(input_ids, 512)

dedup_ids, dedup_pos, recon_info = ZoRRoTrain.create_deduplicated_batch(
    input_ids=input_ids,
    position_ids=position_ids,
    response_length=512,
    prompt_groups=prompt_groups,
    unique_prompts=unique_prompts,
    attention_mask=attention_mask,
    use_unpad=True,
)

reconstruct_sequences()

Reconstruct the full batch from deduplicated per-token output.

@staticmethod
reconstruct_sequences(
    dedup_hidden: torch.Tensor,
    reconstruction_info: Dict,
) -> torch.Tensor

Parameters:

ParameterTypeDescription
dedup_hiddentorch.Tensor[1, total_tokens, hidden_dim] deduplicated hidden states
reconstruction_infoDictMetadata returned by create_deduplicated_batch()

Returns:

torch.Tensor of shape [batch_size, seq_len, hidden_dim] reconstructed to original batch layout.

deduplicate_sequences()

Inverse of reconstruct_sequences(). Extract deduplicated format from full batch.

@staticmethod
deduplicate_sequences(
    full_hidden: torch.Tensor,
    reconstruction_info: Dict,
) -> torch.Tensor

Parameters:

ParameterTypeDescription
full_hiddentorch.Tensor[batch_size, seq_len, hidden_dim] full batch hidden states
reconstruction_infoDictMetadata returned by create_deduplicated_batch()

Returns:

torch.Tensor of shape [1, total_tokens, hidden_dim] in deduplicated format.

extract_unpadded_responses_from_deduped_packed_ids()

Pull each rollout's own response tokens from the packed sequence.

@staticmethod
extract_unpadded_responses_from_deduped_packed_ids(
    packed_ids: torch.Tensor,
    reconstruction_info: Dict,
    offset: int = 0,
) -> torch.Tensor

Parameters:

ParameterTypeDefaultDescription
packed_idstorch.TensorDeduplicated packed token IDs
reconstruction_infoDictMetadata from create_deduplicated_batch()
offsetint0Token offset

Returns:

torch.Tensor of response tokens in deduplicated packed format.

responses_in_orig_sample_order()

Undo the prompt-group permutation, returning tokens in original sample order.

@staticmethod
responses_in_orig_sample_order(
    packed_responses: torch.Tensor,
    reconstruction_info: Dict,
) -> torch.Tensor

Parameters:

ParameterTypeDescription
packed_responsestorch.TensorResponse tokens in deduplicated packed format
reconstruction_infoDictMetadata from create_deduplicated_batch()

Returns:

torch.Tensor of response tokens reordered to original sample order.

attention_mask_to_flash_attn_params()

Convert packed attention mask to Flash Attention varlen parameters.

@staticmethod
attention_mask_to_flash_attn_params(
    attention_mask: torch.Tensor,
    device: torch.device = None,
) -> Dict[str, torch.Tensor]

Parameters:

ParameterTypeDefaultDescription
attention_masktorch.Tensor[total_q_tokens, total_kv_tokens] sparse block-diagonal mask (1 for valid, 0 for masked)
devicetorch.deviceNoneDevice for output tensors (defaults to attention_mask.device)

Returns:

Dict containing:

  • cu_seqlens_q: [num_sequences + 1] cumulative sequence lengths for queries
  • cu_seqlens_k: [num_sequences + 1] cumulative sequence lengths for keys/values
  • max_seqlen_q: Maximum query sequence length
  • max_seqlen_k: Maximum key/value sequence length
  • total_q_tokens: Total number of query tokens
  • total_kv_tokens: Total number of key/value tokens
  • num_sequences: Number of packed sequences
  • seq_lengths_q: List of query sequence lengths
  • seq_lengths_k: List of key sequence lengths

Example:

# Self-attention with 3 sequences: [5, 3, 4] tokens each
flash_params = ZoRRoTrain.attention_mask_to_flash_attn_params(attention_mask)
# cu_seqlens_q: [0, 5, 8, 12]
# cu_seqlens_k: [0, 5, 8, 12]
# max_seqlen_q: 5
# num_sequences: 3

ReconstructionInfo

Dict subclass used to persist and share reconstruction metadata through closures.

class ReconstructionInfo(dict):
    """Ensures object identity persists; forces use of update() to overwrite contents."""
    pass

Usage:

from arctic_platform.rl.zorro_train import ReconstructionInfo

recon_info = ReconstructionInfo(a=1, b=2)
old_id = id(recon_info)

recon_info.update(a=2, b=3)  # Overwrites contents, same object
new_id = id(recon_info)

assert old_id == new_id  # Object identity preserved

Utilities

packed_ppo_policy_loss()

PPO clipped policy loss over packed (1D) response tokens.

def packed_ppo_policy_loss(
    log_prob: torch.Tensor,
    old_log_prob: torch.Tensor,
    advantages: torch.Tensor,
    ref_log_prob: Optional[torch.Tensor] = None,
    clip_ratio: float = 0.2,
    kl_loss_coef: float = 0.001,
) -> Tuple[torch.Tensor, Dict[str, float]]

Parameters:

ParameterTypeDefaultDescription
log_probtorch.Tensor1D log probabilities of current policy
old_log_probtorch.Tensor1D log probabilities of old policy
advantagestorch.Tensor1D advantage estimates
ref_log_probOptional[torch.Tensor]NoneReference log probabilities (for KL penalty)
clip_ratiofloat0.2PPO clip coefficient
kl_loss_coeffloat0.001KL loss coefficient

Returns:

  • policy_loss: Scalar loss tensor (before gradient accumulation scaling)
  • metrics: Dict with keys "actor/pg_loss", "actor/policy_loss", "actor/pg_clipfrac", "actor/ppo_kl", and optionally "actor/kl_loss"

Supported Models

ZoRRo Train currently supports these model families:

  • qwen3
  • qwen3-moe
  • qwen3-next-moe
  • qwen3.6
  • qwen3.6-moe

Support spans dense, MoE, and hybrid (linear + full attention) architectures. Additional models will be added in the future.


Complete Example

from arctic_platform.rl.zorro_train import ZoRRoTrain
from arctic_platform.rl.zorro_train.actor import DeduplicatedActor
from arctic_platform.rl.zorro_train.tests import create_dummy_batch

# 1. Initialize actor (installs Qwen3ModelOncePatcher on first forward)
actor = DeduplicatedActor(
    model_name_or_path="Qwen/Qwen3-0.6B",
    device="cuda",
    logits_optimization="none",
    use_split_attention=True,
    attn_implementation="eager",
)

# 2. Create batch with shared prompts
batch = create_dummy_batch(
    batch_size=8,
    num_unique_prompts=2,  # Only 2 unique prompts for 8 samples
    prompt_len=4096,
    response_len=512,
    device="cuda",
    include_training_fields=True,
    add_padding=True,
)

# 3. Forward pass (automatically deduplicates)
output = actor.forward(batch, temperature=1.0, calculate_entropy=True)
log_probs = output.logprobs  # [num_valid_response_tokens]
entropy = output.entropy     # [num_valid_response_tokens]

# 4. Training step
actor.model.train()
metrics = actor.compute_policy_loss_and_backward(
    batch,
    temperature=1.0,
    gradient_accumulation=1
)
print(f"Policy loss: {metrics['actor/policy_loss']:.4f}")

Performance Expectations

Expected speedups depend on deduplication ratio:

ScenarioBatch SizeUnique PromptsPrompt LenResponse LenExpected Speedup
High dedup1618K1K~2-4x
Medium dedup1648K1K~1.5-2x
Low dedup16168K1K~1x (no benefit)

Note: Actual speedups depend on hardware (GPU compute vs memory bottleneck), attention implementation (Flash Attention gives best results), and sequence lengths (longer prompts = more benefit).


Testing

Run the test suite to verify correctness:

# All ZoRRo Train tests
pytest tests/zorro_train/

# Specific test suites
pytest tests/zorro_train/test_dedup.py             # CPU: dedup algorithm round-trips
pytest tests/zorro_train/test_once_patcher.py      # GPU: forward/backward correctness
pytest tests/zorro_train/test_seqlen_balancing.py  # CPU: sequence-length balancing

# Performance benchmark
python arctic_platform/rl/zorro_train/test_perf.py

References