Evolve heuristics using LLM-driven Genetic Programming.
Project description
HeuristAI (v0.1.0)
Overview
HeuristAI is a Python package that demonstrates how Large Language Models (LLMs) can enhance Genetic Programming (GP). Traditional GP evolves programs or heuristics by applying random mutations and crossover operations, often termed “blind” due to their lack of external knowledge beyond the fitness function. By integrating LLMs (e.g., GPT-4-based models), HeuristAI enables more informed and intelligent manipulations of candidate solutions. Leveraging the vast domain knowledge of LLMs, the package facilitates the generation of refined variations rather than purely random ones, significantly improving the efficiency and effectiveness of the evolutionary search process.
Table of Contents
- Overview
- Citations
- Why Genetic Programming with LLMs?
- Features
- Implemented Models
- Installation
- Quick Start
- Usage
- Parallelization & Concurrency
- Customization
- License
Citations
HeuristAI includes implementations based on the following key research papers:
-
DeepMind FunSearch (Nature)
Citation:
Romera-Paredes, Bernardino, Barekatain, Mohammadamin, Novikov, Alexander, Balog, Matej, Kumar, M. Pawan, Dupont, Emilien, Ruiz, Francisco J. R., Ellenberg, Jordan S., Wang, Pengming, Fawzi, Omar, Kohli, Pushmeet, and Fawzi, Alhussein. Mathematical discoveries from program search with large language models. Nature, 625(7995): 468-475, 2024.
DOI: 10.1038/s41586-023-06924-6
URL: Nature Article -
ReEvo (NeurIPS 2024)
Citation:
Ye, Haoran, Wang, Jiarui, Cao, Zhiguang, Berto, Federico, Hua, Chuanbo, Kim, Haeyeon, Park, Jinkyoo, Song, Guojie. ReEvo: Large Language Models as Hyper-Heuristics with Reflective Evolution. arXiv preprint, 2402.01145, 2024.
URL: arXiv Paper -
Evolution of Heuristics (EoH) (ICML 2024)
Citation:
Liu, Fei, Tong, Xialiang, Yuan, Mingxuan, Lin, Xi, Luo, Fu, Wang, Zhenkun, Lu, Zhichao, Zhang, Qingfu. Evolution of Heuristics: Towards Efficient Automatic Algorithm Design Using Large Language Model. arXiv preprint, 2401.02051, 2024.
URL: arXiv Paper
These implementations faithfully reproduce the methodologies and prompt structures as outlined in their respective publications.
Why Genetic Programming with LLMs?
Traditional Genetic Programming (GP) evolves programs or heuristics by randomly mutating and combining parts of existing code, guided solely by a fitness function. While powerful, this approach can lead to inefficient explorations of the solution space.
Incorporating Large Language Models (LLMs) offers several advantages:
-
Informed Mutations and Crossover: LLMs can suggest meaningful code modifications based on vast training data, ensuring that mutations and crossover operations are more likely to produce functional and efficient heuristics.
-
Domain Expertise: LLMs possess extensive domain knowledge, allowing them to incorporate established algorithms and best practices into the evolutionary process, reducing the randomness inherent in traditional GP.
-
Reduced Blindness: By leveraging LLMs, the evolutionary process becomes less "blind," focusing on more promising regions of the solution space and potentially discovering novel solutions that purely random methods might miss.
This synergy between GP and LLMs enhances the search capabilities, making the evolutionary process more efficient and effective.
Features
-
Easy to Use and Modify
- Easily configure and modify models.
- Define custom initial populations and fitness functions without altering core logic.
-
Structured LLM Outputs
- Ensures clean code generation with error-free parsing by enforcing structured responses from LLMs.
-
Prompt Alignment with Research Papers
- Utilizes prompt templates that closely mirror those used in foundational research, ensuring methodological consistency.
-
Concurrent LLM Calls with LangChain
- Leverages LangChain and
asynciofor asynchronous and concurrent interactions with LLMs, speeding up the generation process.
- Leverages LangChain and
-
Parallel Fitness Computation with Ray
- Utilizes Ray to parallelize fitness evaluations, effectively bypassing Python’s Global Interpreter Lock (GIL) for enhanced performance.
-
Population Tracking
- Logs each generation’s population and their fitness scores in a JSON file (
evolution_log.json) for easy analysis and reproducibility.
- Logs each generation’s population and their fitness scores in a JSON file (
-
Model-Specific Enhancements
- FunSearch: Transitioned from using only completion-based models (e.g., GPT-3.5) to instruction-based models (e.g., GPT-4) to align with API updates and deprecations.
- ReEvo: Optimized token usage by generating reflections and code in a single LLM call, reducing the total token count by half.
-
Ease of Using Different LLMs
- Flexible LLM Integration: HeuristAI abstracts the LLM interface, allowing seamless integration of various language models such as GPT-4o, Llama-3 or other compatible models.
- Minimal Configuration Changes: Switching between different LLMs requires minimal adjustments, enabling users to leverage the strengths of different models without extensive code modifications.
- Custom LLM Support: Beyond OpenAI’s models, HeuristAI can integrate with other LLM providers by adhering to the standardized interface, facilitating broader applicability and customization.
Implemented Models
HeuristAI currently includes implementations for the following models:
-
FunSearch
- Description: An island-model genetic programming approach that employs multi-parent crossover and periodic population resets to maintain diversity and avoid local maxima.
- Publication: Mathematical discoveries from program search with large language models. Nature
- Example Script:
examples/example_FunSearch.py
-
ReEvo
- Description: An evolutionary algorithm that utilizes short-term and long-term considerations to iteratively improve heuristic functions. Incorporates elitist mutations based on aggregated considerations.
- Publication: ReEvo: Large Language Models as Hyper-Heuristics with Reflective Evolution. arXiv
- Example Script:
examples/example_ReEvo.py
-
Evolution of Heuristics (EoH)
- Description: A standard genetic programming model enhanced with LLM-guided mutation and crossover operations. Utilizes prompt templates to steer the generation of new heuristics.
- Publication: Evolution of Heuristics: Towards Efficient Automatic Algorithm Design Using Large Language Model. arXiv
- Example Script:
examples/example_EvolutionofHeuristics.py
Check the examples/ directory for detailed usage demonstrations of each model.
Installation
-
Clone the Repository
git clone https://github.com/m229abd/HeuristAI.git cd HeuristAI
-
Set Up a Virtual Environment (Optional but Recommended)
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install the Package and Dependencies
You can install using
pip:pip install -e .
The
-eflag installs the package in editable mode, allowing you to make changes to the source code that are immediately reflected without reinstalling.Alternatively, install dependencies from
requirements.txt:pip install -r requirements.txt
-
Set Up Environment Variables
Ensure you have your OpenAI API key set up. You can set it as an environment variable:
export OPENAI_API_KEY='your-api-key-here' # On Windows: set OPENAI_API_KEY=your-api-key-here
Or input it when prompted by the example scripts.
Quick Start
-
Obtain an OpenAI API Key
Register and obtain an API key from OpenAI.
-
Run an Example Script
Navigate to the
examples/directory and run one of the example scripts. For instance, to run ReEvo:cd examples python example_ReEvo.py
You will be prompted to enter your OpenAI API key if it's not set as an environment variable.
-
Monitor Evolution
The evolutionary process logs each generation’s population and fitness scores to
evolution_log.json. You can monitor this file to track progress and analyze results.
Usage
1. FunSearch
FunSearch is an island-model evolutionary algorithm that maintains multiple sub-populations (islands) evolving independently. Periodically, the best individuals from the strongest islands replace the worst-performing islands to maintain diversity and drive the search towards optimal solutions.
Example:
import asyncio
from HeuristAI.examples.example_FunSearch import main
if __name__ == "__main__":
asyncio.run(main())
Running the Example:
python examples/example_FunSearch.py
2. ReEvo
ReEvo leverages short-term and long-term considerations to iteratively improve heuristic functions. It compares "worse" code snippets to "better" ones, generates improved offspring, aggregates considerations, and applies elitist mutations based on these aggregated insights.
Example:
import asyncio
from HeuristAI.examples.example_ReEvo import main
if __name__ == "__main__":
asyncio.run(main())
Running the Example:
python examples/example_ReEvo.py
3. Evolution of Heuristics (EoH)
Evolution of Heuristics (EoH) uses standard evolutionary operators—mutation and crossover—enhanced by LLM-guided prompts to generate and refine heuristics. It ensures every crossover and mutation operation is applied at least once per generation, maintaining a robust search process.
Example:
examples/example_EvolutionofHeuristics.py
import asyncio
from HeuristAI.examples.example_EvolutionofHeuristics import main
if __name__ == "__main__":
asyncio.run(main())
Running the Example:
python examples/example_EvolutionofHeuristics.py
Parallelization & Concurrency
HeuristAI leverages parallel computing and asynchronous programming to optimize performance:
-
Ray: The fitness function is decorated with
@ray.remote, enabling parallel execution of fitness evaluations across multiple cores or machines. This parallelization effectively bypasses Python’s Global Interpreter Lock (GIL), allowing for scalable fitness computations. -
LangChain & Asyncio: Utilizes LangChain and
asynciofor asynchronous interactions with LLMs. This concurrency allows multiple LLM calls to be handled simultaneously, significantly reducing the time required for generating and refining heuristics, especially with large populations.
Customization
HeuristAI is designed for flexibility and ease of customization. You can tailor the evolutionary process to fit your specific needs by modifying the following components:
-
Initial Population
Provide your custom set of heuristic solutions. For example, in ReEvo, you can initialize the population with your own heuristics:
from HeuristAI.structures.ReEvo import HeuristicInstance custom_seed = [ HeuristicInstance( consideration="Custom heuristic consideration.", function="def custom_sort(arr): return sorted(arr)" ), # Add more HeuristicInstance objects as needed ] re_evo.initialize_population(custom_seed)
-
Fitness Function
Modify or replace the
default_fitness_functionwith your domain-specific evaluation logic. Ensure that the function takes an individual and test cases as input and returns a scalar fitness score.@ray.remote def custom_fitness_function(instance, test_cases): # Implement custom evaluation logic return fitness_score
Then, pass this custom function when initializing your model:
re_evo = ReEvo( population_size=5, max_iterations=3, test_cases=SEARCH_TEST_CASES, llm=llm, fitness_function=custom_fitness_function.remote, num_retries=3 )
-
Prompt Templates
Modify or create new prompt templates to guide the LLM in generating and refining heuristics. Prompt templates are located in the
prompts/directory for each model. For example, to adjust mutation prompts in EoH, editprompts/EvolutionOfHeuristics.py:from langchain.prompts import PromptTemplate CUSTOM_MUTATION_PROMPT = PromptTemplate( input_variables=["design", "function"], template=""" Your custom mutation instructions here... """ )
Then, integrate the new prompt into the model’s workflow as needed.
-
Logging and Analysis
All evolutionary logs are stored in
evolution_log.json. You can parse and analyze this file to understand the progression of the population across generations. For custom logging or alternative storage formats, modify theEvolutionaryBaseModel’slog_populationmethod accordingly. -
Using Different LLMs
HeuristAI is designed to facilitate the integration of various LLMs with minimal configuration changes. Here's how you can leverage this flexibility:
-
Abstracted LLM Interface: The package abstracts the LLM interactions, allowing you to switch between different language models seamlessly. Whether you prefer OpenAI's GPT models, Hugging Face's transformers, or any other compatible LLM, you can integrate them without altering the core evolutionary algorithms.
-
Configuration-Based Integration: To use a different LLM, adjust the initialization parameters in your example scripts or main application. For instance, to switch from OpenAI's GPT-4 to a Hugging Face model, you might modify the
ChatOpenAIinstance accordingly. -
Example Integration with a Different LLM:
Suppose you want to use Hugging Face's
transformerslibrary instead of OpenAI's models. You can create a custom LLM wrapper that adheres to the expected interface used by HeuristAI.from transformers import pipeline class HuggingFaceLLM: def __init__(self, model_name: str, temperature: float = 0.7): self.generator = pipeline('text-generation', model=model_name) self.temperature = temperature async def ainvoke(self, prompt: str): result = self.generator(prompt, max_length=150, temperature=self.temperature) return {"text": result[0]['generated_text']}
Then, initialize your model with this custom LLM:
from HeuristAI.models.ReEvo import ReEvo from HeuristAI.structures.ReEvo import HeuristicInstance # Initialize the custom HuggingFace LLM hf_llm = HuggingFaceLLM(model_name="gpt2", temperature=0.7) # Initialize ReEvo with the custom LLM re_evo = ReEvo( population_size=5, max_iterations=3, test_cases=SEARCH_TEST_CASES, llm=hf_llm, fitness_function=custom_fitness_function.remote, num_retries=3 )
-
Minimal Code Changes: As shown above, switching LLMs primarily involves changing the LLM initialization. The rest of the HeuristAI package interacts with the LLM through a standardized interface, ensuring compatibility and reducing the need for extensive code modifications.
-
Extensibility: You can further extend support for additional LLMs by implementing similar wrapper classes that conform to the expected interface, allowing HeuristAI to remain agnostic to the underlying language model provider.
-
License
This project is licensed under the MIT License. See the LICENSE file for details.
Happy Evolving!
If you have any questions or suggestions, please open an issue on GitHub or email me at m229abd@gmail.com.
HeuristAI - Empowered by LLM-driven Genetic Programming.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file HeuristAI-0.1.0.tar.gz.
File metadata
- Download URL: HeuristAI-0.1.0.tar.gz
- Upload date:
- Size: 11.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6432441e88e1bee5bc81e3094555c29b6617882f9b3ca4e657b3ab5af9ff088
|
|
| MD5 |
73ce5ad0051cb1bbdb8e9ef5a20dfd33
|
|
| BLAKE2b-256 |
c942ec7a810bed9dae2178a1204ab3920471f203b89fa29b65d3a017fefae066
|
File details
Details for the file HeuristAI-0.1.0-py3-none-any.whl.
File metadata
- Download URL: HeuristAI-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57255c98713e0a5a46f5acf587ee63e30eff0c9be5b681788a25ee3f705a75bd
|
|
| MD5 |
2297e78f9ef632b4d2c2f8c3a0bf7750
|
|
| BLAKE2b-256 |
60c3be5280bd2bc1ace8d0caafc23f02ab1b8cc52be45f3c30327a2b944d75b7
|