From b538a768da3c08b4bc95e201becd994b858ce305 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Thu, 17 Jul 2025 16:07:43 -0700 Subject: [PATCH 01/13] init tests, src, and worfklow --- .github/workflows/tests.yml | 0 src/cara/__init__.py | 1 + tests/__init__.py | 1 + 3 files changed, 2 insertions(+) create mode 100644 .github/workflows/tests.yml create mode 100644 src/cara/__init__.py create mode 100644 tests/__init__.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/cara/__init__.py b/src/cara/__init__.py new file mode 100644 index 0000000..b74775f --- /dev/null +++ b/src/cara/__init__.py @@ -0,0 +1 @@ +"""src package init.""" \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..1fb7499 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ +"""Test package.""" \ No newline at end of file From 8c22a4ce490587ffcf12d3fbac4cdf44aa47eb51 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Fri, 18 Jul 2025 11:14:38 -0700 Subject: [PATCH 02/13] complete uv --- .python-version | 1 + pyproject.toml | 94 +++ src/cara/cara.py | 136 ++++ uv.lock | 1705 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1936 insertions(+) create mode 100644 .python-version create mode 100644 pyproject.toml create mode 100644 src/cara/cara.py create mode 100644 uv.lock diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..7671800 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.8.20 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..bf646cd --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,94 @@ +[project] +name = "cara" +version = "0.1.0" +description = "[ICML2025] Canonical Rank Adaptation" +readme = "README.md" +requires-python = "==3.8.20" +dependencies = [ + "avalanche-lib==0.3.0", + "matplotlib==3.7.5", + "numpy==1.24.4", + "tensorly==0.8.1", + "timm==0.4.12", + "tqdm==4.66.6", +] + + +[project.optional-dependencies] +cpu = [ + "torch==2.0.0", + "torchvision==0.15", +] +cu118 = [ + "torch==2.0.0", + "torchvision==0.15", +] + +[tool.uv] +conflicts = [ + [ + { extra = "cpu" }, + { extra = "cu118" }, + ], +] + +[tool.uv.sources] +torch = [ + { index = "pytorch-cpu", extra = "cpu" }, + { index = "pytorch-cu118", extra = "cu118" }, +] +torchvision = [ + { index = "pytorch-cpu", extra = "cpu" }, + { index = "pytorch-cu118", extra = "cu118" }, +] + +[[tool.uv.index]] +name = "pytorch-cpu" +url = "https://download.pytorch.org/whl/cpu" +explicit = true +priority = "primary" + +[[tool.uv.index]] +name = "pytorch-cu118" +url = "https://download.pytorch.org/whl/cu118" +explicit = true + + +[tool.isort] +profile = "black" +py_version = 38 + +[tool.black] +line-length = 79 +target-version = ['py38'] + +[tool.mypy] +python_version = "3.8.20" # or your target Python version +install_types = true +non_interactive = true +ignore_missing_imports = true +strict_optional = false +warn_return_any = false +implicit_reexport = true +allow_untyped_calls = true +explicit_package_bases = true + +[dependency-groups] +dev = [ + "black", + "darglint", + "flake8", + "flake8-black", + "flake8-broken-line", + "flake8-bugbear", + "flake8-docstrings", + "isort", + "mypy", + "pep8-naming", + "pre-commit", + "pydocstyle", + "types-pyyaml", + "types-requests", + "types-simplejson", + "types-tabulate", +] \ No newline at end of file diff --git a/src/cara/cara.py b/src/cara/cara.py new file mode 100644 index 0000000..9305a49 --- /dev/null +++ b/src/cara/cara.py @@ -0,0 +1,136 @@ +from copy import deepcopy +from typing import Dict, Any + +import torch as th +import torch.nn as nn +import timm +import tensorly as tl +tl.set_backend("pytorch") + + +def cp_attn(self, x): + B, N, C = x.shape + qkv = self.qkv(x) + f1 = global_model.CP_A1[self.attn_idx:self.attn_idx+3, :] + tensor_attn = tl.cp_to_tensor((global_model.CP_R1, (f1, global_model.CP_A2, global_model.CP_A3, global_model.CP_A4))) + K, E, H, D = tensor_attn.shape + tensor_attn = tensor_attn.reshape((K, E, H*D)) + qkv_delta = th.einsum("bnd, kde->kbne", x, self.dp(tensor_attn)) + qkv_delta = qkv_delta.reshape(3, B, N, self.num_heads, C//self.num_heads).permute( + 0, 1, 3, 2, 4 + ) + qkv = qkv.reshape(B, N, 3, self.num_heads, C//self.num_heads).permute( + 2, 0, 3, 1, 4 + ) + qkv += qkv_delta * self.s + q, k, v = qkv[0], qkv[1], qkv[2] + attn = (q @ k.transpose(-2, -1)) * self.scale + attn = attn.softmax(dim=-1) + attn = self.attn_drop(attn) + + x = (attn@v).transpose(1, 2).reshape(B, N, C) + + proj = self.proj(x) + p1 = global_model.CP_P1[self.idx:self.idx+1, :] + tensor_proj = tl.cp_to_tensor((global_model.CP_R2, (p1, global_model.CP_P2, global_model.CP_P3))) + AA, AB, AC = tensor_proj.shape + tensor_proj = tensor_proj.reshape((AA*AB, AC)) + proj_delta = x@self.dp(tensor_proj.T) + global_model.CP_bias1 + proj += proj_delta * self.s + x = self.proj_drop(proj) + return x + + +def cp_mlp(self, x): + p1_up = global_model.CP_P1[self.idx:self.idx+4, :] + p1_down = global_model.CP_P1[self.idx+4: self.idx+8, :] + + up = self.fc1(x) + tensor_up = tl.cp_to_tensor((global_model.CP_R2, (p1_up, global_model.CP_P2, global_model.CP_P3))) + AA, AB, AC = tensor_up.shape + tensor_up = tensor_up.reshape((AA*AB, AC)) + up_delta = x@self.dp(tensor_up.T) + global_model.CP_bias2 + up += up_delta * self.s + + x = self.act(up) + x = self.drop(x) + + down = self.fc2(x) + tensor_down = tl.cp_to_tensor((global_model.CP_R2, (p1_down, global_model.CP_P2, global_model.CP_P3))) + tensor_down = tensor_down.reshape((AA*AB, AC)) + down_delta = x@self.dp(tensor_down) + global_model.CP_bias3 + down += down_delta * self.s + x = self.drop(down) + return x + + +def set_cara(model: nn.Module, rank: int, scale: float, l_mu: float, l_std: float): + if type(model) == timm.models.vision_transformer.VisionTransformer: + # Declare CaRA parameters + model.CP_A1 = nn.Parameter(th.empty([36, rank]), requires_grad=True) + model.CP_A2 = nn.Parameter(th.empty([768, rank]), requires_grad=True) + model.CP_A3 = nn.Parameter(th.empty([12, rank]), requires_grad=True) + model.CP_A4 = nn.Parameter(th.empty([768//12, rank]), requires_grad=True) + model.CP_P1 = nn.Parameter(th.empty([108, rank]), requires_grad=True) + model.CP_P2 = nn.Parameter(th.empty([768, rank]), requires_grad=True) + model.CP_P3 = nn.Parameter(th.empty([768, rank]), requires_grad=True) + model.CP_R1 = nn.Parameter(th.empty([rank]), requires_grad=True) + model.CP_R2 = nn.Parameter(th.empty([rank]), requires_grad=True) + model.CP_bias1 = nn.Parameter(th.empty([768]), requires_grad=True) + model.CP_bias2 = nn.Parameter(th.empty([768*4]), requires_grad=True) + model.CP_bias3 = nn.Parameter(th.empty([768]), requires_grad=True) + # Initialise CaRA parameters + nn.init.xavier_normal_(model.CP_A1) + nn.init.zeros_(model.CP_A2) + nn.init.orthogonal_(model.CP_A3) + nn.init.orthogonal_(model.CP_A4) + nn.init.xavier_normal_(model.CP_P1) + nn.init.zeros_(model.CP_P2) + nn.init.orthogonal_(model.CP_P3) + if l_std != 0.0: + nn.init.normal_(model.CP_R1, mean=l_mu, std=l_std) + nn.init.normal_(model.CP_R2, mean=l_mu, std=l_std) + elif l_mu == 1.0 and l_std == 0.0: + nn.init.ones_(model.CP_R1) + nn.init.ones_(model.CP_R2) + nn.init.zeros_(model.CP_bias1) + nn.init.zeros_(model.CP_bias2) + nn.init.zeros_(model.CP_bias3) + # CaRA indexing + model.idx = 0 + model.attn_idx = 0 + for child in model.children(): + if type(child) == timm.models.vision_transformer.Attention: + child.dp = nn.Dropout(0.1) + child.s = scale + child.dim = rank + child.idx = global_model.idx + child.attn_idx = global_model.attn_idx + global_model.idx += 1 + global_model.attn_idx += 3 + bound_method = cp_attn.__get__(child, child.__class__) + setattr(child, "forward", bound_method) + elif type(child) == timm.models.layers.mlp.Mlp: + child.dp = nn.Dropout(0.1) + child.s = scale + child.dim = rank + child.idx = global_model.idx + global_model.idx += 8 + bound_method = cp_mlp.__get__(child, child.__class__) + setattr(child, "forward", bound_method) + elif len(list(child.children())) != 0: + set_cara(child, rank, scale, l_mu, l_std) + + +def cara(config): + # CaRA parameters + model = config["model"] + rank = config["rank"] + scale = config["scale"] + l_mu = config["l_mu"] + l_std = config["l_std"] + + global global_model + global_model = model + set_cara(model, rank, scale, l_mu, l_std) + return global_model \ No newline at end of file diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..743def1 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1705 @@ +version = 1 +revision = 2 +requires-python = "==3.8.20" +resolution-markers = [ + "platform_machine != 'aarch64' and sys_platform == 'linux' and extra != 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118'", + "sys_platform != 'linux' and extra != 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118'", + "platform_machine == 'aarch64' and sys_platform == 'linux' and extra != 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118'", + "platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118'", + "sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118'", + "platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118'", + "sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118'", + "sys_platform == 'linux' and extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118'", + "sys_platform != 'linux' and extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118'", +] +conflicts = [[ + { package = "cara", extra = "cpu" }, + { package = "cara", extra = "cu118" }, +]] + +[[package]] +name = "absl-py" +version = "2.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "avalanche-lib" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dill" }, + { name = "gdown" }, + { name = "gputil" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "psutil" }, + { name = "pytorchcv" }, + { name = "quadprog" }, + { name = "scikit-learn" }, + { name = "setuptools" }, + { name = "tensorboard" }, + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchmetrics" }, + { name = "torchvision", version = "0.15.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "tqdm" }, + { name = "typing-extensions" }, + { name = "wandb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/2b/531abf18d47ac61df56739e1f200f4681237919ae070ba6a124eb4f42707/avalanche-lib-0.3.0.tar.gz", hash = "sha256:2a67f6d1ee4dba52d8d2147c6a4f36c16f1137aba198cd1ff5109c77b96edbce", size = 611195, upload-time = "2022-12-14T01:06:48.889Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/9a/eadedf8435b91cc6abcb2b4d4c10d98956dab52f05335a533e588e3920b1/avalanche_lib-0.3.0-py3-none-any.whl", hash = "sha256:4df2961c8c0cb277b4ef06836211c00703438d28160f6088e5ebe9b6083f8d28", size = 811041, upload-time = "2022-12-14T01:06:45.754Z" }, +] + +[[package]] +name = "beautifulsoup4" +version = "4.13.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d8/e4/0c4c39e18fd76d6a628d4dd8da40543d136ce2d1752bd6eeeab0791f4d6b/beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195", size = 621067, upload-time = "2025-04-15T17:05:13.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/cd/30110dc0ffcf3b131156077b90e9f60ed75711223f306da4db08eff8403b/beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b", size = 187285, upload-time = "2025-04-15T17:05:12.221Z" }, +] + +[[package]] +name = "black" +version = "24.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, + { name = "tomli" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/b0/46fb0d4e00372f4a86a6f8efa3cb193c9f64863615e39010b1477e010578/black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", size = 644810, upload-time = "2024-08-02T17:43:18.405Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/d4/ae03761ddecc1a37d7e743b89cccbcf3317479ff4b88cfd8818079f890d0/black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd", size = 1617322, upload-time = "2024-08-02T17:51:20.203Z" }, + { url = "https://files.pythonhosted.org/packages/14/4b/4dfe67eed7f9b1ddca2ec8e4418ea74f0d1dc84d36ea874d618ffa1af7d4/black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2", size = 1442108, upload-time = "2024-08-02T17:50:40.824Z" }, + { url = "https://files.pythonhosted.org/packages/97/14/95b3f91f857034686cae0e73006b8391d76a8142d339b42970eaaf0416ea/black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e", size = 1745786, upload-time = "2024-08-02T17:46:02.939Z" }, + { url = "https://files.pythonhosted.org/packages/95/54/68b8883c8aa258a6dde958cd5bdfada8382bec47c5162f4a01e66d839af1/black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920", size = 1426754, upload-time = "2024-08-02T17:46:38.603Z" }, + { url = "https://files.pythonhosted.org/packages/27/1e/83fa8a787180e1632c3d831f7e58994d7aaf23a0961320d21e84f922f919/black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed", size = 206504, upload-time = "2024-08-02T17:43:15.747Z" }, +] + +[[package]] +name = "cachetools" +version = "5.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, +] + +[[package]] +name = "cara" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "avalanche-lib" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "tensorly" }, + { name = "timm" }, + { name = "tqdm" }, +] + +[package.optional-dependencies] +cpu = [ + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +cu118 = [ + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] + +[package.dev-dependencies] +dev = [ + { name = "black" }, + { name = "darglint" }, + { name = "flake8" }, + { name = "flake8-black" }, + { name = "flake8-broken-line" }, + { name = "flake8-bugbear" }, + { name = "flake8-docstrings" }, + { name = "isort" }, + { name = "mypy" }, + { name = "pep8-naming" }, + { name = "pre-commit" }, + { name = "pydocstyle" }, + { name = "types-pyyaml" }, + { name = "types-requests" }, + { name = "types-simplejson" }, + { name = "types-tabulate" }, +] + +[package.metadata] +requires-dist = [ + { name = "avalanche-lib", specifier = "==0.3.0" }, + { name = "matplotlib", specifier = "==3.7.5" }, + { name = "numpy", specifier = "==1.24.4" }, + { name = "tensorly", specifier = "==0.8.1" }, + { name = "timm", specifier = "==0.4.12" }, + { name = "torch", marker = "extra == 'cpu'", specifier = "==2.0.0", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "cara", extra = "cpu" } }, + { name = "torch", marker = "extra == 'cu118'", specifier = "==2.0.0", index = "https://download.pytorch.org/whl/cu118", conflict = { package = "cara", extra = "cu118" } }, + { name = "torchvision", marker = "extra == 'cpu'", specifier = "==0.15", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "cara", extra = "cpu" } }, + { name = "torchvision", marker = "extra == 'cu118'", specifier = "==0.15", index = "https://download.pytorch.org/whl/cu118", conflict = { package = "cara", extra = "cu118" } }, + { name = "tqdm", specifier = "==4.66.6" }, +] +provides-extras = ["cpu", "cu118"] + +[package.metadata.requires-dev] +dev = [ + { name = "black" }, + { name = "darglint" }, + { name = "flake8" }, + { name = "flake8-black" }, + { name = "flake8-broken-line" }, + { name = "flake8-bugbear" }, + { name = "flake8-docstrings" }, + { name = "isort" }, + { name = "mypy" }, + { name = "pep8-naming" }, + { name = "pre-commit" }, + { name = "pydocstyle" }, + { name = "types-pyyaml" }, + { name = "types-requests" }, + { name = "types-simplejson" }, + { name = "types-tabulate" }, +] + +[[package]] +name = "certifi" +version = "2025.7.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981, upload-time = "2025-07-14T03:29:28.449Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" }, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114, upload-time = "2023-08-12T20:38:17.776Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249, upload-time = "2023-08-12T20:38:16.269Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/fd/f700cfd4ad876def96d2c769d8a32d808b12d1010b6003dc6639157f99ee/charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb", size = 198257, upload-time = "2025-05-02T08:33:45.511Z" }, + { url = "https://files.pythonhosted.org/packages/3a/95/6eec4cbbbd119e6a402e3bfd16246785cc52ce64cf21af2ecdf7b3a08e91/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a", size = 143453, upload-time = "2025-05-02T08:33:47.463Z" }, + { url = "https://files.pythonhosted.org/packages/b6/b3/d4f913660383b3d93dbe6f687a312ea9f7e89879ae883c4e8942048174d4/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45", size = 153130, upload-time = "2025-05-02T08:33:50.568Z" }, + { url = "https://files.pythonhosted.org/packages/e5/69/7540141529eabc55bf19cc05cd9b61c2078bebfcdbd3e799af99b777fc28/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5", size = 145688, upload-time = "2025-05-02T08:33:52.828Z" }, + { url = "https://files.pythonhosted.org/packages/2e/bb/d76d3d6e340fb0967c43c564101e28a78c9a363ea62f736a68af59ee3683/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1", size = 147418, upload-time = "2025-05-02T08:33:54.718Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ef/b7c1f39c0dc3808160c8b72e0209c2479393966313bfebc833533cfff9cc/charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027", size = 150066, upload-time = "2025-05-02T08:33:56.597Z" }, + { url = "https://files.pythonhosted.org/packages/20/26/4e47cc23d2a4a5eb6ed7d6f0f8cda87d753e2f8abc936d5cf5ad2aae8518/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b", size = 144499, upload-time = "2025-05-02T08:33:58.637Z" }, + { url = "https://files.pythonhosted.org/packages/d7/9c/efdf59dd46593cecad0548d36a702683a0bdc056793398a9cd1e1546ad21/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455", size = 152954, upload-time = "2025-05-02T08:34:00.552Z" }, + { url = "https://files.pythonhosted.org/packages/59/b3/4e8b73f7299d9aaabd7cd26db4a765f741b8e57df97b034bb8de15609002/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01", size = 155876, upload-time = "2025-05-02T08:34:02.527Z" }, + { url = "https://files.pythonhosted.org/packages/53/cb/6fa0ccf941a069adce3edb8a1e430bc80e4929f4d43b5140fdf8628bdf7d/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58", size = 153186, upload-time = "2025-05-02T08:34:04.481Z" }, + { url = "https://files.pythonhosted.org/packages/ac/c6/80b93fabc626b75b1665ffe405e28c3cef0aae9237c5c05f15955af4edd8/charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681", size = 148007, upload-time = "2025-05-02T08:34:06.888Z" }, + { url = "https://files.pythonhosted.org/packages/41/eb/c7367ac326a2628e4f05b5c737c86fe4a8eb3ecc597a4243fc65720b3eeb/charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7", size = 97923, upload-time = "2025-05-02T08:34:08.792Z" }, + { url = "https://files.pythonhosted.org/packages/7c/02/1c82646582ccf2c757fa6af69b1a3ea88744b8d2b4ab93b7686b2533e023/charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a", size = 105020, upload-time = "2025-05-02T08:34:10.6Z" }, + { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, +] + +[[package]] +name = "click" +version = "8.1.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, +] + +[[package]] +name = "cmake" +version = "4.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/25/3f/30c0f44ec5d727f547c35510ae479053abf56bed24b08f3e128f93d09905/cmake-4.0.3.tar.gz", hash = "sha256:215732f09ea8a7088fe1ab46bbd61669437217278d709fd3851bf8211e8c59e3", size = 34504, upload-time = "2025-06-13T15:34:11.68Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/d2/5579b66d4421ab11dd00f32f4184be383a74e28ad0685a6604e0e7a8fd29/cmake-4.0.3-py3-none-macosx_10_10_universal2.whl", hash = "sha256:f2adfb459747025f40f9d3bdd1f3a485d43e866c0c4eb66373d1fcd666b13e4a", size = 48740112, upload-time = "2025-06-13T15:33:08.513Z" }, + { url = "https://files.pythonhosted.org/packages/67/4d/410c3ebb4a46a236cbc0e3202f5507483ce24c96c1d4a73445675f11b402/cmake-4.0.3-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:04c40c92fdcaa96c66a5731b5b3fbbdf87da99cc68fdd30ff30b90c34d222986", size = 27740648, upload-time = "2025-06-13T15:33:12.877Z" }, + { url = "https://files.pythonhosted.org/packages/77/a7/f845c1e129ad37059612e5d66ffe3dac824fdfd7dec58918a802f38650ff/cmake-4.0.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d41b83d061bcc375a7a5f2942ba523a7563368d296d91260f9d8a53a10f5e5e5", size = 26983727, upload-time = "2025-06-13T15:33:16.394Z" }, + { url = "https://files.pythonhosted.org/packages/45/ee/750dae28fa12493052c44f744affbfeff0f35a526b4346bd86050e9903e5/cmake-4.0.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:434f84fdf1e21578974876b8414dc47afeaea62027d9adc37a943a6bb08eb053", size = 27256957, upload-time = "2025-06-13T15:33:19.658Z" }, + { url = "https://files.pythonhosted.org/packages/23/1e/05b08c18145cd8e5ad3f506bfa21fe5277c00faf9052b3fb9bf6d279df42/cmake-4.0.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:beec48371a4b906fe398758ded5df57fc16e9bb14fd34244d9d66ee35862fb9f", size = 29020848, upload-time = "2025-06-13T15:33:23.161Z" }, + { url = "https://files.pythonhosted.org/packages/db/b5/578e5b50cb848775aee4e04ceecef3c6595c30fb5fe0642a14eaafa02597/cmake-4.0.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:47dc28bee6cfb4de00c7cf7e87d565b5c86eb4088da81b60a49e214fcdd4ffda", size = 30872393, upload-time = "2025-06-13T15:33:26.316Z" }, + { url = "https://files.pythonhosted.org/packages/42/7d/e4cdb9903b971dbbab1127e96bab86d3d77cedbb637f47a8e44ec02c3672/cmake-4.0.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10fdc972b3211915b65cc89e8cd24e1a26c9bd684ee71c3f369fb488f2c4388", size = 27028264, upload-time = "2025-06-13T15:33:29.619Z" }, + { url = "https://files.pythonhosted.org/packages/60/cb/1e4d8baab7c946f809d6c59914428c10acaf39d9f4b52e1dffff834a9f0a/cmake-4.0.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d840e780c48c5df1330879d50615176896e8e6eee554507d21ce8e2f1a5f0ff8", size = 27912444, upload-time = "2025-06-13T15:33:33.296Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3a/ff653130b91d73c172205ac10ad71c62a1474bd85ae110eec085e04aec08/cmake-4.0.3-py3-none-manylinux_2_31_armv7l.whl", hash = "sha256:6ef63bbabcbe3b89c1d80547913b6caceaad57987a27e7afc79ebc88ecd829e4", size = 25156436, upload-time = "2025-06-13T15:33:36.316Z" }, + { url = "https://files.pythonhosted.org/packages/7a/6f/514ba65cf1e2d0a80a97c3c4a2ae3805bf8cb3286de41b864b03b44ca47a/cmake-4.0.3-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:67103f2bcce8f57b8705ba8e353f18fdc3684a346eee97dc5f94d11575a424c6", size = 28026300, upload-time = "2025-06-13T15:33:39.497Z" }, + { url = "https://files.pythonhosted.org/packages/83/b9/49f847fa09b48110cc0f38b72720f979912ac69742de784998b2e36fda18/cmake-4.0.3-py3-none-musllinux_1_1_i686.whl", hash = "sha256:880a1e1ae26d440d7e4f604fecbf839728ca7b096c870f2e7359855cc4828532", size = 31557948, upload-time = "2025-06-13T15:33:43.099Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d8/bbd8eb74bb6c972572293f043a5cd5a56ec9791f8c46ccfbcf53a84aa556/cmake-4.0.3-py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:c403b660bbff1fd4d7f1c5d9e015ea27566e49ca9461e260c9758f2fd4e5e813", size = 32281822, upload-time = "2025-06-13T15:33:46.544Z" }, + { url = "https://files.pythonhosted.org/packages/df/a4/aebacccbcab31a1896190d57ac3ad9fdeded18f6ce7634b24958c6de8090/cmake-4.0.3-py3-none-musllinux_1_1_s390x.whl", hash = "sha256:2a66ecdd4c3238484cb0c377d689c086a9b8b533e25329f73d21bd1c38f1ae86", size = 28104040, upload-time = "2025-06-13T15:33:49.687Z" }, + { url = "https://files.pythonhosted.org/packages/a2/b3/42cd72162e7b466863ca4c033fb30ef51109b4eaef9686aa81b86f5afd8b/cmake-4.0.3-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:004e58b1a1a384c2ca799c9c41ac4ed86ac3b80129462992c43c1121f8729ffd", size = 29638511, upload-time = "2025-06-13T15:33:53.063Z" }, + { url = "https://files.pythonhosted.org/packages/d4/4d/d81d27a0d86bf2e24e4574f672b17230db676be2dd878d747439f1f4abfa/cmake-4.0.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:133dbc33f995cb97a4456d83d67fa0a7a798f53f979454359140588baa928f43", size = 33324625, upload-time = "2025-06-13T15:33:57.463Z" }, + { url = "https://files.pythonhosted.org/packages/5d/eb/c7736686066bbaacd06b69228a8cd3cbdac279a069658e4a646b3dee4a9c/cmake-4.0.3-py3-none-win32.whl", hash = "sha256:3e07bdd14e69ea67d1e67a4f5225ac2fd91ee9e349c440143cdddd7368be1f46", size = 33683662, upload-time = "2025-06-13T15:34:01.075Z" }, + { url = "https://files.pythonhosted.org/packages/a6/03/70e3bfff49ee89b3e4a137b5504ad003b0cae8dbc291cb753228f55b4b9f/cmake-4.0.3-py3-none-win_amd64.whl", hash = "sha256:9a349ff2b4a7c63c896061676bc0f4e6994f373d54314d79ba3608ee7fa75442", size = 36911867, upload-time = "2025-06-13T15:34:04.774Z" }, + { url = "https://files.pythonhosted.org/packages/50/ce/9cfee241950e700a3ac67a0dbbd26da24c7e252bd48c5af129586a4caadd/cmake-4.0.3-py3-none-win_arm64.whl", hash = "sha256:94a52e67b264a51089907c9e74ca5a9e2f3e65c57c457e0f40f02629a0de74d8", size = 35706970, upload-time = "2025-06-13T15:34:08.703Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "contourpy" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/7d/087ee4295e7580d3f7eb8a8a4e0ec8c7847e60f34135248ccf831cf5bbfc/contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab", size = 13433167, upload-time = "2023-09-16T10:25:49.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/7e/ffaba1bf3719088be3ad6983a5e85e1fc9edccd7b406b98e433436ecef74/contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d", size = 247023, upload-time = "2023-09-16T10:22:26.954Z" }, + { url = "https://files.pythonhosted.org/packages/a6/82/29f5ff4ae074c3230e266bc9efef449ebde43721a727b989dd8ef8f97d73/contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9", size = 232380, upload-time = "2023-09-16T10:22:30.423Z" }, + { url = "https://files.pythonhosted.org/packages/9b/cb/08f884c4c2efd433a38876b1b8069bfecef3f2d21ff0ce635d455962f70f/contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217", size = 285830, upload-time = "2023-09-16T10:22:33.787Z" }, + { url = "https://files.pythonhosted.org/packages/8e/57/cd4d4c99d999a25e9d518f628b4793e64b1ecb8ad3147f8469d8d4a80678/contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684", size = 322038, upload-time = "2023-09-16T10:22:37.627Z" }, + { url = "https://files.pythonhosted.org/packages/32/b6/c57ed305a6f86731107fc183e97c7e6a6005d145f5c5228a44718082ad12/contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce", size = 295797, upload-time = "2023-09-16T10:22:41.952Z" }, + { url = "https://files.pythonhosted.org/packages/8e/71/7f20855592cc929bc206810432b991ec4c702dc26b0567b132e52c85536f/contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8", size = 301124, upload-time = "2023-09-16T10:22:45.993Z" }, + { url = "https://files.pythonhosted.org/packages/86/6d/52c2fc80f433e7cdc8624d82e1422ad83ad461463cf16a1953bbc7d10eb1/contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251", size = 819787, upload-time = "2023-09-16T10:22:53.511Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b0/f8d4548e89f929d6c5ca329df9afad6190af60079ec77d8c31eb48cf6f82/contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7", size = 400031, upload-time = "2023-09-16T10:22:57.78Z" }, + { url = "https://files.pythonhosted.org/packages/96/1b/b05cd42c8d21767a0488b883b38658fb9a45f86c293b7b42521a8113dc5d/contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9", size = 477949, upload-time = "2023-09-16T10:23:02.587Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3c/fc36884b6793e2066a6ff25c86e21b8bd62553456b07e964c260bcf22711/contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e", size = 246493, upload-time = "2023-09-16T10:23:45.721Z" }, + { url = "https://files.pythonhosted.org/packages/3d/85/f4c5b09ce79828ed4553a8ae2ebdf937794f57b45848b1f5c95d9744ecc2/contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3", size = 289240, upload-time = "2023-09-16T10:23:49.207Z" }, + { url = "https://files.pythonhosted.org/packages/18/d3/9d7c0a372baf5130c1417a4b8275079d5379c11355436cb9fc78af7d7559/contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23", size = 476043, upload-time = "2023-09-16T10:23:54.495Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "darglint" +version = "1.8.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/2c/86e8549e349388c18ca8a4ff8661bb5347da550f598656d32a98eaaf91cc/darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da", size = 74435, upload-time = "2021-10-18T03:40:37.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/28/85d1e0396d64422c5218d68e5cdcc53153aa8a2c83c7dbc3ee1502adf3a1/darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d", size = 120767, upload-time = "2021-10-18T03:40:35.034Z" }, +] + +[[package]] +name = "dill" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, +] + +[[package]] +name = "eval-type-backport" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/ea/8b0ac4469d4c347c6a385ff09dc3c048c2d021696664e26c7ee6791631b5/eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1", size = 9079, upload-time = "2024-12-21T20:09:46.005Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a", size = 5830, upload-time = "2024-12-21T20:09:44.175Z" }, +] + +[[package]] +name = "filelock" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037, upload-time = "2024-09-17T19:02:01.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163, upload-time = "2024-09-17T19:02:00.268Z" }, +] + +[[package]] +name = "flake8" +version = "7.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mccabe" }, + { name = "pycodestyle" }, + { name = "pyflakes" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/16/3f2a0bb700ad65ac9663262905a025917c020a3f92f014d2ba8964b4602c/flake8-7.1.2.tar.gz", hash = "sha256:c586ffd0b41540951ae41af572e6790dbd49fc12b3aa2541685d253d9bd504bd", size = 48119, upload-time = "2025-02-16T18:45:44.296Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/f8/08d37b2cd89da306e3520bd27f8a85692122b42b56c0c2c3784ff09c022f/flake8-7.1.2-py2.py3-none-any.whl", hash = "sha256:1cbc62e65536f65e6d754dfe6f1bada7f5cf392d6f5db3c2b85892466c3e7c1a", size = 57745, upload-time = "2025-02-16T18:45:42.351Z" }, +] + +[[package]] +name = "flake8-black" +version = "0.3.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "black" }, + { name = "flake8" }, + { name = "tomli" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/52/dfb29b60cf14ae2d5b6119733b60fb32dc1ce0b35746f53b8dcc92d21f5c/flake8-black-0.3.6.tar.gz", hash = "sha256:0dfbca3274777792a5bcb2af887a4cad72c72d0e86c94e08e3a3de151bb41c34", size = 14565, upload-time = "2022-12-20T09:29:30.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/89/0b4551179632da06da3770047fdfd927abe9e3c9f45182d216d5d177cfb3/flake8_black-0.3.6-py3-none-any.whl", hash = "sha256:fe8ea2eca98d8a504f22040d9117347f6b367458366952862ac3586e7d4eeaca", size = 9898, upload-time = "2022-12-20T09:29:29.272Z" }, +] + +[[package]] +name = "flake8-broken-line" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flake8" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/5e/eca08446205afb79e74b6af8e227f06f0b1a26ae892708adbc4e65ccaa86/flake8_broken_line-1.0.0.tar.gz", hash = "sha256:e2c6a17f8d9a129e99c1320fce89b33843e2963871025c4c2bb7b8b8d8732a85", size = 3458, upload-time = "2023-05-31T10:09:11.716Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/ff/57d0101933527b5202cc9f80bc15aa85b207916c722a00e7adde0e33f413/flake8_broken_line-1.0.0-py3-none-any.whl", hash = "sha256:96c964336024a5030dc536a9f6fb02aa679e2d2a6b35b80a558b5136c35832a9", size = 4202, upload-time = "2023-05-31T10:09:10.027Z" }, +] + +[[package]] +name = "flake8-bugbear" +version = "24.12.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "flake8" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/25/48ba712ff589b0149f21135234f9bb45c14d6689acc6151b5e2ff8ac2ae9/flake8_bugbear-24.12.12.tar.gz", hash = "sha256:46273cef0a6b6ff48ca2d69e472f41420a42a46e24b2a8972e4f0d6733d12a64", size = 82907, upload-time = "2024-12-12T16:49:26.307Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/21/0a875f75fbe4008bd171e2fefa413536258fe6b4cfaaa087986de74588f4/flake8_bugbear-24.12.12-py3-none-any.whl", hash = "sha256:1b6967436f65ca22a42e5373aaa6f2d87966ade9aa38d4baf2a1be550767545e", size = 36664, upload-time = "2024-12-12T16:49:23.584Z" }, +] + +[[package]] +name = "flake8-docstrings" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flake8" }, + { name = "pydocstyle" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/93/24/f839e3a06e18f4643ccb81370909a497297909f15106e6af2fecdef46894/flake8_docstrings-1.7.0.tar.gz", hash = "sha256:4c8cc748dc16e6869728699e5d0d685da9a10b0ea718e090b1ba088e67a941af", size = 5995, upload-time = "2023-01-25T14:27:13.903Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/7d/76a278fa43250441ed9300c344f889c7fb1817080c8fb8996b840bf421c2/flake8_docstrings-1.7.0-py2.py3-none-any.whl", hash = "sha256:51f2344026da083fc084166a9353f5082b01f72901df422f74b4d953ae88ac75", size = 4994, upload-time = "2023-01-25T14:27:12.32Z" }, +] + +[[package]] +name = "fonttools" +version = "4.57.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/2d/a9a0b6e3a0cf6bd502e64fc16d894269011930cabfc89aee20d1635b1441/fonttools-4.57.0.tar.gz", hash = "sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de", size = 3492448, upload-time = "2025-04-03T11:07:13.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/3f/c16dbbec7221783f37dcc2022d5a55f0d704ffc9feef67930f6eb517e8ce/fonttools-4.57.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9d57b4e23ebbe985125d3f0cabbf286efa191ab60bbadb9326091050d88e8213", size = 2753756, upload-time = "2025-04-03T11:06:36.875Z" }, + { url = "https://files.pythonhosted.org/packages/48/9f/5b4a3d6aed5430b159dd3494bb992d4e45102affa3725f208e4f0aedc6a3/fonttools-4.57.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:579ba873d7f2a96f78b2e11028f7472146ae181cae0e4d814a37a09e93d5c5cc", size = 2283179, upload-time = "2025-04-03T11:06:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/17/b2/4e887b674938b4c3848029a4134ac90dd8653ea80b4f464fa1edeae37f25/fonttools-4.57.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3e1ec10c29bae0ea826b61f265ec5c858c5ba2ce2e69a71a62f285cf8e4595", size = 4647139, upload-time = "2025-04-03T11:06:41.315Z" }, + { url = "https://files.pythonhosted.org/packages/a5/0e/b6314a09a4d561aaa7e09de43fa700917be91e701f07df6178865962666c/fonttools-4.57.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1968f2a2003c97c4ce6308dc2498d5fd4364ad309900930aa5a503c9851aec8", size = 4691211, upload-time = "2025-04-03T11:06:43.566Z" }, + { url = "https://files.pythonhosted.org/packages/bf/1d/b9f4b70d165c25f5c9aee61eb6ae90b0e9b5787b2c0a45e4f3e50a839274/fonttools-4.57.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:aff40f8ac6763d05c2c8f6d240c6dac4bb92640a86d9b0c3f3fff4404f34095c", size = 4873755, upload-time = "2025-04-03T11:06:45.457Z" }, + { url = "https://files.pythonhosted.org/packages/3b/fa/a731c8f42ae2c6761d1c22bd3c90241d5b2b13cabb70598abc74a828b51f/fonttools-4.57.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d07f1b64008e39fceae7aa99e38df8385d7d24a474a8c9872645c4397b674481", size = 5070072, upload-time = "2025-04-03T11:06:47.853Z" }, + { url = "https://files.pythonhosted.org/packages/1f/1e/6a988230109a2ba472e5de0a4c3936d49718cfc4b700b6bad53eca414bcf/fonttools-4.57.0-cp38-cp38-win32.whl", hash = "sha256:51d8482e96b28fb28aa8e50b5706f3cee06de85cbe2dce80dbd1917ae22ec5a6", size = 1484098, upload-time = "2025-04-03T11:06:50.167Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7a/2b3666e8c13d035adf656a8ae391380656144760353c97f74747c64fd3e5/fonttools-4.57.0-cp38-cp38-win_amd64.whl", hash = "sha256:03290e818782e7edb159474144fca11e36a8ed6663d1fcbd5268eb550594fd8e", size = 1529536, upload-time = "2025-04-03T11:06:52.468Z" }, + { url = "https://files.pythonhosted.org/packages/90/27/45f8957c3132917f91aaa56b700bcfc2396be1253f685bd5c68529b6f610/fonttools-4.57.0-py3-none-any.whl", hash = "sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f", size = 1093605, upload-time = "2025-04-03T11:07:11.341Z" }, +] + +[[package]] +name = "gdown" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "filelock" }, + { name = "requests", extra = ["socks"] }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/6a/37e6b70c5bda3161e40265861e63b64a86bfc6ca6a8f1c35328a675c84fd/gdown-5.2.0.tar.gz", hash = "sha256:2145165062d85520a3cd98b356c9ed522c5e7984d408535409fd46f94defc787", size = 284647, upload-time = "2024-05-12T06:45:12.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/70/e07c381e6488a77094f04c85c9caf1c8008cdc30778f7019bc52e5285ef0/gdown-5.2.0-py3-none-any.whl", hash = "sha256:33083832d82b1101bdd0e9df3edd0fbc0e1c5f14c9d8c38d2a35bf1683b526d6", size = 18235, upload-time = "2024-05-12T06:45:10.017Z" }, +] + +[[package]] +name = "gitdb" +version = "4.0.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, +] + +[[package]] +name = "gitpython" +version = "3.1.44" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269", size = 214196, upload-time = "2025-01-02T07:32:43.59Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599, upload-time = "2025-01-02T07:32:40.731Z" }, +] + +[[package]] +name = "google-auth" +version = "2.40.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "pyasn1-modules" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/9b/e92ef23b84fa10a64ce4831390b7a4c2e53c0132568d99d4ae61d04c8855/google_auth-2.40.3.tar.gz", hash = "sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77", size = 281029, upload-time = "2025-06-04T18:04:57.577Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/63/b19553b658a1692443c62bd07e5868adaa0ad746a0751ba62c59568cd45b/google_auth-2.40.3-py2.py3-none-any.whl", hash = "sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca", size = 216137, upload-time = "2025-06-04T18:04:55.573Z" }, +] + +[[package]] +name = "google-auth-oauthlib" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "requests-oauthlib" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e3/b4/ef2170c5f6aa5bc2461bab959a84e56d2819ce26662b50038d2d0602223e/google-auth-oauthlib-1.0.0.tar.gz", hash = "sha256:e375064964820b47221a7e1b7ee1fd77051b6323c3f9e3e19785f78ab67ecfc5", size = 20530, upload-time = "2023-02-07T20:53:20.679Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4a/07/8d9a8186e6768b55dfffeb57c719bc03770cf8a970a074616ae6f9e26a57/google_auth_oauthlib-1.0.0-py2.py3-none-any.whl", hash = "sha256:95880ca704928c300f48194d1770cf5b1462835b6e49db61445a520f793fd5fb", size = 18926, upload-time = "2023-02-07T20:53:18.837Z" }, +] + +[[package]] +name = "gputil" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/0e/5c61eedde9f6c87713e89d794f01e378cfd9565847d4576fa627d758c554/GPUtil-1.4.0.tar.gz", hash = "sha256:099e52c65e512cdfa8c8763fca67f5a5c2afb63469602d5dcb4d296b3661efb9", size = 5545, upload-time = "2018-12-18T09:12:13.63Z" } + +[[package]] +name = "grpcio" +version = "1.70.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/e1/4b21b5017c33f3600dcc32b802bb48fe44a4d36d6c066f52650c7c2690fa/grpcio-1.70.0.tar.gz", hash = "sha256:8d1584a68d5922330025881e63a6c1b54cc8117291d382e4fa69339b6d914c56", size = 12788932, upload-time = "2025-01-23T18:00:17.288Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/5f/d7fe323c18a2ec98a2a9b38fb985f5e843f76990298d7c4ce095f44b46a7/grpcio-1.70.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:8058667a755f97407fca257c844018b80004ae8035565ebc2812cc550110718d", size = 5232027, upload-time = "2025-01-23T17:55:07.597Z" }, + { url = "https://files.pythonhosted.org/packages/d4/4b/3d3b5548575b635f51883212a482cd237e8525535d4591b9dc7e5b2c2ddc/grpcio-1.70.0-cp38-cp38-macosx_10_14_universal2.whl", hash = "sha256:879a61bf52ff8ccacbedf534665bb5478ec8e86ad483e76fe4f729aaef867cab", size = 11448811, upload-time = "2025-01-23T17:55:11.773Z" }, + { url = "https://files.pythonhosted.org/packages/8a/d7/9a0922fc12d339271c7e4e6691470172b7c13715fed7bd934274803f1527/grpcio-1.70.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:0ba0a173f4feacf90ee618fbc1a27956bfd21260cd31ced9bc707ef551ff7dc7", size = 5711890, upload-time = "2025-01-23T17:55:17.167Z" }, + { url = "https://files.pythonhosted.org/packages/1e/ae/d4dbf8bff0f1d270f118d08558bc8dc0489e026d6620a4e3ee2d79d79041/grpcio-1.70.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558c386ecb0148f4f99b1a65160f9d4b790ed3163e8610d11db47838d452512d", size = 6331933, upload-time = "2025-01-23T17:55:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/2c/64/66a74c02b00e00b919c245ca9da8e5c44e8692bf3fe7f27efbc97572566c/grpcio-1.70.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:412faabcc787bbc826f51be261ae5fa996b21263de5368a55dc2cf824dc5090e", size = 5950685, upload-time = "2025-01-23T17:55:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/b0/64/e992ac693118c37164e085676216d258804d7a5bbf3581d3f989c843a9a5/grpcio-1.70.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3b0f01f6ed9994d7a0b27eeddea43ceac1b7e6f3f9d86aeec0f0064b8cf50fdb", size = 6640974, upload-time = "2025-01-23T17:55:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/57/17/34d0a6af4477fd48b8b41d13782fb1e35b8841b17d6ac7a3eb24d2f3b17e/grpcio-1.70.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7385b1cb064734005204bc8994eed7dcb801ed6c2eda283f613ad8c6c75cf873", size = 6204792, upload-time = "2025-01-23T17:55:27Z" }, + { url = "https://files.pythonhosted.org/packages/d3/e5/e45d8eb81929c0becd5bda413b60262f79d862e19cff632d496909aa3bd0/grpcio-1.70.0-cp38-cp38-win32.whl", hash = "sha256:07269ff4940f6fb6710951116a04cd70284da86d0a4368fd5a3b552744511f5a", size = 3620015, upload-time = "2025-01-23T17:55:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/87/7d/36009c38093e62969c708f20b86ab6761c2ba974b12ff10def6f397f24fa/grpcio-1.70.0-cp38-cp38-win_amd64.whl", hash = "sha256:aba19419aef9b254e15011b230a180e26e0f6864c90406fdbc255f01d83bc83c", size = 4307043, upload-time = "2025-01-23T17:55:31.823Z" }, +] + +[[package]] +name = "identify" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/bb/25024dbcc93516c492b75919e76f389bac754a3e4248682fba32b250c880/identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98", size = 99097, upload-time = "2024-09-14T23:50:32.513Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/0c/4ef72754c050979fdcc06c744715ae70ea37e734816bb6514f79df77a42f/identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0", size = 98972, upload-time = "2024-09-14T23:50:30.747Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304, upload-time = "2024-09-11T14:56:08.937Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514, upload-time = "2024-09-11T14:56:07.019Z" }, +] + +[[package]] +name = "importlib-resources" +version = "6.4.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/be/f3e8c6081b684f176b761e6a2fef02a0be939740ed6f54109a2951d806f3/importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", size = 43372, upload-time = "2024-09-09T17:03:14.677Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717", size = 36115, upload-time = "2024-09-09T17:03:13.39Z" }, +] + +[[package]] +name = "isort" +version = "5.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "joblib" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/64/33/60135848598c076ce4b231e1b1895170f45fbcaeaa2c9d5e38b04db70c35/joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e", size = 2116621, upload-time = "2024-05-02T12:15:05.765Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6", size = 301817, upload-time = "2024-05-02T12:15:00.765Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/4d/2255e1c76304cbd60b48cee302b66d1dde4468dc5b1160e4b7cb43778f2a/kiwisolver-1.4.7.tar.gz", hash = "sha256:9893ff81bd7107f7b685d3017cc6583daadb4fc26e4a888350df530e41980a60", size = 97286, upload-time = "2024-09-04T09:39:44.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/d6/620247574d9e26fe24384087879e8399e309f0051782f95238090afa6ccc/kiwisolver-1.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5d5abf8f8ec1f4e22882273c423e16cae834c36856cac348cfbfa68e01c40f3a", size = 122325, upload-time = "2024-09-04T09:05:31.648Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c6/572ad7d73dbd898cffa9050ffd7ff7e78a055a1d9b7accd6b4d1f50ec858/kiwisolver-1.4.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:aeb3531b196ef6f11776c21674dba836aeea9d5bd1cf630f869e3d90b16cfade", size = 65679, upload-time = "2024-09-04T09:05:32.934Z" }, + { url = "https://files.pythonhosted.org/packages/14/a7/bb8ab10e12cc8764f4da0245d72dee4731cc720bdec0f085d5e9c6005b98/kiwisolver-1.4.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b7d755065e4e866a8086c9bdada157133ff466476a2ad7861828e17b6026e22c", size = 64267, upload-time = "2024-09-04T09:05:34.11Z" }, + { url = "https://files.pythonhosted.org/packages/54/a4/3b5a2542429e182a4df0528214e76803f79d016110f5e67c414a0357cd7d/kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08471d4d86cbaec61f86b217dd938a83d85e03785f51121e791a6e6689a3be95", size = 1387236, upload-time = "2024-09-04T09:05:35.97Z" }, + { url = "https://files.pythonhosted.org/packages/a6/d7/bc3005e906c1673953a3e31ee4f828157d5e07a62778d835dd937d624ea0/kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7bbfcb7165ce3d54a3dfbe731e470f65739c4c1f85bb1018ee912bae139e263b", size = 1500555, upload-time = "2024-09-04T09:05:37.552Z" }, + { url = "https://files.pythonhosted.org/packages/09/a7/87cb30741f13b7af08446795dca6003491755805edc9c321fe996c1320b8/kiwisolver-1.4.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d34eb8494bea691a1a450141ebb5385e4b69d38bb8403b5146ad279f4b30fa3", size = 1431684, upload-time = "2024-09-04T09:05:39.75Z" }, + { url = "https://files.pythonhosted.org/packages/37/a4/1e4e2d8cdaa42c73d523413498445247e615334e39401ae49dae74885429/kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9242795d174daa40105c1d86aba618e8eab7bf96ba8c3ee614da8302a9f95503", size = 1125811, upload-time = "2024-09-04T09:05:41.31Z" }, + { url = "https://files.pythonhosted.org/packages/76/36/ae40d7a3171e06f55ac77fe5536079e7be1d8be2a8210e08975c7f9b4d54/kiwisolver-1.4.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a0f64a48bb81af7450e641e3fe0b0394d7381e342805479178b3d335d60ca7cf", size = 1179987, upload-time = "2024-09-04T09:05:42.893Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5d/6e4894b9fdf836d8bd095729dff123bbbe6ad0346289287b45c800fae656/kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8e045731a5416357638d1700927529e2b8ab304811671f665b225f8bf8d8f933", size = 2186817, upload-time = "2024-09-04T09:05:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/f0/2d/603079b2c2fd62890be0b0ebfc8bb6dda8a5253ca0758885596565b0dfc1/kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4322872d5772cae7369f8351da1edf255a604ea7087fe295411397d0cfd9655e", size = 2332538, upload-time = "2024-09-04T09:05:46.206Z" }, + { url = "https://files.pythonhosted.org/packages/bb/2a/9a28279c865c38a27960db38b07179143aafc94877945c209bfc553d9dd3/kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e1631290ee9271dffe3062d2634c3ecac02c83890ada077d225e081aca8aab89", size = 2293890, upload-time = "2024-09-04T09:05:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/1a/4d/4da8967f3bf13c764984b8fbae330683ee5fbd555b4a5624ad2b9decc0ab/kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:edcfc407e4eb17e037bca59be0e85a2031a2ac87e4fed26d3e9df88b4165f92d", size = 2434677, upload-time = "2024-09-04T09:05:49.459Z" }, + { url = "https://files.pythonhosted.org/packages/08/e9/a97a2b6b74dd850fa5974309367e025c06093a143befe9b962d0baebb4f0/kiwisolver-1.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:4d05d81ecb47d11e7f8932bd8b61b720bf0b41199358f3f5e36d38e28f0532c5", size = 2250339, upload-time = "2024-09-04T09:05:51.165Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e7/55507a387ba1766e69f5e13a79e1aefabdafe0532bee5d1972dfc42b3d16/kiwisolver-1.4.7-cp38-cp38-win32.whl", hash = "sha256:b38ac83d5f04b15e515fd86f312479d950d05ce2368d5413d46c088dda7de90a", size = 46932, upload-time = "2024-09-04T09:05:52.49Z" }, + { url = "https://files.pythonhosted.org/packages/52/77/7e04cca2ff1dc6ee6b7654cebe233de72b7a3ec5616501b6f3144fb70740/kiwisolver-1.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:d83db7cde68459fc803052a55ace60bea2bae361fc3b7a6d5da07e11954e4b09", size = 55836, upload-time = "2024-09-04T09:05:54.078Z" }, + { url = "https://files.pythonhosted.org/packages/64/f3/2403d90821fffe496df16f6996cb328b90b0d80c06d2938a930a7732b4f1/kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bfa1acfa0c54932d5607e19a2c24646fb4c1ae2694437789129cf099789a3b00", size = 59662, upload-time = "2024-09-04T09:06:33.551Z" }, + { url = "https://files.pythonhosted.org/packages/fa/7d/8f409736a4a6ac04354fa530ebf46682ddb1539b0bae15f4731ff2c575bc/kiwisolver-1.4.7-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:eee3ea935c3d227d49b4eb85660ff631556841f6e567f0f7bda972df6c2c9935", size = 57753, upload-time = "2024-09-04T09:06:35.095Z" }, + { url = "https://files.pythonhosted.org/packages/4c/a5/3937c9abe8eedb1356071739ad437a0b486cbad27d54f4ec4733d24882ac/kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f3160309af4396e0ed04db259c3ccbfdc3621b5559b5453075e5de555e1f3a1b", size = 103564, upload-time = "2024-09-04T09:06:36.756Z" }, + { url = "https://files.pythonhosted.org/packages/b2/18/a5ae23888f010b90d5eb8d196fed30e268056b2ded54d25b38a193bb70e9/kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a17f6a29cf8935e587cc8a4dbfc8368c55edc645283db0ce9801016f83526c2d", size = 95264, upload-time = "2024-09-04T09:06:38.786Z" }, + { url = "https://files.pythonhosted.org/packages/f9/d0/c4240ae86306d4395e9701f1d7e6ddcc6d60c28cb0127139176cfcfc9ebe/kiwisolver-1.4.7-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10849fb2c1ecbfae45a693c070e0320a91b35dd4bcf58172c023b994283a124d", size = 78197, upload-time = "2024-09-04T09:06:40.453Z" }, + { url = "https://files.pythonhosted.org/packages/62/db/62423f0ab66813376a35c1e7da488ebdb4e808fcb54b7cec33959717bda1/kiwisolver-1.4.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ac542bf38a8a4be2dc6b15248d36315ccc65f0743f7b1a76688ffb6b5129a5c2", size = 56080, upload-time = "2024-09-04T09:06:42.061Z" }, +] + +[[package]] +name = "lightning-utilities" +version = "0.11.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "setuptools" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8c/4d/54d38e237ab437f25f191602373d99b89d1d047ad2a3bb5ad0d84ea5daa6/lightning_utilities-0.11.9.tar.gz", hash = "sha256:f5052b81344cc2684aa9afd74b7ce8819a8f49a858184ec04548a5a109dfd053", size = 29362, upload-time = "2024-11-19T17:20:01.723Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/f3/1305321a12c984405e26fc64b5d521569e9872fb811f4aace8e168099160/lightning_utilities-0.11.9-py3-none-any.whl", hash = "sha256:ac6d4e9e28faf3ff4be997876750fee10dc604753dbc429bf3848a95c5d7e0d2", size = 28356, upload-time = "2024-11-19T17:20:00.746Z" }, +] + +[[package]] +name = "lit" +version = "18.1.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/b4/d7e210971494db7b9a9ac48ff37dfa59a8b14c773f9cf47e6bda58411c0d/lit-18.1.8.tar.gz", hash = "sha256:47c174a186941ae830f04ded76a3444600be67d5e5fb8282c3783fba671c4edb", size = 161127, upload-time = "2024-06-25T14:33:14.489Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/06/b36f150fa7c5bcc96a31a4d19a20fddbd1d965b6f02510b57a3bb8d4b930/lit-18.1.8-py3-none-any.whl", hash = "sha256:a873ff7acd76e746368da32eb7355625e2e55a2baaab884c9cc130f2ee0300f7", size = 96365, upload-time = "2024-06-25T14:33:12.101Z" }, +] + +[[package]] +name = "markdown" +version = "3.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086, upload-time = "2024-08-16T15:55:17.812Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349, upload-time = "2024-08-16T15:55:16.176Z" }, +] + +[[package]] +name = "markupsafe" +version = "2.1.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384, upload-time = "2024-02-02T16:31:22.863Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", size = 18192, upload-time = "2024-02-02T16:30:57.715Z" }, + { url = "https://files.pythonhosted.org/packages/4f/14/6f294b9c4f969d0c801a4615e221c1e084722ea6114ab2114189c5b8cbe0/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", size = 14072, upload-time = "2024-02-02T16:30:58.844Z" }, + { url = "https://files.pythonhosted.org/packages/81/d4/fd74714ed30a1dedd0b82427c02fa4deec64f173831ec716da11c51a50aa/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", size = 26928, upload-time = "2024-02-02T16:30:59.922Z" }, + { url = "https://files.pythonhosted.org/packages/c7/bd/50319665ce81bb10e90d1cf76f9e1aa269ea6f7fa30ab4521f14d122a3df/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", size = 26106, upload-time = "2024-02-02T16:31:01.582Z" }, + { url = "https://files.pythonhosted.org/packages/4c/6f/f2b0f675635b05f6afd5ea03c094557bdb8622fa8e673387444fe8d8e787/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68", size = 25781, upload-time = "2024-02-02T16:31:02.71Z" }, + { url = "https://files.pythonhosted.org/packages/51/e0/393467cf899b34a9d3678e78961c2c8cdf49fb902a959ba54ece01273fb1/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", size = 30518, upload-time = "2024-02-02T16:31:04.392Z" }, + { url = "https://files.pythonhosted.org/packages/f6/02/5437e2ad33047290dafced9df741d9efc3e716b75583bbd73a9984f1b6f7/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", size = 29669, upload-time = "2024-02-02T16:31:05.53Z" }, + { url = "https://files.pythonhosted.org/packages/0e/7d/968284145ffd9d726183ed6237c77938c021abacde4e073020f920e060b2/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", size = 29933, upload-time = "2024-02-02T16:31:06.636Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f3/ecb00fc8ab02b7beae8699f34db9357ae49d9f21d4d3de6f305f34fa949e/MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", size = 16656, upload-time = "2024-02-02T16:31:07.767Z" }, + { url = "https://files.pythonhosted.org/packages/92/21/357205f03514a49b293e214ac39de01fadd0970a6e05e4bf1ddd0ffd0881/MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", size = 17206, upload-time = "2024-02-02T16:31:08.843Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.7.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "importlib-resources" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b6/f0/3836719cc3982fbba3b840d18a59db1d0ee9ac7986f24e8c0a092851b67b/matplotlib-3.7.5.tar.gz", hash = "sha256:1e5c971558ebc811aa07f54c7b7c677d78aa518ef4c390e14673a09e0860184a", size = 38098611, upload-time = "2024-02-16T10:50:56.19Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/72/50a38c8fd5dc845b06f8e71c9da802db44b81baabf4af8be78bb8a5622ea/matplotlib-3.7.5-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:cfff9b838531698ee40e40ea1a8a9dc2c01edb400b27d38de6ba44c1f9a8e3d2", size = 8322659, upload-time = "2024-02-16T10:49:23.206Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ea/129163dcd21db6da5d559a8160c4a74c1dc5f96ac246a3d4248b43c7648d/matplotlib-3.7.5-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:1dbcca4508bca7847fe2d64a05b237a3dcaec1f959aedb756d5b1c67b770c5ee", size = 7438408, upload-time = "2024-02-16T10:49:27.462Z" }, + { url = "https://files.pythonhosted.org/packages/aa/59/4d13e5b6298b1ca5525eea8c68d3806ae93ab6d0bb17ca9846aa3156b92b/matplotlib-3.7.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4cdf4ef46c2a1609a50411b66940b31778db1e4b73d4ecc2eaa40bd588979b13", size = 7341782, upload-time = "2024-02-16T10:49:32.173Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c4/f562df04b08487731743511ff274ae5d31dce2ff3e5621f8b070d20ab54a/matplotlib-3.7.5-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:167200ccfefd1674b60e957186dfd9baf58b324562ad1a28e5d0a6b3bea77905", size = 9196487, upload-time = "2024-02-16T10:49:37.971Z" }, + { url = "https://files.pythonhosted.org/packages/30/33/cc27211d2ffeee4fd7402dca137b6e8a83f6dcae3d4be8d0ad5068555561/matplotlib-3.7.5-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:53e64522934df6e1818b25fd48cf3b645b11740d78e6ef765fbb5fa5ce080d02", size = 9213051, upload-time = "2024-02-16T10:49:43.916Z" }, + { url = "https://files.pythonhosted.org/packages/9b/9d/8bd37c86b79312c9dbcfa379dec32303f9b38e8456e0829d7e666a0e0a05/matplotlib-3.7.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3e3bc79b2d7d615067bd010caff9243ead1fc95cf735c16e4b2583173f717eb", size = 11370807, upload-time = "2024-02-16T10:49:47.701Z" }, + { url = "https://files.pythonhosted.org/packages/c0/1e/b24a07a849c8d458f1b3724f49029f0dedf748bdedb4d5f69491314838b6/matplotlib-3.7.5-cp38-cp38-win32.whl", hash = "sha256:6b641b48c6819726ed47c55835cdd330e53747d4efff574109fd79b2d8a13748", size = 7340461, upload-time = "2024-02-16T10:49:51.597Z" }, + { url = "https://files.pythonhosted.org/packages/16/51/58b0b9de42fe1e665736d9286f88b5f1556a0e22bed8a71f468231761083/matplotlib-3.7.5-cp38-cp38-win_amd64.whl", hash = "sha256:f0b60993ed3488b4532ec6b697059897891927cbfc2b8d458a891b60ec03d9d7", size = 7507471, upload-time = "2024-02-16T10:49:54.353Z" }, + { url = "https://files.pythonhosted.org/packages/27/6c/1bb10f3d6f337b9faa2e96a251bd87ba5fed85a608df95eb4d69acc109f0/matplotlib-3.7.5-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2a9a3f4d6a7f88a62a6a18c7e6a84aedcaf4faf0708b4ca46d87b19f1b526f88", size = 7397285, upload-time = "2024-02-16T10:50:27.375Z" }, + { url = "https://files.pythonhosted.org/packages/b2/36/66cfea213e9ba91cda9e257542c249ed235d49021af71c2e8007107d7d4c/matplotlib-3.7.5-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9b3fd853d4a7f008a938df909b96db0b454225f935d3917520305b90680579c", size = 7552612, upload-time = "2024-02-16T10:50:30.65Z" }, + { url = "https://files.pythonhosted.org/packages/77/df/16655199bf984c37c6a816b854bc032b56aef521aadc04f27928422f3c91/matplotlib-3.7.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0ad550da9f160737d7890217c5eeed4337d07e83ca1b2ca6535078f354e7675", size = 7515564, upload-time = "2024-02-16T10:50:33.589Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c8/3534c3705a677b71abb6be33609ba129fdeae2ea4e76b2fd3ab62c86fab3/matplotlib-3.7.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:20da7924a08306a861b3f2d1da0d1aa9a6678e480cf8eacffe18b565af2813e7", size = 7521336, upload-time = "2024-02-16T10:50:36.4Z" }, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "mypy" +version = "1.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "tomli" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/eb/2c92d8ea1e684440f54fa49ac5d9a5f19967b7b472a281f419e69a8d228e/mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6", size = 3216051, upload-time = "2024-12-30T16:39:07.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/02/1817328c1372be57c16148ce7d2bfcfa4a796bedaed897381b1aad9b267c/mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31", size = 11143050, upload-time = "2024-12-30T16:38:29.743Z" }, + { url = "https://files.pythonhosted.org/packages/b9/07/99db9a95ece5e58eee1dd87ca456a7e7b5ced6798fd78182c59c35a7587b/mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6", size = 10321087, upload-time = "2024-12-30T16:38:14.739Z" }, + { url = "https://files.pythonhosted.org/packages/9a/eb/85ea6086227b84bce79b3baf7f465b4732e0785830726ce4a51528173b71/mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319", size = 12066766, upload-time = "2024-12-30T16:38:47.038Z" }, + { url = "https://files.pythonhosted.org/packages/4b/bb/f01bebf76811475d66359c259eabe40766d2f8ac8b8250d4e224bb6df379/mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac", size = 12787111, upload-time = "2024-12-30T16:39:02.444Z" }, + { url = "https://files.pythonhosted.org/packages/2f/c9/84837ff891edcb6dcc3c27d85ea52aab0c4a34740ff5f0ccc0eb87c56139/mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b", size = 12974331, upload-time = "2024-12-30T16:38:23.849Z" }, + { url = "https://files.pythonhosted.org/packages/84/5f/901e18464e6a13f8949b4909535be3fa7f823291b8ab4e4b36cfe57d6769/mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837", size = 9763210, upload-time = "2024-12-30T16:38:36.299Z" }, + { url = "https://files.pythonhosted.org/packages/a0/b5/32dd67b69a16d088e533962e5044e51004176a9952419de0370cdaead0f8/mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1", size = 2752905, upload-time = "2024-12-30T16:38:42.021Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "networkx" +version = "3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/a1/47b974da1a73f063c158a1f4cc33ed0abf7c04f98a19050e80c533c31f0c/networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61", size = 2021691, upload-time = "2023-04-04T20:07:56.693Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/05/9d4f9b78ead6b2661d6e8ea772e111fc4a9fbd866ad0c81906c11206b55e/networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36", size = 2072251, upload-time = "2023-04-04T20:07:53.63Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.9.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, +] + +[[package]] +name = "numpy" +version = "1.24.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a4/9b/027bec52c633f6556dba6b722d9a0befb40498b9ceddd29cbe67a45a127c/numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463", size = 10911229, upload-time = "2023-06-26T13:39:33.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/10/943cfb579f1a02909ff96464c69893b1d25be3731b5d3652c2e0cf1281ea/numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61", size = 19780722, upload-time = "2023-06-26T13:27:49.573Z" }, + { url = "https://files.pythonhosted.org/packages/a7/ae/f53b7b265fdc701e663fbb322a8e9d4b14d9cb7b2385f45ddfabfc4327e4/numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f", size = 13843102, upload-time = "2023-06-26T13:28:12.288Z" }, + { url = "https://files.pythonhosted.org/packages/25/6f/2586a50ad72e8dbb1d8381f837008a0321a3516dfd7cb57fc8cf7e4bb06b/numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e", size = 14039616, upload-time = "2023-06-26T13:28:35.659Z" }, + { url = "https://files.pythonhosted.org/packages/98/5d/5738903efe0ecb73e51eb44feafba32bdba2081263d40c5043568ff60faf/numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc", size = 17316263, upload-time = "2023-06-26T13:29:09.272Z" }, + { url = "https://files.pythonhosted.org/packages/d1/57/8d328f0b91c733aa9aa7ee540dbc49b58796c862b4fbcb1146c701e888da/numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2", size = 12455660, upload-time = "2023-06-26T13:29:33.434Z" }, + { url = "https://files.pythonhosted.org/packages/69/65/0d47953afa0ad569d12de5f65d964321c208492064c38fe3b0b9744f8d44/numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706", size = 14868112, upload-time = "2023-06-26T13:29:58.385Z" }, + { url = "https://files.pythonhosted.org/packages/a4/fd/8dff40e25e937c94257455c237b9b6bf5a30d42dd1cc11555533be099492/numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef", size = 19156590, upload-time = "2023-06-26T13:33:10.36Z" }, + { url = "https://files.pythonhosted.org/packages/42/e7/4bf953c6e05df90c6d351af69966384fed8e988d0e8c54dad7103b59f3ba/numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a", size = 16705744, upload-time = "2023-06-26T13:33:36.703Z" }, + { url = "https://files.pythonhosted.org/packages/fc/dd/9106005eb477d022b60b3817ed5937a43dad8fd1f20b0610ea8a32fcb407/numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2", size = 14734290, upload-time = "2023-06-26T13:34:05.409Z" }, +] + +[[package]] +name = "oauthlib" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + +[[package]] +name = "pep8-naming" +version = "0.14.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flake8" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/be/8e/1de32e908d8b008bb9352bfe7749aedecb71e2793d36c7ee342716acd1ec/pep8-naming-0.14.1.tar.gz", hash = "sha256:1ef228ae80875557eb6c1549deafed4dabbf3261cfcafa12f773fe0db9be8a36", size = 16546, upload-time = "2024-05-17T14:08:44.862Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/a2/450b71d1a87fcee50a7b994a53b1c68fc6a6b718df0eb035f2bffb2d3a4f/pep8_naming-0.14.1-py3-none-any.whl", hash = "sha256:63f514fc777d715f935faf185dedd679ab99526a7f2f503abb61587877f7b1c5", size = 8859, upload-time = "2024-05-17T14:08:42.738Z" }, +] + +[[package]] +name = "pillow" +version = "10.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059, upload-time = "2024-07-01T09:48:43.583Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/70/f40009702a477ce87d8d9faaa4de51d6562b3445d7a314accd06e4ffb01d/pillow-10.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736", size = 3509213, upload-time = "2024-07-01T09:47:11.662Z" }, + { url = "https://files.pythonhosted.org/packages/10/43/105823d233c5e5d31cea13428f4474ded9d961652307800979a59d6a4276/pillow-10.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b", size = 3375883, upload-time = "2024-07-01T09:47:14.453Z" }, + { url = "https://files.pythonhosted.org/packages/3c/ad/7850c10bac468a20c918f6a5dbba9ecd106ea1cdc5db3c35e33a60570408/pillow-10.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2", size = 4330810, upload-time = "2024-07-01T09:47:16.695Z" }, + { url = "https://files.pythonhosted.org/packages/84/4c/69bbed9e436ac22f9ed193a2b64f64d68fcfbc9f4106249dc7ed4889907b/pillow-10.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680", size = 4444341, upload-time = "2024-07-01T09:47:19.334Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4f/c183c63828a3f37bf09644ce94cbf72d4929b033b109160a5379c2885932/pillow-10.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b", size = 4356005, upload-time = "2024-07-01T09:47:21.805Z" }, + { url = "https://files.pythonhosted.org/packages/fb/ad/435fe29865f98a8fbdc64add8875a6e4f8c97749a93577a8919ec6f32c64/pillow-10.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd", size = 4525201, upload-time = "2024-07-01T09:47:24.457Z" }, + { url = "https://files.pythonhosted.org/packages/80/74/be8bf8acdfd70e91f905a12ae13cfb2e17c0f1da745c40141e26d0971ff5/pillow-10.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84", size = 4460635, upload-time = "2024-07-01T09:47:26.841Z" }, + { url = "https://files.pythonhosted.org/packages/e4/90/763616e66dc9ad59c9b7fb58f863755e7934ef122e52349f62c7742b82d3/pillow-10.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0", size = 4590283, upload-time = "2024-07-01T09:47:29.247Z" }, + { url = "https://files.pythonhosted.org/packages/69/66/03002cb5b2c27bb519cba63b9f9aa3709c6f7a5d3b285406c01f03fb77e5/pillow-10.4.0-cp38-cp38-win32.whl", hash = "sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e", size = 2235185, upload-time = "2024-07-01T09:47:32.205Z" }, + { url = "https://files.pythonhosted.org/packages/f2/75/3cb820b2812405fc7feb3d0deb701ef0c3de93dc02597115e00704591bc9/pillow-10.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab", size = 2554594, upload-time = "2024-07-01T09:47:34.285Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.3.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302, upload-time = "2024-09-17T19:06:50.688Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439, upload-time = "2024-09-17T19:06:49.212Z" }, +] + +[[package]] +name = "pre-commit" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/b3/4ae08d21eb097162f5aad37f4585f8069a86402ed7f5362cc9ae097f9572/pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32", size = 177079, upload-time = "2023-10-13T15:57:48.334Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/75/526915fedf462e05eeb1c75ceaf7e3f9cde7b5ce6f62740fe5f7f19a0050/pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660", size = 203698, upload-time = "2023-10-13T15:57:46.378Z" }, +] + +[[package]] +name = "protobuf" +version = "5.29.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" }, + { url = "https://files.pythonhosted.org/packages/81/7f/73cefb093e1a2a7c3ffd839e6f9fcafb7a427d300c7f8aef9c64405d8ac6/protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc", size = 434818, upload-time = "2025-05-28T23:51:44.297Z" }, + { url = "https://files.pythonhosted.org/packages/dd/73/10e1661c21f139f2c6ad9b23040ff36fee624310dc28fba20d33fdae124c/protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671", size = 418091, upload-time = "2025-05-28T23:51:45.907Z" }, + { url = "https://files.pythonhosted.org/packages/6c/04/98f6f8cf5b07ab1294c13f34b4e69b3722bb609c5b701d6c169828f9f8aa/protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015", size = 319824, upload-time = "2025-05-28T23:51:47.545Z" }, + { url = "https://files.pythonhosted.org/packages/85/e4/07c80521879c2d15f321465ac24c70efe2381378c00bf5e56a0f4fbac8cd/protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61", size = 319942, upload-time = "2025-05-28T23:51:49.11Z" }, + { url = "https://files.pythonhosted.org/packages/b1/24/dc0e489944b3cba0403f26223c0cc552a222af91a42257cbd25ef968b0c0/protobuf-5.29.5-cp38-cp38-win32.whl", hash = "sha256:ef91363ad4faba7b25d844ef1ada59ff1604184c0bcd8b39b8a6bef15e1af238", size = 422886, upload-time = "2025-05-28T23:51:50.688Z" }, + { url = "https://files.pythonhosted.org/packages/a2/bb/9a6e6ec4a99bccd35e326e8e5eab30ca42f3df987c13ca6522b8b4fbd5ff/protobuf-5.29.5-cp38-cp38-win_amd64.whl", hash = "sha256:7318608d56b6402d2ea7704ff1e1e4597bee46d760e7e4dd42a3d45e24b87f2e", size = 434837, upload-time = "2025-05-28T23:51:52.298Z" }, + { url = "https://files.pythonhosted.org/packages/7e/cc/7e77861000a0691aeea8f4566e5d3aa716f2b1dece4a24439437e41d3d25/protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5", size = 172823, upload-time = "2025-05-28T23:51:58.157Z" }, +] + +[[package]] +name = "psutil" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" }, + { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" }, + { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" }, + { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + +[[package]] +name = "pycodestyle" +version = "2.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/aa/210b2c9aedd8c1cbeea31a50e42050ad56187754b34eb214c46709445801/pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521", size = 39232, upload-time = "2024-08-04T20:26:54.576Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/d8/a211b3f85e99a0daa2ddec96c949cac6824bd305b040571b82a03dd62636/pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", size = 31284, upload-time = "2024-08-04T20:26:53.173Z" }, +] + +[[package]] +name = "pydantic" +version = "2.10.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681, upload-time = "2025-01-24T01:42:12.693Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696, upload-time = "2025-01-24T01:42:10.371Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/53/13e9917fc69c0a4aea06fd63ed6a8d6cda9cf140ca9584d49c1650b0ef5e/pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506", size = 1899595, upload-time = "2024-12-18T11:29:40.887Z" }, + { url = "https://files.pythonhosted.org/packages/f4/20/26c549249769ed84877f862f7bb93f89a6ee08b4bee1ed8781616b7fbb5e/pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320", size = 1775010, upload-time = "2024-12-18T11:29:44.823Z" }, + { url = "https://files.pythonhosted.org/packages/35/eb/8234e05452d92d2b102ffa1b56d801c3567e628fdc63f02080fdfc68fd5e/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145", size = 1830727, upload-time = "2024-12-18T11:29:46.904Z" }, + { url = "https://files.pythonhosted.org/packages/8f/df/59f915c8b929d5f61e5a46accf748a87110ba145156f9326d1a7d28912b2/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1", size = 1868393, upload-time = "2024-12-18T11:29:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/d5/52/81cf4071dca654d485c277c581db368b0c95b2b883f4d7b736ab54f72ddf/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228", size = 2040300, upload-time = "2024-12-18T11:29:51.43Z" }, + { url = "https://files.pythonhosted.org/packages/9c/00/05197ce1614f5c08d7a06e1d39d5d8e704dc81971b2719af134b844e2eaf/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046", size = 2738785, upload-time = "2024-12-18T11:29:55.001Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a3/5f19bc495793546825ab160e530330c2afcee2281c02b5ffafd0b32ac05e/pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5", size = 1996493, upload-time = "2024-12-18T11:29:57.13Z" }, + { url = "https://files.pythonhosted.org/packages/ed/e8/e0102c2ec153dc3eed88aea03990e1b06cfbca532916b8a48173245afe60/pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a", size = 1998544, upload-time = "2024-12-18T11:30:00.681Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a3/4be70845b555bd80aaee9f9812a7cf3df81550bce6dadb3cfee9c5d8421d/pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d", size = 2007449, upload-time = "2024-12-18T11:30:02.985Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9f/b779ed2480ba355c054e6d7ea77792467631d674b13d8257085a4bc7dcda/pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9", size = 2129460, upload-time = "2024-12-18T11:30:06.55Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f0/a6ab0681f6e95260c7fbf552874af7302f2ea37b459f9b7f00698f875492/pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da", size = 2159609, upload-time = "2024-12-18T11:30:09.428Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2b/e1059506795104349712fbca647b18b3f4a7fd541c099e6259717441e1e0/pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b", size = 1819886, upload-time = "2024-12-18T11:30:11.777Z" }, + { url = "https://files.pythonhosted.org/packages/aa/6d/df49c17f024dfc58db0bacc7b03610058018dd2ea2eaf748ccbada4c3d06/pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad", size = 1980773, upload-time = "2024-12-18T11:30:14.828Z" }, +] + +[[package]] +name = "pydocstyle" +version = "6.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "snowballstemmer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/d5385ca59fd065e3c6a5fe19f9bc9d5ea7f2509fa8c9c22fb6b2031dd953/pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1", size = 36796, upload-time = "2023-01-17T20:29:19.838Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/ea/99ddefac41971acad68f14114f38261c1f27dac0b3ec529824ebc739bdaa/pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019", size = 38038, upload-time = "2023-01-17T20:29:18.094Z" }, +] + +[[package]] +name = "pyflakes" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/f9/669d8c9c86613c9d568757c7f5824bd3197d7b1c6c27553bc5618a27cce2/pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", size = 63788, upload-time = "2024-01-05T00:28:47.703Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725, upload-time = "2024-01-05T00:28:45.903Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/08/13f3bce01b2061f2bbd582c9df82723de943784cf719a35ac886c652043a/pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032", size = 900231, upload-time = "2024-08-25T15:00:47.416Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/0c/0e3c05b1c87bb6a1c76d281b0f35e78d2d80ac91b5f8f524cebf77f51049/pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c", size = 104100, upload-time = "2024-08-25T15:00:45.361Z" }, +] + +[[package]] +name = "pysocks" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pytorchcv" +version = "0.0.67" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/b3/2f7b3ea53aff801fe7a9d37117f074b4325831934bb760f52697e1d18542/pytorchcv-0.0.67.tar.gz", hash = "sha256:aa9c64378ff2f0b74624e60ab4529bc4e28042f7bd9fd0e4e43e33f86a442067", size = 361050, upload-time = "2021-09-21T10:21:23.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c3/50a0bf26acd8821aeb3d9ab1380a3aa9581e66e04e7b685d2379a91cc442/pytorchcv-0.0.67-py2.py3-none-any.whl", hash = "sha256:c40fd3db1e9276010b0334c8f3c362d7f35e9e2409eee6a4b80c2e8846a97c4b", size = 532355, upload-time = "2021-09-21T10:21:19.046Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/d9/323a59d506f12f498c2097488d80d16f4cf965cee1791eab58b56b19f47a/PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", size = 183218, upload-time = "2024-08-06T20:33:06.411Z" }, + { url = "https://files.pythonhosted.org/packages/74/cc/20c34d00f04d785f2028737e2e2a8254e1425102e730fee1d6396f832577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", size = 728067, upload-time = "2024-08-06T20:33:07.879Z" }, + { url = "https://files.pythonhosted.org/packages/20/52/551c69ca1501d21c0de51ddafa8c23a0191ef296ff098e98358f69080577/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", size = 757812, upload-time = "2024-08-06T20:33:12.542Z" }, + { url = "https://files.pythonhosted.org/packages/fd/7f/2c3697bba5d4aa5cc2afe81826d73dfae5f049458e44732c7a0938baa673/PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", size = 746531, upload-time = "2024-08-06T20:33:14.391Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ab/6226d3df99900e580091bb44258fde77a8433511a86883bd4681ea19a858/PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", size = 800820, upload-time = "2024-08-06T20:33:16.586Z" }, + { url = "https://files.pythonhosted.org/packages/a0/99/a9eb0f3e710c06c5d922026f6736e920d431812ace24aae38228d0d64b04/PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", size = 145514, upload-time = "2024-08-06T20:33:22.414Z" }, + { url = "https://files.pythonhosted.org/packages/75/8a/ee831ad5fafa4431099aa4e078d4c8efd43cd5e48fbc774641d233b683a9/PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", size = 162702, upload-time = "2024-08-06T20:33:23.813Z" }, +] + +[[package]] +name = "quadprog" +version = "0.1.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0d/dc/7c435d10d5d2cfaf74b9c737b71b45be3fac74decac38c498f981e5f24ad/quadprog-0.1.12.tar.gz", hash = "sha256:594c18327e13c4246b06b14d9e90c43faac4ba702be6ae0aa0192e50a7795e47", size = 16884, upload-time = "2024-02-21T20:34:45.719Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/f2/bad93d07fa2723d4192d406965870816a40b42d6a92cdcbb6efdc59692de/quadprog-0.1.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08aa0c5512d865f6e0e548590d74734c624ae5c20acff24e6af947005ec7b975", size = 105950, upload-time = "2024-02-21T20:34:34.518Z" }, + { url = "https://files.pythonhosted.org/packages/01/18/02b5d399ad473e561858ba62f1c238c70d9d39477b8e88b1ab3a77517145/quadprog-0.1.12-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:58df266c3bd8f45a537715af237fe4f2f64615d6b09841e47900aebf720454c4", size = 95732, upload-time = "2024-02-21T20:34:35.701Z" }, + { url = "https://files.pythonhosted.org/packages/1c/87/7e1af6b1ee5e3f862bd2cf3fcfb29abc2821ea8e9ccd66b02349de9c5c5b/quadprog-0.1.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cbd5e9e16bc0afd44d91299ef0fb68f95f276452845cac830dac9c8e488d56f", size = 523146, upload-time = "2024-02-21T20:34:36.864Z" }, + { url = "https://files.pythonhosted.org/packages/1d/74/f0ade50ce7890ccdd8adbc1604e25d05174427c8bbaf7b6057d711654e9d/quadprog-0.1.12-cp38-cp38-win_amd64.whl", hash = "sha256:75c3adf214ae6f1c5eaad88d97e60aa8093374fd7f8bdb6e7767ef52ad2b883f", size = 91951, upload-time = "2024-02-21T20:34:38.225Z" }, +] + +[[package]] +name = "requests" +version = "2.32.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, +] + +[package.optional-dependencies] +socks = [ + { name = "pysocks" }, +] + +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "oauthlib" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, +] + +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/88/00/835e3d280fdd7784e76bdef91dd9487582d7951a7254f59fc8004fc8b213/scikit-learn-1.3.2.tar.gz", hash = "sha256:a2f54c76accc15a34bfb9066e6c7a56c1e7235dda5762b990792330b52ccfb05", size = 7510251, upload-time = "2023-10-23T13:47:55.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/52/fd60b0b022af41fbf3463587ddc719288f0f2d4e46603ab3184996cd5f04/scikit_learn-1.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a19f90f95ba93c1a7f7924906d0576a84da7f3b2282ac3bfb7a08a32801add93", size = 10064879, upload-time = "2023-10-23T13:47:21.392Z" }, + { url = "https://files.pythonhosted.org/packages/a4/62/92e9cec3deca8b45abf62dd8f6469d688b3f28b9c170809fcc46f110b523/scikit_learn-1.3.2-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:b8692e395a03a60cd927125eef3a8e3424d86dde9b2370d544f0ea35f78a8073", size = 9373934, upload-time = "2023-10-23T13:47:24.645Z" }, + { url = "https://files.pythonhosted.org/packages/49/81/91585dc83ec81dcd52e934f6708bf350b06949d8bfa13bf3b711b851c3f4/scikit_learn-1.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15e1e94cc23d04d39da797ee34236ce2375ddea158b10bee3c343647d615581d", size = 10499159, upload-time = "2023-10-23T13:47:28.41Z" }, + { url = "https://files.pythonhosted.org/packages/3f/48/6fdd99f5717045f9984616b5c2ec683d6286d30c0ac234563062132b83ab/scikit_learn-1.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:785a2213086b7b1abf037aeadbbd6d67159feb3e30263434139c98425e3dcfcf", size = 11067392, upload-time = "2023-10-23T13:47:32.087Z" }, + { url = "https://files.pythonhosted.org/packages/52/2d/ad6928a578c78bb0e44e34a5a922818b14c56716b81d145924f1f291416f/scikit_learn-1.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:64381066f8aa63c2710e6b56edc9f0894cc7bf59bd71b8ce5613a4559b6145e0", size = 9257871, upload-time = "2023-10-23T13:47:36.142Z" }, +] + +[[package]] +name = "scipy" +version = "1.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/a9/2bf119f3f9cff1f376f924e39cfae18dec92a1514784046d185731301281/scipy-1.10.1.tar.gz", hash = "sha256:2cf9dfb80a7b4589ba4c40ce7588986d6d5cebc5457cad2c2880f6bc2d42f3a5", size = 42407997, upload-time = "2023-02-19T21:20:13.395Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/37508a11dae501349d7c16e4dd18c706a023629eedc650ee094593887a89/scipy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5678f88c68ea866ed9ebe3a989091088553ba12c6090244fdae3e467b1139c35", size = 35041063, upload-time = "2023-02-19T20:49:02.296Z" }, + { url = "https://files.pythonhosted.org/packages/93/4a/50c436de1353cce8b66b26e49a687f10b91fe7465bf34e4565d810153003/scipy-1.10.1-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:39becb03541f9e58243f4197584286e339029e8908c46f7221abeea4b749fa88", size = 28797694, upload-time = "2023-02-19T20:50:19.381Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b5/ff61b79ad0ebd15d87ade10e0f4e80114dd89fac34a5efade39e99048c91/scipy-1.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bce5869c8d68cf383ce240e44c1d9ae7c06078a9396df68ce88a1230f93a30c1", size = 31024657, upload-time = "2023-02-19T20:51:49.175Z" }, + { url = "https://files.pythonhosted.org/packages/69/f0/fb07a9548e48b687b8bf2fa81d71aba9cfc548d365046ca1c791e24db99d/scipy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07c3457ce0b3ad5124f98a86533106b643dd811dd61b548e78cf4c8786652f6f", size = 34540352, upload-time = "2023-02-19T20:53:30.821Z" }, + { url = "https://files.pythonhosted.org/packages/32/8e/7f403535ddf826348c9b8417791e28712019962f7e90ff845896d6325d09/scipy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:049a8bbf0ad95277ffba9b3b7d23e5369cc39e66406d60422c8cfef40ccc8415", size = 42215036, upload-time = "2023-02-19T20:55:09.639Z" }, +] + +[[package]] +name = "sentry-sdk" +version = "2.33.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/0b/6139f589436c278b33359845ed77019cd093c41371f898283bbc14d26c02/sentry_sdk-2.33.0.tar.gz", hash = "sha256:cdceed05e186846fdf80ceea261fe0a11ebc93aab2f228ed73d076a07804152e", size = 335233, upload-time = "2025-07-15T12:07:42.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/e5/f24e9f81c9822a24a2627cfcb44c10a3971382e67e5015c6e068421f5787/sentry_sdk-2.33.0-py2.py3-none-any.whl", hash = "sha256:a762d3f19a1c240e16c98796f2a5023f6e58872997d5ae2147ac3ed378b23ec2", size = 356397, upload-time = "2025-07-15T12:07:40.729Z" }, +] + +[[package]] +name = "setuptools" +version = "59.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/e2/f2bfdf364e016f7a464db709ea40d1101c4c5a463dd7019dae0a42dbd1c6/setuptools-59.5.0.tar.gz", hash = "sha256:d144f85102f999444d06f9c0e8c737fd0194f10f2f7e5fdb77573f6e2fa4fad0", size = 2281671, upload-time = "2021-12-05T17:28:45.563Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/a9/7deac76c58fa47c95360116a06b53b9b62f6db11336fe61b6ab53784d98b/setuptools-59.5.0-py3-none-any.whl", hash = "sha256:6d10741ff20b89cd8c6a536ee9dc90d3002dec0226c78fb98605bfb9ef8a7adf", size = 952351, upload-time = "2021-12-05T17:28:43.837Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { 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" }, +] + +[[package]] +name = "smmap" +version = "5.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, +] + +[[package]] +name = "snowballstemmer" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/75/a7/9810d872919697c9d01295633f5d574fb416d47e535f258272ca1f01f447/snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895", size = 105575, upload-time = "2025-05-09T16:34:51.843Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/78/3565d011c61f5a43488987ee32b6f3f656e7f107ac2782dd57bdd7d91d9a/snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064", size = 103274, upload-time = "2025-05-09T16:34:50.371Z" }, +] + +[[package]] +name = "soupsieve" +version = "2.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/f4/4a80cd6ef364b2e8b65b15816a843c0980f7a5a2b4dc701fc574952aa19f/soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a", size = 103418, upload-time = "2025-04-20T18:50:08.518Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/9c/0e6afc12c269578be5c0c1c9f4b49a8d32770a080260c333ac04cc1c832d/soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4", size = 36677, upload-time = "2025-04-20T18:50:07.196Z" }, +] + +[[package]] +name = "sympy" +version = "1.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/11/8a/5a7fd6284fa8caac23a26c9ddf9c30485a48169344b4bd3b0f02fef1890f/sympy-1.13.3.tar.gz", hash = "sha256:b27fd2c6530e0ab39e275fc9b683895367e51d5da91baa8d3d64db2565fec4d9", size = 7533196, upload-time = "2024-09-18T21:54:25.591Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/ff/c87e0622b1dadea79d2fb0b25ade9ed98954c9033722eb707053d310d4f3/sympy-1.13.3-py3-none-any.whl", hash = "sha256:54612cf55a62755ee71824ce692986f23c88ffa77207b30c1368eda4a7060f73", size = 6189483, upload-time = "2024-09-18T21:54:23.097Z" }, +] + +[[package]] +name = "tensorboard" +version = "2.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "google-auth" }, + { name = "google-auth-oauthlib" }, + { name = "grpcio" }, + { name = "markdown" }, + { name = "numpy" }, + { name = "protobuf" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "tensorboard-data-server" }, + { name = "werkzeug" }, + { name = "wheel" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/a2/ff5f4c299eb37c95299a76015da3f30211468e29d8d6f1d011683279baee/tensorboard-2.14.0-py3-none-any.whl", hash = "sha256:3667f9745d99280836ad673022362c840f60ed8fefd5a3e30bf071f5a8fd0017", size = 5508926, upload-time = "2023-08-08T22:35:21.153Z" }, +] + +[[package]] +name = "tensorboard-data-server" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/13/e503968fefabd4c6b2650af21e110aa8466fe21432cd7c43a84577a89438/tensorboard_data_server-0.7.2-py3-none-any.whl", hash = "sha256:7e0610d205889588983836ec05dc098e80f97b7e7bbff7e994ebb78f578d0ddb", size = 2356, upload-time = "2023-10-23T21:23:32.16Z" }, + { url = "https://files.pythonhosted.org/packages/b7/85/dabeaf902892922777492e1d253bb7e1264cadce3cea932f7ff599e53fea/tensorboard_data_server-0.7.2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9fe5d24221b29625dbc7328b0436ca7fc1c23de4acf4d272f1180856e32f9f60", size = 4823598, upload-time = "2023-10-23T21:23:33.714Z" }, + { url = "https://files.pythonhosted.org/packages/73/c6/825dab04195756cf8ff2e12698f22513b3db2f64925bdd41671bfb33aaa5/tensorboard_data_server-0.7.2-py3-none-manylinux_2_31_x86_64.whl", hash = "sha256:ef687163c24185ae9754ed5650eb5bc4d84ff257aabdc33f0cc6f74d8ba54530", size = 6590363, upload-time = "2023-10-23T21:23:35.583Z" }, +] + +[[package]] +name = "tensorly" +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "scipy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/75/7f/813ac904fc85733a93a9703aea5fe320f0573855cf0eb092531c6b0a8a88/tensorly-0.8.1.tar.gz", hash = "sha256:cf78e4ffe612feca3510214002845c6831b267b1f2c1181154d41430310b237d", size = 171251, upload-time = "2023-03-08T01:07:44.591Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/6c/b07811af60b429d29ff1aab7a8d7b845f24e27462c7455c3df734007dd67/tensorly-0.8.1-py3-none-any.whl", hash = "sha256:08988dbc5e433c3f255d0e00855f99a613fe273d50a1627b7e82b03ff2a6da9a", size = 229666, upload-time = "2023-03-08T01:07:42.612Z" }, +] + +[[package]] +name = "threadpoolctl" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/55/b5148dcbf72f5cde221f8bfe3b6a540da7aa1842f6b491ad979a6c8b84af/threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107", size = 41936, upload-time = "2024-04-29T13:50:16.544Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467", size = 18414, upload-time = "2024-04-29T13:50:14.014Z" }, +] + +[[package]] +name = "timm" +version = "0.4.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torchvision", version = "0.15.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/12/34f304a4b913069058f63613bf52d003b1f9af76586c25bc5577455ac4d6/timm-0.4.12.tar.gz", hash = "sha256:b14be70dbd4528b5ca8657cf5bc2672c7918c3d9ebfbffe80f4785b54e884b1e", size = 307439, upload-time = "2021-06-30T16:31:02.19Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/fc/606bc5cf46acac3aa9bd179b3954433c026aaf88ea98d6b19f5d14c336da/timm-0.4.12-py3-none-any.whl", hash = "sha256:dba6b1702b7d24bf9f0f1c2fc394b4ee28f93cde5404f1dc732d63ccd00533b6", size = 376973, upload-time = "2021-06-30T16:31:00.256Z" }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, +] + +[[package]] +name = "torch" +version = "2.0.0" +source = { registry = "https://download.pytorch.org/whl/cpu" } +resolution-markers = [ + "platform_machine == 'aarch64' and sys_platform == 'linux'", + "sys_platform == 'darwin'", +] +dependencies = [ + { name = "filelock", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "jinja2", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "networkx", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "sympy", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "typing-extensions", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/torch-2.0.0-1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8969aa8375bcbc0c2993e7ede0a7f889df9515f18b9b548433f412affed478d9" }, + { url = "https://download.pytorch.org/whl/torch-2.0.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:11b0384fe3c18c01b8fc5992e70fc519cde65e44c51cc87be1838c1803daf42f" }, + { url = "https://download.pytorch.org/whl/cpu/torch-2.0.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:cc788cbbbbc6eb4c90e52c550efd067586c2693092cf367c135b34893a64ae78" }, + { url = "https://download.pytorch.org/whl/cpu/torch-2.0.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:d292640f0fd72b7a31b2a6e3b635eb5065fcbedd4478f9cad1a1e7a9ec861d35" }, +] + +[[package]] +name = "torch" +version = "2.0.0" +source = { registry = "https://download.pytorch.org/whl/cu118" } +resolution-markers = [ + "platform_machine == 'aarch64' and sys_platform == 'linux'", +] +dependencies = [ + { name = "filelock", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "jinja2", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "networkx", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "sympy", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "typing-extensions", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/torch-2.0.0-1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8969aa8375bcbc0c2993e7ede0a7f889df9515f18b9b548433f412affed478d9" }, + { url = "https://download.pytorch.org/whl/torch-2.0.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:11b0384fe3c18c01b8fc5992e70fc519cde65e44c51cc87be1838c1803daf42f" }, +] + +[[package]] +name = "torch" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "sys_platform == 'linux'", + "sys_platform != 'linux'", +] +dependencies = [ + { name = "filelock", marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "jinja2", marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "networkx", marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "sympy", marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "typing-extensions", marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/b5/449aa2a51b48dc389b50deae7d9260377a5925e63359cd0dd96d7ebc81a9/torch-2.0.0-1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8969aa8375bcbc0c2993e7ede0a7f889df9515f18b9b548433f412affed478d9", size = 74263470, upload-time = "2023-03-17T22:55:45.515Z" }, + { url = "https://files.pythonhosted.org/packages/89/5a/0d017d8d45cc309f9de8e5b8edc9b6b204d8c47936a3f2b84cf01650cf98/torch-2.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ec5fff2447663e369682838ff0f82187b4d846057ef4d119a8dea7772a0b17dd", size = 619877846, upload-time = "2023-03-15T15:58:23.187Z" }, + { url = "https://files.pythonhosted.org/packages/47/af/8266ea35c6a4e8a59b5e348288debdfc7d9a91356dd674b838131546aa6e/torch-2.0.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:11b0384fe3c18c01b8fc5992e70fc519cde65e44c51cc87be1838c1803daf42f", size = 63206408, upload-time = "2023-03-15T16:04:08.793Z" }, + { url = "https://files.pythonhosted.org/packages/49/97/fdb166f3123b4c3017d301e972a9ef10effd050ffc725ba0df6f962176d7/torch-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:e54846aa63855298cfb1195487f032e413e7ac9cbfa978fda32354cc39551475", size = 172333281, upload-time = "2023-03-15T16:03:39.105Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ee/e00f3fab0383fccf8ee1697ba468e0248bd36a9942d00d6c12fb08cb393a/torch-2.0.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:cc788cbbbbc6eb4c90e52c550efd067586c2693092cf367c135b34893a64ae78", size = 139531957, upload-time = "2023-03-15T16:03:58.458Z" }, + { url = "https://files.pythonhosted.org/packages/67/14/f4b5fb08f3fe59c610e07daa798d194dc40158b2011229dea7e7f5ab182b/torch-2.0.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:d292640f0fd72b7a31b2a6e3b635eb5065fcbedd4478f9cad1a1e7a9ec861d35", size = 55830206, upload-time = "2023-03-15T16:03:09.513Z" }, +] + +[[package]] +name = "torch" +version = "2.0.0+cpu" +source = { registry = "https://download.pytorch.org/whl/cpu" } +resolution-markers = [ + "platform_machine != 'aarch64' and sys_platform == 'linux'", + "sys_platform != 'darwin' and sys_platform != 'linux'", +] +dependencies = [ + { name = "filelock", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "jinja2", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "networkx", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "sympy", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/cpu/torch-2.0.0%2Bcpu-cp38-cp38-linux_x86_64.whl", hash = "sha256:354f281351cddb590990089eced60f866726415f7b287db5105514aa3c5f71ca" }, + { url = "https://download.pytorch.org/whl/cpu/torch-2.0.0%2Bcpu-cp38-cp38-win_amd64.whl", hash = "sha256:af9b9161572f18e325e38725610511d7bb5608677b8e0c0d89135ae2a9056ac7" }, +] + +[[package]] +name = "torch" +version = "2.0.0+cu118" +source = { registry = "https://download.pytorch.org/whl/cu118" } +resolution-markers = [ + "platform_machine != 'aarch64' and sys_platform == 'linux'", + "sys_platform != 'linux'", +] +dependencies = [ + { name = "filelock", marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "jinja2", marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "networkx", marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "sympy", marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "triton", marker = "(platform_machine == 'x86_64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'x86_64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "typing-extensions", marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/cu118/torch-2.0.0%2Bcu118-cp38-cp38-linux_x86_64.whl", hash = "sha256:1f8efaebfcbb7ec3962fd8c7c3be02c6666eff53a12043006a749d647656163e" }, + { url = "https://download.pytorch.org/whl/cu118/torch-2.0.0%2Bcu118-cp38-cp38-win_amd64.whl", hash = "sha256:2588926725750c9ba799c133d4f6ee8fa477f6f0d88d6c2cebfe5bcfe8d7d7c3" }, +] + +[[package]] +name = "torchmetrics" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lightning-utilities" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/cd/9b3f4b1342c4dc1bb2046a102c40e429902c3e3a02ab3fc7a3054920b340/torchmetrics-1.5.2.tar.gz", hash = "sha256:2d0e4957af0ea76438d2779fe1a626d8cba6cda8607eadb54267598153e7ea63", size = 521943, upload-time = "2024-11-08T10:42:16.477Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/5f/61483e589f87c3709236ce6ee5d44ffeadec12d04b1b0ae3e0900667edf5/torchmetrics-1.5.2-py3-none-any.whl", hash = "sha256:22dfddc93a66c0e46b46da2f8f7c57be4ba256070ed1e627e5e8de27bbe5b376", size = 891423, upload-time = "2024-11-08T10:42:14.084Z" }, +] + +[[package]] +name = "torchvision" +version = "0.15.0" +source = { registry = "https://download.pytorch.org/whl/cpu" } +resolution-markers = [ + "platform_machine == 'aarch64' and sys_platform == 'linux'", + "sys_platform == 'darwin'", +] +dependencies = [ + { name = "numpy", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "pillow", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "requests", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/cpu/torchvision-0.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cc9b09044d9c11e67373e9104fef5859a3808d29c557bcb888c8e64603c3bad8" }, + { url = "https://download.pytorch.org/whl/cpu/torchvision-0.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc53aa30ef18841e4dcbc826ee66d4a9b8baf805e41bfeabdf581868a9f7d8a" }, + { url = "https://download.pytorch.org/whl/torchvision-0.15.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:76035603bd2bfc9811c732bdb87e9b85298222ed9b5261a12d19ecd9ffa8ebc2" }, +] + +[[package]] +name = "torchvision" +version = "0.15.0" +source = { registry = "https://download.pytorch.org/whl/cu118" } +resolution-markers = [ + "platform_machine == 'aarch64' and sys_platform == 'linux'", +] +dependencies = [ + { name = "numpy", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "pillow", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "requests", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine == 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine != 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/torchvision-0.15.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:76035603bd2bfc9811c732bdb87e9b85298222ed9b5261a12d19ecd9ffa8ebc2" }, +] + +[[package]] +name = "torchvision" +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "sys_platform == 'linux'", + "sys_platform != 'linux'", +] +dependencies = [ + { name = "numpy", marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "pillow", marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "requests", marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0", source = { registry = "https://pypi.org/simple" }, marker = "(extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (extra != 'extra-4-cara-cpu' and extra != 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/7e/b5ac1d89ab3dfad492f60abb0c26579c52571e33a0d5bbc06f2bcb14b9a9/torchvision-0.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cc9b09044d9c11e67373e9104fef5859a3808d29c557bcb888c8e64603c3bad8", size = 1544694, upload-time = "2023-03-15T16:07:23.451Z" }, + { url = "https://files.pythonhosted.org/packages/ac/87/f0b1ee255c84923179c8dc57d0220224ff32d5ff55dae20525fcc6ab7897/torchvision-0.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc53aa30ef18841e4dcbc826ee66d4a9b8baf805e41bfeabdf581868a9f7d8a", size = 1446194, upload-time = "2023-03-15T16:07:21.344Z" }, + { url = "https://files.pythonhosted.org/packages/ba/26/ff4bf089f2de836fdea923e2f54859fb3910c951c7106a9688edf96f3b5a/torchvision-0.15.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cb9df39b8ae75cc09f2718182bf9a9268ee36c2ef292cff0d0ce91261c2b3529", size = 33756257, upload-time = "2023-03-15T16:06:57.513Z" }, + { url = "https://files.pythonhosted.org/packages/cf/04/9c07ac5dce8fe216bc730b68e37480b3d58676a57d55cc99228fd6c1c35f/torchvision-0.15.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:76035603bd2bfc9811c732bdb87e9b85298222ed9b5261a12d19ecd9ffa8ebc2", size = 13681938, upload-time = "2023-03-15T16:07:01.883Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ca/7f14521aca52b01527bcda66ce61c51c88eaf4cf8c4a88bfe8c7d500b5ce/torchvision-0.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:87ed73c3eb7c00434ecd9fe3a342a329d3b83d27c4cafc03bf52bf4362d1b8eb", size = 1195675, upload-time = "2023-03-15T16:07:25.241Z" }, +] + +[[package]] +name = "torchvision" +version = "0.15.0+cpu" +source = { registry = "https://download.pytorch.org/whl/cpu" } +resolution-markers = [ + "platform_machine != 'aarch64' and sys_platform == 'linux'", + "sys_platform != 'darwin' and sys_platform != 'linux'", +] +dependencies = [ + { name = "numpy", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "pillow", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "requests", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform != 'darwin' and sys_platform != 'linux' and extra == 'extra-4-cara-cpu') or (sys_platform == 'darwin' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform == 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/cpu/torchvision-0.15.0%2Bcpu-cp38-cp38-linux_x86_64.whl", hash = "sha256:c15340f67f05633e0368dfcd1518e604165a0bfdbeccbdcf884e0a6772dceb90" }, + { url = "https://download.pytorch.org/whl/cpu/torchvision-0.15.0%2Bcpu-cp38-cp38-win_amd64.whl", hash = "sha256:2ec4921d8575b935aca52e4dc5281bfde7dad1674f41e2e97beb989408e4ad52" }, +] + +[[package]] +name = "torchvision" +version = "0.15.0+cu118" +source = { registry = "https://download.pytorch.org/whl/cu118" } +resolution-markers = [ + "platform_machine != 'aarch64' and sys_platform == 'linux'", + "sys_platform != 'linux'", +] +dependencies = [ + { name = "numpy", marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "pillow", marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "requests", marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cu118') or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://download.pytorch.org/whl/cu118/torchvision-0.15.0%2Bcu118-cp38-cp38-linux_x86_64.whl", hash = "sha256:03a67002cdae2f4cc8316358f0627d35e8aa1d61be4595e7c9fbea3ac16b7c00" }, + { url = "https://download.pytorch.org/whl/cu118/torchvision-0.15.0%2Bcu118-cp38-cp38-win_amd64.whl", hash = "sha256:a43a77f457eb8ccdd006edffe0aaacbde063248981fcffcdfd8962730d581ce6" }, +] + +[[package]] +name = "tqdm" +version = "4.66.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/34/bef135b27fe1864993a5284ad001157ee9b5538e859ac90f5b0e8cc8c9ec/tqdm-4.66.6.tar.gz", hash = "sha256:4bdd694238bef1485ce839d67967ab50af8f9272aab687c0d7702a01da0be090", size = 169533, upload-time = "2024-10-28T12:49:58.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/73/02342de9c2d20922115f787e101527b831c0cffd2105c946c4a4826bcfd4/tqdm-4.66.6-py3-none-any.whl", hash = "sha256:223e8b5359c2efc4b30555531f09e9f2f3589bcd7fdd389271191031b49b7a63", size = 78326, upload-time = "2024-10-28T12:49:56.931Z" }, +] + +[[package]] +name = "triton" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cmake", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine == 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "filelock", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine == 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "lit", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine == 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "torch", version = "2.0.0+cu118", source = { registry = "https://download.pytorch.org/whl/cu118" }, marker = "(platform_machine != 'aarch64' and sys_platform == 'linux' and extra == 'extra-4-cara-cu118') or (platform_machine == 'aarch64' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118') or (sys_platform != 'linux' and extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/4b/28142a3c70621cb3398ac626c276268ca87af50a3fa43667a834fa5d13bf/triton-2.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9d4978298b74fcf59a75fe71e535c092b023088933b2f1df933ec32615e4beef", size = 63232347, upload-time = "2023-03-20T17:32:40.846Z" }, + { url = "https://files.pythonhosted.org/packages/72/90/91059851af9ffbceb40eeabb2e2522cd8b184b005f4b4ba44f6cba081ef0/triton-2.0.0-1-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aca3303629cd3136375b82cb9921727f804e47ebee27b2677fef23005c3851a", size = 63158993, upload-time = "2023-03-20T17:32:57.186Z" }, +] + +[[package]] +name = "types-pyyaml" +version = "6.0.12.20241230" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/f9/4d566925bcf9396136c0a2e5dc7e230ff08d86fa011a69888dd184469d80/types_pyyaml-6.0.12.20241230.tar.gz", hash = "sha256:7f07622dbd34bb9c8b264fe860a17e0efcad00d50b5f27e93984909d9363498c", size = 17078, upload-time = "2024-12-30T02:44:38.168Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/c1/48474fbead512b70ccdb4f81ba5eb4a58f69d100ba19f17c92c0c4f50ae6/types_PyYAML-6.0.12.20241230-py3-none-any.whl", hash = "sha256:fa4d32565219b68e6dee5f67534c722e53c00d1cfc09c435ef04d7353e1e96e6", size = 20029, upload-time = "2024-12-30T02:44:36.162Z" }, +] + +[[package]] +name = "types-requests" +version = "2.32.0.20241016" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fa/3c/4f2a430c01a22abd49a583b6b944173e39e7d01b688190a5618bd59a2e22/types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95", size = 18065, upload-time = "2024-10-16T02:46:10.818Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/01/485b3026ff90e5190b5e24f1711522e06c79f4a56c8f4b95848ac072e20f/types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747", size = 15836, upload-time = "2024-10-16T02:46:09.734Z" }, +] + +[[package]] +name = "types-simplejson" +version = "3.19.0.20241221" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/f0/3d4dd216dc527a52ab564cbecd2fd8b3c8b96722348745f8f5cb9ab59801/types_simplejson-3.19.0.20241221.tar.gz", hash = "sha256:114af9db0f49ad15755d2b6ad8e6fd04b5a493815e2fc1e011729d4650defc70", size = 9688, upload-time = "2024-12-21T02:40:56.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/2f/4a5fcab9225bec1d075d543d00f005fe83685ddc1bd395ab1b382b9553db/types_simplejson-3.19.0.20241221-py3-none-any.whl", hash = "sha256:179dfaef8c357156c781fa47cfdfcd953a7953fc375dfe9ab19a20054a828980", size = 10285, upload-time = "2024-12-21T02:40:55.706Z" }, +] + +[[package]] +name = "types-tabulate" +version = "0.9.0.20241207" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/43/16030404a327e4ff8c692f2273854019ed36718667b2993609dc37d14dd4/types_tabulate-0.9.0.20241207.tar.gz", hash = "sha256:ac1ac174750c0a385dfd248edc6279fa328aaf4ea317915ab879a2ec47833230", size = 8195, upload-time = "2024-12-07T02:54:42.554Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/86/a9ebfd509cbe74471106dffed320e208c72537f9aeb0a55eaa6b1b5e4d17/types_tabulate-0.9.0.20241207-py3-none-any.whl", hash = "sha256:b8dad1343c2a8ba5861c5441370c3e35908edd234ff036d4298708a1d4cf8a85", size = 8307, upload-time = "2024-12-07T02:54:41.031Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" }, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677, upload-time = "2024-09-12T10:52:18.401Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338, upload-time = "2024-09-12T10:52:16.589Z" }, +] + +[[package]] +name = "virtualenv" +version = "20.31.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/56/2c/444f465fb2c65f40c3a104fd0c495184c4f2336d65baf398e3c75d72ea94/virtualenv-20.31.2.tar.gz", hash = "sha256:e10c0a9d02835e592521be48b332b6caee6887f332c111aa79a09b9e79efc2af", size = 6076316, upload-time = "2025-05-08T17:58:23.811Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/40/b1c265d4b2b62b58576588510fc4d1fe60a86319c8de99fd8e9fec617d2c/virtualenv-20.31.2-py3-none-any.whl", hash = "sha256:36efd0d9650ee985f0cad72065001e66d49a6f24eb44d98980f630686243cf11", size = 6057982, upload-time = "2025-05-08T17:58:21.15Z" }, +] + +[[package]] +name = "wandb" +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "eval-type-backport" }, + { name = "gitpython" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "protobuf" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sentry-sdk" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/09/c84264a219e20efd615e4d5d150cc7d359d57d51328d3fa94ee02d70ed9c/wandb-0.21.0.tar.gz", hash = "sha256:473e01ef200b59d780416062991effa7349a34e51425d4be5ff482af2dc39e02", size = 40085784, upload-time = "2025-07-02T00:24:15.516Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/dd/65eac086e1bc337bb5f0eed65ba1fe4a6dbc62c97f094e8e9df1ef83ffed/wandb-0.21.0-py3-none-any.whl", hash = "sha256:316e8cd4329738f7562f7369e6eabeeb28ef9d473203f7ead0d03e5dba01c90d", size = 6504284, upload-time = "2025-07-02T00:23:46.671Z" }, + { url = "https://files.pythonhosted.org/packages/17/a7/80556ce9097f59e10807aa68f4a9b29d736a90dca60852a9e2af1641baf8/wandb-0.21.0-py3-none-macosx_10_14_x86_64.whl", hash = "sha256:701d9cbdfcc8550a330c1b54a26f1585519180e0f19247867446593d34ace46b", size = 21717388, upload-time = "2025-07-02T00:23:49.348Z" }, + { url = "https://files.pythonhosted.org/packages/23/ae/660bc75aa37bd23409822ea5ed616177d94873172d34271693c80405c820/wandb-0.21.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:01689faa6b691df23ba2367e0a1ecf6e4d0be44474905840098eedd1fbcb8bdf", size = 21141465, upload-time = "2025-07-02T00:23:52.602Z" }, + { url = "https://files.pythonhosted.org/packages/23/ab/9861929530be56557c74002868c85d0d8ac57050cc21863afe909ae3d46f/wandb-0.21.0-py3-none-macosx_11_0_x86_64.whl", hash = "sha256:55d3f42ddb7971d1699752dff2b85bcb5906ad098d18ab62846c82e9ce5a238d", size = 21793511, upload-time = "2025-07-02T00:23:55.447Z" }, + { url = "https://files.pythonhosted.org/packages/de/52/e5cad2eff6fbed1ac06f4a5b718457fa2fd437f84f5c8f0d31995a2ef046/wandb-0.21.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:893508f0c7da48917448daa5cd622c27ce7ce15119adaa861185034c2bd7b14c", size = 20704643, upload-time = "2025-07-02T00:23:58.255Z" }, + { url = "https://files.pythonhosted.org/packages/83/8f/6bed9358cc33767c877b221d4f565e1ddf00caf4bbbe54d2e3bbc932c6a7/wandb-0.21.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4e8245a8912247ddf7654f7b5330f583a6c56ab88fee65589158490d583c57d", size = 22243012, upload-time = "2025-07-02T00:24:01.423Z" }, + { url = "https://files.pythonhosted.org/packages/be/61/9048015412ea5ca916844af55add4fed7c21fe1ad70bb137951e70b550c5/wandb-0.21.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2e4c4f951e0d02755e315679bfdcb5bc38c1b02e2e5abc5432b91a91bb0cf246", size = 20716440, upload-time = "2025-07-02T00:24:04.198Z" }, + { url = "https://files.pythonhosted.org/packages/02/d9/fcd2273d8ec3f79323e40a031aba5d32d6fa9065702010eb428b5ffbab62/wandb-0.21.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:873749966eeac0069e0e742e6210641b6227d454fb1dae2cf5c437c6ed42d3ca", size = 22320652, upload-time = "2025-07-02T00:24:07.175Z" }, + { url = "https://files.pythonhosted.org/packages/80/68/b8308db6b9c3c96dcd03be17c019aee105e1d7dc1e74d70756cdfb9241c6/wandb-0.21.0-py3-none-win32.whl", hash = "sha256:9d3cccfba658fa011d6cab9045fa4f070a444885e8902ae863802549106a5dab", size = 21484296, upload-time = "2025-07-02T00:24:10.147Z" }, + { url = "https://files.pythonhosted.org/packages/cf/96/71cc033e8abd00e54465e68764709ed945e2da2d66d764f72f4660262b22/wandb-0.21.0-py3-none-win_amd64.whl", hash = "sha256:28a0b2dad09d7c7344ac62b0276be18a2492a5578e4d7c84937a3e1991edaac7", size = 21484301, upload-time = "2025-07-02T00:24:12.658Z" }, +] + +[[package]] +name = "werkzeug" +version = "3.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d4/f9/0ba83eaa0df9b9e9d1efeb2ea351d0677c37d41ee5d0f91e98423c7281c9/werkzeug-3.0.6.tar.gz", hash = "sha256:a8dd59d4de28ca70471a34cba79bed5f7ef2e036a76b3ab0835474246eb41f8d", size = 805170, upload-time = "2024-10-25T18:52:31.688Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/69/05837f91dfe42109203ffa3e488214ff86a6d68b2ed6c167da6cdc42349b/werkzeug-3.0.6-py3-none-any.whl", hash = "sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17", size = 227979, upload-time = "2024-10-25T18:52:30.129Z" }, +] + +[[package]] +name = "wheel" +version = "0.45.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545, upload-time = "2024-11-23T00:18:23.513Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494, upload-time = "2024-11-23T00:18:21.207Z" }, +] + +[[package]] +name = "zipp" +version = "3.20.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199, upload-time = "2024-09-13T13:44:16.101Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", size = 9200, upload-time = "2024-09-13T13:44:14.38Z" }, +] From c412cf37397088b02936734dc82c029c9fc5a3a9 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Sat, 19 Jul 2025 12:45:41 -0700 Subject: [PATCH 03/13] Complete cara tests --- .gitignore | 3 ++- pyproject.toml | 3 ++- tests/test_cara.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++ uv.lock | 49 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 tests/test_cara.py diff --git a/.gitignore b/.gitignore index 89bbc69..873271e 100644 --- a/.gitignore +++ b/.gitignore @@ -166,4 +166,5 @@ data/ *.pt vtab-1k/ -wandb/ \ No newline at end of file +wandb/ +.vscode/ \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index bf646cd..a6a5d9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,8 +87,9 @@ dev = [ "pep8-naming", "pre-commit", "pydocstyle", + "pytest>=8.3.5", "types-pyyaml", "types-requests", "types-simplejson", "types-tabulate", -] \ No newline at end of file +] diff --git a/tests/test_cara.py b/tests/test_cara.py new file mode 100644 index 0000000..5638daa --- /dev/null +++ b/tests/test_cara.py @@ -0,0 +1,57 @@ +import torch as th +import numpy as np +import random + +from src.cara.cara import cara +from timm.models import create_model + + +def _get_vit(): + return create_model( + "vit_base_patch16_224_in21k", + drop_path_rate=0.1 + ) + + +def _get_cara_config(): + random.seed(0) + th.manual_seed(0) + np.random.seed(0) + th.cuda.manual_seed_all(0) + th.backends.cudnn.deterministic = True + th.backends.cudnn.benchmark = False + return { + "model": _get_vit(), + "rank": 32, + "scale": 1.0, + "l_mu": 1.0, + "l_std": 0.0 + } + + +def test_vit_without_cara(): + vit = _get_vit() + assert (not hasattr(vit, "CP_A1")) and (not hasattr(vit, "CP_A2")) and (not hasattr(vit, "CP_A3")) and (not hasattr(vit, "CP_A4")) + assert (not hasattr(vit, "CP_P1")) and (not hasattr(vit, "CP_P2")) and (not hasattr(vit, "CP_P3")) + assert (not hasattr(vit, "CP_R1")) + assert (not hasattr(vit, "CP_R2")) + + +def test_vit_with_cara(): + vit = cara(_get_cara_config()) + assert (hasattr(vit, "CP_A1")) and (hasattr(vit, "CP_A2")) and (hasattr(vit, "CP_A3")) and (hasattr(vit, "CP_A4")) + assert (hasattr(vit, "CP_P1")) and (hasattr(vit, "CP_P2")) and (hasattr(vit, "CP_P3")) + assert (hasattr(vit, "CP_R1")) + assert (hasattr(vit, "CP_R2")) + + +def test_cara_zero_init(): + vit = cara(_get_cara_config()) + assert th.allclose(vit.CP_A2, th.zeros_like(vit.CP_A2)) + assert th.allclose(vit.CP_P2, th.zeros_like(vit.CP_P2)) + + +def test_cara_lambda_init(): + vit = cara(_get_cara_config()) + assert th.allclose(vit.CP_R1, th.ones_like(vit.CP_R1)) + assert th.allclose(vit.CP_R2, th.ones_like(vit.CP_R2)) diff --git a/uv.lock b/uv.lock index 743def1..634adf3 100644 --- a/uv.lock +++ b/uv.lock @@ -168,6 +168,7 @@ dev = [ { name = "pep8-naming" }, { name = "pre-commit" }, { name = "pydocstyle" }, + { name = "pytest" }, { name = "types-pyyaml" }, { name = "types-requests" }, { name = "types-simplejson" }, @@ -203,6 +204,7 @@ dev = [ { name = "pep8-naming" }, { name = "pre-commit" }, { name = "pydocstyle" }, + { name = "pytest", specifier = ">=8.3.5" }, { name = "types-pyyaml" }, { name = "types-requests" }, { name = "types-simplejson" }, @@ -364,6 +366,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a", size = 5830, upload-time = "2024-12-21T20:09:44.175Z" }, ] +[[package]] +name = "exceptiongroup" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, +] + [[package]] name = "filelock" version = "3.16.1" @@ -587,6 +601,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717", size = 36115, upload-time = "2024-09-09T17:03:13.39Z" }, ] +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + [[package]] name = "isort" version = "5.13.2" @@ -879,6 +902,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439, upload-time = "2024-09-17T19:06:49.212Z" }, ] +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, +] + [[package]] name = "pre-commit" version = "3.5.0" @@ -1033,6 +1065,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, ] +[[package]] +name = "pytest" +version = "8.3.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-4-cara-cpu' and extra == 'extra-4-cara-cu118')" }, + { name = "exceptiongroup" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "tomli" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" From 423f9af4394aac091eeaadf3f631acc06ffc5336 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Mon, 28 Jul 2025 10:50:02 +0200 Subject: [PATCH 04/13] Add new forward pass test --- tests/test_cara.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_cara.py b/tests/test_cara.py index 5638daa..59943f2 100644 --- a/tests/test_cara.py +++ b/tests/test_cara.py @@ -55,3 +55,10 @@ def test_cara_lambda_init(): vit = cara(_get_cara_config()) assert th.allclose(vit.CP_R1, th.ones_like(vit.CP_R1)) assert th.allclose(vit.CP_R2, th.ones_like(vit.CP_R2)) + + +def test_cara_forward(): + vit = _get_vit() + dummy_input = th.randn((2, 3, 224, 224)) + output = vit(dummy_input) + assert np.allclose(list(output.shape), (2, 21843)) \ No newline at end of file From a942c6a83458cbb36a7dbc86e010cc90816f74cd Mon Sep 17 00:00:00 2001 From: loki-veera Date: Mon, 28 Jul 2025 10:50:27 +0200 Subject: [PATCH 05/13] Link training script to CaRA --- image_classification/vit_cp.py | 246 ++------------------------------- 1 file changed, 10 insertions(+), 236 deletions(-) diff --git a/image_classification/vit_cp.py b/image_classification/vit_cp.py index b95f5ca..64387f1 100644 --- a/image_classification/vit_cp.py +++ b/image_classification/vit_cp.py @@ -1,5 +1,4 @@ import torch as th -from torch import nn from tqdm import tqdm import numpy as np from timm.models import create_model @@ -7,13 +6,12 @@ from avalanche.evaluation.metrics.accuracy import Accuracy from vtab import * from vtab_config import config -import timm import random import os import wandb from timm.scheduler import CosineLRScheduler -import tensorly as tl -tl.set_backend("pytorch") + +from src.cara.cara import cara best_acc = 0.0 @@ -25,7 +23,6 @@ def train(args, model, dl, tdl, opt, sched, epochs): global old_name old_name = None for epoch in (pbar:=tqdm(range(epochs))): - # for epoch in range(epochs): if log: logger.log({"epoch":epoch}) for batch in dl: @@ -56,7 +53,6 @@ def train(args, model, dl, tdl, opt, sched, epochs): pbar.set_description(f"e: {epoch}, l: {round(loss.item(), 7)}, a:{acc}") if sched is not None: sched.step(epoch) - # Add accuracy calculation here if epoch % 5 == 0 and epoch != 0 and epoch >= 50: sched = None acc = test(model, tdl)[1] @@ -68,8 +64,6 @@ def train(args, model, dl, tdl, opt, sched, epochs): th.save(vit.state_dict(), old_name) if log: logger.log({"val_acc": acc}) - # model.train() - # print(f"Epoch: {epoch}, Accuracy: {acc}") model = model.cpu() return model @@ -77,8 +71,6 @@ def train(args, model, dl, tdl, opt, sched, epochs): @th.no_grad() def test(model, dl): model.eval() - # acc = [] - # ex = [] acc = Accuracy() model = model.cuda() for batch in tqdm(dl): @@ -86,230 +78,7 @@ def test(model, dl): out = model(x).data acc.update(out.argmax(dim=1).view(-1), y, 1) return acc.result() - # out = th.argmax(out, dim=1) - # correct = (out == y).float() - # acc.extend(correct) - # ex.append(len(y)) - # ac = sum(acc) / sum(ex) - # return round(ac.cpu().item(), 4) - # Add accuracy calculation here - - -def split_weight(weight): - d1, d2 = weight.shape - if d1 != 3 * d2: - raise RuntimeError("Weight out dimension is not 3 times its input dimensions.") - d1 //= 3 - layer_weight = weight.reshape(3, d1, d2) - return layer_weight.unbind(0) - - -def attn_thunder_forward(factors, input_, dropout=None): - if dropout is None: - dropout = nn.Identity() - # F_1, F_2, F_3, F_4 = factors - B, N, C = input_.shape - heads = 12 - input_ = input_.reshape((B, N, heads, C//heads)) - # input_ = input_.unsqueeze(0) - preprocess = ( - lambda x: x.unsqueeze(0).unsqueeze(0).unsqueeze(0).permute((-1, 0, 1, 2, 3)) - ) - # F_1 = preprocess(F_1) - # F_2 = preprocess(F_2) - # F_3 = preprocess(F_3) - # F_4 = preprocess(F_4) - F_1, F_2, F_3, F_4 = map(preprocess, factors) - - inter_1 = input_.unsqueeze(0) @ F_4.swapaxes(-2, -1) - del F_4 - inter_2 = F_3 @ inter_1 - del F_3, inter_1 - inter_3 = inter_2 @ F_2 - del F_2, inter_2 - output = F_1.swapaxes(-2, -1) @ dropout(inter_3) - del F_1, inter_3 - output = th.sum(output, 0).permute((2, 0, 1, 3)) - K, B, N, C = output.shape - return output.reshape((K, B, N, heads, C//heads)).permute(0, 1, 3, 2, 4) - - -def mlp_thunder_forward(factors, input_, dropout = None): - if dropout is None: - dropout = nn.Identity() - P_1, P_2, P_3 = factors - B, N, C = input_.shape - input_ = input_.unsqueeze(0).unsqueeze(-2) - preprocess = ( - lambda x: x.unsqueeze(0).unsqueeze(0).unsqueeze(0).permute((-1, 0, 1, 2, 3)) - ) - P_1 = preprocess(P_1) - P_2 = preprocess(P_2) - P_3 = preprocess(P_3) - - inter_1 = input_ @ P_3.swapaxes(-2, -1) - del P_3 - inter_2 = inter_1 @ dropout(P_2) - del P_2, inter_1 - output = P_1.swapaxes(-2, -1) @ inter_2 - del P_1, inter_2 - R, B, N, e, k = output.shape - output = output.reshape((R, B, N, e*k)) - output = th.sum(output, dim=0) - return output - - -def mlp_down_forward(factors, input_, dropout=None): - if dropout is None: - dropout = nn.Identity() - P_1, P_2, P_3 = factors - B, N, C = input_.shape - x_ = input_.reshape(B, N, C//4, 4) - x_ = x_.unsqueeze(0) - preprocess = ( - lambda x: x.unsqueeze(0).unsqueeze(0).unsqueeze(0).permute((-1, 0, 1, 2, 3)) - ) - P_1 = preprocess(P_1) - P_2 = preprocess(P_2) - P_3 = preprocess(P_3) - inter_1 = x_ @ P_1.swapaxes(-2, -1) - del P_1 - inter_2 = dropout(P_2) @ inter_1 - del P_2, inter_1 - inter_2 = inter_2.squeeze(-1) - output = inter_2 @ P_3.squeeze(1) - del P_3, inter_2 - output = th.sum(output, dim=0) - return output - - -def cp_attn(self, x): - B, N, C = x.shape - qkv = self.qkv(x) - f1 = vit.CP_A1[self.attn_idx:self.attn_idx+3, :] - # # 4D Implementation - Memory expensive - # qkv_delta = attn_thunder_forward((f1, vit.CP_A2, vit.CP_A3, vit.CP_A4), x, self.dp) - # Convert 4D to 2D - tensor_attn = tl.cp_to_tensor((vit.CP_R1, (f1, vit.CP_A2, vit.CP_A3, vit.CP_A4))) - K, E, H, D = tensor_attn.shape - tensor_attn = tensor_attn.reshape((K, E, H*D))#.swapaxes(-2, -1) - qkv_delta = th.einsum("bnd, kde->kbne", x, self.dp(tensor_attn)) - qkv_delta = qkv_delta.reshape(3, B, N, self.num_heads, C//self.num_heads).permute( - 0, 1, 3, 2, 4 - ) - # tensor_attn = tensor_attn.permute(1, 0, 2) - # tensor_attn = tensor_attn.reshape((tensor_attn.shape[0], -1)) - # qkv_delta = x @ self.dp(tensor_attn) - # qkv_delta = qkv_delta.reshape(B, N, 3, self.num_heads, C//self.num_heads).permute( - # 2, 0, 3, 1, 4 - # ) - qkv = qkv.reshape(B, N, 3, self.num_heads, C//self.num_heads).permute( - 2, 0, 3, 1, 4 - ) - qkv += qkv_delta * self.s - # q, k, v = qkv.unbind(0) - q, k, v = qkv[0], qkv[1], qkv[2] - attn = (q @ k.transpose(-2, -1)) * self.scale - attn = attn.softmax(dim=-1) - attn = self.attn_drop(attn) - - x = (attn@v).transpose(1, 2).reshape(B, N, C) - - proj = self.proj(x) - p1 = vit.CP_P1[self.idx:self.idx+1, :] - # proj_delta = mlp_thunder_forward((p1, vit.CP_P2, vit.CP_P3), x, self.dp) - tensor_proj = tl.cp_to_tensor((vit.CP_R2, (p1, vit.CP_P2, vit.CP_P3))) - AA, AB, AC = tensor_proj.shape - tensor_proj = tensor_proj.reshape((AA*AB, AC)) - proj_delta = x@self.dp(tensor_proj.T) + vit.CP_bias1 - proj += proj_delta * self.s - x = self.proj_drop(proj) - return x - - -def cp_mlp(self, x): - p1_up = vit.CP_P1[self.idx:self.idx+4, :] - p1_down = vit.CP_P1[self.idx+4: self.idx+8, :] - - up = self.fc1(x) - # up_delta = mlp_thunder_forward((p1_up, vit.CP_P2, vit.CP_P3), x, self.dp) - tensor_up = tl.cp_to_tensor((vit.CP_R2, (p1_up, vit.CP_P2, vit.CP_P3))) - AA, AB, AC = tensor_up.shape - tensor_up = tensor_up.reshape((AA*AB, AC)) - up_delta = x@self.dp(tensor_up.T) + vit.CP_bias2 - up += up_delta * self.s - - x = self.act(up) - x = self.drop(x) - - down = self.fc2(x) - # down_delta = mlp_down_forward((p1_down, vit.CP_P2, vit.CP_P3), x, self.dp) - tensor_down = tl.cp_to_tensor((vit.CP_R2, (p1_down, vit.CP_P2, vit.CP_P3))) - tensor_down = tensor_down.reshape((AA*AB, AC)) - down_delta = x@self.dp(tensor_down) + vit.CP_bias3 - down += down_delta * self.s - x = self.drop(down) - return x - - -def set_CP(model, dim, s, l_mu, l_std): - if type(model) == timm.models.vision_transformer.VisionTransformer: - model.CP_A1 = nn.Parameter(th.empty([36, dim]), requires_grad=True) - model.CP_A2 = nn.Parameter(th.empty([768, dim]), requires_grad=True) - model.CP_A3 = nn.Parameter(th.empty([12, dim]), requires_grad=True) - model.CP_A4 = nn.Parameter(th.empty([768//12, dim]), requires_grad=True) - model.CP_P1 = nn.Parameter(th.empty([108, dim]), requires_grad=True) - model.CP_P2 = nn.Parameter(th.empty([768, dim]), requires_grad=True) - model.CP_P3 = nn.Parameter(th.empty([768, dim]), requires_grad=True) - model.CP_R1 = nn.Parameter(th.empty([dim], requires_grad=True)) - model.CP_R2 = nn.Parameter(th.empty([dim], requires_grad=True)) - - model.CP_bias1 = nn.Parameter(th.empty([768]), requires_grad=True) - model.CP_bias2 = nn.Parameter(th.empty([768*4]), requires_grad=True) - model.CP_bias3 = nn.Parameter(th.empty([768]), requires_grad=True) - - nn.init.xavier_normal_(model.CP_A1) - nn.init.zeros_(model.CP_A2) - nn.init.orthogonal_(model.CP_A3) - nn.init.orthogonal_(model.CP_A4) - nn.init.xavier_normal_(model.CP_P1) - nn.init.zeros_(model.CP_P2) - nn.init.orthogonal_(model.CP_P3) - - if l_std != 0.0: - nn.init.normal_(model.CP_R1, mean=l_mu, std=l_std) - nn.init.normal_(model.CP_R2, mean=l_mu, std=l_std) - elif l_mu == 1.0 and l_std == 0.0: - nn.init.ones_(model.CP_R1) - nn.init.ones_(model.CP_R2) - - nn.init.zeros_(model.CP_bias1) - nn.init.zeros_(model.CP_bias2) - nn.init.zeros_(model.CP_bias3) - model.idx = 0 - model.attn_idx = 0 - for child in model.children(): - if type(child) == timm.models.vision_transformer.Attention: - child.dp = nn.Dropout(0.1) - child.s = s - child.dim = dim - child.idx = vit.idx - child.attn_idx = vit.attn_idx - vit.idx += 1 - vit.attn_idx += 3 - bound_method = cp_attn.__get__(child, child.__class__) - setattr(child, "forward", bound_method) - elif type(child) == timm.models.layers.mlp.Mlp: - child.dim = dim - child.s = s - child.dp = nn.Dropout(0.1) - child.idx = vit.idx - vit.idx += 8 - bound_method = cp_mlp.__get__(child, child.__class__) - setattr(child, "forward", bound_method) - elif len(list(child.children())) != 0: - set_CP(child, dim, s, l_mu, l_std) def _parse_args(): parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) @@ -376,11 +145,16 @@ def main(sd = None): num_classes = get_classes_num(name) global vit vit = create_model(args.model, checkpoint_path="./ViT-B_16.npz", drop_path_rate=0.1) - # vit = th.nn.DataParallel(vit) - set_CP(vit, dim=args.dim, s=scale, l_mu=lambda_mean, l_std=lambda_std) + cara_config = { + "model": vit, + "rank": args.dim, + "scale": scale, + "l_mu": lambda_mean, + "l_std": lambda_std + } + vit = cara(cara_config) trainable = [] vit.reset_classifier(num_classes) - # vit.load_state_dict(th.load("./vit_caltech101_0.91915_seed_56.pt")) total_param = 0 for n, p in vit.named_parameters(): if "CP" in n or "head" in n: From 771b9a012c67e0d9e07b7f3abacb402b84e1dbf5 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Mon, 28 Jul 2025 10:50:47 +0200 Subject: [PATCH 06/13] Add wandb --- pyproject.toml | 1 + uv.lock | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index a6a5d9c..1be0a92 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,6 +11,7 @@ dependencies = [ "tensorly==0.8.1", "timm==0.4.12", "tqdm==4.66.6", + "wandb>=0.21.0", ] diff --git a/uv.lock b/uv.lock index 634adf3..abdacad 100644 --- a/uv.lock +++ b/uv.lock @@ -138,6 +138,7 @@ dependencies = [ { name = "tensorly" }, { name = "timm" }, { name = "tqdm" }, + { name = "wandb" }, ] [package.optional-dependencies] @@ -187,6 +188,7 @@ requires-dist = [ { name = "torchvision", marker = "extra == 'cpu'", specifier = "==0.15", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "cara", extra = "cpu" } }, { name = "torchvision", marker = "extra == 'cu118'", specifier = "==0.15", index = "https://download.pytorch.org/whl/cu118", conflict = { package = "cara", extra = "cu118" } }, { name = "tqdm", specifier = "==4.66.6" }, + { name = "wandb", specifier = ">=0.21.0" }, ] provides-extras = ["cpu", "cu118"] From 56fd325b77701d1571f8e22bb3161ecfd7775212 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Mon, 28 Jul 2025 13:33:26 +0200 Subject: [PATCH 07/13] Fix errors in training script --- image_classification/vit_cp.py | 28 +++++++++++++++++++++++----- image_classification/vtab.py | 4 ++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/image_classification/vit_cp.py b/image_classification/vit_cp.py index 64387f1..cf46430 100644 --- a/image_classification/vit_cp.py +++ b/image_classification/vit_cp.py @@ -8,6 +8,7 @@ from vtab_config import config import random import os +import sys import wandb from timm.scheduler import CosineLRScheduler @@ -53,9 +54,10 @@ def train(args, model, dl, tdl, opt, sched, epochs): pbar.set_description(f"e: {epoch}, l: {round(loss.item(), 7)}, a:{acc}") if sched is not None: sched.step(epoch) - if epoch % 5 == 0 and epoch != 0 and epoch >= 50: - sched = None - acc = test(model, tdl)[1] + if epoch % 10 == 0 and epoch != 0: + if epoch >= 50: + sched = None + acc = test(model, tdl) if acc > args.best_acc: args.best_acc = acc if old_name is not None: @@ -76,7 +78,7 @@ def test(model, dl): for batch in tqdm(dl): x, y = batch[0].cuda(), batch[1].cuda() out = model(x).data - acc.update(out.argmax(dim=1).view(-1), y, 1) + acc.update(out.argmax(dim=1).view(-1), y) return acc.result() @@ -104,6 +106,12 @@ def _parse_args(): "smallnorb_ele", "sun397", "svhn", "dsprites_ori"], help="Dataset to train" ) + parser.add_argument( + "--evaluate", + default=None, + type=str, + help="Evalute model only" + ) parser.add_argument('--model', type=str, default='vit_base_patch16_224_in21k') return parser.parse_args() @@ -153,8 +161,17 @@ def main(sd = None): "l_std": lambda_std } vit = cara(cara_config) + trainable = [] vit.reset_classifier(num_classes) + + if args.evaluate is not None: + print("Only evaluation") + vit.load_state_dict(th.load(args.evaluate)) + acc = test(vit, test_dl) + print(f"Accuracy: {acc}") + sys.exit(0) + total_param = 0 for n, p in vit.named_parameters(): if "CP" in n or "head" in n: @@ -171,7 +188,7 @@ def main(sd = None): vit = train(args, vit, train_dl, test_dl, optimizer, scheduler, epochs=100) print("\n\n Evaluating....") _, test_dl = get_data(name, evaluate=True) - acc = test(vit, test_dl)[1] + acc = test(vit, test_dl) print(acc) if acc > args.best_acc: args.best_acc = acc @@ -180,5 +197,6 @@ def main(sd = None): print(f"Accuracy: {args.best_acc}") + if __name__ == "__main__": main() diff --git a/image_classification/vtab.py b/image_classification/vtab.py index f6df353..b0043cb 100644 --- a/image_classification/vtab.py +++ b/image_classification/vtab.py @@ -74,7 +74,7 @@ def __len__(self): def get_data(name, evaluate=True, batch_size=64): - root = './vtab-1k/' + name + root = './data/vtab-1k/' + name print(f"Getting data from root: {root}") transform = transforms.Compose([ transforms.Resize((224, 224), interpolation=3), # Change to 224 for ViTB @@ -104,4 +104,4 @@ def get_data(name, evaluate=True, batch_size=64): transform=transform), batch_size=256, shuffle=False, num_workers=4, pin_memory=True) - return train_loader, val_loader \ No newline at end of file + return train_loader, val_loader From 9a01bc76b7736d0423f631dcea30360ca2caee0a Mon Sep 17 00:00:00 2001 From: loki-veera Date: Mon, 28 Jul 2025 13:34:03 +0200 Subject: [PATCH 08/13] Add avalanche-lib-detection to requirements --- pyproject.toml | 2 +- uv.lock | 82 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1be0a92..35dca5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ description = "[ICML2025] Canonical Rank Adaptation" readme = "README.md" requires-python = "==3.8.20" dependencies = [ - "avalanche-lib==0.3.0", + "avalanche-lib[detection]==0.3.0", "matplotlib==3.7.5", "numpy==1.24.4", "tensorly==0.8.1", diff --git a/uv.lock b/uv.lock index abdacad..73eb2e4 100644 --- a/uv.lock +++ b/uv.lock @@ -83,6 +83,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/9a/eadedf8435b91cc6abcb2b4d4c10d98956dab52f05335a533e588e3920b1/avalanche_lib-0.3.0-py3-none-any.whl", hash = "sha256:4df2961c8c0cb277b4ef06836211c00703438d28160f6088e5ebe9b6083f8d28", size = 811041, upload-time = "2022-12-14T01:06:45.754Z" }, ] +[package.optional-dependencies] +detection = [ + { name = "lvis" }, + { name = "pycocotools" }, +] + [[package]] name = "beautifulsoup4" version = "4.13.4" @@ -132,7 +138,7 @@ name = "cara" version = "0.1.0" source = { virtual = "." } dependencies = [ - { name = "avalanche-lib" }, + { name = "avalanche-lib", extra = ["detection"] }, { name = "matplotlib" }, { name = "numpy" }, { name = "tensorly" }, @@ -178,7 +184,7 @@ dev = [ [package.metadata] requires-dist = [ - { name = "avalanche-lib", specifier = "==0.3.0" }, + { name = "avalanche-lib", extras = ["detection"], specifier = "==0.3.0" }, { name = "matplotlib", specifier = "==3.7.5" }, { name = "numpy", specifier = "==1.24.4" }, { name = "tensorly", specifier = "==0.8.1" }, @@ -332,6 +338,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] +[[package]] +name = "cython" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/40/7b17cd866158238db704965da1b5849af261dbad393ea3ac966f934b2d39/cython-3.1.2.tar.gz", hash = "sha256:6bbf7a953fa6762dfecdec015e3b054ba51c0121a45ad851fa130f63f5331381", size = 3184825, upload-time = "2025-06-09T07:08:48.465Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/28/c77e08e0b97a90f1cf93de7d3a2338616074fe5f8f77bc20f2d85498995d/cython-3.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dbc1f225cb9f9be7a025589463507e10bb2d76a3258f8d308e0e2d0b966c556e", size = 3089231, upload-time = "2025-06-09T07:10:35.789Z" }, + { url = "https://files.pythonhosted.org/packages/31/b4/39e2b4cf08f368a4f0c78397807bbdf9497230ea7c1ceae55d058b775bd8/cython-3.1.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c1661c1701c96e1866f839e238570c96a97535a81da76a26f45f99ede18b3897", size = 2949656, upload-time = "2025-06-09T07:10:37.903Z" }, + { url = "https://files.pythonhosted.org/packages/88/53/2debb403f3650896e0f5ba4cfa3f2c781881b133fd9aba63aa2588a0a84e/cython-3.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955bc6032d89ce380458266e65dcf5ae0ed1e7c03a7a4457e3e4773e90ba7373", size = 3150254, upload-time = "2025-06-09T07:10:40.521Z" }, + { url = "https://files.pythonhosted.org/packages/c9/64/1ad051720a3c7897edb2673eef9d8a478e998f44c285ab5b9ed30a2fe3a1/cython-3.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b58e859889dd0fc6c3a990445b930f692948b28328bb4f3ed84b51028b7e183", size = 3251858, upload-time = "2025-06-09T07:10:42.84Z" }, + { url = "https://files.pythonhosted.org/packages/50/cd/29b9763b9e093a87c54dbc36af134eb06c782b14b26f99e3e6abdfabdc30/cython-3.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:992a6504aa3eed50dd1fc3d1fa998928b08c1188130bd526e177b6d7f3383ec4", size = 3347027, upload-time = "2025-06-09T07:10:44.983Z" }, + { url = "https://files.pythonhosted.org/packages/94/a2/ee4a09b8652883e9e1d9f6954cb905c37412f294017ab6998f6a0742f1fe/cython-3.1.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f3d03077938b02ec47a56aa156da7bfc2379193738397d4e88086db5b0a374e0", size = 3205297, upload-time = "2025-06-09T07:10:47.782Z" }, + { url = "https://files.pythonhosted.org/packages/5e/24/071240e32e025f2d85418728a980c18051de721c249b9351450d5270cc58/cython-3.1.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:b7e1d3c383a5f4ca5319248b9cb1b16a04fb36e153d651e558897171b7dbabb9", size = 3435498, upload-time = "2025-06-09T07:10:50.076Z" }, + { url = "https://files.pythonhosted.org/packages/27/51/96f786beaa3e0d5ea5e9169215998d895637566cd466a31b0222ad204ff2/cython-3.1.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:58d4d45e40cadf4f602d96b7016cf24ccfe4d954c61fa30b79813db8ccb7818f", size = 3345928, upload-time = "2025-06-09T07:10:52.771Z" }, + { url = "https://files.pythonhosted.org/packages/fd/42/afabdcbd7132c5dd6cdebeecbc014bbc066aa4c15063e169df2a037e6dac/cython-3.1.2-cp38-cp38-win32.whl", hash = "sha256:919ff38a93f7c21829a519693b336979feb41a0f7ca35969402d7e211706100e", size = 2510356, upload-time = "2025-06-09T07:10:55.274Z" }, + { url = "https://files.pythonhosted.org/packages/5b/a0/eb9f7493a0ee09b39e50d2c57fa440cb2128f7e8ff7f4979e42d58eab39a/cython-3.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:aca994519645ba8fb5e99c0f9d4be28d61435775552aaf893a158c583cd218a5", size = 2698667, upload-time = "2025-06-09T07:10:57.242Z" }, + { url = "https://files.pythonhosted.org/packages/25/d6/ef8557d5e75cc57d55df579af4976935ee111a85bbee4a5b72354e257066/cython-3.1.2-py3-none-any.whl", hash = "sha256:d23fd7ffd7457205f08571a42b108a3cf993e83a59fe4d72b42e6fc592cf2639", size = 1224753, upload-time = "2025-06-09T07:08:44.849Z" }, +] + [[package]] name = "darglint" version = "1.8.1" @@ -694,6 +719,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/06/b36f150fa7c5bcc96a31a4d19a20fddbd1d965b6f02510b57a3bb8d4b930/lit-18.1.8-py3-none-any.whl", hash = "sha256:a873ff7acd76e746368da32eb7355625e2e55a2baaab884c9cc130f2ee0300f7", size = 96365, upload-time = "2024-06-25T14:33:12.101Z" }, ] +[[package]] +name = "lvis" +version = "0.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cycler" }, + { name = "cython" }, + { name = "kiwisolver" }, + { name = "matplotlib" }, + { name = "numpy" }, + { name = "opencv-python" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/fe/c18531099e7538bd6a53de8b2f8e900a5cf6a82d0c603325031a4122da5a/lvis-0.5.3.tar.gz", hash = "sha256:55aeeb84174abea2ed0d6985a8e93aa9bdbb60c61c6db130c8269a275ef61a6e", size = 12084, upload-time = "2020-06-18T01:34:01.582Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/b6/1992240ab48310b5360bfdd1d53163f43bb97d90dc5dc723c67d41c38e78/lvis-0.5.3-py3-none-any.whl", hash = "sha256:4f07153330df342b3161fafb46641ce7c02864113a8ddf0d6ffab6b02407bef0", size = 14024, upload-time = "2020-06-18T01:34:00.332Z" }, +] + [[package]] name = "markdown" version = "3.7" @@ -847,6 +892,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, ] +[[package]] +name = "opencv-python" +version = "4.12.0.88" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/71/25c98e634b6bdeca4727c7f6d6927b056080668c5008ad3c8fc9e7f8f6ec/opencv-python-4.12.0.88.tar.gz", hash = "sha256:8b738389cede219405f6f3880b851efa3415ccd674752219377353f017d2994d", size = 95373294, upload-time = "2025-07-07T09:20:52.389Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/68/3da40142e7c21e9b1d4e7ddd6c58738feb013203e6e4b803d62cdd9eb96b/opencv_python-4.12.0.88-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:f9a1f08883257b95a5764bf517a32d75aec325319c8ed0f89739a57fae9e92a5", size = 37877727, upload-time = "2025-07-07T09:13:31.47Z" }, + { url = "https://files.pythonhosted.org/packages/33/7c/042abe49f58d6ee7e1028eefc3334d98ca69b030e3b567fe245a2b28ea6f/opencv_python-4.12.0.88-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:812eb116ad2b4de43ee116fcd8991c3a687f099ada0b04e68f64899c09448e81", size = 57326471, upload-time = "2025-07-07T09:13:41.26Z" }, + { url = "https://files.pythonhosted.org/packages/62/3a/440bd64736cf8116f01f3b7f9f2e111afb2e02beb2ccc08a6458114a6b5d/opencv_python-4.12.0.88-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:51fd981c7df6af3e8f70b1556696b05224c4e6b6777bdd2a46b3d4fb09de1a92", size = 45887139, upload-time = "2025-07-07T09:13:50.761Z" }, + { url = "https://files.pythonhosted.org/packages/68/1f/795e7f4aa2eacc59afa4fb61a2e35e510d06414dd5a802b51a012d691b37/opencv_python-4.12.0.88-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:092c16da4c5a163a818f120c22c5e4a2f96e0db4f24e659c701f1fe629a690f9", size = 67041680, upload-time = "2025-07-07T09:14:01.995Z" }, + { url = "https://files.pythonhosted.org/packages/02/96/213fea371d3cb2f1d537612a105792aa0a6659fb2665b22cad709a75bd94/opencv_python-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:ff554d3f725b39878ac6a2e1fa232ec509c36130927afc18a1719ebf4fbf4357", size = 30284131, upload-time = "2025-07-07T09:14:08.819Z" }, + { url = "https://files.pythonhosted.org/packages/fa/80/eb88edc2e2b11cd2dd2e56f1c80b5784d11d6e6b7f04a1145df64df40065/opencv_python-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:d98edb20aa932fd8ebd276a72627dad9dc097695b3d435a4257557bbb49a79d2", size = 39000307, upload-time = "2025-07-07T09:14:16.641Z" }, +] + [[package]] name = "packaging" version = "25.0" @@ -981,6 +1043,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] +[[package]] +name = "pycocotools" +version = "2.0.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e3/0a/f2c7565edb94530fa9205779a537df50bf315b928de095a0e3aa7fbdb366/pycocotools-2.0.7.tar.gz", hash = "sha256:da8b7815196eebf0adabf67fcc459126cbc6498bbc6ab1fd144c371465d86879", size = 24965, upload-time = "2023-08-14T10:00:24.856Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/ad/815326ed4455ecf17a72e6145f57a81b5047aed0bde37a95fa34398a51cc/pycocotools-2.0.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6469089b9b36a1f645dc9ee830f29d261e99b4b3be73cb260688fd8b6d02760c", size = 168823, upload-time = "2023-08-14T10:00:14.841Z" }, + { url = "https://files.pythonhosted.org/packages/c1/82/28716322af53339d4651aed913fa80a4124475529f3f79db22019ea9fb30/pycocotools-2.0.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dbc429018149dc34e206ea32ee6297ff30b55a8615a3f7f4c6e3842f9df73db", size = 424586, upload-time = "2023-08-14T10:00:15.975Z" }, + { url = "https://files.pythonhosted.org/packages/6c/11/6cb76ebc71388ac17691bc3da76276d1642af30bf9097de9bb5f64c92cfa/pycocotools-2.0.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66864bec8b30d47faa946bb55c8e8d6b7acb9fba0c17ff6aaa37abd78cda962a", size = 439537, upload-time = "2023-08-14T10:00:17.163Z" }, + { url = "https://files.pythonhosted.org/packages/85/1a/f3f95a5c994be2b554f370ac314b034d43d82c69be3fd40fabed5cfd5347/pycocotools-2.0.7-cp38-cp38-win_amd64.whl", hash = "sha256:625388f52e543f6f798f75f1ec125fe519580f22e72ccbd75eee0355ce336e18", size = 85266, upload-time = "2023-08-14T10:00:18.274Z" }, +] + [[package]] name = "pycodestyle" version = "2.12.1" From f0d645bbffe93fc3a489f8ed735d7de0142b9d72 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Mon, 28 Jul 2025 13:37:22 +0200 Subject: [PATCH 09/13] Update with rst file --- README.md | 13 ------------- README.rst | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 13 deletions(-) delete mode 100644 README.md create mode 100644 README.rst diff --git a/README.md b/README.md deleted file mode 100644 index 4c28b35..0000000 --- a/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Canonical Decomposition and Approximation -Perform finetuning using Canonical Polyadic Decomposition - -## Image Classification -We use VisionTransformer-B/16 evaluated on VTAB-1k datasets. -Please refer to ```image_classification``` folder for the experiments. - -## Commonsense Reasoning -We use LLAMA-7B evaluated on eight commonsense reasoning tasks. -Please refer to ```commonsense_reasoning``` folder for the experiments. - -## Image/Video-Text Understanding -We plan use VL-BART evaluated on variety of datasets for Image and video text understanding. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..1f9efab --- /dev/null +++ b/README.rst @@ -0,0 +1,41 @@ +Canonical Rank Approximation (CaRA): An Efficient Fine-Tuning Strategy for Vision Transformers +********************************************************************************************** + +`Lokesh Veeramacheneni `__\ :sup:`1`, `Moritz +Wolter `__\ :sup:`1`, `Hilde +Kuehne `__\ :sup:`2`, and `Juergen +Gall `__\ :sup:`1,3` + +| 1. *University of Bonn* +| 2. *University of Tübingen, MIT-IBM Watson AI Lab* +| 3. *Lamarr Institute for Machine Learning and Artificial Intelligence* +| + + +|License| |Arxiv| |Project| + +**Keywords:** CaRA, Canonical Polyadic Decomposition, CPD, Tensor methods, ViT, LoRA + +**Abstract:** Modern methods for fine-tuning a Vision Transformer (ViT) like Low-Rank Adaptation (LoRA) and its variants demonstrate impressive performance. However, these methods ignore the high-dimensional nature of Multi-Head Attention (MHA) weight tensors. To address this limitation, we propose Canonical Rank Adaptation (CaRA). CaRA leverages tensor mathematics, first by tensorising the transformer into two different tensors; one for projection layers in MHA and the other for feed-forward layers. Second, the tensorised formulation is fine-tuned using the low-rank adaptation in Canonical-Polyadic Decomposition (CPD) form. Employing CaRA efficiently minimizes the number of trainable parameters. Experimentally, CaRA outperforms existing Parameter-Efficient Fine-Tuning (PEFT) methods in visual classification benchmarks such as Visual Task Adaptation Benchmark (VTAB)-1k and Fine-Grained Visual Categorization (FGVC). + + +Note +**** +We are commited to providing thoroughly tested and well-packaged code. +The code will be soon released once the process is completed. + + +Acknowledgments +=============== +The code is built on the implementation of `FacT `__. Thanks to `Zahra Ganji `__ for reimplementing VeRA baseline. + + + +.. |License| image:: https://img.shields.io/badge/License-Apache_2.0-blue.svg + :target: https://opensource.org/licenses/Apache-2.0 +.. |Project| image:: https://img.shields.io/badge/Project-Website-blue + :target: https://lokiv.dev/cara/ + :alt: Project Page +.. |Arxiv| image:: https://img.shields.io/badge/OpenReview-Paper-blue + :target: https://openreview.net/pdf?id=vexHifrbJg + :alt: Paper \ No newline at end of file From e86b6a56e1bbeed591778b3197e9b6a18f1a2e77 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Mon, 28 Jul 2025 13:40:07 +0200 Subject: [PATCH 10/13] add tensorisation image --- images/tensorisation.jpg | Bin 0 -> 191056 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/tensorisation.jpg diff --git a/images/tensorisation.jpg b/images/tensorisation.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf01c5d699aef8c7a426a0897fb77d0632a0372c GIT binary patch literal 191056 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

