Guide

Async

Async APIs are useful when throughput, concurrency, or multi-step training logic matters. They let the local process submit a PyTRIO task without blocking, continue local work, and wait for the result later.

PyTRIO training APIs usually provide both sync and async versions. Async methods end with _async.

  • Sync: forward_backward
  • Async: forward_backward_async

Usage

Synchronous usage:

for i in range(15):
    fwdbwd_future = training_client.forward_backward(...)
    fwdbwd_result = fwdbwd_future.result()

Asynchronous usage:

async def main():
    for i in range(15):
        fwdbwd_future = await training_client.forward_backward_async(...)
        fwdbwd_result = await fwdbwd_future

if __name__ == "__main__":
    asyncio.run(main())

Calling an async method has two stages:

  1. Submit the task with await training_client.forward_backward_async(...). This returns an APIFutureResult for the remote result.
  2. Read the result with await fwdbwd_future. This waits until the PyTRIO task completes.

This structure lets you overlap local work, scheduling, logging, and remote computation.

Example

import pytrio as trio
import numpy as np
import asyncio

async def main():
    service_client = trio.ServiceClient()

    base_model = "Qwen/Qwen3.5-4B"
    training_client = await service_client.create_lora_training_client_async(
        base_model=base_model,
        rank=32,
    )

    examples = [
        {"input": "what is trio", "output": "TRIO is an AI infrastructure product from EmotionMachine."},
        {"input": "can you explain what trio is", "output": "TRIO helps teams run large-scale LLM post-training from a CPU-only machine."},
        {"input": "tell me about trio", "output": "TRIO provides APIs for LLM training, sampling, and reinforcement learning workflows."},
    ]

    print("Loading tokenizer...")
    tokenizer = training_client.get_tokenizer()
    print("Tokenizer loaded")

    def process_example(example: dict, tokenizer) -> trio.Datum:
        prompt = f"Question: {example['input']}\nAnswer:"
        prompt_tokens = tokenizer.encode(prompt, add_special_tokens=True)
        prompt_weights = [0] * len(prompt_tokens)
        completion_tokens = tokenizer.encode(f" {example['output']}\n\n", add_special_tokens=False)
        completion_weights = [1] * len(completion_tokens)
        tokens = prompt_tokens + completion_tokens
        weights = prompt_weights + completion_weights

        return trio.Datum(
            model_input=trio.ModelInput.from_ints(tokens=tokens[:-1]),
            loss_fn_inputs=dict(weights=weights[1:], target_tokens=tokens[1:])
        )

    processed_examples = [process_example(ex, tokenizer) for ex in examples]

    print("Starting training")
    print_task_queue = []
    for iter in range(15):
        fwdbwd_future = await training_client.forward_backward_async(processed_examples, "cross_entropy")
        optim_future = await training_client.optim_step_async(trio.AdamParams(learning_rate=1e-4))

        async def print_loss_async(fwdbwd_future, optim_future, iter: int):
            fwdbwd_result = await fwdbwd_future
            await optim_future
            logprobs = np.concatenate([output['logprobs'].tolist() for output in fwdbwd_result.loss_fn_outputs])
            weights = np.concatenate([example.loss_fn_inputs['weights'].tolist() for example in processed_examples])
            loss = -np.dot(logprobs, weights) / weights.sum()
            print(f"Iter{iter+1} Loss per token: {loss:.4f}")
            return loss
        
        print_task_queue.append(print_loss_async(fwdbwd_future, optim_future, iter))
        
    await asyncio.gather(*print_task_queue)

if __name__ == "__main__":
    asyncio.run(main())

Supported Async Methods

ServiceClient

SyncAsync
create_lora_training_clientcreate_lora_training_client_async
create_sampling_clientcreate_sampling_client_async
create_training_client_from_statecreate_training_client_from_state_async
create_training_client_from_state_with_optimizercreate_training_client_from_state_with_optimizer_async

SamplingClient

SyncAsync
samplesample_async
compute_logprobscompute_logprobs_async

TrainingClient

SyncAsync
forwardforward_async
forward_backwardforward_backward_async
forward_backward_customforward_backward_custom_async
optim_stepoptim_step_async
save_statesave_state_async
save_weights_for_samplersave_weights_for_sampler_async
create_sampling_clientcreate_sampling_client_async
save_weights_and_get_sampling_clientsave_weights_and_get_sampling_client_async
Was this documentation helpful?

On this page