PopTorch

repository·sdk-release-3.4·Indexed 41 days ago

https://github.com/graphcore/poptorch

PyTorch extensions for training and evaluating models on Graphcore IPUs. Includes PopTorch Geometric for Graph Neural Network (GNN) workloads and a Dispatch Tracing system with JIT and MLIR backends for model tracing in inference mode.

Tokens
24.1K
Snippets
59
Records
108
Agent score
51%

What's inside PopTorch

  1. What is PopTorch Geometric?

    sdk-release-3.4

    PopTorch Geometric is a set of extensions for PyTorch Geometric designed to enable Graph Neural Network (GNN) models to be trained, evaluated, and used on Graphcore IPU hardware.

    It is built to require minimal changes to existing PyTorch Geometric models, though it introduces some differences from native PyTorch Geometric execution to optimize performance for IPU hardware. PopTorch Geometric relies on the core functionality provided by PopTorch.

  2. Understand Dispatch Tracing backends (JIT vs MLIR)

    sdk-release-3.4

    PopTorch uses a custom implementation of torch::jit::trace called Dispatch Tracing. This allows tracing autograd functions and sidestepping standard PyTorch JIT constraints. There are two available backends:

    1. JIT Backend: Traces the user model into standard PyTorch JIT IR, then canonicalizes it into PopART-compatible JIT IR. This is useful for decomposing operations into the PopART subset.
    2. MLIR Backend: Traces the model directly into the PyTorch native MLIR backend. It can either map operations directly to MLIR or use the JIT path internally to decompose operations into the PopART subset.

    Key Constraint: Models can only be traced in inference mode. For training, PopART can optionally apply its own autograd to convert the traced inference graph into a training graph.

  3. Configure Stages and Phases for execution

    sdk-release-3.4

    PopTorch uses a hierarchy of Blocks $\rightarrow$ Stages $\rightarrow$ Phases to manage execution:

    • Stage: A collection of blocks that run on one IPU. A stage is identified by a user_id or stage_id.
      • Use poptorch.AutoStage to automatically assign stages.
      • If AutoStage.SameAsIpu is true, stage_id matches the ipu_id.
      • If AutoStage.AutoIncrement is true, each block gets a unique, incrementing stage_id. This is useful in PipelinedExecution to avoid scheduling conflicts where the model flow contradicts the stage_id order.
    • Phase: A processing unit used in SerialPhasedExecution and ParallelPhasedExecution. A phase can contain one or more stages.

    In phased execution, weights and activations are transferred to/from Streaming Memory between phases. This allows running larger models that exceed IPU memory by trading off performance for capacity.

  4. Configure Loss Scaling for float16 training

    sdk-release-3.4

    When training with half or float16 values, use loss scaling to prevent gradient underflow. PopTorch scales the loss by the loss_scaling parameter before gradient calculation and multiplies gradients by the inverse scale before the optimizer update. This process does not affect training hyper-parameters.

    Options:

    1. Manual Scaling: Set the loss_scaling parameter directly on the optimizer.
    2. Automatic Scaling: Use poptorch.options._TrainingOptions.setAutomaticLossScaling to enable a global automatic scaling factor.

    Note: If automatic loss scaling causes convergence issues or compilation errors, switch to manual scaling.

  5. Slicing tensors in PopTorch

    sdk-release-3.4

    When slicing a tensor in a PopTorch model, you must satisfy one of two conditions for the operation to be supported on IPU hardware:

    1. The start and end indices are constants (or can be resolved to constants, such as a function of the tensor shape that remains invariant between runs).
    2. The start and end indices are related by a constant (e.g., tensor[x:x+5]).

    Note on behavior: If the end value of a slice exceeds the length of the tensor, PopTorch behaves differently than PyTorch. While PyTorch returns a smaller tensor, PopTorch allows the slice to wrap around to the start of the relevant dimension.

  6. How to use PyTorch buffers for persistent tensors

    sdk-release-3.4

    PopTorch supports PyTorch buffers to make tensors persistent across runs without making them model parameters.

    Important Requirements:

    1. In-place modifications only: You must use PyTorch in-place operations (e.g., += or methods ending in _ like torch.Tensor.copy_) to modify the buffer. Standard assignments (e.g., model.i += 1) will fail because the PyTorch dispatcher captures the value during graph construction and freezes it as a constant.
    2. Inference Models: When using poptorch.inferenceModel, buffers modified by the model are not automatically copied to the host. You must call poptorch.PoplarExecutor.copyWeightsToHost before reading the updated buffer values.
    3. Replicas: By default, PopTorch broadcasts buffers between replicas. To give each replica its own separate buffer, set the broadcastBuffers option to False using poptorch.Options().broadcastBuffers(False).
    # Correct way to use a persistent buffer
    class MyModel(torch.nn.Module):
        def __init__(self):
            super().__init__()
            self.register_buffer('i', torch.zeros(1))
    
        def forward(self, x):
            self.i += 1  # Must be an in-place operation
            return x
  7. Manage Constant and Variable attributes in PopTorch optimizers

    sdk-release-3.4

    PopTorch optimizes performance by embedding constant attributes directly in the program.

    For poptorch.optim optimizers:

    • Attributes passed to the constructor are treated as variables by default.
    • Other attributes are treated as constants.
    • You can override this using poptorch.optim.VariableAttributes.markAsConstant or poptorch.optim.VariableAttributes.markAsVariable before model compilation.
    • Warning: Modifying a constant attribute after compilation results in an error.

    For native torch.optim optimizers:

    • Attributes left at their default values are treated as constants. There is no way to override this behavior, so it is recommended to use poptorch.optim instead.
    # Constant and variable attributes for PopTorch optimizers
    optimizer = poptorch.optim.Adam(model.parameters(), lr=0.01)
    optimizer.markAsConstant('lr') # This would make lr a constant
  8. Manage optimizers and optimizer state in PopTorch

    sdk-release-3.4

    In PopTorch, the optimizer state is encapsulated within the poptorch_model.

    Important considerations:

    • Updating Optimizers: If you make changes to an optimizer outside of the model, you must call poptorch_model.setOptimizer(updated_optimizer) to synchronize the state.
    • Custom Optimizers: PopTorch uses built-in implementations for performance. You cannot currently use custom Python-based optimizers; subclassing a built-in optimizer will trigger a warning and custom behavior is unlikely to take effect.
    • PopTorch Optimizers: It is recommended to use the optimizers provided in poptorch.optim. These are wrapper classes that offer performance/memory advantages and allow for parameters like loss scaling and velocity scaling.
    # If you update the optimizer externally, sync it with the model:
    poptorch_model.setOptimizer(new_optimizer)
  9. How PopTorch training differs from native PyTorch

    sdk-release-3.4

    When using poptorch.trainingModel, the training workflow changes significantly from native PyTorch due to PopTorch's custom automatic differentiation (autograd) engine:

    1. Loss Integration: The input torch.nn.Module must have at least one loss value built into its forward pass. The model should return the loss value(s) as part of its output.
    2. No Manual Backpropagation: You do not call loss.backward(). PopTorch automatically detects the loss value and backpropagates gradients from it.
    3. No Manual Optimizer Steps: You pass the optimizer (e.g., torch.optim.AdamW) as an argument to poptorch.trainingModel. PopTorch manages the optimizer state and applies the algorithm automatically; you do not call optimizer.step() in your training loop.
    4. Data Loading: Use the poptorch.DataLoader class for efficient data batching on the IPU.
  10. Configure parallel execution and sharding

    sdk-release-3.4

    PopTorch provides several abstractions to define how computation is distributed across IPUs:

    • Execution Patterns:
      • poptorch.PipelinedExecution: For pipeline parallelism.
      • poptorch.ShardedExecution: For sharding parameters/data.
      • poptorch.SerialPhasedExecution and poptorch.ParallelPhasedExecution: For controlling execution phases.
    • Structural Primitives:
      • poptorch.Block and poptorch.BeginBlock: Define computation blocks.
      • poptorch.Stage and poptorch.AutoStage: Define stages in a pipeline.
      • poptorch.Phase: Defines specific phases of execution.
    • Replica Grouping: Use poptorch.replicaGrouping(tensor, comm_group_type, shards, variable_retrieval_mode) on a weight tensor (after wrapping with trainingModel or inferenceModel) to configure how replicas receive different values of that tensor.