CLRS Algorithmic Reasoning Benchmark

repository·master·Indexed 17 days ago

https://github.com/google-deepmind/clrs

An algorithmic reasoning benchmark providing implementations of classical algorithms from the CLRS textbook represented as graphs. It is designed to evaluate how machine learning models, particularly Graph Neural Networks and language models (via the CLRS-Text textual wrapper), learn and generalize algorithmic logic using input/output pairs and intermediate state 'hints'.

Tokens
1.6K
Snippets
5
Records
10
Agent score
19%

What's inside clrs

  1. Overview of the CLRS-Text Benchmark

    master
    CLRS-Text is a textual version of the traces generated by thirty algorithms selected from the Introduction to Algorithms textbook. It is designed to evaluate the out-of-distribution (OOD) reasoning capabilities of language models (LMs), specifically focusing on tasks like length generalization. It acts as a text-based wrapper around the base CLRS benchmark.
  2. How algorithms are represented as graphs

    master

    CLRS represents algorithms as manipulations of sets of objects and their relations using a graph representation. For algorithms involving ordered structures like arrays or rooted trees, ordering is imposed via predecessor links.

    This representation allows the benchmark to provide:

    • Input/Output pairs: Automatically generated by controlling input distributions to match algorithm preconditions.
    • Trajectories of 'hints': These expose the internal state of the algorithm, which can be used to simplify learning or to distinguish between different algorithms that solve the same task (e.g., different sorting methods).
  3. Use CLRS-Text libraries and utilities

    master

    CLRS-Text provides several specialized libraries to facilitate working with textual algorithmic traces:

    • clrs_utils.py: Contains base functionalities for converting a CLRS trace into strings. Important: Current converters do not manage padding. It is recommended to process traces sampled with a batch size of 1 and without max-hint tracking.
    • generate_clrs_text.py: Pre-packaged scripts to generate the full CLRS-Text training and evaluation sets in JSON format. Refer to the script's docstring for specific launch instructions.
    • huggingface_generators.py: A convenience function that abstracts sampler and generation calls to CLRS/CLRS-Text, providing Hugging Face-compatible samples based on provided hyperparameters.
  4. Add a new algorithm to the benchmark

    master

    To add a new algorithm to the CLRS suite, follow these three steps:

    1. Define the Specification: Determine the input, hint, and output requirements and add them to the SPECS dictionary in clrs/_src/specs.py.
    2. Implement the Algorithm: Implement the algorithm in an abstractified form (refer to clrs/_src/algorithms/ for examples).
      • Use probing.push to capture inputs, outputs, and intermediate states (probes).
      • Use probing.finalize to format these probes before returning them with the algorithm output.
    3. Implement a Sampler: Create an appropriate input data sampler and add it to the SAMPLERS dictionary in clrs/_src/samplers.py.

    Once completed, the algorithm can be accessed via clrs.build_sampler and included in datasets generated by clrs/dataset.py.

  5. Install the CLRS Benchmark

    master

    You can install the CLRS Algorithmic Reasoning Benchmark via pip from PyPI or directly from the GitHub repository. It is recommended to use a virtual environment to avoid dependency conflicts.

    From PyPI:

    pip install dm-clrs

    From GitHub (latest):

    pip install git+https://github.com/google-deepmind/clrs.git

    Using a virtual environment:

    python3 -m venv clrs_env
    source clrs_env/bin/activate
    pip install git+https://github.com/google-deepmind/clrs.git
    pip install git+https://github.com/google-deepmind/clrs.git
  6. Run the example baseline model

    master

    Once installed, you can run the provided example baseline model using the following command. On the first run, the dataset will be automatically downloaded and stored in --dataset_path (defaulting to /tmp/CLRS30).

    python3 -m clrs.examples.run
    python3 -m clrs.examples.run
  7. Load algorithm trajectories using `clrs.create_dataset`

    master

    You can load training, evaluation, or test trajectories for a specific algorithm using clrs.create_dataset.

    Each item in the dataset is a Feedback namedtuple containing:

    • features: A Features namedtuple with inputs, hints (padded to max(T)), and lengths (the true trajectory length for masking).
    • outputs: The algorithm's final output.

    All fields are ndarrays with a leading batch dimension.

    train_ds, num_samples, spec = clrs.create_dataset(
          folder='/tmp/CLRS30',
          algorithm='bfs',
          split='train',
          batch_size=32)
    
    for i, feedback in enumerate(train_ds.as_numpy_iterator()):
      # feedback.features contains inputs, hints, and lengths
      # feedback.outputs contains the target outputs
      if i == 0:
        model.init(feedback.features, initial_seed)
      loss = model.feedback(rng_key, feedback)
    train_ds, num_samples, spec = clrs.create_dataset(
          folder='/tmp/CLRS30', algorithm='bfs',
          split='train', batch_size=32)
    
    for i, feedback in enumerate(train_ds.as_numpy_iterator()):
      if i == 0:
        model.init(feedback.features, initial_seed)
      loss = model.feedback(rng_key, feedback)
  8. Generate algorithm samples using `clrs.build_sampler`

    master

    If you want to generate samples without using the tensorflow_dataset generator, you can instantiate samplers directly using clrs.build_sampler from clrs/_src/samplers.py.

    sampler, spec = clrs.build_sampler(
        name='bfs',
        seed=42,
        num_samples=1000,
        length=16)
    
    def _iterate_sampler(batch_size):
      while True:
        yield sampler.next(batch_size)
    
    for feedback in _iterate_sampler(batch_size=32):
      # Process feedback
      ...
    sampler, spec = clrs.build_sampler(
        name='bfs',
        seed=42,
        num_samples=1000,
        length=16)
    
    def _iterate_sampler(batch_size):
      while True:
        yield sampler.next(batch_size)
    
    for feedback in _iterate_sampler(batch_size=32):
      ...
  9. Implement a new GNN processor

    master

    To add a new GNN baseline processor, add it to the processors.py file and register it via the get_processor_factory method. A processor must implement a __call__ method with the following signature:

    __call__(self,
             node_fts, edge_fts, graph_fts,
             adj_mat, hidden,
             nb_nodes, batch_size)

    Parameter Shapes:

    • node_fts: batch_size x nb_nodes x H (float array)
    • edge_fts: batch_size x nb_nodes x nb_nodes x H (float array)
    • graph_fts: batch_size x H (float array)
    • adj_mat: batch_size x nb_nodes x nb_nodes (boolean array of connectivity)
    • hidden: batch_size x nb_nodes x H (float array of previous-step outputs)
    • nb_nodes: Number of nodes
    • batch_size: Batch size

    Returns:

    • A float array of shape batch_size x nb_nodes x H.

    For fundamentally different baselines, extend the Model API found in clrs/_src/model.py.

    __call__(self,
             node_fts, edge_fts, graph_fts,
             adj_mat, hidden,
             nb_nodes, batch_size)