|
| 1 | +# LwFlow (Lab workFlow) |
| 2 | + |
| 3 | +## Domain-Independent, Secure, and Offline Computational Research Management |
| 4 | + |
| 5 | +LwFlow is a self-contained Python framework for managing computational research experiments. It is designed to work with various domains, from machine learning and data processing to simulation and numerical analysis. Built on the principles of flexibility, reproducibility, and data privacy, LwFlow allows researchers to define, run, track, and transfer entire custom workflows offline. |
| 6 | + |
| 7 | +LwFlow is **domain-agnostic**, leveraging abstract `Component` and `WorkFlow` classes that users can customize to fit their needs. This makes it ideal for use with frameworks like **PyTorch**, **TensorFlow**, or any other complex pipeline structures used in scientific computing. |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +## ✨ Key Capabilities |
| 12 | + |
| 13 | +- **Offline-First**: |
| 14 | + - All experiment tracking and data management are handled locally using file systems and SQLite databases, ensuring **complete data privacy** and uninterrupted work, even without an internet connection. |
| 15 | + |
| 16 | +- **100% Customization**: |
| 17 | + - Built on abstract `Component` and `WorkFlow` classes, users can define their own logic for data loading, processing, simulation, and analysis. |
| 18 | + |
| 19 | +- **Pipeline Tracking (PPLs)**: |
| 20 | + - Centralized management of experiment configurations, status (e.g., `init`, `running`, `frozen`, `cleaned`), and history. |
| 21 | + |
| 22 | +- **Reproducibility Guarantee**: |
| 23 | + - Each pipeline (PPL) is uniquely identified by the cryptographic hash of its entire configuration, preventing configuration drift and ensuring exact reproducibility. |
| 24 | + |
| 25 | +- **Seamless Transfer**: |
| 26 | + - Easily archive experiments, or transfer project setups (including configurations and output artifacts) between local directories, cloud storage, or high-performance computing (HPC) nodes without path reconfiguration. |
| 27 | + |
| 28 | +- **Session Logging**: |
| 29 | + - Automatic tracking of the session origin (e.g., Jupyter session, script filename) and execution time for enhanced auditability. |
| 30 | + |
| 31 | +--- |
| 32 | + |
| 33 | +## 🛠 Installation |
| 34 | + |
| 35 | +You can install **LwFlow** using pip: |
| 36 | + |
| 37 | +``` |
| 38 | +
|
| 39 | +pip install lwflow |
| 40 | +
|
| 41 | +``` |
| 42 | + |
| 43 | +Alternatively, clone the repository for development purposes: |
| 44 | + |
| 45 | +``` |
| 46 | +
|
| 47 | +git clone [https://github.com/ExperQuick/lwf.git](https://github.com/ExperQuick/lwf.git) |
| 48 | +cd LwFlow |
| 49 | +pip install -e . |
| 50 | +
|
| 51 | +```` |
| 52 | +
|
| 53 | +--- |
| 54 | +
|
| 55 | +## 🚀 Getting Started: Running an Experiment Pipeline |
| 56 | +
|
| 57 | +LwFlow structures work around **Labs** (your project environment) and **Pipelines (PPLs)** (customizable experiment runs). |
| 58 | +
|
| 59 | +### 1. Setting Up the Lab Environment |
| 60 | +
|
| 61 | +The Lab manages file paths and databases. You only need to run this once per project. |
| 62 | +
|
| 63 | +```python |
| 64 | +import os |
| 65 | +from lwf.lab import create_project, lab_setup |
| 66 | +
|
| 67 | +# Define mandatory project settings |
| 68 | +SETTINGS = { |
| 69 | + "project_name": "General_Research_Lab", |
| 70 | + "project_dir": "/path/to/my/research_projects", # Parent directory for the project |
| 71 | + "component_dir": "/path/to/my/custom_components", # Directory for custom components and workflows |
| 72 | +} |
| 73 | +
|
| 74 | +# Create project structure, databases, and settings file |
| 75 | +settings_path = create_project(SETTINGS) |
| 76 | +print(f"Project structure and settings created at: {settings_path}") |
| 77 | +
|
| 78 | +# Set up the lab environment for the current Python session |
| 79 | +lab_setup(settings_path) |
| 80 | +```` |
| 81 | +
|
| 82 | +--- |
| 83 | +
|
| 84 | +### 2. Defining a Custom WorkFlow |
| 85 | +
|
| 86 | +Since LwFlow is domain-independent, you define your experiment logic by subclassing `WorkFlow` and `Component`. |
| 87 | +
|
| 88 | +```python |
| 89 | +import os |
| 90 | +from lwf.utils import WorkFlow, Component |
| 91 | +from typing import Dict, Any |
| 92 | +
|
| 93 | +# A generic computational component |
| 94 | +class MyComputationalComponent(Component): |
| 95 | + def _setup(self, args: Dict[str, Any]): |
| 96 | + print(f"Setting up component with args: {args}") |
| 97 | + self.data = args.get("initial_value", 0) |
| 98 | +
|
| 99 | +# Define the flow that combines components and executes the run logic |
| 100 | +class GenericDataWorkflow(WorkFlow): |
| 101 | + |
| 102 | + # Initialize the pipeline run configuration |
| 103 | + def new(self, args: Dict[str, Any]): |
| 104 | + self.data_source = self.load_component(**args['data_source']) |
| 105 | + self.algorithm = self.load_component(**args['algorithm']) |
| 106 | + self.paths = ['results'] # Define artifact paths |
| 107 | +
|
| 108 | + # Perform setup (e.g., loading large datasets/models into memory) |
| 109 | + def prepare(self): |
| 110 | + print("Preparing workflow: loading external data or setting up environment...") |
| 111 | + return True |
| 112 | +
|
| 113 | + # Main execution logic (e.g., training loop, simulation run) |
| 114 | + def run(self): |
| 115 | + print(f"Running PPL: {self.P.pplid}") |
| 116 | + result = self.data_source.data + 10 |
| 117 | + print(f"Final result: {result}") |
| 118 | +
|
| 119 | + # Define standardized paths for saving artifacts |
| 120 | + def get_path(self, of: str, pplid: str, args: Dict) -> str: |
| 121 | + if of == 'results': |
| 122 | + return os.path.join(self.P.settings['data_path'], 'Results', f'{pplid}_output.txt') |
| 123 | + raise NotImplementedError(f"Path for artifact type '{of}' is not defined in GenericDataWorkflow.") |
| 124 | +
|
| 125 | + # Clean up temporary files or output artifacts |
| 126 | + def clean(self): |
| 127 | + print(f"Cleaning artifacts for {self.P.pplid}...") |
| 128 | + # Add logic to delete files here |
| 129 | +
|
| 130 | + # Return execution status or key metrics |
| 131 | + def status(self): |
| 132 | + return {"last_result": 100, "status_detail": "Completed successfully"} |
| 133 | +``` |
| 134 | + |
| 135 | +--- |
| 136 | + |
| 137 | +### 3. Creating and Executing a Pipeline |
| 138 | + |
| 139 | +Once your components are defined, you can create and execute the pipeline using the `PipeLine` class. |
| 140 | + |
| 141 | +```python |
| 142 | +from lwf.experiment import PipeLine |
| 143 | + |
| 144 | +# Define the full configuration with fully qualified paths to components |
| 145 | +pipeline_config = { |
| 146 | + "workflow": { |
| 147 | + "loc": "my_workflows.GenericDataWorkflow", |
| 148 | + "args": {} |
| 149 | + }, |
| 150 | + "args": { |
| 151 | + "data_source": {"loc": "my_workflows.MyComputationalComponent", "args": {"initial_value": 42}}, |
| 152 | + "algorithm": {"loc": "my_workflows.MyComputationalComponent", "args": {"param_b": 5}}, |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +# Create a new pipeline. Configuration is hashed and logged |
| 157 | +P = PipeLine() |
| 158 | +P.new(pplid="ppl_data_run_001", args=pipeline_config) |
| 159 | + |
| 160 | +# Prepare the environment |
| 161 | +P.prepare() |
| 162 | + |
| 163 | +# Run the workflow |
| 164 | +P.run() |
| 165 | +``` |
| 166 | + |
| 167 | +--- |
| 168 | + |
| 169 | +## 💾 Experiment Management Tools |
| 170 | + |
| 171 | +The `lwf.experiment` module provides powerful tools for managing your PPL database: |
| 172 | + |
| 173 | +* **`get_ppls()`**: List all active pipeline IDs in the current Lab. |
| 174 | +* **`get_ppl_status()`**: Returns a DataFrame summarizing the status, last run, and key metrics for all PPLs. |
| 175 | +* **`filter_ppls(query)`**: Filters PPLs based on configuration arguments (e.g., `filter_ppls("data_source=my_workflows.MyComponent")`). |
| 176 | +* **`archive_ppl(ppls)`**: Archives a pipeline, moving its configurations and artifacts to an archived folder for safe storage. |
| 177 | +* **`archive_ppl(ppls, reverse=True)`**: Unarchives a pipeline and returns it to the active environment. |
| 178 | +* **`delete_ppl(ppls)`**: Permanently deletes a pipeline from the archive. |
| 179 | +* **`stop_running()`**: Gracefully stops a currently running pipeline after its current iteration completes. |
| 180 | + |
| 181 | +--- |
| 182 | + |
| 183 | +## 📜 License |
| 184 | + |
| 185 | +This project is licensed under the **Apache License 2.0**. © 2024 BBEK Anand |
0 commit comments