Skip to content

Add API docs #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/build_documentation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Build documentation

on:
push:
paths:
- "docs/source/**"
branches:
- main
- doc-builder*
- v*-release

jobs:
build:
uses: huggingface/doc-builder/.github/workflows/build_main_documentation.yml@main
with:
commit_sha: ${{ github.sha }}
package: kernels
secrets:
hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }}
18 changes: 18 additions & 0 deletions .github/workflows/build_pr_documentation.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Build PR Documentation

on:
pull_request:
paths:
- "docs/source/**"

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
build:
uses: huggingface/doc-builder/.github/workflows/build_pr_documentation.yml@main
with:
commit_sha: ${{ github.event.pull_request.head.sha }}
pr_number: ${{ github.event.number }}
package: kernels
26 changes: 26 additions & 0 deletions docs/source/_toctree.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
- sections:
- local: index
title: Introduction
- local: installation
title: Installation
title: Getting started
- sections:
- local: basic_usage
title: Basic Usage
- local: layers
title: Using Layers
- local: locking
title: Locking Kernel Versions
- local: env
title: Environment Variables
title: Usage Guide
- sections:
- local: api/kernels
title: Kernels
- local: api/layers
title: Layers
title: API Reference
- sections:
- local: kernel_requirements
title: Kernel Requirements
title: Developer Guide
21 changes: 21 additions & 0 deletions docs/source/api/kernels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Kernels API Reference

## Main Functions

### get_kernel

[[autodoc]] kernels.get_kernel

### has_kernel

[[autodoc]] kernels.has_kernel

## Loading locked kernels

### load_kernel

[[autodoc]] kernels.load_kernel

### get_locked_kernel

[[autodoc]] kernels.get_locked_kernel
31 changes: 31 additions & 0 deletions docs/source/api/layers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Layers API Reference

## Making layers kernel-aware

### use_kernel_forward_from_hub

[[autodoc]] kernels.use_kernel_forward_from_hub

### replace_kernel_forward_from_hub

[[autodoc]] kernels.replace_kernel_forward_from_hub

## Registering kernel mappings

### use_kernel_mapping

[[autodoc]] kernels.use_kernel_mapping

### register_kernel_mapping

[[autodoc]] kernels.register_kernel_mapping

## Classes

### LayerRepository

[[autodoc]] kernels.LayerRepository

### Device

[[autodoc]] kernels.Device
34 changes: 34 additions & 0 deletions docs/source/basic_usage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Basic Usage

## Loading Kernels