xqvqIZV0BWINna*;g){93!EPdtH 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ê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 B`M&@F literal 0 HcmV?d00001 From 70f26455269146994b86b86ce81a6115c833b836 Mon Sep 17 00:00:00 2001 From: Lokesh Veeramacheneni Date: Mon, 28 Jul 2025 13:59:27 +0200 Subject: [PATCH 11/13] Update README.rst --- README.rst | 60 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 1f9efab..f069cd5 100644 --- a/README.rst +++ b/README.rst @@ -19,10 +19,60 @@ Gall `__\ :sup:`1,3` **Abstract:** Modern methods for fine-tuning a Vision Transformer (ViT) like Low-Rank Adaptation (LoRA) and its variants demonstrate impressive performance. However, these methods ignore the high-dimensional nature of Multi-Head Attention (MHA) weight tensors. To address this limitation, we propose Canonical Rank Adaptation (CaRA). CaRA leverages tensor mathematics, first by tensorising the transformer into two different tensors; one for projection layers in MHA and the other for feed-forward layers. Second, the tensorised formulation is fine-tuned using the low-rank adaptation in Canonical-Polyadic Decomposition (CPD) form. Employing CaRA efficiently minimizes the number of trainable parameters. Experimentally, CaRA outperforms existing Parameter-Efficient Fine-Tuning (PEFT) methods in visual classification benchmarks such as Visual Task Adaptation Benchmark (VTAB)-1k and Fine-Grained Visual Categorization (FGVC). -Note -**** -We are commited to providing thoroughly tested and well-packaged code. -The code will be soon released once the process is completed. +.. image:: https://raw.githubusercontent.com/BonnBytes/CaRA/refs/heads/dev/images/tensorisation.jpg + :width: 100% + :alt: Alternative text + + +Installation +============ + +Use `UV `_ to install the requirements + +For CPU based pytorch + +.. code:: bash + + uv sync --extra cpu + +For CUDA based pytorch + +.. code:: bash + + uv sync --extra cu118 + + +Datasets +======= + +In the case of VTAB-1k benchmark, refer to the dataset download instructions from `NOAH `_. We download the datasets for FGVC benchmark from their respective sources. + +Note: Create a ``data`` folder in the root and place the datasets inside this folder. + + +Pretrained models +================= +Please refer to the download links provided in the paper. + + +Training +======== +For fine-tuning ViT use the following command. + +.. code:: bash + + export PYTHONPATH=. + python image_classification/vit_cp.py --dataset= --dim= + + +Evaluation +========== +We provide the link for fine-tuned models for each dataset in VTAB-1k benchmark `here `_. To reproduce results from the paper, download the model and execute the following command + +.. code:: bash + + export PYTHONPATH=. + python image_classification/vit_cp.py --dataset= --dim= --evaluate= Acknowledgments @@ -38,4 +88,4 @@ The code is built on the implementation of `FacT Date: Mon, 28 Jul 2025 14:31:59 +0200 Subject: [PATCH 12/13] update flake8 and format --- .flake8 | 45 +++++++++++++ .github/workflows/tests.yml | 33 +++++++++ .pre-commit-config.yaml | 33 +++++++++ Makefile | 24 +++++++ src/cara/__init__.py | 2 +- src/cara/cara.py | 130 +++++++++++++++++++++++++----------- tests/__init__.py | 2 +- tests/test_cara.py | 76 +++++++++++++++------ 8 files changed, 283 insertions(+), 62 deletions(-) create mode 100644 .flake8 create mode 100644 .pre-commit-config.yaml create mode 100644 Makefile diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..d310bf5 --- /dev/null +++ b/.flake8 @@ -0,0 +1,45 @@ +######################### +# Flake8 Configuration # +# (.flake8) # +######################### +[flake8] +ignore = + # asserts are ok when testing. + S101 + # pickle + S301 + # pickle + S403 + S404 + S603 + # Line break before binary operator (flake8 is wrong) + W503 + # Ignore the spaces black puts before columns. + E203 + # allow path extensions for testing. + E402 + DAR101 + DAR201 + # flake and pylance disagree on linebreaks in strings. + N400 + N806 +exclude = + .tox, + .git, + __pycache__, + docs/source/conf.py, + build, + dist, + tests/fixtures/*, + *.pyc, + *.bib, + *.egg-info, + .cache, + .eggs, + data. +max-line-length = 120 +max-complexity = 20 +import-order-style = pycharm +application-import-names = + seleqt + tests \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e69de29..176c10b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -0,0 +1,33 @@ +name: Tests +on: [ push, pull_request ] +jobs: + tests: + name: Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v3 + - name: Set up Python 3.8.20 + run: uv python install 3.8.20 + - name: Install dependencies (CPU only) + run: uv sync --extra cpu --no-dev + - name: Test with pytest + run: uv run pytest + + lint: + name: Lint + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.8.20"] + steps: + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v3 + - name: Set up Python ${{ matrix.python-version }} + run: uv python install ${{ matrix.python-version }} + - name: Install dependencies + run: uv tool install flake8 + - name: Run flake8 + run: uv tool run flake8 src/ tests/ \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..6b9f164 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,33 @@ +repos: + - repo: local + hooks: + - id: isort + name: isort + entry: uv run isort + language: system + args: ["--profile", "black"] + files: ^(src/|tests/) + types: [python] + + - id: black + name: black + entry: uv run black + language: system + args: ["--target-version", "py312"] + files: ^(src/|tests/) + types: [python] + + - id: flake8 + name: flake8 + entry: uv run flake8 + language: system + files: ^(src/|tests/)$ + types: [python] + + - id: pytest + name: pytest + entry: uv run pytest + language: system + files: ^(tests/)$ + pass_filenames: false + always_run: true \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ffe9592 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.PHONY: format check-format test lint check-all typing all + +# Format code +format: + uv run isort tests/ src/ + uv run black tests/ src/ + +# Check formatting (without making changes) +check-format: + uv run isort --check-only --diff tests/ src/ + uv run black --check --diff tests/ src/ + +lint: + uv run flake8 tests/ src/ + +test: + uv run pytest + +# Run all pre-commit checks manually +check-all: + uv run pre-commit run --all-files + +all: format test lint + @echo "All checks passed!" \ No newline at end of file diff --git a/src/cara/__init__.py b/src/cara/__init__.py index b74775f..faeaa1e 100644 --- a/src/cara/__init__.py +++ b/src/cara/__init__.py @@ -1 +1 @@ -"""src package init.""" \ No newline at end of file +"""src package init.""" diff --git a/src/cara/cara.py b/src/cara/cara.py index 9305a49..662d0a4 100644 --- a/src/cara/cara.py +++ b/src/cara/cara.py @@ -1,25 +1,42 @@ -from copy import deepcopy -from typing import Dict, Any +"""Implement CaRA.""" +from typing import Any, Dict + +import tensorly as tl +import timm import torch as th import torch.nn as nn -import timm -import tensorly as tl + tl.set_backend("pytorch") +global_model: th.nn.Module -def cp_attn(self, x): + +def cp_attn(self, x: th.Tensor) -> th.Tensor: + """Attention with CP parameters. + + Args: + x (th.Tensor): Input tensor. + + Returns: + th.Tensor: CaRA attention output. + """ B, N, C = x.shape qkv = self.qkv(x) - f1 = global_model.CP_A1[self.attn_idx:self.attn_idx+3, :] - tensor_attn = tl.cp_to_tensor((global_model.CP_R1, (f1, global_model.CP_A2, global_model.CP_A3, global_model.CP_A4))) + f1 = global_model.CP_A1[self.attn_idx : self.attn_idx + 3, :] + tensor_attn = tl.cp_to_tensor( + ( + global_model.CP_R1, + (f1, global_model.CP_A2, global_model.CP_A3, global_model.CP_A4), + ) + ) K, E, H, D = tensor_attn.shape - tensor_attn = tensor_attn.reshape((K, E, H*D)) + tensor_attn = tensor_attn.reshape((K, E, H * D)) qkv_delta = th.einsum("bnd, kde->kbne", x, self.dp(tensor_attn)) - qkv_delta = qkv_delta.reshape(3, B, N, self.num_heads, C//self.num_heads).permute( - 0, 1, 3, 2, 4 - ) - qkv = qkv.reshape(B, N, 3, self.num_heads, C//self.num_heads).permute( + qkv_delta = qkv_delta.reshape( + 3, B, N, self.num_heads, C // self.num_heads + ).permute(0, 1, 3, 2, 4) + qkv = qkv.reshape(B, N, 3, self.num_heads, C // self.num_heads).permute( 2, 0, 3, 1, 4 ) qkv += qkv_delta * self.s @@ -28,56 +45,83 @@ def cp_attn(self, x): attn = attn.softmax(dim=-1) attn = self.attn_drop(attn) - x = (attn@v).transpose(1, 2).reshape(B, N, C) + x = (attn @ v).transpose(1, 2).reshape(B, N, C) proj = self.proj(x) - p1 = global_model.CP_P1[self.idx:self.idx+1, :] - tensor_proj = tl.cp_to_tensor((global_model.CP_R2, (p1, global_model.CP_P2, global_model.CP_P3))) + p1 = global_model.CP_P1[self.idx : self.idx + 1, :] + tensor_proj = tl.cp_to_tensor( + (global_model.CP_R2, (p1, global_model.CP_P2, global_model.CP_P3)) + ) AA, AB, AC = tensor_proj.shape - tensor_proj = tensor_proj.reshape((AA*AB, AC)) - proj_delta = x@self.dp(tensor_proj.T) + global_model.CP_bias1 + tensor_proj = tensor_proj.reshape((AA * AB, AC)) + proj_delta = x @ self.dp(tensor_proj.T) + global_model.CP_bias1 proj += proj_delta * self.s x = self.proj_drop(proj) return x -def cp_mlp(self, x): - p1_up = global_model.CP_P1[self.idx:self.idx+4, :] - p1_down = global_model.CP_P1[self.idx+4: self.idx+8, :] +def cp_mlp(self, x: th.Tensor) -> th.Tensor: + """Mlp with CP parameters. + + Args: + x (th.Tensor): Input tensor. + + Returns: + th.Tensor: Mlp projected output. + """ + p1_up = global_model.CP_P1[self.idx : self.idx + 4, :] + p1_down = global_model.CP_P1[self.idx + 4 : self.idx + 8, :] up = self.fc1(x) - tensor_up = tl.cp_to_tensor((global_model.CP_R2, (p1_up, global_model.CP_P2, global_model.CP_P3))) + tensor_up = tl.cp_to_tensor( + (global_model.CP_R2, (p1_up, global_model.CP_P2, global_model.CP_P3)) + ) AA, AB, AC = tensor_up.shape - tensor_up = tensor_up.reshape((AA*AB, AC)) - up_delta = x@self.dp(tensor_up.T) + global_model.CP_bias2 + tensor_up = tensor_up.reshape((AA * AB, AC)) + up_delta = x @ self.dp(tensor_up.T) + global_model.CP_bias2 up += up_delta * self.s x = self.act(up) x = self.drop(x) - + down = self.fc2(x) - tensor_down = tl.cp_to_tensor((global_model.CP_R2, (p1_down, global_model.CP_P2, global_model.CP_P3))) - tensor_down = tensor_down.reshape((AA*AB, AC)) - down_delta = x@self.dp(tensor_down) + global_model.CP_bias3 + tensor_down = tl.cp_to_tensor( + (global_model.CP_R2, (p1_down, global_model.CP_P2, global_model.CP_P3)) + ) + tensor_down = tensor_down.reshape((AA * AB, AC)) + down_delta = x @ self.dp(tensor_down) + global_model.CP_bias3 down += down_delta * self.s x = self.drop(down) return x -def set_cara(model: nn.Module, rank: int, scale: float, l_mu: float, l_std: float): - if type(model) == timm.models.vision_transformer.VisionTransformer: +def set_cara( + model: nn.Module, rank: int, scale: float, l_mu: float, l_std: float +) -> None: + """Cara setup. + + Args: + model (nn.Module): ViT model. + rank (int): FT Rank. + scale (float): FT scale. + l_mu (float): Init lambda_mu. + l_std (float): Init lambda_std. + """ + if type(model) is timm.models.vision_transformer.VisionTransformer: # Declare CaRA parameters model.CP_A1 = nn.Parameter(th.empty([36, rank]), requires_grad=True) model.CP_A2 = nn.Parameter(th.empty([768, rank]), requires_grad=True) model.CP_A3 = nn.Parameter(th.empty([12, rank]), requires_grad=True) - model.CP_A4 = nn.Parameter(th.empty([768//12, rank]), requires_grad=True) + model.CP_A4 = nn.Parameter( + th.empty([768 // 12, rank]), requires_grad=True + ) model.CP_P1 = nn.Parameter(th.empty([108, rank]), requires_grad=True) model.CP_P2 = nn.Parameter(th.empty([768, rank]), requires_grad=True) model.CP_P3 = nn.Parameter(th.empty([768, rank]), requires_grad=True) model.CP_R1 = nn.Parameter(th.empty([rank]), requires_grad=True) model.CP_R2 = nn.Parameter(th.empty([rank]), requires_grad=True) model.CP_bias1 = nn.Parameter(th.empty([768]), requires_grad=True) - model.CP_bias2 = nn.Parameter(th.empty([768*4]), requires_grad=True) + model.CP_bias2 = nn.Parameter(th.empty([768 * 4]), requires_grad=True) model.CP_bias3 = nn.Parameter(th.empty([768]), requires_grad=True) # Initialise CaRA parameters nn.init.xavier_normal_(model.CP_A1) @@ -100,7 +144,7 @@ def set_cara(model: nn.Module, rank: int, scale: float, l_mu: float, l_std: floa model.idx = 0 model.attn_idx = 0 for child in model.children(): - if type(child) == timm.models.vision_transformer.Attention: + if type(child) is timm.models.vision_transformer.Attention: child.dp = nn.Dropout(0.1) child.s = scale child.dim = rank @@ -109,28 +153,36 @@ def set_cara(model: nn.Module, rank: int, scale: float, l_mu: float, l_std: floa global_model.idx += 1 global_model.attn_idx += 3 bound_method = cp_attn.__get__(child, child.__class__) - setattr(child, "forward", bound_method) - elif type(child) == timm.models.layers.mlp.Mlp: + setattr(child, "forward", bound_method) # noqa: B010 + elif type(child) is timm.models.layers.mlp.Mlp: child.dp = nn.Dropout(0.1) child.s = scale child.dim = rank child.idx = global_model.idx global_model.idx += 8 bound_method = cp_mlp.__get__(child, child.__class__) - setattr(child, "forward", bound_method) + setattr(child, "forward", bound_method) # noqa: B010 elif len(list(child.children())) != 0: set_cara(child, rank, scale, l_mu, l_std) - -def cara(config): + +def cara(config: Dict[str, Any]) -> th.nn.Module: + """Set CaRA for the given configuration. + + Args: + config (Dict[str, Any]): Dictionary containing CaRA configuration. + + Returns: + th.nn.Module: CaRA model. + """ # CaRA parameters model = config["model"] rank = config["rank"] scale = config["scale"] l_mu = config["l_mu"] l_std = config["l_std"] - + global global_model global_model = model set_cara(model, rank, scale, l_mu, l_std) - return global_model \ No newline at end of file + return global_model diff --git a/tests/__init__.py b/tests/__init__.py index 1fb7499..38bb211 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +1 @@ -"""Test package.""" \ No newline at end of file +"""Test package.""" diff --git a/tests/test_cara.py b/tests/test_cara.py index 59943f2..3842049 100644 --- a/tests/test_cara.py +++ b/tests/test_cara.py @@ -1,19 +1,30 @@ -import torch as th -import numpy as np +"""Test CaRA module setup.""" + import random +from typing import Any, Dict -from src.cara.cara import cara +import numpy as np +import torch as th from timm.models import create_model +from src.cara.cara import cara + + +def _get_vit() -> th.nn.Module: + """Create ViT model. -def _get_vit(): - return create_model( - "vit_base_patch16_224_in21k", - drop_path_rate=0.1 - ) + Returns: + th.nn.Module: ViT model. + """ + return create_model("vit_base_patch16_224_in21k", drop_path_rate=0.1) -def _get_cara_config(): +def _get_cara_config() -> Dict[str, Any]: + """Create configuration dictionary. + + Returns: + Dict[str, Any]: Configuration dictionary. + """ random.seed(0) th.manual_seed(0) np.random.seed(0) @@ -25,40 +36,63 @@ def _get_cara_config(): "rank": 32, "scale": 1.0, "l_mu": 1.0, - "l_std": 0.0 - } + "l_std": 0.0, + } def test_vit_without_cara(): + """Vit test without CaRA.""" vit = _get_vit() - assert (not hasattr(vit, "CP_A1")) and (not hasattr(vit, "CP_A2")) and (not hasattr(vit, "CP_A3")) and (not hasattr(vit, "CP_A4")) - assert (not hasattr(vit, "CP_P1")) and (not hasattr(vit, "CP_P2")) and (not hasattr(vit, "CP_P3")) - assert (not hasattr(vit, "CP_R1")) - assert (not hasattr(vit, "CP_R2")) + assert ( + (not hasattr(vit, "CP_A1")) + and (not hasattr(vit, "CP_A2")) + and (not hasattr(vit, "CP_A3")) + and (not hasattr(vit, "CP_A4")) + ) + assert ( + (not hasattr(vit, "CP_P1")) + and (not hasattr(vit, "CP_P2")) + and (not hasattr(vit, "CP_P3")) + ) + assert not hasattr(vit, "CP_R1") + assert not hasattr(vit, "CP_R2") def test_vit_with_cara(): + """Vit test with CaRA module.""" vit = cara(_get_cara_config()) - assert (hasattr(vit, "CP_A1")) and (hasattr(vit, "CP_A2")) and (hasattr(vit, "CP_A3")) and (hasattr(vit, "CP_A4")) - assert (hasattr(vit, "CP_P1")) and (hasattr(vit, "CP_P2")) and (hasattr(vit, "CP_P3")) - assert (hasattr(vit, "CP_R1")) - assert (hasattr(vit, "CP_R2")) + assert ( + (hasattr(vit, "CP_A1")) + and (hasattr(vit, "CP_A2")) + and (hasattr(vit, "CP_A3")) + and (hasattr(vit, "CP_A4")) + ) + assert ( + (hasattr(vit, "CP_P1")) + and (hasattr(vit, "CP_P2")) + and (hasattr(vit, "CP_P3")) + ) + assert hasattr(vit, "CP_R1") + assert hasattr(vit, "CP_R2") def test_cara_zero_init(): + """Check for zero initialisation in CaRA params.""" vit = cara(_get_cara_config()) assert th.allclose(vit.CP_A2, th.zeros_like(vit.CP_A2)) assert th.allclose(vit.CP_P2, th.zeros_like(vit.CP_P2)) def test_cara_lambda_init(): + """Check for Lambda initis in CaRA params.""" vit = cara(_get_cara_config()) assert th.allclose(vit.CP_R1, th.ones_like(vit.CP_R1)) assert th.allclose(vit.CP_R2, th.ones_like(vit.CP_R2)) def test_cara_forward(): - vit = _get_vit() + """Check for dummy forward pass.""" + vit = cara(_get_cara_config()) dummy_input = th.randn((2, 3, 224, 224)) output = vit(dummy_input) - assert np.allclose(list(output.shape), (2, 21843)) \ No newline at end of file + assert np.allclose(list(output.shape), (2, 21843)) From fa711ac34328b59e1b165b6dbf9925c8d894e4f9 Mon Sep 17 00:00:00 2001 From: loki-veera Date: Mon, 28 Jul 2025 14:37:44 +0200 Subject: [PATCH 13/13] Update makefile --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index ffe9592..ec6cf94 100644 --- a/Makefile +++ b/Makefile @@ -20,5 +20,8 @@ test: check-all: uv run pre-commit run --all-files +install-precommit: + uv run pre-commit install --hook-type pre-push + all: format test lint @echo "All checks passed!" \ No newline at end of file