ParaRNN

repository·main·Indexed 41 days ago

https://github.com/apple/ml-pararnn

A high-performance framework for automating the parallel application of Recurrent Neural Networks (RNNs) along the sequence length. ParaRNN utilizes Newton methods and parallel reduction algorithms to overcome sequential bottlenecks, offering four application modes: sequential, parallel, parallel_CUDA, and parallel_FUSED. It requires Python 3.9+, PyTorch, and CUDA support.

Tokens
2K
Snippets
5
Records
5
Agent score
3%

What's inside ParaRNN

  1. Understand RNN Application Modes

    main

    ParaRNN provides four application modes that trade off ease of implementation against execution performance. You can switch modes by setting model.mode.

    1. sequential: Classical sequential application. Best for testing, debugging, or inference.
    2. parallel: A reference implementation using Newton + Parallel Reduction implemented purely in native PyTorch. Ideal for prototyping and debugging new cell definitions.
    3. parallel_CUDA: High-performance mode. Jacobian assembly and Newton iterations happen in PyTorch, but the parallel reduction solver uses a custom CUDA kernel optimized for diagonal or NxN-block-diagonal Jacobians.
    4. parallel_FUSED: Maximum performance. Features a fully-fused custom CUDA kernel for the entire Newton routine. This requires you to provide the RNN cell action and Jacobian assembly in CUDA.
    model.mode = 'parallel_CUDA'
  2. Install ParaRNN

    main

    ParaRNN requires Python 3.9+, PyTorch, and CUDA support. Because the package compiles custom CUDA kernels during installation, you must have a compatible C++ compiler and CUDA toolkit installed on your system.

    To install in development mode:

    1. Clone the repository.
    2. (Optional) Set up a virtual environment.
    3. Ensure PyTorch is installed.
    4. Install the package using pip install -e . --no-build-isolation.
    WARNING

    Ensure your environment has CUDA available; the package requires GPU support for accelerated modes.

    git clone https://github.com/apple/ml-pararnn
    cd ml-pararnn
    
    # Optional: Setup virtual environment
    # virtualenv venv
    # source venv/bin/activate
    
    # Ensure torch is installed
    # pip install torch
    
    pip install -e . --no-build-isolation
  3. Create a custom RNN cell

    main

    To implement a custom RNN cell in ParaRNN, you must define three distinct components:

    1. System Parameters

    Create a dataclass inheriting from SystemParameters. This defines the learnable parameters (e.g., weights) and functions (e.g., activations) passed to the recurrence step. You must implement unpack() and repack() methods to allow the framework to manipulate parameters.

    2. Implementation Class

    Choose a base class based on your Jacobian structure to enable CUDA acceleration:

    • RNNCellDenseImpl: For dense Jacobians (no optimization).
    • RNNCellDiagImpl: For diagonal Jacobians (enables parallel_CUDA).
    • RNNCellBlockDiagImpl: For block-diagonal Jacobians (enables parallel_CUDA).

    Implement the recurrence_step class method: recurrence_step(cls, x, h, system_parameters) where h_t = f(h_{t-1}, x_t; params).

    3. Cell Class

    Create a class inheriting from BaseRNNCell. This manages the state, handles parameter initialization in _specific_init, and provides the _system_parameters property.

    Once defined, the cell automatically supports sequential and parallel modes. If you used a -Diag or -BlockDiag implementation, parallel_CUDA is also available out-of-the-box.

    # 1. Define System Parameters
    @dataclass
    class MyRNNSystemParameters(SystemParameters[MyRNNTrait]):
        my_weight: torch.Tensor
        my_nonlin: typ.Callable
    
        def unpack(self) -> typ.Tuple[torch.Tensor, typ.Callable]:
            return (self.my_weight, self.my_nonlin)
    
        @classmethod
        def repack(cls: T, pars: typ.Tuple[torch.Tensor, typ.Callable]) -> T:
            return MyRNNSystemParameters(my_weight=pars[0], my_nonlin=pars[1])
    
    # 2. Choose Implementation
    class MyRNNImpl(RNNCellDiagImpl[MyRNNSystemParameters]):
        @classmethod
        def recurrence_step(cls, x, h, system_parameters):
            # Core recurrence logic here
            ...
    
    # 3. Define Cell Class
    class MyRNNCell(BaseRNNCell[MyRNNConfig, MyRNNSystemParameters, MyRNNImpl]):
        def __init__(self, config):
            super().__init__(config)
        
        def _specific_init(self, config):
            self.my_weight = torch.nn.Parameter(...)
            self.my_nonlin = ...
    
        @property
        def _system_parameters(self):
            return MyRNNSystemParameters(my_weight=self.my_weight, my_nonlin=self.my_nonlin)
    
    # Usage
    config = MyRNNConfig(state_dim=64, input_dim=32, mode='parallel')
    model = MyRNNCell(config)
    output = model(x)
  4. Compare sequential vs parallel performance

    main

    You can use the built-in sequential_vs_parallel testing function to compare the speedup and numerical accuracy of different application modes. This is useful for verifying the performance gains of parallel processing against the baseline sequential approach.

    Note that as seq_length increases, you should expect numerical errors in outputs and gradients to increase proportional to machine_precision * seq_length due to sequence-wise accumulation of approximations.

    import torch
    from pararnn.rnn_cell.test import sequential_vs_parallel
    from pararnn.rnn_cell.gru_diag_mh import GRUDiagMH, GRUDiagMHConfig
    
    # Run the sequential vs parallel comparison
    sequential_vs_parallel(
        model_type=GRUDiagMH,
        model_config_type=GRUDiagMHConfig,
        seq_length=256,
        device='cuda'
    )
  5. Cite ParaRNN in research

    main

    If you use ParaRNN in your research, please cite the following paper:

    ParaRNN: Unlocking Parallel Training of Nonlinear RNNs for Large Language Models

    ArXiv link: https://arxiv.org/abs/2510.21450

    @misc{danieli2025pararnnunlockingparalleltraining,
          title={{ParaRNN}: Unlocking Parallel Training of Nonlinear {RNNs} for Large Language Models},
          author={Federico Danieli and Pau Rodr\'\'iguez and Miguel Sarabia and Xavier Suau and Luca Zappella},
          year={2025},
          eprint={2510.21450},
          archivePrefix={arXiv},
          primaryClass={cs.LG},
          url={https://arxiv.org/abs/2510.21450},
    }