TorchSpec

repository·main·Indexed 42 days ago

https://github.com/lightseekorg/torchspec

A torch-native speculative decoding training framework featuring a disaggregated architecture to decouple inference and training via a Mooncake store. It supports draft model configurations for Eagle3 and DFlash, with integration for SGLang, vLLM, and HuggingFace backends.

Tokens
20.7K
Snippets
62
Records
89
Agent score
53%

What's inside TorchSpec

  1. Understand the TorchSpec package layout

    main

    TorchSpec is organized into several functional domains to support asynchronous training and inference pipelines:

    • config/: Hierarchical configuration using OmegaConf (e.g., train_config.py, inference_config.py).
    • ray/: Ray infrastructure for GPU setup and resource management.
    • controller/: Orchestration of the async pipeline via AsyncTrainingController and AsyncInferenceManager.
    • inference/: Inference engine layer providing unified interfaces for HFEngine, SglEngine, and VllmEngine.
    • models/: Model definitions including draft/ (lightweight transformers), target/ (target model abstractions), and ops/ (custom operations like KL loss).
    • training/: Training logic including TrainerActor (Ray actor), Eagle3Trainer, and FSDP2 helpers.
    • transfer/mooncake/: Distributed tensor transfer using Mooncake for multi-node RDMA-based communication.
    • data/: Data pipelines for loading, parsing, and preprocessing datasets.
    • utils/: Shared utilities for distributed setup, logging, and memory estimation.
  2. What is TorchSpec and how does its architecture work?

    main

    TorchSpec is a torch-native speculative decoding training framework designed for disaggregated training.

    In the TorchSpec architecture, training and inference are fully decoupled to allow each side to scale independently:

    1. Inference engines generate target-model hidden states.
    2. Mooncake store transfers these tensors between inference and training without materializing them on disk.
    3. Training workers consume the streamed hidden states to train speculative decoding draft models.

    This separation ensures that the training side remains focused on optimization while the inference side scales for hidden-state generation throughput.

  3. What is DFlash?

    main

    DFlash is a block-diffusion draft model designed for speculative decoding. Unlike autoregressive models (like Eagle3) that predict tokens sequentially, DFlash predicts 16-token blocks in parallel. It achieves this using dual-source KV attention derived from the target model's hidden states.

    Key technical characteristics:

    • Prediction Mode: Block-parallel (default block_size=16).
    • Loss Function: Cross-entropy (CE) against ground truth tokens.
    • Architecture: Uses a 5-layer transformer that reuses the target model's embedding and LM head (frozen).
  4. Configure Placement Groups for GPU resource management

    main

    Placement groups reserve GPUs and place them on specific nodes using create_placement_groups(args, roles=...). The mode selected determines how training and inference GPUs are allocated:

    ModeTraining GPUsInference GPUsUse case
    DefaultSliced from unified PGSliced from unified PGProduction: deterministic node-to-role assignment
    Online customSliced from custom unified PGSliced from custom unified PGProduction: explicit node choice
    colocateShared PGShared PGDev: share GPUs between train & inference
    Offline trainingDedicated PGNoneTrain from materialized target outputs
    MaterializationNoneDedicated PGProduce target outputs for offline training

    Note: placement_strategy only applies when online training creates both roles; single-role workflows use PACK placement.

  5. Mooncake Integration for Distributed Tensor Transfer

    main

    TorchSpec uses Mooncake for efficient, multi-node distributed tensor transfer via RDMA.

    Core Components:

    • MooncakeHiddenStateStore: The base class for RDMA buffer management.
    • EagleMooncakeStore: An Eagle3-specific wrapper providing:
      • batch_put_from: Zero-copy tensor storage.
      • batch_remove(force=True): Forced deletion of stored tensors.
      • A lazy tensor retrieval interface.
    • HostBufferPool & GPUReceiveBuffer: Managed buffers for host-side pre-allocation and GPU Direct RDMA.
    • helpers.py: Handles buffer size calculations and Mooncake master process management.
  6. Analyze capacity metric relationships

    main

    Compare Inference capacity (I) and Training capacity (T) to understand system balance:

    • I > T: Inference is faster than training. Training is the bottleneck. The sample pool will grow.
    • T > I: Training is faster than inference. Inference is the bottleneck. You will see high dispatch_wait.
    • I ~ T: The system is balanced. Pipeline throughput (thru) will approach both capacity values.
  7. Dataset format for Kimi-K2.5

    main

    The training dataset must be a JSONL file where each row contains a conversations field following the OpenAI-style conversation format. This supports text-only, multimodal (single/multi-image), system messages, multi-turn, and tool calls.

    Multimodal Requirements

    • Config: Set chat_template=kimi-k25-vlm and inference.sglang.enable_multimodal=true in your configuration.
    • Content Structure: For multimodal samples, use a list-of-dicts content format with image_url or image fields. Do not use plain-string placeholders for images, as they will not send pixel data to the engine.
    • Image URLs: For images stored in remote storage (S3, GCS, etc.), use pre-signed URLs so the SGLang engine can fetch them without credentials.
    • Assistant Responses: Assistant content should include <think>...</think> blocks.

    Example of a multimodal JSONL row:

    {
      "id": "kimi_mm_001",
      "conversations": [
        {
          "role": "user",
          "content": [
            {"type": "image_url", "image_url": {"url": "https://upload.wikimedia.org/...jpg"}},
            {"type": "text", "text": "What animal is in this image?"}
          ]
        },
        {
          "role": "assistant",
          "content": "<think>The image shows a domestic cat.</think>This is a cat."
        }
      ]
    }
  8. How to use a 'tap' to probe the residual stream

    main

    A 'tap' is a probe used to read the signal from the residual stream without interrupting the forward pass. To ensure a tap is a 'pure read' and does not corrupt the model state, it must be called with specific parameters that prevent side effects (like folding the delta or writing to the bank).

    To perform a pure read, use the attn_res call with the following configuration:

    • Set output_norm_weight = None: This ensures the kernel returns the mixed (softmax mixture) value rather than the normed value.
    • Set delta = None: Prevents the kernel from folding the delta back into the prefix.
    • Set block_write_idx = -1: Prevents the kernel from committing a new block into the bank.
    • Pass a freshly computed prefix (calculated as prefix_sum + pending_mlp_out) rather than the live prefix_sum used by the model.
    # Example of a pure tap call
    attn_res(prefix, None, bank, score_norm, score_proj, None, num_blocks=...,
             block_write_idx=-1, ...)
    # Note: output_norm_weight = None returns the `mixed` value
  9. Format datasets for Kimi-K2.5 multimodal training

    main

    Datasets must be in JSONL format where each row contains a conversations field following an OpenAI-style structure.

    Multimodal Requirements:

    • Set chat_template=kimi-k25-vlm and inference.sglang.enable_multimodal=true in your configuration.
    • Assistant responses must include <think>...</think> blocks.
    • For multimodal samples, use a list-of-dicts content structure with image_url or image fields. Do not use plain-string `` placeholders for multimodal samples, as they will not send pixel data to the engine.
    • For remote images (S3/GCS), use pre-signed URLs so the engine can fetch them without credentials.

    Example JSONL row (multimodal):

    {
      "id": "kimi_mm_001",
      "conversations": [
        {
          "role": "user",
          "content": [
            {"type": "image_url", "image_url": {"url": "https://upload.wikimedia.org/...jpg"}},
            {"type": "text", "text": "What animal is in this image?"}
          ]
        },
        {
          "role": "assistant",
          "content": "<think>The image shows a domestic cat.</think>This is a cat."
        }
      ]
    }
  10. How offline training works in TorchSpec

    main

    Offline training is a workflow designed to decouple target-model inference from draft-model training. Instead of running target inference simultaneously with training (which requires multiple GPUs), you run target-model inference once to generate and save the hidden states. These saved states are then reused for training.

    This approach allows for development and testing on a single GPU.

    Important Requirements:

    • The materialization and training configurations must use the same target model, tokenizer, draft method, and hidden-state layout.
    • Target-model weights must remain accessible during training, as TorchSpec utilizes the target embedding, normalization, and LM-head weights.
    • Limitations: Offline training does not currently support USP or train_with_decode.
  11. Understand the TorchSpec training startup sequence

    main

    The training entry point (torchspec/train_entry.py → train_async_no_generation) follows a specific sequence. If a job appears stuck, use this guide to identify the current phase:

    PhaseDescriptionVisible in main logTypical duration
    1. Config & datasetParse YAML, load datasetAdded N samples to controllerseconds
    2. Placement groupsReserve GPUs, probe mappingbundle N, actual_bundle_index: M...seconds
    3. Mooncake masterLaunch mooncake subprocessAuto-resolved mooncake master_server_addressseconds
    4. TrainerActor initNCCL/FSDP2 model initDevice mesh (1D), Draft model: N trainable~1 min
    5. SglEngine initModel shard loading → KV cache → CUDA graphsMulti-thread loading shards: N%5–15 min
    6. Queue wiringConnect mooncake queuesset_train_queueseconds
    7. Training loopDispatch + train stepsTraining: N% progress barongoing

    Note on Phase 5: This is the most common phase where jobs appear stuck. After shards reach 100%, the system silently allocates KV cache and captures CUDA graphs, which can take several minutes without any log output.

  12. Understand the Training Architecture layers

    main

    The training implementation is structured in three distinct layers to separate Ray orchestration from model logic:

    1. TrainerActor (trainer_actor.py): The Ray actor layer. It owns the distributed process group (dist.init_process_group), holds the Eagle3Trainer instance, and exposes remote APIs like init, train_from_queue, save_model, and set_vocab_buffers.
    2. Trainer (trainer.py): The abstract base class layer. It handles device mesh setup, MooncakeDataFetcher initialization, checkpointing, profiling, and defines the training/evaluation loop skeleton.
    3. Eagle3Trainer (eagle3_trainer.py): The specific implementation layer. It initializes the Eagle3Model using FSDP2, executes the forward/backward passes, and aggregates metrics.