KLEB38 commited on
Commit
b21e63d
·
verified ·
1 Parent(s): 456e520

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -3,3 +3,4 @@
3
  *.pkl filter=lfs diff=lfs merge=lfs -text
4
  *.pt filter=lfs diff=lfs merge=lfs -text
5
  *.bin filter=lfs diff=lfs merge=lfs -text
 
 
3
  *.pkl filter=lfs diff=lfs merge=lfs -text
4
  *.pt filter=lfs diff=lfs merge=lfs -text
5
  *.bin filter=lfs diff=lfs merge=lfs -text
6
+ models/model.onnx filter=lfs diff=lfs merge=lfs -text
models/model.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d7c7423d4f48ddb07090b4db04b566ecf778384e0f9d5278c38f528a42a04621
3
+ size 16320803
pyproject.toml CHANGED
@@ -32,6 +32,8 @@ dev = [
32
  "evidently>=0.7",
33
  "httpx>=0.28.1",
34
  "line-profiler>=5.0.2",
 
 
35
  "pytest>=9.0.3",
36
  "pytest-cov>=7.1.0",
37
  "ruff>=0.15.12",
 
32
  "evidently>=0.7",
33
  "httpx>=0.28.1",
34
  "line-profiler>=5.0.2",
35
+ "onnxmltools>=1.16.0",
36
+ "onnxruntime>=1.26.0",
37
  "pytest>=9.0.3",
38
  "pytest-cov>=7.1.0",
39
  "ruff>=0.15.12",
scripts/benchmark_onnx.py ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Benchmark LightGBM joblib vs ONNX Runtime inference.
2
+
3
+ Loads N real feature rows from `data/reference_dataset.parquet`, runs each
4
+ sample one at a time through both backends (simulating the per-request path),
5
+ and reports p50/p95/p99 latency plus numerical equivalence.
6
+
7
+ Run:
8
+ uv run python scripts/benchmark_onnx.py --n 1000
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import json
15
+ import time
16
+ from pathlib import Path
17
+ from statistics import median
18
+
19
+ import joblib
20
+ import numpy as np
21
+ import onnxruntime as ort
22
+ import pandas as pd
23
+
24
+ ROOT = Path(__file__).resolve().parents[1]
25
+ DEFAULT_MODEL_PATH = ROOT / "models" / "model.joblib"
26
+ DEFAULT_ONNX_PATH = ROOT / "models" / "model.onnx"
27
+ DEFAULT_FEATURE_NAMES_PATH = ROOT / "models" / "feature_names.json"
28
+ DEFAULT_REFERENCE_PATH = ROOT / "data" / "reference_dataset.parquet"
29
+
30
+
31
+ def percentile(samples: list[float], pct: float) -> float:
32
+ """Linear-interpolated percentile (pct in 0..100)."""
33
+ return float(np.percentile(samples, pct))
34
+
35
+
36
+ def fmt_ms(seconds: float) -> str:
37
+ return f"{seconds * 1000:.3f} ms"
38
+
39
+
40
+ def bench_lightgbm(model, samples_df: pd.DataFrame) -> tuple[list[float], np.ndarray]:
41
+ """Run predict_proba one row at a time. Returns (latencies_s, probas)."""
42
+ latencies: list[float] = []
43
+ probas = np.empty(len(samples_df), dtype=np.float64)
44
+ for i in range(len(samples_df)):
45
+ row = samples_df.iloc[[i]]
46
+ t0 = time.perf_counter()
47
+ p = model.predict_proba(row)[0, 1]
48
+ latencies.append(time.perf_counter() - t0)
49
+ probas[i] = p
50
+ return latencies, probas
51
+
52
+
53
+ def bench_onnx(
54
+ session: ort.InferenceSession,
55
+ input_name: str,
56
+ output_name: str,
57
+ samples_array: np.ndarray,
58
+ ) -> tuple[list[float], np.ndarray]:
59
+ """Run ONNX inference one row at a time. Returns (latencies_s, probas)."""
60
+ latencies: list[float] = []
61
+ probas = np.empty(len(samples_array), dtype=np.float64)
62
+ for i in range(len(samples_array)):
63
+ # Reshape to (1, n_features); float32 is required by the ONNX graph.
64
+ row = samples_array[i : i + 1]
65
+ t0 = time.perf_counter()
66
+ out = session.run([output_name], {input_name: row})[0]
67
+ latencies.append(time.perf_counter() - t0)
68
+ # zipmap=False → out shape is (1, 2): [prob_class_0, prob_class_1].
69
+ probas[i] = out[0, 1]
70
+ return latencies, probas
71
+
72
+
73
+ def summarise(name: str, latencies: list[float]) -> dict[str, float]:
74
+ return {
75
+ "backend": name,
76
+ "n": len(latencies),
77
+ "p50_ms": percentile(latencies, 50) * 1000,
78
+ "p95_ms": percentile(latencies, 95) * 1000,
79
+ "p99_ms": percentile(latencies, 99) * 1000,
80
+ "mean_ms": float(np.mean(latencies)) * 1000,
81
+ "total_s": sum(latencies),
82
+ }
83
+
84
+
85
+ def print_table(rows: list[dict[str, float]]) -> None:
86
+ print(
87
+ f"{'Backend':<14}{'n':>6}{'p50':>12}{'p95':>12}{'p99':>12}{'mean':>12}"
88
+ )
89
+ for r in rows:
90
+ print(
91
+ f"{r['backend']:<14}{r['n']:>6}"
92
+ f"{r['p50_ms']:>10.3f}ms"
93
+ f"{r['p95_ms']:>10.3f}ms"
94
+ f"{r['p99_ms']:>10.3f}ms"
95
+ f"{r['mean_ms']:>10.3f}ms"
96
+ )
97
+
98
+
99
+ def main() -> None:
100
+ parser = argparse.ArgumentParser(description=__doc__)
101
+ parser.add_argument("--n", type=int, default=1000, help="Number of inferences")
102
+ parser.add_argument("--warmup", type=int, default=20)
103
+ parser.add_argument("--model", type=Path, default=DEFAULT_MODEL_PATH)
104
+ parser.add_argument("--onnx", type=Path, default=DEFAULT_ONNX_PATH)
105
+ parser.add_argument(
106
+ "--feature-names", type=Path, default=DEFAULT_FEATURE_NAMES_PATH
107
+ )
108
+ parser.add_argument("--reference", type=Path, default=DEFAULT_REFERENCE_PATH)
109
+ parser.add_argument("--seed", type=int, default=42)
110
+ parser.add_argument(
111
+ "--out",
112
+ type=Path,
113
+ default=None,
114
+ help="Optional path to write a JSON report (e.g. profiling/benchmark_onnx.json).",
115
+ )
116
+ args = parser.parse_args()
117
+
118
+ feature_names = json.loads(args.feature_names.read_text())
119
+
120
+ # Sample N rows from the reference dataset, aligned to model feature order.
121
+ reference = pd.read_parquet(args.reference)
122
+ rng = np.random.default_rng(args.seed)
123
+ idx = rng.choice(len(reference), size=args.n + args.warmup, replace=True)
124
+ samples_df = reference.iloc[idx][feature_names].reset_index(drop=True)
125
+ samples_array = samples_df.to_numpy(dtype=np.float32)
126
+
127
+ # --- Load both backends ---
128
+ print("Loading LightGBM model...")
129
+ model = joblib.load(args.model)
130
+ raw_model = model.get_raw_model() if hasattr(model, "get_raw_model") else model
131
+
132
+ print("Loading ONNX session...")
133
+ session = ort.InferenceSession(
134
+ str(args.onnx), providers=["CPUExecutionProvider"]
135
+ )
136
+ input_name = session.get_inputs()[0].name
137
+ output_name = session.get_outputs()[1].name # probabilities output
138
+
139
+ # --- Warmup (excluded from stats) ---
140
+ print(f"Warmup x{args.warmup}...")
141
+ bench_lightgbm(raw_model, samples_df.iloc[: args.warmup])
142
+ bench_onnx(session, input_name, output_name, samples_array[: args.warmup])
143
+
144
+ # --- Measured runs ---
145
+ print(f"Benchmarking LightGBM (n={args.n})...")
146
+ lgbm_lat, lgbm_proba = bench_lightgbm(raw_model, samples_df.iloc[args.warmup :])
147
+
148
+ print(f"Benchmarking ONNX (n={args.n})...")
149
+ onnx_lat, onnx_proba = bench_onnx(
150
+ session, input_name, output_name, samples_array[args.warmup :]
151
+ )
152
+
153
+ # --- Numerical equivalence ---
154
+ diff = np.abs(lgbm_proba - onnx_proba)
155
+ print()
156
+ print("=== Numerical equivalence ===")
157
+ print(f"max |delta_proba| = {diff.max():.2e}")
158
+ print(f"mean |delta_proba| = {diff.mean():.2e}")
159
+ print(f"# rows with |delta| > 1e-5: {(diff > 1e-5).sum()} / {len(diff)}")
160
+
161
+ # --- Latency summary ---
162
+ print()
163
+ print("=== Latency (single-row predict_proba) ===")
164
+ rows = [
165
+ summarise("LightGBM", lgbm_lat),
166
+ summarise("ONNX-Runtime", onnx_lat),
167
+ ]
168
+ print_table(rows)
169
+
170
+ speedup = median(lgbm_lat) / median(onnx_lat) if median(onnx_lat) > 0 else float("inf")
171
+ gain_pct = (1 - median(onnx_lat) / median(lgbm_lat)) * 100
172
+ print()
173
+ print(f"Speed-up (p50): x{speedup:.2f}")
174
+ print(f"Gain (p50): {gain_pct:.1f}%")
175
+
176
+ if args.out is not None:
177
+ report = {
178
+ "config": {
179
+ "n": args.n,
180
+ "warmup": args.warmup,
181
+ "seed": args.seed,
182
+ "model_joblib": str(args.model),
183
+ "model_onnx": str(args.onnx),
184
+ "reference": str(args.reference),
185
+ },
186
+ "equivalence": {
187
+ "max_abs_delta": float(diff.max()),
188
+ "mean_abs_delta": float(diff.mean()),
189
+ "rows_above_1e-5": int((diff > 1e-5).sum()),
190
+ "n_compared": int(len(diff)),
191
+ },
192
+ "latency": rows,
193
+ "speedup_p50": speedup,
194
+ "gain_p50_pct": gain_pct,
195
+ }
196
+ args.out.parent.mkdir(parents=True, exist_ok=True)
197
+ args.out.write_text(json.dumps(report, indent=2))
198
+ print()
199
+ print(f"Wrote report → {args.out}")
200
+
201
+
202
+ if __name__ == "__main__":
203
+ main()
scripts/export_to_onnx.py ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Convert the LightGBM credit-scoring model to ONNX format.
2
+
3
+ Reads `models/model.joblib`, unwraps the MLflow PyFunc layer if present,
4
+ converts the underlying LightGBM model to ONNX via `onnxmltools`, and writes
5
+ `models/model.onnx`.
6
+
7
+ Run:
8
+ uv run python scripts/export_to_onnx.py
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import json
15
+ from pathlib import Path
16
+
17
+ import joblib
18
+ from onnxmltools import convert_lightgbm
19
+ from onnxmltools.convert.common.data_types import FloatTensorType
20
+
21
+ ROOT = Path(__file__).resolve().parents[1]
22
+ DEFAULT_MODEL_PATH = ROOT / "models" / "model.joblib"
23
+ DEFAULT_FEATURE_NAMES_PATH = ROOT / "models" / "feature_names.json"
24
+ DEFAULT_OUT_PATH = ROOT / "models" / "model.onnx"
25
+
26
+
27
+ def export(
28
+ model_path: Path,
29
+ feature_names_path: Path,
30
+ out_path: Path,
31
+ target_opset: int = 13,
32
+ ) -> Path:
33
+ """Convert LightGBM joblib → ONNX file. Returns the output path."""
34
+ model = joblib.load(model_path)
35
+ raw_model = model.get_raw_model() if hasattr(model, "get_raw_model") else model
36
+
37
+ feature_names = json.loads(feature_names_path.read_text())
38
+ n_features = len(feature_names)
39
+
40
+ # ONNX requires a fixed-shape input declaration. None = dynamic batch dim.
41
+ initial_types = [("input", FloatTensorType([None, n_features]))]
42
+
43
+ onnx_model = convert_lightgbm(
44
+ raw_model,
45
+ initial_types=initial_types,
46
+ target_opset=target_opset,
47
+ zipmap=False, # Output raw probability array instead of list-of-dicts.
48
+ )
49
+
50
+ out_path.write_bytes(onnx_model.SerializeToString())
51
+ return out_path
52
+
53
+
54
+ def main() -> None:
55
+ parser = argparse.ArgumentParser(description=__doc__)
56
+ parser.add_argument("--model", type=Path, default=DEFAULT_MODEL_PATH)
57
+ parser.add_argument(
58
+ "--feature-names", type=Path, default=DEFAULT_FEATURE_NAMES_PATH
59
+ )
60
+ parser.add_argument("--out", type=Path, default=DEFAULT_OUT_PATH)
61
+ parser.add_argument("--opset", type=int, default=13)
62
+ args = parser.parse_args()
63
+
64
+ out = export(
65
+ model_path=args.model,
66
+ feature_names_path=args.feature_names,
67
+ out_path=args.out,
68
+ target_opset=args.opset,
69
+ )
70
+ size_mb = out.stat().st_size / (1024 * 1024)
71
+ print(f"Wrote {out} ({size_mb:.2f} MB)")
72
+
73
+
74
+ if __name__ == "__main__":
75
+ main()
uv.lock CHANGED
@@ -1,6 +1,10 @@
1
  version = 1
2
  revision = 3
3
  requires-python = "==3.12.*"
 
 
 
 
4
 
5
  [[package]]
6
  name = "aiohappyeyeballs"
@@ -680,6 +684,14 @@ wheels = [
680
  { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257, upload-time = "2025-12-12T20:31:41.3Z" },
681
  ]
682
 
 
 
 
 
 
 
 
 
683
  [[package]]
684
  name = "fonttools"
685
  version = "4.62.1"
@@ -1585,6 +1597,22 @@ wheels = [
1585
  { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" },
1586
  ]
1587
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1588
  [[package]]
1589
  name = "mlflow"
1590
  version = "3.11.1"
@@ -1919,6 +1947,8 @@ dev = [
1919
  { name = "evidently" },
1920
  { name = "httpx" },
1921
  { name = "line-profiler" },
 
 
1922
  { name = "pytest" },
1923
  { name = "pytest-cov" },
1924
  { name = "ruff" },
@@ -1956,6 +1986,8 @@ dev = [
1956
  { name = "evidently", specifier = ">=0.7" },
1957
  { name = "httpx", specifier = ">=0.28.1" },
1958
  { name = "line-profiler", specifier = ">=5.0.2" },
 
 
1959
  { name = "pytest", specifier = ">=9.0.3" },
1960
  { name = "pytest-cov", specifier = ">=7.1.0" },
1961
  { name = "ruff", specifier = ">=0.15.12" },
@@ -1963,6 +1995,59 @@ dev = [
1963
  { name = "streamlit", specifier = ">=1.57.0" },
1964
  ]
1965
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1966
  [[package]]
1967
  name = "opentelemetry-api"
1968
  version = "1.41.0"
@@ -2835,6 +2920,19 @@ wheels = [
2835
  { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
2836
  ]
2837
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2838
  [[package]]
2839
  name = "skops"
2840
  version = "0.14.0"
 
1
  version = 1
2
  revision = 3
3
  requires-python = "==3.12.*"
4
+ resolution-markers = [
5
+ "platform_machine != 's390x'",
6
+ "platform_machine == 's390x'",
7
+ ]
8
 
9
  [[package]]
10
  name = "aiohappyeyeballs"
 
684
  { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257, upload-time = "2025-12-12T20:31:41.3Z" },
685
  ]
686
 
687
+ [[package]]
688
+ name = "flatbuffers"
689
+ version = "25.12.19"
690
+ source = { registry = "https://pypi.org/simple" }
691
+ wheels = [
692
+ { url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" },
693
+ ]
694
+
695
  [[package]]
696
  name = "fonttools"
697
  version = "4.62.1"
 
1597
  { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" },
1598
  ]
1599
 
1600
+ [[package]]
1601
+ name = "ml-dtypes"
1602
+ version = "0.5.4"
1603
+ source = { registry = "https://pypi.org/simple" }
1604
+ dependencies = [
1605
+ { name = "numpy" },
1606
+ ]
1607
+ sdist = { url = "https://files.pythonhosted.org/packages/0e/4a/c27b42ed9b1c7d13d9ba8b6905dece787d6259152f2309338aed29b2447b/ml_dtypes-0.5.4.tar.gz", hash = "sha256:8ab06a50fb9bf9666dd0fe5dfb4676fa2b0ac0f31ecff72a6c3af8e22c063453", size = 692314, upload-time = "2025-11-17T22:32:31.031Z" }
1608
+ wheels = [
1609
+ { url = "https://files.pythonhosted.org/packages/a8/b8/3c70881695e056f8a32f8b941126cf78775d9a4d7feba8abcb52cb7b04f2/ml_dtypes-0.5.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a174837a64f5b16cab6f368171a1a03a27936b31699d167684073ff1c4237dac", size = 676927, upload-time = "2025-11-17T22:31:48.182Z" },
1610
+ { url = "https://files.pythonhosted.org/packages/54/0f/428ef6881782e5ebb7eca459689448c0394fa0a80bea3aa9262cba5445ea/ml_dtypes-0.5.4-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a7f7c643e8b1320fd958bf098aa7ecf70623a42ec5154e3be3be673f4c34d900", size = 5028464, upload-time = "2025-11-17T22:31:50.135Z" },
1611
+ { url = "https://files.pythonhosted.org/packages/3a/cb/28ce52eb94390dda42599c98ea0204d74799e4d8047a0eb559b6fd648056/ml_dtypes-0.5.4-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ad459e99793fa6e13bd5b7e6792c8f9190b4e5a1b45c63aba14a4d0a7f1d5ff", size = 5009002, upload-time = "2025-11-17T22:31:52.001Z" },
1612
+ { url = "https://files.pythonhosted.org/packages/f5/f0/0cfadd537c5470378b1b32bd859cf2824972174b51b873c9d95cfd7475a5/ml_dtypes-0.5.4-cp312-cp312-win_amd64.whl", hash = "sha256:c1a953995cccb9e25a4ae19e34316671e4e2edaebe4cf538229b1fc7109087b7", size = 212222, upload-time = "2025-11-17T22:31:53.742Z" },
1613
+ { url = "https://files.pythonhosted.org/packages/16/2e/9acc86985bfad8f2c2d30291b27cd2bb4c74cea08695bd540906ed744249/ml_dtypes-0.5.4-cp312-cp312-win_arm64.whl", hash = "sha256:9bad06436568442575beb2d03389aa7456c690a5b05892c471215bfd8cf39460", size = 160793, upload-time = "2025-11-17T22:31:55.358Z" },
1614
+ ]
1615
+
1616
  [[package]]
1617
  name = "mlflow"
1618
  version = "3.11.1"
 
1947
  { name = "evidently" },
1948
  { name = "httpx" },
1949
  { name = "line-profiler" },
1950
+ { name = "onnxmltools" },
1951
+ { name = "onnxruntime" },
1952
  { name = "pytest" },
1953
  { name = "pytest-cov" },
1954
  { name = "ruff" },
 
1986
  { name = "evidently", specifier = ">=0.7" },
1987
  { name = "httpx", specifier = ">=0.28.1" },
1988
  { name = "line-profiler", specifier = ">=5.0.2" },
1989
+ { name = "onnxmltools", specifier = ">=1.16.0" },
1990
+ { name = "onnxruntime", specifier = ">=1.26.0" },
1991
  { name = "pytest", specifier = ">=9.0.3" },
1992
  { name = "pytest-cov", specifier = ">=7.1.0" },
1993
  { name = "ruff", specifier = ">=0.15.12" },
 
1995
  { name = "streamlit", specifier = ">=1.57.0" },
1996
  ]
1997
 
1998
+ [[package]]
1999
+ name = "onnx"
2000
+ version = "1.21.0"
2001
+ source = { registry = "https://pypi.org/simple" }
2002
+ dependencies = [
2003
+ { name = "ml-dtypes" },
2004
+ { name = "numpy" },
2005
+ { name = "protobuf" },
2006
+ { name = "typing-extensions" },
2007
+ ]
2008
+ sdist = { url = "https://files.pythonhosted.org/packages/c5/93/942d2a0f6a70538eea042ce0445c8aefd46559ad153469986f29a743c01c/onnx-1.21.0.tar.gz", hash = "sha256:4d8b67d0aaec5864c87633188b91cc520877477ec0254eda122bef8be43cd764", size = 12074608, upload-time = "2026-03-27T21:33:36.118Z" }
2009
+ wheels = [
2010
+ { url = "https://files.pythonhosted.org/packages/7d/ae/cb644ec84c25e63575d9d8790fdcc5d1a11d67d3f62f872edb35fa38d158/onnx-1.21.0-cp312-abi3-macosx_12_0_universal2.whl", hash = "sha256:fc2635400fe39ff37ebc4e75342cc54450eadadf39c540ff132c319bf4960095", size = 17965930, upload-time = "2026-03-27T21:32:48.089Z" },
2011
+ { url = "https://files.pythonhosted.org/packages/6f/b6/eeb5903586645ef8a49b4b7892580438741acc3df91d7a5bd0f3a59ea9cb/onnx-1.21.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9003d5206c01fa2ff4b46311566865d8e493e1a6998d4009ec6de39843f1b59b", size = 17531344, upload-time = "2026-03-27T21:32:50.837Z" },
2012
+ { url = "https://files.pythonhosted.org/packages/a7/00/4823f06357892d1e60d6f34e7299d2ba4ed2108c487cc394f7ce85a3ff14/onnx-1.21.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a9261bd580fb8548c9c37b3c6750387eb8f21ea43c63880d37b2c622e1684285", size = 17613697, upload-time = "2026-03-27T21:32:54.222Z" },
2013
+ { url = "https://files.pythonhosted.org/packages/23/1d/391f3c567ae068c8ac4f1d1316bae97c9eb45e702f05975fe0e17ad441f0/onnx-1.21.0-cp312-abi3-win32.whl", hash = "sha256:9ea4e824964082811938a9250451d89c4ec474fe42dd36c038bfa5df31993d1e", size = 16287200, upload-time = "2026-03-27T21:32:57.277Z" },
2014
+ { url = "https://files.pythonhosted.org/packages/9c/a6/5eefbe5b40ea96de95a766bd2e0e751f35bdea2d4b951991ec9afaa69531/onnx-1.21.0-cp312-abi3-win_amd64.whl", hash = "sha256:458d91948ad9a7729a347550553b49ab6939f9af2cddf334e2116e45467dc61f", size = 16441045, upload-time = "2026-03-27T21:33:00.081Z" },
2015
+ { url = "https://files.pythonhosted.org/packages/63/c4/0ed8dc037a39113d2a4d66e0005e07751c299c46b993f1ad5c2c35664c20/onnx-1.21.0-cp312-abi3-win_arm64.whl", hash = "sha256:ca14bc4842fccc3187eb538f07eabeb25a779b39388b006db4356c07403a7bbb", size = 16403134, upload-time = "2026-03-27T21:33:03.987Z" },
2016
+ ]
2017
+
2018
+ [[package]]
2019
+ name = "onnxmltools"
2020
+ version = "1.16.0"
2021
+ source = { registry = "https://pypi.org/simple" }
2022
+ dependencies = [
2023
+ { name = "numpy" },
2024
+ { name = "onnx" },
2025
+ { name = "protobuf" },
2026
+ { name = "skl2onnx" },
2027
+ ]
2028
+ sdist = { url = "https://files.pythonhosted.org/packages/41/3e/85a40b6e56a8aaa45bffc9eb00f93182b87841b4dc5a4198ea609993e17c/onnxmltools-1.16.0.tar.gz", hash = "sha256:cd76e0a7ba6a3c4ca4acf3b4c7973cda6a70f2edc146ab11d4efc3dfbee6805a", size = 208397, upload-time = "2026-01-30T12:45:06.1Z" }
2029
+ wheels = [
2030
+ { url = "https://files.pythonhosted.org/packages/fb/e6/6713d9a089a6861b4bf748f02a6238cb2759968aadf672dccef3e960376b/onnxmltools-1.16.0-py3-none-any.whl", hash = "sha256:7b27196e7dcc0d9de29110f211e7941ad1c71dd97606baa729144d9acd105d3c", size = 303991, upload-time = "2026-01-30T12:45:04.809Z" },
2031
+ ]
2032
+
2033
+ [[package]]
2034
+ name = "onnxruntime"
2035
+ version = "1.26.0"
2036
+ source = { registry = "https://pypi.org/simple" }
2037
+ dependencies = [
2038
+ { name = "flatbuffers" },
2039
+ { name = "numpy" },
2040
+ { name = "packaging" },
2041
+ { name = "protobuf" },
2042
+ ]
2043
+ wheels = [
2044
+ { url = "https://files.pythonhosted.org/packages/81/b1/d111b1df656761f980d9e298a60039a9cb66036b1d039e777537743d0ac3/onnxruntime-1.26.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05b028781b322ad74b57ce5b50aa5280bb1fe96ceec334628ade681e0b24c1ac", size = 18016624, upload-time = "2026-05-12T00:41:01.735Z" },
2045
+ { url = "https://files.pythonhosted.org/packages/f6/a0/3f9d896a0385a36bd04345d6d0b802821a5782adde562e7e135f6bb71c73/onnxruntime-1.26.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:91f2bb870a4b9224eba0a6728c1fa7a9e552b8e59e1083c51fbbc3d013f2b5c0", size = 16052692, upload-time = "2026-05-08T19:07:13.829Z" },
2046
+ { url = "https://files.pythonhosted.org/packages/7c/43/2a4e04f8dbeffad19bbcced4bcd4289bf478921518437404d6b92bdf213b/onnxruntime-1.26.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b6dd70599005bd1bf29779f04a91978b92b5e719c11a20068a8f8e535f725b6", size = 18185439, upload-time = "2026-05-08T19:07:36.299Z" },
2047
+ { url = "https://files.pythonhosted.org/packages/44/fc/026d0a7162b9c2153dac292baea9e027c42304dc1d9dc6f8ff5b4cfbaedd/onnxruntime-1.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:a26374dc7fbcaae593601086b242120e13f2310558df0991da6dd8b8fac00414", size = 13026427, upload-time = "2026-05-08T19:08:03.503Z" },
2048
+ { url = "https://files.pythonhosted.org/packages/3e/27/1dcf88e45e4c69db5f7b106f2dacc3801ba98994e082ca03e1dfdf7bfe57/onnxruntime-1.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:54a8053410fd31fd66469bd754fcfe8a4df9f7eb44756b4b5479bf50c842d948", size = 12796647, upload-time = "2026-05-08T19:07:52.108Z" },
2049
+ ]
2050
+
2051
  [[package]]
2052
  name = "opentelemetry-api"
2053
  version = "1.41.0"
 
2920
  { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
2921
  ]
2922
 
2923
+ [[package]]
2924
+ name = "skl2onnx"
2925
+ version = "1.20.0"
2926
+ source = { registry = "https://pypi.org/simple" }
2927
+ dependencies = [
2928
+ { name = "onnx" },
2929
+ { name = "scikit-learn" },
2930
+ ]
2931
+ sdist = { url = "https://files.pythonhosted.org/packages/cb/39/a5015fefb613d5172541740540851a301c53392b57051cf4d313cb6d5718/skl2onnx-1.20.0.tar.gz", hash = "sha256:c74ea827d92ba186fe659695e8fc989cd97bfc320edce3d32b9936a5878da10a", size = 956369, upload-time = "2026-01-30T10:52:07.694Z" }
2932
+ wheels = [
2933
+ { url = "https://files.pythonhosted.org/packages/24/d3/b0db77025a4683ec1b9aafc301b78c7e2e2059a1e2543e918435f3d03582/skl2onnx-1.20.0-py3-none-any.whl", hash = "sha256:30cac34803d1776c14b336ae945e48ef28debfc339215acde1cc04b963ed3f7b", size = 317169, upload-time = "2026-01-30T10:52:05.824Z" },
2934
+ ]
2935
+
2936
  [[package]]
2937
  name = "skops"
2938
  version = "0.14.0"