diff --git a/docs/source/_toctree.yml b/docs/source/_toctree.yml index 34dea504..c39adcae 100644 --- a/docs/source/_toctree.yml +++ b/docs/source/_toctree.yml @@ -46,3 +46,21 @@ - local: cli title: Kernels CLI title: API Reference +- sections: + - local: cli-init + title: kernels init + - local: cli-upload + title: kernels upload + - local: cli-benchmark + title: kernels benchmark + - local: cli-check + title: kernels check + - local: cli-versions + title: kernels versions + - local: cli-generate-readme + title: kernels generate-readme + - local: cli-lock + title: kernels lock + - local: cli-download + title: kernels download + title: CLI Reference diff --git a/docs/source/cli-benchmark.md b/docs/source/cli-benchmark.md new file mode 100644 index 00000000..2c41ef21 --- /dev/null +++ b/docs/source/cli-benchmark.md @@ -0,0 +1,147 @@ +# kernels benchmark + +Use `kernels benchmark` to run benchmark scripts shipped with a kernel repository. + +The command: + +- Downloads the kernel repo at a specific **branch** or **version** +- Runs all `benchmarks/benchmark*.py` scripts +- Times each `benchmark_*` workload and prints a results table +- Optionally saves results as JSON + +## Installation + +`kernels benchmark` requires extra dependencies: + +```bash +uv pip install 'kernels[benchmark]' # or pip install 'kernels[benchmark]' +``` + +## Example + +```bash +kernels benchmark kernels-community/activation --version 1 +``` + +Example output: + +```text +Downloading kernels-community/activation@v1... +Running benchmark.py... + + GPU Apple M3 Max (30 cores) + CPU Apple M3 Max + OS Darwin 25.2.0 + PyTorch 2.10.0 + + Running SiluWorkloads on mps + +┌───────────────┬────────────┬─────┬───────────┬────────────┬───────────┬───────────┬───────────┬───────────┬────────────┬───────────┬─────────┐ +│ Benchmark │ Workload │ N │ Speedup │ Mean(ms) │ Std(ms) │ Min(ms) │ Max(ms) │ IQR(ms) │ Outliers │ Ref(ms) │ Match │ +├───────────────┼────────────┼─────┼───────────┼────────────┼───────────┼───────────┼───────────┼───────────┼────────────┼───────────┼─────────┤ +│ SiluWorkloads │ large │ 100 │ 1.72x │ 6.5153 │ 0.4343 │ 6.2883 │ 8.4699 │ 0.1701 │ 8 │ 11.2048 │ ✓ │ +│ SiluWorkloads │ medium │ 100 │ 2.48x │ 1.1813 │ 0.3976 │ 1.04 │ 4.2146 │ 0.0698 │ 5 │ 2.9332 │ ✓ │ +│ SiluWorkloads │ small │ 100 │ 1.96x │ 0.4909 │ 0.2175 │ 0.4407 │ 2.6438 │ 0.0085 │ 16 │ 0.9622 │ ✓ │ +└───────────────┴────────────┴─────┴───────────┴────────────┴───────────┴───────────┴───────────┴───────────┴────────────┴───────────┴─────────┘ + + large: 1.72x faster (95% CI: 6.4302-6.6004ms vs ref 11.2048ms) ✓ significant + medium: 2.48x faster (95% CI: 1.1034-1.2592ms vs ref 2.9332ms) ✓ significant + small: 1.96x faster (95% CI: 0.4483-0.5335ms vs ref 0.9622ms) ✓ significant + +Kernel: 2385e44 Benchmark: 5b53516 +``` + +## Usage + +You must specify which revision to benchmark, either via flags or with `@...` in the repo id: + +```bash +kernels benchmark --version +kernels benchmark --branch +kernels benchmark @v +kernels benchmark @ +``` + +## Examples + +Benchmark a tagged kernel version: + +```bash +kernels benchmark kernels-community/activation --version 1 +``` + +Equivalent shorthand: + +```bash +kernels benchmark kernels-community/activation@v1 +``` + +Benchmark a branch: + +```bash +kernels benchmark kernels-community/activation --branch main +``` + +Tune warmup and iteration count: + +```bash +kernels benchmark kernels-community/activation@v1 --warmup 20 --iterations 200 +``` + +Save results to a file (JSON): + +```bash +kernels benchmark kernels-community/activation@v1 --output results.json +``` + +Benchmark a local kernel checkout (must contain `benchmarks/`): + +```bash +kernels benchmark ./my_kernel +``` + +## Output + +- By default, a table is printed (timings in ms). +- `--output .json` writes a JSON payload to disk. + +## Writing Benchmark Scripts + +Benchmark scripts must live under `benchmarks/` in the kernel repository and match `benchmark*.py`. +Each script should define one or more subclasses of `kernels.benchmark.Benchmark`. + +Minimal example (`benchmarks/benchmark_activation.py`): + +```python +import torch + +from kernels.benchmark import Benchmark + + +class ActivationBenchmark(Benchmark): + seed = 0 + + def setup(self): + self.x = torch.randn(128, 1024, device=self.device, dtype=torch.float16) + self.out = torch.empty(128, 512, device=self.device, dtype=torch.float16) + + def benchmark_silu_and_mul(self): + self.kernel.silu_and_mul(self.out, self.x) + + def verify_silu_and_mul(self): + # Return reference tensor; runner compares with self.out + return torch.nn.functional.silu(self.x[..., :512]) * self.x[..., 512:] +``` + +The runner will: + +- Call `setup()` once per workload (or `setup_()` if present) +- Warm up (`--warmup`) +- Time `benchmark_()` for `--iterations` +- If `verify_()` exists, check that outputs match (`torch.allclose(..., atol=1e-2)`) and show a speedup vs the reference computation + +## Troubleshooting + +- If the repo does not contain a `benchmarks/` directory (or no `benchmark*.py` files), the command exits with an error. +- If a benchmark script defines no `Benchmark` subclasses, the command exits with an error. +- If `verify_()` exists and the outputs do not match, the command exits with an error. diff --git a/docs/source/cli-check.md b/docs/source/cli-check.md new file mode 100644 index 00000000..226b802d --- /dev/null +++ b/docs/source/cli-check.md @@ -0,0 +1,65 @@ +# kernels check + +Use `kernels check` to verify that a kernel on the Hub meets compliance requirements. + +## What It Checks + +- Python ABI compatibility (default: 3.9) +- Operating system compatibility (macOS 15.0+, manylinux_2_28) + +## Usage + +```bash +kernels check [--revision ] [--macos ] [--manylinux ] [--python-abi ] +``` + +## Installation + +`kernels check` requires an additional dependency: + +```bash +uv pip install kernel-abi-check # or pip install kernel-abi-check +``` + +## Examples + +Check a kernel on the Hub: + +```bash +kernels check kernels-community/flash-attn3 +``` + +Check a specific revision: + +```bash +kernels check kernels-community/flash-attn3 --revision v2 +``` + +Check with custom compatibility requirements: + +```bash +kernels check kernels-community/flash-attn3 --python-abi 3.10 --manylinux manylinux_2_31 +``` + +## Example Output + +```text +Checking variant: torch210-metal-aarch64-darwin + Dynamic library _example_kernel_metal_2juixjwdznbhy.abi3.so: + 🐍 Python ABI 3.9 compatible + 🍏 compatible with macOS 15.0 +Checking variant: torch29-metal-aarch64-darwin + Dynamic library _example_kernel_metal_vtlnpevkb6uum.abi3.so: + 🐍 Python ABI 3.9 compatible + 🍏 compatible with macOS 15.0 +``` + +## Options + +| Option | Default | Description | +| -------------- | ---------------- | ----------------------------------- | +| `--revision` | `main` | Branch, tag, or commit SHA to check | +| `--macos` | `15.0` | Minimum macOS version to require | +| `--manylinux` | `manylinux_2_28` | Manylinux version to require | +| `--python-abi` | `3.9` | Python ABI version to require | + diff --git a/docs/source/cli-download.md b/docs/source/cli-download.md new file mode 100644 index 00000000..cf9e919f --- /dev/null +++ b/docs/source/cli-download.md @@ -0,0 +1,50 @@ +# kernels download + +Use `kernels download` to download kernels that have been locked in a project's `kernels.lock` file. + +## Usage + +```bash +kernels download [--all-variants] +``` + +## What It Does + +- Reads the `kernels.lock` file from the specified project directory +- Downloads each locked kernel at its pinned revision (SHA) +- Installs the appropriate variant for your platform (or all variants with `--all-variants`) + +## Examples + +Download kernels for the current project: + +```bash +kernels download . +``` + +Download all build variants (useful for CI or multi-platform builds): + +```bash +kernels download . --all-variants +``` + +Download kernels for a specific project: + +```bash +kernels download /path/to/my-project +``` + +## Options + +| Option | Description | +| ---------------- | ----------------------------------------------------------------------------------------- | +| `--all-variants` | Download all build variants of each kernel instead of just the current platform's variant | + +## Prerequisites + +Your project directory must contain a `kernels.lock` file. Generate one using [`kernels lock`](cli-lock.md). + +## See Also + +- [kernels lock](cli-lock.md) - Generate the lock file +- [kernels versions](cli-versions.md) - View available kernel versions diff --git a/docs/source/cli-generate-readme.md b/docs/source/cli-generate-readme.md new file mode 100644 index 00000000..5d5c721c --- /dev/null +++ b/docs/source/cli-generate-readme.md @@ -0,0 +1,61 @@ +# kernels generate-readme + +Use `kernels generate-readme` to automatically generate documentation snippets for a kernel's public functions. + +## Usage + +```bash +kernels generate-readme [--revision ] +``` + +## What It Does + +- Downloads the specified kernel from the Hub +- Inspects the kernel's public API +- Generates markdown documentation snippets showing function signatures and usage + +## Examples + +Generate README snippets for a kernel: + +```bash +kernels generate-readme kernels-community/activation > README.md +``` + +## Example Output + +README.md snippet for `kernels-community/activation`: +```md +--- +tags: +- kernels +--- + +## Functions + +### Function `fatrelu_and_mul` + +`(out: torch.Tensor, x: torch.Tensor, threshold: float = 0.0) -> None` + +No documentation available. + +### Function `gelu` + +`(out: torch.Tensor, x: torch.Tensor) -> None` + +No documentation available. + +### Function `gelu_and_mul` + +`(out: torch.Tensor, x: torch.Tensor) -> None` + +No documentation available. + +### Function `gelu_fast` + +`(out: torch.Tensor, x: torch.Tensor) -> None` + +No documentation available. + +... +``` \ No newline at end of file diff --git a/docs/source/cli-init.md b/docs/source/cli-init.md new file mode 100644 index 00000000..8901e050 --- /dev/null +++ b/docs/source/cli-init.md @@ -0,0 +1,62 @@ +# kernels init + +Use `kernels init` to initialize a new kernel project. + +## Usage + +```bash +kernels init / [--backends ] [--overwrite] +``` + +This creates a new directory in the current working directory with the (normalized) repo name. + +## What It Does + +- Downloads a project template and replaces placeholders in file names, paths, and file contents +- Optionally restricts enabled backends (updates `build.toml` and removes unused backend folders) +- Initializes a Git repo and stages the files (`git init`, `git add .`) + +## Examples + +Initialize a new kernel project (defaults to `metal` on macOS, `cuda` on Linux/Windows): + +```bash +kernels init my-user/my-kernel +``` + +Enable multiple backends: + +```bash +kernels init my-user/my-kernel --backends cuda cpu +``` + +Enable all supported backends: + +```bash +kernels init my-user/my-kernel --backends all +``` + +Overwrite an existing directory if it exists: + +```bash +kernels init my-user/my-kernel --overwrite +``` + +## Next Steps + +`kernels init` prints suggested next steps after creating the project. A typical flow looks like: + +```bash +cd my-kernel +cachix use huggingface +nix run -L --max-jobs 1 --cores 8 .#build-and-copy +uv run example.py +``` + +## Notes + +- The `` part is normalized to lowercase with dashes preferred. For example, `my-user/My_Kernel` becomes a directory named `my-kernel` and a repo id `my-user/my-kernel`. +- Python package names use underscores (e.g., `my_kernel`) since dashes are not valid in Python identifiers. +- `--backends` can be one of: `cpu`, `cuda`, `metal`, `rocm`, `xpu`, `npu`, or `all`. +- If the target directory already exists and is not empty, `kernels init` exits with an error unless `--overwrite` is set. +- The project is initialized as a Git repo (via `git init`) because Nix flakes require it. diff --git a/docs/source/cli-lock.md b/docs/source/cli-lock.md new file mode 100644 index 00000000..e25ea1e8 --- /dev/null +++ b/docs/source/cli-lock.md @@ -0,0 +1,78 @@ +# kernels lock + +Use `kernels lock` to generate a `kernels.lock` file that pins kernel dependencies to specific revisions. + +## Usage + +```bash +kernels lock +``` + +## What It Does + +- Reads kernel dependencies from `pyproject.toml` under `[tool.kernels.dependencies]` +- Resolves each kernel to its current revision SHA +- Writes a `kernels.lock` file with pinned versions and variant information + +## Examples + +Lock kernels in the current project: + +```bash +kernels lock . +``` + +Lock kernels in a specific project: + +```bash +kernels lock /path/to/my-project +``` + +## pyproject.toml Format + +Add your kernel dependencies to `pyproject.toml`: + +```toml +[tool.kernels.dependencies] +"kernels-community/activation" = 1 +``` + +The version can be: + +- A version number (e.g., `1`, `2`) + +## kernels.lock Format + +The generated lock file contains: + +```json +[ + { + "repo_id": "kernels-community/activation", + "sha": "ece277f908b9453112722d584fee4b5696f21c49", + "variants": { + "torch210-cu128-x86_64-windows": { + "hash": "sha256-cbf085e1d297d990d9cb074fb5079ff48e9682c729f53a0899a36b5164a6fb45", + "hash_type": "git_lfs_concat" + }, + // ... + "torch29-metal-aarch64-darwin": { + "hash": "sha256-9f665b54a53246a7d3627422f8a0d41d7956dc5409043dbd14c4ec0327aea310", + "hash_type": "git_lfs_concat" + } + } + } +] +``` + +## Workflow + +1. Add dependencies to `pyproject.toml` +2. Run `kernels lock .` to generate the lock file +3. Commit both `pyproject.toml` and `kernels.lock` +4. Use `kernels download .` to install locked kernels + +## See Also + +- [kernels download](cli-download.md) - Download locked kernels +- [kernels versions](cli-versions.md) - View available kernel versions diff --git a/docs/source/cli-upload.md b/docs/source/cli-upload.md new file mode 100644 index 00000000..39a5d29b --- /dev/null +++ b/docs/source/cli-upload.md @@ -0,0 +1,62 @@ +# kernels upload + +Use `kernels upload` to upload built kernels to the Hugging Face Hub. + +## Usage + +```bash +kernels upload --repo-id [--branch ] [--private] +``` + +## What It Does + +- Creates a repository on the Hub if it doesn't exist +- Uploads the kernel build artifacts from the specified directory +- If a build variant already exists in the repo, replaces the existing files + +## Examples + +Upload a kernel build: + +```bash +kernels upload ./build --repo-id my-username/my-kernel +``` + +Upload to a specific branch: + +```bash +kernels upload ./build --repo-id my-username/my-kernel --branch dev +``` + +Upload as a private repository: + +```bash +kernels upload ./build --repo-id my-username/my-kernel --private +``` + +## Options + +| Option | Required | Description | +| ----------- | -------- | ------------------------------------------------------- | +| `--repo-id` | Yes | Repository ID on the Hub (e.g., `username/kernel-name`) | +| `--branch` | No | Upload to a specific branch instead of main | +| `--private` | No | Create the repository as private | + +## Prerequisites + +You must be authenticated with the Hugging Face Hub: + +```bash +huggingface-cli login +``` + +## Notes + +- The `kernel_dir` should contain the build output (typically the `build/` directory from your kernel project) +- If uploading a new variant to an existing repo, only that variant's files are replaced +- Make sure your kernel passes [`kernels check`](cli-check.md) before uploading + +## See Also + +- [kernels check](cli-check.md) - Verify kernel compliance before uploading +- [kernels init](cli-init.md) - Create a new kernel project diff --git a/docs/source/cli-versions.md b/docs/source/cli-versions.md new file mode 100644 index 00000000..fcbcdb49 --- /dev/null +++ b/docs/source/cli-versions.md @@ -0,0 +1,34 @@ +# kernels versions + +Use `kernels versions` to list all available versions of a kernel on the Hub. + +## Usage + +```bash +kernels versions +``` + +## Examples + +List versions of a kernel: + +```bash +kernels versions kernels-community/activation +``` + +## Example Output + +```text +Version 1: torch210-cu128-x86_64-windows, torch210-cxx11-cu126-x86_64-linux, torch210-cxx11-cu128-x86_64-linux, torch210-cxx11-cu130-x86_64-linux, torch210-metal-aarch64-darwin ✅, torch27-cxx11-cu118-x86_64-linux, torch27-cxx11-cu126-x86_64-linux, torch27-cxx11-cu128-aarch64-linux, torch27-cxx11-cu128-x86_64-linux, torch28-cxx11-cu126-aarch64-linux, torch28-cxx11-cu126-x86_64-linux, torch28-cxx11-cu128-aarch64-linux, torch28-cxx11-cu128-x86_64-linux, torch28-cxx11-cu129-aarch64-linux, torch28-cxx11-cu129-x86_64-linux, torch29-cxx11-cu126-aarch64-linux, torch29-cxx11-cu126-x86_64-linux, torch29-cxx11-cu128-aarch64-linux, torch29-cxx11-cu128-x86_64-linux, torch29-cxx11-cu130-aarch64-linux, torch29-cxx11-cu130-x86_64-linux, torch29-metal-aarch64-darwin +``` + +## Use Cases + +- Check which versions are available before locking dependencies +- Find the latest version of a kernel +- Identify version SHAs for pinning in `pyproject.toml` + +## See Also + +- [kernels lock](cli-lock.md) - Lock kernel versions in your project +- [kernels download](cli-download.md) - Download locked kernels diff --git a/docs/source/cli.md b/docs/source/cli.md index c7588c51..99042295 100644 --- a/docs/source/cli.md +++ b/docs/source/cli.md @@ -1,33 +1,83 @@ # Kernels CLI Reference -## Main Functions +The `kernels` CLI provides commands for managing compute kernels. -### kernels check +```bash +kernels [-h] {check,download,versions,upload,lock,generate-readme,benchmark,init} ... +``` + +## Commands + +| Command | Description | +| ----------------------------------------- | -------------------------------------------------------- | +| [init](cli-init.md) | Initialize a new kernel project from template | +| [upload](cli-upload.md) | Upload kernels to the Hub | +| [benchmark](cli-benchmark.md) | Run benchmark results for a kernel | +| [check](cli-check.md) | Check a kernel for compliance | +| [versions](cli-versions.md) | Show kernel versions | +| [generate-readme](cli-generate-readme.md) | Generate README snippets for a kernel's public functions | +| [lock](cli-lock.md) | Lock kernel revisions | +| [download](cli-download.md) | Download locked kernels | -You can use `kernels check` to test compliance of a kernel on the Hub. -This currently checks that the kernel: +## Quick Start -- Supports the currently-required Python ABI version. -- Works on supported operating system versions. +### Create a new kernel project + +```bash +kernels init my-username/my-kernel +cd my-kernel +``` -For example: +### Build and test locally ```bash -$ kernels check kernels-community/flash-attn3 -Checking variant: torch28-cxx11-cu128-aarch64-linux - 🐍 Python ABI 3.9 compatible - 🐧 manylinux_2_28 compatible -[...] +cachix use huggingface +nix run -L --max-jobs 1 --cores 8 .#build-and-copy +uv run example.py ``` -### kernels upload +### Upload to the Hub + +```bash +kernels upload ./build --repo-id my-username/my-kernel +``` + +### Use kernels in your project + +#### Directly from the Hub + +```python +import torch -Use `kernels upload --repo_id="hub-username/kernel"` to upload -your kernel builds to the Hub. To know the supported arguments run: `kernels upload -h`. +from kernels import get_kernel -**Notes**: +# Download optimized kernels from the Hugging Face hub +my_kernel = get_kernel("my-username/my-kernel", version=1) -- This will take care of creating a repository on the Hub with the `repo_id` provided. -- If a repo with the `repo_id` already exists and if it contains a `build` with the build variant - being uploaded, it will attempt to delete the files existing under it. -- Make sure to be authenticated (run `hf auth login` if not) to be able to perform uploads to the Hub. +# Random tensor +x = torch.randn((10, 10), dtype=torch.float16, device="cuda") + +# Run the kernel +y = torch.empty_like(x) +my_kernel.my_kernel_function(y, x) + +print(y) +``` + +or + +#### Locked and downloaded + +Add to `pyproject.toml`: + +```toml +[tool.kernels.dependencies] +"my-username/my-kernel" = "1" +``` + +Then lock and download: + +```bash +kernels lock . +kernels download . +``` diff --git a/docs/source/installation.md b/docs/source/installation.md index c6e19142..df846c31 100644 --- a/docs/source/installation.md +++ b/docs/source/installation.md @@ -6,6 +6,12 @@ Install the `kernels` package with `pip` (requires `torch>=2.5` and CUDA): pip install kernels ``` +or with `uv` + +```bash +uv pip install kernels +``` + # Using kernels in a Docker container Build and run the reference `examples/basic.py` in a Docker container with the following commands: diff --git a/kernels/src/kernels/cli/init.py b/kernels/src/kernels/cli/init.py index 3be085e3..638f69de 100644 --- a/kernels/src/kernels/cli/init.py +++ b/kernels/src/kernels/cli/init.py @@ -23,13 +23,26 @@ def parse_kernel_name(value: str) -> NamedTuple: if "/" in name or "\\" in name: # validate kernel name raise argparse.ArgumentTypeError("repo name cannot contain path separators") - name = name.lower().replace("-", "_") # normalize name - RepoInfo = NamedTuple("RepoInfo", [("name", str), ("owner", str), ("repo_id", str)]) - return RepoInfo(name=name, owner=owner, repo_id=f"{owner}/{name}") + # Display name uses dashes (for repo name, directory, build.toml name) + display_name = name.replace("_", "-") + # Normalized name uses underscores (for Python package names) + normalized_name = name.lower().replace("-", "_") + + RepoInfo = NamedTuple( + "RepoInfo", + [("name", str), ("normalized_name", str), ("owner", str), ("repo_id", str)], + ) + return RepoInfo( + name=display_name, + normalized_name=normalized_name, + owner=owner, + repo_id=f"{owner}/{display_name}", + ) def run_init(args: Namespace) -> None: kernel_name = args.kernel_name.name + normalized_name = args.kernel_name.normalized_name repo_id = args.kernel_name.repo_id backends = KNOWN_BACKENDS if "all" in args.backends else set(args.backends) @@ -54,7 +67,9 @@ def run_init(args: Namespace) -> None: template_dir = Path( snapshot_download(repo_id=args.template_repo, repo_type="model") ) - _init_from_local_template(template_dir, target_dir, kernel_name, repo_id) + _init_from_local_template( + template_dir, target_dir, kernel_name, normalized_name, repo_id + ) if backends: _update_build_backends(target_dir / "build.toml", backends) @@ -84,12 +99,13 @@ def _init_from_local_template( template_dir: Path, target_dir: Path, kernel_name: str, + normalized_name: str, repo_id: str, ) -> None: # Placeholder mappings replacements = { "__KERNEL_NAME__": kernel_name, - "__KERNEL_NAME_NORMALIZED__": kernel_name, + "__KERNEL_NAME_NORMALIZED__": normalized_name, "__REPO_ID__": repo_id, } diff --git a/kernels/tests/test_init.py b/kernels/tests/test_init.py index 67ec09f0..95c3f3a0 100644 --- a/kernels/tests/test_init.py +++ b/kernels/tests/test_init.py @@ -16,6 +16,7 @@ def e2e_init(backends: list[str]) -> None: backends=backends, overwrite=False, ) + expected_dir_name = "test-kernel" expected_normalized_name = "test_kernel" expected_backend_dirs = { Path(f"{expected_normalized_name}_{backend}") for backend in args.backends @@ -43,8 +44,8 @@ def e2e_init(backends: list[str]) -> None: try: run_init(args) - # make sure normalized dir was created - target_dir = Path(tmpdir) / expected_normalized_name + # make sure dir was created + target_dir = Path(tmpdir) / expected_dir_name if not target_dir.exists(): raise AssertionError(f"Target directory was not created: {target_dir}") diff --git a/kernels/uv.lock b/kernels/uv.lock index c80145a3..581b37dc 100644 --- a/kernels/uv.lock +++ b/kernels/uv.lock @@ -618,7 +618,7 @@ requires-dist = [ { name = "pyyaml", specifier = ">=6" }, { name = "tabulate", marker = "extra == 'benchmark'", specifier = ">=0.9.0" }, { name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.0" }, - { name = "tomlkit", specifier = ">=0.14.0" }, + { name = "tomlkit", specifier = ">=0.13.3" }, { name = "torch", marker = "extra == 'benchmark'" }, { name = "torch", marker = "extra == 'torch'" }, ]