optuna-hpf 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Skill(update-config)",
5
+ "Bash(gh --version)",
6
+ "Bash(git --version)",
7
+ "Bash(gh auth:*)",
8
+ "Bash(git add:*)",
9
+ "Bash(git commit:*)",
10
+ "Bash(gh repo:*)",
11
+ "Bash(git tag:*)",
12
+ "Bash(git push:*)",
13
+ "Bash(gh release:*)",
14
+ "Bash(curl -s https://pypi.org/pypi/hpf/json)",
15
+ "Bash(python3 -c \"import sys,json; d=json.load\\(sys.stdin\\); print\\(d['info']['name'], d['info']['version']\\)\")",
16
+ "Bash(curl -s -o /dev/null -w \"hpranges: %{http_code}\\\\n\" https://pypi.org/pypi/hpranges/json)",
17
+ "Bash(curl -s -o /dev/null -w \"hyperparameter-finder: %{http_code}\\\\n\" https://pypi.org/pypi/hyperparameter-finder/json)",
18
+ "Bash(curl -s -o /dev/null -w \"optuna-hpf: %{http_code}\\\\n\" https://pypi.org/pypi/optuna-hpf/json)",
19
+ "Bash(curl -s -o /dev/null -w \"hpfinder: %{http_code}\\\\n\" https://pypi.org/pypi/hpfinder/json)",
20
+ "Bash(curl -s -o /dev/null -w \"optuna-ranger: %{http_code}\\\\n\" https://pypi.org/pypi/optuna-ranger/json)"
21
+ ]
22
+ }
23
+ }
@@ -0,0 +1,13 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ .pytest_cache/
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .env
10
+ *.db
11
+ *.sqlite
12
+ .DS_Store
13
+ ~/.hpf/
@@ -0,0 +1,49 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ # Activate venv (always do this first)
9
+ source .venv/bin/activate
10
+
11
+ # Run tests
12
+ python -m pytest tests/ -v --tb=short
13
+
14
+ # Run a single test file
15
+ python -m pytest tests/test_analyzer.py -v
16
+
17
+ # Install in editable mode (after pulling changes)
18
+ pip install -e ".[dev]"
19
+
20
+ # Run the CLI
21
+ hpf analyze --study <name> --file <path.db>
22
+ hpf setup
23
+ ```
24
+
25
+ ## Architecture
26
+
27
+ The pipeline is linear: `StudyAnalyzer → RangeSuggester → LLMClient → Reporter`
28
+
29
+ **`hpf/models.py`** — all shared dataclasses (`AnalysisResult`, `ParameterStats`, `ParameterSuggestion`, `HPFReport`). Every module imports from here; never duplicate these types.
30
+
31
+ **`hpf/analyzer.py`** — `StudyAnalyzer.analyze(study, model_type)` filters complete trials, sorts by objective direction, takes top-K% (floor 3), and builds `ParameterStats` per parameter. Uses Optuna's `FloatDistribution`, `IntDistribution`, `CategoricalDistribution` to detect type and scale.
32
+
33
+ **`hpf/range_suggester.py`** — `RangeSuggester.suggest(analysis)` applies a 4-rule waterfall per numeric param: LOG_SCALE → EXPAND → NARROW → KEEP. Uses numpy for percentile calculations. Also contains `_generate_optuna_code()`.
34
+
35
+ **`hpf/llm/`** — abstract `LLMClient` base with `_build_prompt()` shared logic. `OllamaClient` and `OpenAIClient` are concrete implementations. `SetupWizard` saves config to `~/.hpf/config.json`.
36
+
37
+ **`hpf/formatters/report.py`** — `Reporter.print_report(HPFReport)` renders the full terminal output using `rich`. Order: welcome banner → study summary → parameter table → LLM panel → code block → next steps.
38
+
39
+ **`hpf/formatters/code_gen.py`** — standalone `generate_optuna_code(suggestions, study_name)` function, no external state.
40
+
41
+ **`hpf/cli.py`** — two Typer commands: `analyze` (full pipeline) and `setup` (wizard). Error handling with rich panels.
42
+
43
+ ## Key design rules
44
+
45
+ - Optuna-only for HPO framework support (no Ray Tune, HyperOpt, etc. yet)
46
+ - LLM is always optional — all statistical analysis works without it
47
+ - `ParameterStats.best_values` are raw sampled values (not normalized); the suggester works in the original parameter space
48
+ - Categorical params use `best_values` as a set membership check (not numeric comparisons)
49
+ - The `boundary_threshold` in `RangeSuggester` is a fraction of the range, not an absolute value
@@ -0,0 +1,204 @@
1
+ Metadata-Version: 2.4
2
+ Name: optuna-hpf
3
+ Version: 0.1.0
4
+ Summary: Automatically find optimal hyperparameter search ranges for Optuna studies
5
+ Keywords: automl,hyperparameter,machine-learning,optimization,optuna
6
+ Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: Intended Audience :: Science/Research
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: numpy>=1.24
15
+ Requires-Dist: ollama>=0.2
16
+ Requires-Dist: openai>=1.0
17
+ Requires-Dist: optuna>=3.0
18
+ Requires-Dist: pydantic-settings>=2.0
19
+ Requires-Dist: pydantic>=2.0
20
+ Requires-Dist: rich>=13.0
21
+ Requires-Dist: scipy>=1.10
22
+ Requires-Dist: typer>=0.9
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest-cov; extra == 'dev'
25
+ Requires-Dist: pytest-mock; extra == 'dev'
26
+ Requires-Dist: pytest>=7.0; extra == 'dev'
27
+ Description-Content-Type: text/markdown
28
+
29
+ # hpf — Hyperparameter Finder
30
+
31
+ **Stop guessing search ranges.** `hpf` analyzes your completed Optuna studies and tells you exactly how to adjust your hyperparameter bounds before the next run — with statistical reasoning and optional LLM-powered explanations.
32
+
33
+ ---
34
+
35
+ ## The Problem
36
+
37
+ When you set up an Optuna study, you pick search ranges somewhat arbitrarily:
38
+
39
+ ```python
40
+ lr = trial.suggest_float("lr", 1e-5, 1.0) # is 1.0 even worth searching?
41
+ depth = trial.suggest_int("max_depth", 1, 20) # are trials wasting time on depth 1–3?
42
+ ```
43
+
44
+ After 100+ trials, most of that space was wasted. `hpf` looks at where your best trials actually landed and tells you how to tighten, expand, or rescale each parameter for the next run.
45
+
46
+ ---
47
+
48
+ ## What it does
49
+
50
+ 1. **Loads** your completed Optuna study (SQLite, PostgreSQL, or in-memory)
51
+ 2. **Identifies** the top-K% best trials (default: top 20%)
52
+ 3. **Analyzes** each hyperparameter:
53
+ - Boundary detection — did optima cluster near the edge? → **expand**
54
+ - Cluster analysis — did optima occupy only a tiny subregion? → **narrow**
55
+ - Scale detection — do values span multiple orders of magnitude on a linear scale? → **switch to log**
56
+ 4. **Outputs** a color-coded terminal report with confidence levels and reasoning
57
+ 5. **Generates** a ready-to-paste Optuna search space you can drop into your objective function
58
+ 6. **Optionally explains** everything in plain English via a local LLM (Ollama) or API (OpenAI / Groq / Together / any OpenAI-compatible endpoint)
59
+
60
+ ---
61
+
62
+ ## Installation
63
+
64
+ ```bash
65
+ pip install hpf
66
+ ```
67
+
68
+ Or from source:
69
+
70
+ ```bash
71
+ git clone https://github.com/ParamChordiya/hpf.git
72
+ cd hpf
73
+ pip install -e .
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Quick start
79
+
80
+ ```bash
81
+ # First-time setup (configure your LLM — optional but recommended)
82
+ hpf setup
83
+
84
+ # Analyze a study stored in SQLite
85
+ hpf analyze --study my_xgboost_study --file study.db
86
+
87
+ # Analyze with model type hint for better LLM tips
88
+ hpf analyze --study my_study --file study.db --model-type xgboost
89
+
90
+ # Skip LLM, just show statistical analysis
91
+ hpf analyze --study my_study --file study.db --no-llm
92
+
93
+ # Use a custom storage URL (PostgreSQL, etc.)
94
+ hpf analyze --study my_study --storage "postgresql://user:pass@host/db"
95
+ ```
96
+
97
+ ---
98
+
99
+ ## LLM setup
100
+
101
+ `hpf` supports two modes for AI-powered explanations:
102
+
103
+ ### Option 1: Local model via Ollama (free, private)
104
+
105
+ 1. Install [Ollama](https://ollama.ai)
106
+ 2. Pull a model: `ollama pull llama3`
107
+ 3. Run `hpf setup` and select option 1
108
+
109
+ ### Option 2: OpenAI-compatible API
110
+
111
+ Works with OpenAI, Groq, Together AI, Anyscale, or any provider with an OpenAI-compatible endpoint.
112
+
113
+ Run `hpf setup` and select option 2. You'll be prompted for:
114
+ - API key
115
+ - Base URL (leave blank for OpenAI, or enter e.g. `https://api.groq.com/openai/v1`)
116
+ - Model name (default: `gpt-4o-mini`)
117
+
118
+ Config is saved to `~/.hpf/config.json`.
119
+
120
+ ---
121
+
122
+ ## Example output
123
+
124
+ ```
125
+ ╭─────────────────────────────────────────╮
126
+ │ HPF — Hyperparameter Finder v0.1.0 │
127
+ ╰─────────────────────────────────────────╯
128
+
129
+ Study: my_xgboost_study │ 300 trials │ best: 0.9412 │ direction: maximize
130
+
131
+ ┌──────────────────┬───────┬──────────────────┬──────────────────┬───────────┬────┐
132
+ │ Parameter │ Type │ Original │ Suggested │ Action │ ● │
133
+ ├──────────────────┼───────┼──────────────────┼──────────────────┼───────────┼────┤
134
+ │ learning_rate │ FLOAT │ [0.001, 1.0] │ [0.001, 1.0] LOG │ LOG_SCALE │ ● │
135
+ │ max_depth │ INT │ [1, 20] │ [3, 9] │ NARROW │ ● │
136
+ │ n_estimators │ INT │ [50, 500] │ [50, 1500] │ EXPAND │ ● │
137
+ │ subsample │ FLOAT │ [0.5, 1.0] │ [0.5, 1.0] │ KEEP │ ● │
138
+ └──────────────────┴───────┴──────────────────┴──────────────────┴───────────┴────┘
139
+
140
+ ╭─── Updated Search Space ────────────────────────────────────────────╮
141
+ │ def objective(trial): │
142
+ │ learning_rate = trial.suggest_float("learning_rate", │
143
+ │ 0.001, 1.0, log=True) │
144
+ │ max_depth = trial.suggest_int("max_depth", 3, 9) │
145
+ │ n_estimators = trial.suggest_int("n_estimators", 50, 1500) │
146
+ │ subsample = trial.suggest_float("subsample", 0.5, 1.0) │
147
+ ╰─────────────────────────────────────────────────────────────────────╯
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Python API
153
+
154
+ You can also use `hpf` directly in your code:
155
+
156
+ ```python
157
+ import optuna
158
+ from hpf.analyzer import StudyAnalyzer
159
+ from hpf.range_suggester import RangeSuggester
160
+ from hpf.formatters.report import Reporter
161
+ from hpf.models import HPFReport
162
+ from hpf.formatters.code_gen import generate_optuna_code
163
+
164
+ study = optuna.load_study(study_name="my_study", storage="sqlite:///study.db")
165
+
166
+ analyzer = StudyAnalyzer(top_k_percent=20)
167
+ analysis = analyzer.analyze(study, model_type="xgboost")
168
+
169
+ suggester = RangeSuggester()
170
+ suggestions = suggester.suggest(analysis)
171
+
172
+ code = generate_optuna_code(suggestions, study.study_name)
173
+ report = HPFReport(analysis=analysis, suggestions=suggestions, llm_explanation=None, optuna_code=code)
174
+
175
+ Reporter().print_report(report)
176
+ ```
177
+
178
+ ---
179
+
180
+ ## How the analysis works
181
+
182
+ | Signal | Action | Example |
183
+ |---|---|---|
184
+ | Best trials' mean/median within 10% of a boundary | **EXPAND** | `n_estimators` best at 490–500 → expand upper bound |
185
+ | Best trials span <30% of original range | **NARROW** | `max_depth` best in 3–7 out of 1–20 → narrow to 3–9 |
186
+ | Values span >100× ratio on linear scale | **LOG SCALE** | `lr` from 0.001–0.5 on linear → switch to log |
187
+ | Well-distributed across range | **KEEP** | `subsample` best from 0.6–0.95 → keep as is |
188
+
189
+ ---
190
+
191
+ ## Requirements
192
+
193
+ - Python 3.10+
194
+ - Optuna 3.0+
195
+
196
+ Optional:
197
+ - `ollama` Python package + [Ollama](https://ollama.ai) running locally
198
+ - `openai` package + API key for cloud LLM
199
+
200
+ ---
201
+
202
+ ## License
203
+
204
+ MIT
@@ -0,0 +1,176 @@
1
+ # hpf — Hyperparameter Finder
2
+
3
+ **Stop guessing search ranges.** `hpf` analyzes your completed Optuna studies and tells you exactly how to adjust your hyperparameter bounds before the next run — with statistical reasoning and optional LLM-powered explanations.
4
+
5
+ ---
6
+
7
+ ## The Problem
8
+
9
+ When you set up an Optuna study, you pick search ranges somewhat arbitrarily:
10
+
11
+ ```python
12
+ lr = trial.suggest_float("lr", 1e-5, 1.0) # is 1.0 even worth searching?
13
+ depth = trial.suggest_int("max_depth", 1, 20) # are trials wasting time on depth 1–3?
14
+ ```
15
+
16
+ After 100+ trials, most of that space was wasted. `hpf` looks at where your best trials actually landed and tells you how to tighten, expand, or rescale each parameter for the next run.
17
+
18
+ ---
19
+
20
+ ## What it does
21
+
22
+ 1. **Loads** your completed Optuna study (SQLite, PostgreSQL, or in-memory)
23
+ 2. **Identifies** the top-K% best trials (default: top 20%)
24
+ 3. **Analyzes** each hyperparameter:
25
+ - Boundary detection — did optima cluster near the edge? → **expand**
26
+ - Cluster analysis — did optima occupy only a tiny subregion? → **narrow**
27
+ - Scale detection — do values span multiple orders of magnitude on a linear scale? → **switch to log**
28
+ 4. **Outputs** a color-coded terminal report with confidence levels and reasoning
29
+ 5. **Generates** a ready-to-paste Optuna search space you can drop into your objective function
30
+ 6. **Optionally explains** everything in plain English via a local LLM (Ollama) or API (OpenAI / Groq / Together / any OpenAI-compatible endpoint)
31
+
32
+ ---
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ pip install hpf
38
+ ```
39
+
40
+ Or from source:
41
+
42
+ ```bash
43
+ git clone https://github.com/ParamChordiya/hpf.git
44
+ cd hpf
45
+ pip install -e .
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Quick start
51
+
52
+ ```bash
53
+ # First-time setup (configure your LLM — optional but recommended)
54
+ hpf setup
55
+
56
+ # Analyze a study stored in SQLite
57
+ hpf analyze --study my_xgboost_study --file study.db
58
+
59
+ # Analyze with model type hint for better LLM tips
60
+ hpf analyze --study my_study --file study.db --model-type xgboost
61
+
62
+ # Skip LLM, just show statistical analysis
63
+ hpf analyze --study my_study --file study.db --no-llm
64
+
65
+ # Use a custom storage URL (PostgreSQL, etc.)
66
+ hpf analyze --study my_study --storage "postgresql://user:pass@host/db"
67
+ ```
68
+
69
+ ---
70
+
71
+ ## LLM setup
72
+
73
+ `hpf` supports two modes for AI-powered explanations:
74
+
75
+ ### Option 1: Local model via Ollama (free, private)
76
+
77
+ 1. Install [Ollama](https://ollama.ai)
78
+ 2. Pull a model: `ollama pull llama3`
79
+ 3. Run `hpf setup` and select option 1
80
+
81
+ ### Option 2: OpenAI-compatible API
82
+
83
+ Works with OpenAI, Groq, Together AI, Anyscale, or any provider with an OpenAI-compatible endpoint.
84
+
85
+ Run `hpf setup` and select option 2. You'll be prompted for:
86
+ - API key
87
+ - Base URL (leave blank for OpenAI, or enter e.g. `https://api.groq.com/openai/v1`)
88
+ - Model name (default: `gpt-4o-mini`)
89
+
90
+ Config is saved to `~/.hpf/config.json`.
91
+
92
+ ---
93
+
94
+ ## Example output
95
+
96
+ ```
97
+ ╭─────────────────────────────────────────╮
98
+ │ HPF — Hyperparameter Finder v0.1.0 │
99
+ ╰─────────────────────────────────────────╯
100
+
101
+ Study: my_xgboost_study │ 300 trials │ best: 0.9412 │ direction: maximize
102
+
103
+ ┌──────────────────┬───────┬──────────────────┬──────────────────┬───────────┬────┐
104
+ │ Parameter │ Type │ Original │ Suggested │ Action │ ● │
105
+ ├──────────────────┼───────┼──────────────────┼──────────────────┼───────────┼────┤
106
+ │ learning_rate │ FLOAT │ [0.001, 1.0] │ [0.001, 1.0] LOG │ LOG_SCALE │ ● │
107
+ │ max_depth │ INT │ [1, 20] │ [3, 9] │ NARROW │ ● │
108
+ │ n_estimators │ INT │ [50, 500] │ [50, 1500] │ EXPAND │ ● │
109
+ │ subsample │ FLOAT │ [0.5, 1.0] │ [0.5, 1.0] │ KEEP │ ● │
110
+ └──────────────────┴───────┴──────────────────┴──────────────────┴───────────┴────┘
111
+
112
+ ╭─── Updated Search Space ────────────────────────────────────────────╮
113
+ │ def objective(trial): │
114
+ │ learning_rate = trial.suggest_float("learning_rate", │
115
+ │ 0.001, 1.0, log=True) │
116
+ │ max_depth = trial.suggest_int("max_depth", 3, 9) │
117
+ │ n_estimators = trial.suggest_int("n_estimators", 50, 1500) │
118
+ │ subsample = trial.suggest_float("subsample", 0.5, 1.0) │
119
+ ╰─────────────────────────────────────────────────────────────────────╯
120
+ ```
121
+
122
+ ---
123
+
124
+ ## Python API
125
+
126
+ You can also use `hpf` directly in your code:
127
+
128
+ ```python
129
+ import optuna
130
+ from hpf.analyzer import StudyAnalyzer
131
+ from hpf.range_suggester import RangeSuggester
132
+ from hpf.formatters.report import Reporter
133
+ from hpf.models import HPFReport
134
+ from hpf.formatters.code_gen import generate_optuna_code
135
+
136
+ study = optuna.load_study(study_name="my_study", storage="sqlite:///study.db")
137
+
138
+ analyzer = StudyAnalyzer(top_k_percent=20)
139
+ analysis = analyzer.analyze(study, model_type="xgboost")
140
+
141
+ suggester = RangeSuggester()
142
+ suggestions = suggester.suggest(analysis)
143
+
144
+ code = generate_optuna_code(suggestions, study.study_name)
145
+ report = HPFReport(analysis=analysis, suggestions=suggestions, llm_explanation=None, optuna_code=code)
146
+
147
+ Reporter().print_report(report)
148
+ ```
149
+
150
+ ---
151
+
152
+ ## How the analysis works
153
+
154
+ | Signal | Action | Example |
155
+ |---|---|---|
156
+ | Best trials' mean/median within 10% of a boundary | **EXPAND** | `n_estimators` best at 490–500 → expand upper bound |
157
+ | Best trials span <30% of original range | **NARROW** | `max_depth` best in 3–7 out of 1–20 → narrow to 3–9 |
158
+ | Values span >100× ratio on linear scale | **LOG SCALE** | `lr` from 0.001–0.5 on linear → switch to log |
159
+ | Well-distributed across range | **KEEP** | `subsample` best from 0.6–0.95 → keep as is |
160
+
161
+ ---
162
+
163
+ ## Requirements
164
+
165
+ - Python 3.10+
166
+ - Optuna 3.0+
167
+
168
+ Optional:
169
+ - `ollama` Python package + [Ollama](https://ollama.ai) running locally
170
+ - `openai` package + API key for cloud LLM
171
+
172
+ ---
173
+
174
+ ## License
175
+
176
+ MIT
@@ -0,0 +1,7 @@
1
+ """HPF — Hyperparameter Finder.
2
+
3
+ Automatically suggests optimal search ranges for Optuna studies
4
+ using statistical analysis and LLM-powered explanations.
5
+ """
6
+
7
+ __version__ = "0.1.0"