kernels 0.4.3__tar.gz → 0.4.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kernels
3
- Version: 0.4.3
3
+ Version: 0.4.4
4
4
  Summary: Download compute kernels
5
5
  Author-email: OlivierDehaene <olivier@huggingface.co>, Daniel de Kok <daniel@huggingface.co>, David Holtz <david@huggingface.co>, Nicolas Patry <nicolas@huggingface.co>
6
6
  License: Apache-2.0
@@ -15,6 +15,17 @@ Requires-Dist: torch; extra == "torch"
15
15
 
16
16
  # kernels
17
17
 
18
+ <div align="center">
19
+ <img src="https://github.com/user-attachments/assets/64a652f3-0cd3-4829-b3c1-df13f7933569" width="450" height="450" alt="kernel-builder logo">
20
+ <p align="center">
21
+ <a href="https://pypi.org/project/kernels"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/kernels"></a>
22
+ <a href="https://github.com/huggingface/kernels/tags"><img alt="GitHub tag" src="https://img.shields.io/github/v/tag/huggingface/kernels"></a>
23
+ <a href="https://github.com/huggingface/kernels/actions/workflows/docker-build-push.yaml"><img alt="Test kernels" src="https://img.shields.io/github/actions/workflow/status/huggingface/kernels/test.yml?label=test"></a>
24
+
25
+ </p>
26
+ </div>
27
+ <hr/>
28
+
18
29
  The Kernel Hub allows Python libraries and applications to load compute