Here is how you would use the [activation](https://huggingface.co/kernels-community/activation) kernels from the Hugging Face Hub:

```python
import torch
from kernels import get_kernel

# Download optimized kernels from the Hugging Face hub
activation = get_kernel("kernels-community/activation")

# Create a random tensor
x = torch.randn((10, 10), dtype=torch.float16, device="cuda")

# Run the kernel
y = torch.empty_like(x)
activation.gelu_fast(y, x)

print(y)
```

## Checking Kernel Availability

You can check if a specific kernel is available for your environment:

```python
from kernels import has_kernel

# Check if kernel is available for current environment
is_available = has_kernel("kernels-community/activation")
print(f"Kernel available: {is_available}")
```
File renamed without changes.
20 changes: 20 additions & 0 deletions docs/source/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Kernels

<div align="center">
<img src="https://github.com/user-attachments/assets/64a652f3-0cd3-4829-b3c1-df13f7933569" width="450" height="450" alt="kernel-builder logo">
</div>

The Kernel Hub allows Python libraries and applications to load compute
kernels directly from the [Hub](https://hf.co/). To support this kind
of dynamic loading, Hub kernels differ from traditional Python kernel
packages in that they are made to be:

- **Portable**: a kernel can be loaded from paths outside `PYTHONPATH`.
- **Unique**: multiple versions of the same kernel can be loaded in the
same Python process.
- **Compatible**: kernels must support all recent versions of Python and
the different PyTorch build configurations (various CUDA versions
and C++ ABIs). Furthermore, older C library versions must be supported.

You can [search for kernels](https://huggingface.co/models?other=kernel) on
the Hub.
16 changes: 16 additions & 0 deletions docs/source/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Installation

Install the `kernels` package with `pip` (requires `torch>=2.5` and CUDA):

```bash
pip install kernels
```

# Using kernels in a Docker container

build and run the reference [examples/basic.py](examples/basic.py) in a Docker container with the following commands:

```bash
docker build --platform linux/amd64 -t kernels-reference -f docker/Dockerfile.reference .
docker run --gpus all -it --rm -e HF_TOKEN=$HF_TOKEN kernels-reference
```
File renamed without changes.
File renamed without changes.
File renamed without changes.
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,16 @@ dev = [
]

[project.optional-dependencies]
torch = ["torch"]
docs = [
"hf-doc-builder",
]

[project.scripts]
kernels = "kernels.cli:main"

[project.entry-points."egg_info.writers"]
"kernels.lock" = "kernels.lockfile:write_egg_lockfile"


[tool.ruff]
exclude = [
".eggs",
Expand Down
4 changes: 4 additions & 0 deletions src/kernels/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import importlib.metadata

from kernels.layer import (
Device,
LayerRepository,
Expand Down Expand Up @@ -27,3 +29,5 @@
"LayerRepository",
"Device",
]

__version__ = importlib.metadata.version("kernels")
94 changes: 69 additions & 25 deletions src/kernels/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,18 @@ def use_kernel_mapping(
inherit_mapping: bool = True,
):
"""
Context manager that sets a mapping for a duration of the context.

When `inherit_mapping` is set to `True` the current mapping will be
extended by `mapping` inside the context. If it is `False`, only
`mapping` is used inside the context.
Context manager that sets a kernel mapping for the duration of the context.

Args:
mapping (`Dict[str, Dict[Union[Device, str], LayerRepository]]`):
A mapping between layer names and their corresponding kernel repositories.
inherit_mapping (`bool`, *optional*, defaults to `True`):
The current mapping will be extended by `mapping` when set to `True`.
When set to `False`, the current mapping will be replaced by `mapping`
for the duration of the context.

Returns:
`ContextManager`: Context manager that sets up the mapping.
"""

class ContextManager:
Expand All @@ -87,27 +94,31 @@ def __exit__(self, exc_type, exc_value, traceback):


def register_kernel_mapping(
mapping: Dict[str, Dict[Union[Device, str], LayerRepository]]
mapping: Dict[str, Dict[Union[Device, str], LayerRepository]],
):
"""
Allows one to register a mapping between a layer name the corresponding kernel to use, depending on the device.
Register a mapping between a layer name the corresponding kernel to use, depending on the device.
This should be use in conjunction with `use_kernel_hub_forward` decorator on the classname.
Exemple usage:

```python
from kernels import LayerRepository, register_kernel_mapping

kernel_layer_mapping = {
"LlamaRMSNorm": {
"cuda": LayerRepository(
repo_id="kernels-community/activation",
layer_name="RmsNorm",
revision="layers",
),
},
}
register_kernel_mapping(kernel_layer_mapping)
```

Args:
mapping (`Dict[str, Dict[Union[Device, str], LayerRepository]]`):
A mapping between layer names and their corresponding kernel repositories.

Example:
```python
from kernels import LayerRepository, register_kernel_mapping

kernel_layer_mapping = {
"LlamaRMSNorm": {
"cuda": LayerRepository(
repo_id="kernels-community/activation",
layer_name="RmsNorm",
revision="layers",
),
},
}
register_kernel_mapping(kernel_layer_mapping)
```
"""
# Merge with existing mappings.
for new_kernel, new_device_repos in mapping.items():
Expand All @@ -125,8 +136,18 @@ def replace_kernel_forward_from_hub(cls, layer_name: str, *, use_fallback: bool
This function monkeypatches a layer, replacing the `forward` method
of the layer with that of a layer from the hub. The replacement is done
when a layer matching `layer_name` and device type is registered through
`register_layer_mapping`. The device type is inferred from the first
[`register_layer_mapping`]. The device type is inferred from the first
argument to `forward`.

Args:
cls (`nn.Module`):
The layer class to replace the forward function of.
layer_name (`str`):
The name to assign to the layer.
use_fallback (`bool`, *optional*, defaults to `True`):
Whether to use the fallback forward function if no kernel mapping
is found. If set to `False`, a `ValueError` will be raised if no kernel
mapping is found.
"""

fallback_forward = cls.forward
Expand Down Expand Up @@ -195,11 +216,34 @@ def forward(self, x, *args, **kwargs):
def use_kernel_forward_from_hub(layer_name: str, *, use_fallback: bool = True):
"""
Replace the forward function of a layer using a layer from the kernel hub.

This decorator can be applied to a layer and replaces the forward method
of the layer with that of a layer from the hub. The replacement is done
when a layer matching `layer_name` and device type is registered through
`register_layer_mapping`. The device type is inferred from the first
[`register_layer_mapping`]. The device type is inferred from the first
argument to `forward`.

Args:
layer_name (`str`):
The name to assign to the layer.
use_fallback (`bool`, *optional*, defaults to `True`):
Whether to use the fallback forward function if no kernel mapping
is found. If set to `False`, a `ValueError` will be raised if no kernel
mapping is found.

Example:
```python
from kernels import use_kernel_forward_from_hub

@use_kernel_forward_from_hub(layer_name="LlamaRMSNorm")
class LlamaRMSNorm(nn.Module):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def forward(self, x):
# Original forward implementation
pass
```
"""

def decorator(cls):
Expand Down
Loading
Loading