AsyncTensorRLHF / src /orchestrator /scheduler.py
tahamajs's picture
Initial release of AsyncTensorRLHF: High-Throughput Asynchronous RLHF with Tensor-Native Rewards
e791b16 verified
Raw History Blame Contribute Delete
2.94 kB
# Scheduler and orchestrator utilities for asynchronous RLHF
import asyncio
from typing import Any, Callable, List, Optional
import torch
from ..rollout.version_manager import VersionManager
class Orchestrator:
"""Coordinates rollout, buffer, trainer, and weight synchronization.
- Maintains a prompt queue.
- Tracks current policy version via VersionManager.
- Periodically triggers weight synchronization and training updates.
"""
def __init__(
self,
version_manager: Optional[VersionManager] = None,
weight_sync_fn: Optional[Callable] = None,
sync_interval: int = 10,
rollout_worker: Optional[Any] = None,
trainer_worker: Optional[Any] = None,
buffer: Optional[Any] = None,
):
self.prompt_queue = asyncio.Queue()
self.version_manager = version_manager or VersionManager()
self.weight_sync_fn = weight_sync_fn
self.sync_interval = sync_interval
self.rollout_worker = rollout_worker
self.trainer_worker = trainer_worker
self.buffer = buffer
self._stop = asyncio.Event()
async def add_prompt(self, prompt: Any):
await self.prompt_queue.put(prompt)
async def step_training(self, batch_size: int = 16) -> Optional[float]:
"""Execute one training step if a trainer worker is configured."""
if self.trainer_worker is None:
return None
if hasattr(self.trainer_worker, "step"):
if hasattr(self.trainer_worker.step, "remote"):
return await self.trainer_worker.step.remote(batch_size)
return self.trainer_worker.step(batch_size)
return None
async def run(self, max_steps: Optional[int] = None):
"""Main orchestration loop."""
step = 0
losses: List[float] = []
while not self._stop.is_set():
if max_steps is not None and step >= max_steps:
break
# If rollout worker is configured, feed a prompt batch
if self.rollout_worker is not None:
prompts = [{"input_ids": torch.tensor([1, 2, 3]), "gt_ids": torch.tensor([2, 3]), "eos_token_id": 99}]
if hasattr(self.rollout_worker, "step"):
await self.rollout_worker.step(prompts)
# Perform a trainer step
loss = await self.step_training()
if loss is not None:
losses.append(loss)
# Check if sync interval reached
if step % self.sync_interval == 0:
new_version = self.version_manager.bump()
if self.weight_sync_fn is not None:
res = self.weight_sync_fn(new_version)
if asyncio.iscoroutine(res):
await res
step += 1
await asyncio.sleep(0.001)
return losses
def stop(self):
self._stop.set()