19
30
  kernels directly from the [Hub](https://hf.co/). To support this kind
20
31
  of dynamic loading, Hub kernels differ from traditional Python kernel
@@ -1,5 +1,16 @@
1
1
  # kernels
2
2
 
3
+ <div align="center">
4
+ <img src="https://github.com/user-attachments/assets/64a652f3-0cd3-4829-b3c1-df13f7933569" width="450" height="450" alt="kernel-builder logo">
5
+ <p align="center">
6
+ <a href="https://pypi.org/project/kernels"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/kernels"></a>
7
+ <a href="https://github.com/huggingface/kernels/tags"><img alt="GitHub tag" src="https://img.shields.io/github/v/tag/huggingface/kernels"></a>
8
+ <a href="https://github.com/huggingface/kernels/actions/workflows/docker-build-push.yaml"><img alt="Test kernels" src="https://img.shields.io/github/actions/workflow/status/huggingface/kernels/test.yml?label=test"></a>
9
+
10
+ </p>
11
+ </div>
12
+ <hr/>
13
+
3
14
  The Kernel Hub allows Python libraries and applications to load compute
4
15
  kernels directly from the [Hub](https://hf.co/). To support this kind
5
16
  of dynamic loading, Hub kernels differ from traditional Python kernel
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "kernels"
3
- version = "0.4.3"
3
+ version = "0.4.4"
4
4
  description = "Download compute kernels"
5
5
  authors = [
6
6
  { name = "OlivierDehaene", email = "olivier@huggingface.co" },
@@ -9,6 +9,7 @@ from kernels.layer import (
9
9
  from kernels.utils import (
10
10
  get_kernel,
11
11
  get_locked_kernel,
12
+ has_kernel,
12
13
  install_kernel,
13
14
  load_kernel,
14
15
  )
@@ -16,6 +17,7 @@ from kernels.utils import (
16
17
  __all__ = [
17
18
  "get_kernel",
18
19
  "get_locked_kernel",
20
+ "has_kernel",
19
21
  "load_kernel",
20
22
  "install_kernel",
21
23
  "use_kernel_forward_from_hub",
@@ -4,7 +4,7 @@ import warnings
4
4
  from contextvars import ContextVar
5
5
  from copy import deepcopy
6
6
  from dataclasses import dataclass, field
7
- from typing import TYPE_CHECKING, Callable, Dict, Union
7
+ from typing import TYPE_CHECKING, Dict, Union
8
8
 
9
9
  from .utils import get_kernel
10
10
 
@@ -131,12 +131,13 @@ def replace_kernel_forward_from_hub(cls, layer_name: str, *, use_fallback: bool
131
131
 
132
132
  fallback_forward = cls.forward
133
133
 
134
- cached_forward: Dict[LayerRepository, Callable] = {}
134
+ cached_layer: Dict[LayerRepository, nn.Module] = {}
135
135
 
136
136
  def forward(self, x, *args, **kwargs):
137
137
  if _DISABLE_KERNEL_MAPPING:
138
138
  return fallback_forward(self, x, *args, **kwargs)
139
139
 
140
+ needs_backward = self.training
140
141
  kernel = _KERNEL_MAPPING.get().get(layer_name)
141
142
  if kernel is None:
142
143
  warnings.warn(
@@ -162,9 +163,11 @@ def replace_kernel_forward_from_hub(cls, layer_name: str, *, use_fallback: bool
162
163
  return fallback_forward(self, x, *args, **kwargs)
163
164
 
164
165
  # Short-circuit if we already loaded the layer.
165
- layer_forward = cached_forward.get(repo, None)
166
- if layer_forward is not None:
167
- return layer_forward(self, x, *args, **kwargs)
166
+ layer = cached_layer.get(repo, None)
167
+ if layer is not None:
168
+ if needs_backward and not getattr(layer, "has_backward", True):
169
+ return fallback_forward(self, x, *args, **kwargs)
170
+ return layer.forward(self, x, *args, **kwargs)
168
171
 
169
172
  layer = _get_kernel_layer(
170
173
  repo_id=repo.repo_id,
@@ -180,10 +183,11 @@ def replace_kernel_forward_from_hub(cls, layer_name: str, *, use_fallback: bool
180
183
  finally:
181
184
  cls.forward = orig_forward
182
185
 
183
- layer_forward = layer.forward
184
- cached_forward[repo] = layer_forward
186
+ cached_layer[repo] = layer
185
187
 
186
- return layer_forward(self, x, *args, **kwargs)
188
+ if needs_backward and not getattr(layer, "has_backward", True):
189
+ return fallback_forward(self, x, *args, **kwargs)
190
+ return layer.forward(self, x, *args, **kwargs)
187
191
 
188
192
  cls.forward = forward
189
193
 
@@ -240,7 +244,8 @@ def _validate_layer(*, check_cls, cls):
240
244
  # ... or predefined member variables.
241
245
  torch_module_members = {name for name, _ in inspect.getmembers(nn.Module)}
242
246
  cls_members = {name for name, _ in inspect.getmembers(cls)}
243
- if cls_members - torch_module_members != set():
247
+ difference = cls_members - torch_module_members
248
+ if difference != set() and difference != {"has_backward"}:
244
249
  raise TypeError("Layer must not contain additional members.")
245
250
 
246
251
  # Check whether the forward signatures are similar.
@@ -13,7 +13,7 @@ from pathlib import Path
13
13
  from types import ModuleType
14
14
  from typing import Dict, List, Optional, Tuple
15
15
 
16
- from huggingface_hub import snapshot_download
16
+ from huggingface_hub import file_exists, snapshot_download
17
17
  from packaging.version import parse
18
18
 
19
19
  from kernels.lockfile import KernelLock, VariantLock
@@ -161,6 +161,29 @@ def get_kernel(repo_id: str, revision: str = "main") -> ModuleType:
161
161
  return import_from_path(package_name, package_path / package_name / "__init__.py")
162
162
 
163
163
 
164
+ def has_kernel(repo_id: str, revision: str = "main") -> bool:
165
+ """
166
+ Check whether a kernel build exists for the current environment
167
+ (Torch version and compute framework).
168
+ """
169
+ package_name = package_name_from_repo_id(repo_id)
170
+ variant = build_variant()
171
+ universal_variant = universal_build_variant()
172
+
173
+ if file_exists(
174
+ repo_id,
175
+ revision=revision,
176
+ filename=f"build/{universal_variant}/{package_name}/__init__.py",
177
+ ):
178
+ return True
179
+
180
+ return file_exists(
181
+ repo_id,
182
+ revision=revision,
183
+ filename=f"build/{variant}/{package_name}/__init__.py",
184
+ )
185
+
186
+
164
187
  def load_kernel(repo_id: str, *, lockfile: Optional[Path] = None) -> ModuleType:
165
188
  """
166
189
  Get a pre-downloaded, locked kernel.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: kernels
3
- Version: 0.4.3
3
+ Version: 0.4.4
4
4
  Summary: Download compute kernels
5
5
  Author-email: OlivierDehaene <olivier@huggingface.co>, Daniel de Kok <daniel@huggingface.co>, David Holtz <david@huggingface.co>, Nicolas Patry <nicolas@huggingface.co>
6
6
  License: Apache-2.0
@@ -15,6 +15,17 @@ Requires-Dist: torch; extra == "torch"
15
15
 
16
16
  # kernels
17
17
 
18
+ <div align="center">
19
+ <img src="https://github.com/user-attachments/assets/64a652f3-0cd3-4829-b3c1-df13f7933569" width="450" height="450" alt="kernel-builder logo">
20
+ <p align="center">
21
+ <a href="https://pypi.org/project/kernels"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/kernels"></a>
22
+ <a href="https://github.com/huggingface/kernels/tags"><img alt="GitHub tag" src="https://img.shields.io/github/v/tag/huggingface/kernels"></a>
23
+ <a href="https://github.com/huggingface/kernels/actions/workflows/docker-build-push.yaml"><img alt="Test kernels" src="https://img.shields.io/github/actions/workflow/status/huggingface/kernels/test.yml?label=test"></a>
24
+
25
+ </p>
26
+ </div>
27
+ <hr/>
28
+
18
29
  The Kernel Hub allows Python libraries and applications to load compute
19
30
  kernels directly from the [Hub](https://hf.co/). To support this kind
20
31
  of dynamic loading, Hub kernels differ from traditional Python kernel
@@ -1,7 +1,7 @@
1
1
  import pytest
2
2
  import torch
3
3
 
4
- from kernels import get_kernel
4
+ from kernels import get_kernel, has_kernel
5
5
 
6
6
 
7
7
  @pytest.fixture
@@ -36,6 +36,22 @@ def test_gelu_fast(kernel, device):
36
36
  assert torch.allclose(y, expected)
37
37
 
38
38
 
39
+ @pytest.mark.parametrize(
40
+ "kernel_exists",
41
+ [
42
+ ("kernels-community/activation", "main", True),
43
+ ("kernels-community/triton-layer-norm", "main", True),
44
+ # Repo only contains Torch 2.4 kernels (and we don't
45
+ # support/test against this version).
46
+ ("kernels-test/only-torch-2.4", "main", False),
47
+ ("google-bert/bert-base-uncased", "87565a309", False),
48
+ ],
49
+ )
50
+ def test_has_kernel(kernel_exists):
51
+ repo_id, revision, kernel = kernel_exists
52
+ assert has_kernel(repo_id, revision=revision) == kernel
53
+
54
+
39
55
  def test_universal_kernel(universal_kernel):
40
56
  torch.manual_seed(0)
41
57
  A = torch.randint(-10, 10, (64, 128), dtype=torch.int8, device="cuda")
@@ -203,3 +203,75 @@ def test_validate_kernel_layer():
203
203
 
204
204
  with pytest.raises(TypeError, match="different kind of arguments"):
205
205
  _validate_layer(cls=BadLayer4, check_cls=SiluAndMul)
206
+
207
+
208
+ def test_fallback_used_when_training():
209
+ @use_kernel_forward_from_hub("Linear")
210
+ class TorchLinear(nn.Linear):
211
+ def __init__(self, *args, **kwargs):
212
+ super().__init__(*args, **kwargs)
213
+ # Used to check that we called hub kernel.
214
+ self.n_calls = 0
215
+
216
+ def forward(self, input: torch.Tensor) -> torch.Tensor:
217
+ self.n_calls += 1
218
+ return super().forward(input)
219
+
220
+ linear = TorchLinear(32, 32).to("cuda")
221
+
222
+ with use_kernel_mapping(
223
+ {
224
+ "Linear": {
225
+ Device(type="cuda"): LayerRepository(
226
+ repo_id="kernels-test/backward-marker-test",
227
+ layer_name="LinearImplicitBackward",
228
+ )
229
+ }
230
+ }
231
+ ):
232
+ linear.train()
233
+ X = torch.randn(10, 32, device="cuda")
234
+ linear(X)
235
+ assert linear.n_calls == 0
236
+
237
+ linear.eval()
238
+ linear(X)
239
+ assert linear.n_calls == 0
240
+
241
+ with use_kernel_mapping(
242
+ {
243
+ "Linear": {
244
+ Device(type="cuda"): LayerRepository(
245
+ repo_id="kernels-test/backward-marker-test",
246
+ layer_name="LinearBackward",
247
+ )
248
+ }
249
+ }
250
+ ):
251
+ linear.train()
252
+ X = torch.randn(10, 32, device="cuda")
253
+ linear(X)
254
+ assert linear.n_calls == 0
255
+
256
+ linear.eval()
257
+ linear(X)
258
+ assert linear.n_calls == 0
259
+
260
+ with use_kernel_mapping(
261
+ {
262
+ "Linear": {
263
+ Device(type="cuda"): LayerRepository(
264
+ repo_id="kernels-test/backward-marker-test",
265
+ layer_name="LinearNoBackward",
266
+ )
267
+ }
268
+ }
269
+ ):
270
+ linear.train()
271
+ X = torch.randn(10, 32, device="cuda")
272
+ linear(X)
273
+ assert linear.n_calls == 1
274
+
275
+ linear.eval()
276
+ linear(X)
277
+ assert linear.n_calls == 1
File without changes
File without changes
File without changes
File without changes
File without changes