CLRS Algorithmic Reasoning Benchmark
repository·master·Indexed 17 days ago
https://github.com/google-deepmind/clrsAn 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'.
What's inside clrs
- 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.
How algorithms are represented as graphs
masterCLRS 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).
Use CLRS-Text libraries and utilities
masterCLRS-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 withoutmax-hinttracking.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.
Add a new algorithm to the benchmark
masterTo add a new algorithm to the CLRS suite, follow these three steps:
- Define the Specification: Determine the input, hint, and output requirements and add them to the
SPECSdictionary inclrs/_src/specs.py. - Implement the Algorithm: Implement the algorithm in an abstractified form (refer to
clrs/_src/algorithms/for examples).- Use
probing.pushto capture inputs, outputs, and intermediate states (probes). - Use
probing.finalizeto format these probes before returning them with the algorithm output.
- Use
- Implement a Sampler: Create an appropriate input data sampler and add it to the
SAMPLERSdictionary inclrs/_src/samplers.py.
Once completed, the algorithm can be accessed via
clrs.build_samplerand included in datasets generated byclrs/dataset.py.- Define the Specification: Determine the input, hint, and output requirements and add them to the
Install the CLRS Benchmark
masterYou can install the CLRS Algorithmic Reasoning Benchmark via
pipfrom PyPI or directly from the GitHub repository. It is recommended to use a virtual environment to avoid dependency conflicts.From PyPI:
pip install dm-clrsFrom GitHub (latest):
pip install git+https://github.com/google-deepmind/clrs.gitUsing a virtual environment:
python3 -m venv clrs_env source clrs_env/bin/activate pip install git+https://github.com/google-deepmind/clrs.gitpip install git+https://github.com/google-deepmind/clrs.gitAccess CLRS-Text datasets on Hugging Face
masterFor immediate use, a Hugging Face Collection is available containing the exact examples used to train and evaluate models in the original CLRS-Text paper's evaluation.
Run the example baseline model
masterOnce 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.runpython3 -m clrs.examples.runLoad algorithm trajectories using `clrs.create_dataset`
masterYou can load training, evaluation, or test trajectories for a specific algorithm using
clrs.create_dataset.Each item in the dataset is a
Feedbacknamedtuple containing:features: AFeaturesnamedtuple withinputs,hints(padded tomax(T)), andlengths(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)Generate algorithm samples using `clrs.build_sampler`
masterIf you want to generate samples without using the
tensorflow_datasetgenerator, you can instantiate samplers directly usingclrs.build_samplerfromclrs/_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): ...Implement a new GNN processor
masterTo add a new GNN baseline processor, add it to the
processors.pyfile and register it via theget_processor_factorymethod. 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_sizexnb_nodesx H (float array)edge_fts:batch_sizexnb_nodesxnb_nodesx H (float array)graph_fts:batch_sizex H (float array)adj_mat:batch_sizexnb_nodesxnb_nodes(boolean array of connectivity)hidden:batch_sizexnb_nodesx H (float array of previous-step outputs)nb_nodes: Number of nodesbatch_size: Batch size
Returns:
- A float array of shape
batch_sizexnb_nodesx H.
For fundamentally different baselines, extend the
ModelAPI found inclrs/_src/model.py.__call__(self, node_fts, edge_fts, graph_fts, adj_mat, hidden, nb_nodes, batch_size)