ninetoothed 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

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.
ninetoothed/jit.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import ast
2
+ import collections
2
3
  import functools
3
4
  import inspect
4
5
  import itertools
@@ -12,6 +13,67 @@ from ninetoothed.tensor import Tensor
12
13
  from ninetoothed.torchifier import Torchifier
13
14
 
14
15
 
16
+ def jit(func):
17
+ return JIT(func)()
18
+
19
+
20
+ class JIT:
21
+ handles = collections.defaultdict(dict)
22
+
23
+ def __init__(self, func):
24
+ self.func = func
25
+
26
+ def __call__(self):
27
+ source_file = inspect.getsourcefile(self.func)
28
+ source_line = inspect.getsourcelines(self.func)[1]
29
+
30
+ if (
31
+ source_file in type(self).handles
32
+ and source_line in type(self).handles[source_file]
33
+ ):
34
+ return type(self).handles[source_file][source_line]
35
+
36
+ source = textwrap.dedent(inspect.getsource(self.func))
37
+ tree = ast.parse(source)
38
+
39
+ CodeGenerator(inspect.get_annotations(self.func)).visit(tree)
40
+ Tritonizer().visit(tree)
41
+ ast.fix_missing_locations(tree)
42
+
43
+ unparsed = ast.unparse(tree).replace("None:", ":").replace(":None", ":")
44
+
45
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".py") as temp_file:
46
+ temp_file.write(unparsed.encode("utf-8"))
47
+ temp_file_name = temp_file.name
48
+
49
+ with open(temp_file_name, "r") as temp_file:
50
+ code = compile(
51
+ source=temp_file.read(),
52
+ filename=temp_file_name,
53
+ mode="exec",
54
+ )
55
+
56
+ namespace = {}
57
+ exec(code, namespace)
58
+
59
+ class Handle:
60
+ def __init__(self, kernel, launch):
61
+ self._kernel = kernel
62
+ self._launch = launch
63
+
64
+ def __call__(self, *args, **kwargs):
65
+ return self._launch(*args, **kwargs)
66
+
67
+ handle = Handle(
68
+ namespace[self.func.__name__],
69
+ namespace[f"launch_{self.func.__name__}"],
70
+ )
71
+
72
+ type(self).handles[source_file][source_line] = handle
73
+
74
+ return handle
75
+
76
+
15
77
  class CodeGenerator(ast.NodeTransformer):
16
78
  def __init__(self, context):
17
79
  super().__init__()
@@ -286,34 +348,3 @@ class Tritonizer(ast.NodeTransformer):
286
348
  )
287
349
 
288
350
  return node
289
-
290
-
291
- def jit(func):
292
- source = textwrap.dedent(inspect.getsource(func))
293
- tree = ast.parse(source)
294
-
295
- CodeGenerator(func.__annotations__).visit(tree)
296
- Tritonizer().visit(tree)
297
- ast.fix_missing_locations(tree)
298
-
299
- unparsed = ast.unparse(tree).replace("None:", ":").replace(":None", ":")
300
-
301
- with tempfile.NamedTemporaryFile(delete=False, suffix=".py") as temp_file:
302
- temp_file.write(unparsed.encode("utf-8"))
303
- temp_file_name = temp_file.name
304
-
305
- with open(temp_file_name, "r") as temp_file:
306
- code = compile(source=temp_file.read(), filename=temp_file_name, mode="exec")
307
-
308
- namespace = {}
309
- exec(code, namespace)
310
-
311
- class Handle:
312
- def __init__(self, kernel, launch):
313
- self._kernel = kernel
314
- self._launch = launch
315
-
316
- def __call__(self, *args, **kwargs):
317
- return self._launch(*args, **kwargs)
318
-
319
- return Handle(namespace[func.__name__], namespace[f"launch_{func.__name__}"])
ninetoothed/tensor.py CHANGED
@@ -46,7 +46,7 @@ class Tensor:
46
46
  new_size = call("cdiv", size, tile_size)
47
47
  outer_shape.append(new_size)
48
48
 
49
- new_stride = call("cdiv", stride * size, (new_size * tile_stride))
49
+ new_stride = stride * tile_size // tile_stride
50
50
  outer_strides.append(new_stride)
51
51
 
52
52
  inner_shape.append(tile_size)
@@ -0,0 +1,79 @@
1
+ Metadata-Version: 2.3
2
+ Name: ninetoothed
3
+ Version: 0.1.1
4
+ Summary: A domain-specific language based on Triton but providing higher-level abstraction.
5
+ Project-URL: Homepage, https://github.com/InfiniTensor/ninetoothed
6
+ Project-URL: Issues, https://github.com/InfiniTensor/ninetoothed/issues
7
+ Author-email: Jiacheng Huang <huangjiacheng0709@outlook.com>
8
+ License-File: LICENSE
9
+ Classifier: License :: OSI Approved :: Apache Software License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+
15
+ # NineToothed
16
+
17
+ A domain-specific language (DSL) based on Triton but providing higher-level abstractions.
18
+
19
+ **Other language versions: [English](README.md), [简体中文](docs/README.zh.md).**
20
+
21
+ ## Installation
22
+
23
+ We can use `pip` to install `ninetoothed`.
24
+
25
+ ```shell
26
+ pip install ninetoothed
27
+ ```
28
+
29
+ After successfully running the above command, `ninetoothed` will be installed. However, to fully utilize its capabilities, you also need to install `triton` and a deep learning framework supported by `ninetoothed`. For trial purposes, we recommend installing `triton` and `torch`.
30
+
31
+ ## Usage
32
+
33
+ Currently, we can use the `Tensor` and `Symbol` classes in the `ninetoothed` package to perform meta-operations like `tile` and `expand` to easily construct kernel functions. Below, we will use these features to create vector addition and matrix multiplication kernel functions.
34
+
35
+ ### Vector Addition
36
+
37
+ ```python
38
+ BLOCK_SIZE = Symbol("BLOCK_SIZE", meta=True)
39
+
40
+ @ninetoothed.jit
41
+ def add_kernel(
42
+ x: Tensor(1).tile((BLOCK_SIZE,)),
43
+ y: Tensor(1).tile((BLOCK_SIZE,)),
44
+ z: Tensor(1).tile((BLOCK_SIZE,)),
45
+ ):
46
+ z = x + y
47
+ ```
48
+
49
+ In this code, we first define `BLOCK_SIZE`, which is a `Symbol`. You can think of `"BLOCK_SIZE"` as its name. We see that `meta` is set to `True`, indicating to the compiler that it is a meta-parameter and its value can be determined by the compiler. The `Tensor(1)` constructs a one-dimensional tensor (vector), and `Tensor(1).tile((BLOCK_SIZE,))` means we want to create a vector and divide it into blocks of size `BLOCK_SIZE`. Suppose the size of this vector is `8192` and `BLOCK_SIZE` is `1024`, then the vector will be divided into `8` blocks, each of size `1024`.
50
+
51
+ By using type annotations, we tell the compiler that we will have three tensor parameters, which will be divided into blocks, and `x`, `y`, and `z` are these blocks. It's important to understand that `x`, `y`, and `z` are the blocks, not the tensors themselves. In the function body, `x`, `y`, and `z` are also the blocks. The rest is straightforward (only one line `z = x + y` left, haha), we add each block of `x` and `y` and store it in `z`. Since each block of the parameter tensors undergoes this operation, the addition is completed for the whole tensors as well.
52
+
53
+ ### Matrix Multiplication
54
+
55
+ ```python
56
+ BLOCK_SIZE_M = Symbol("BLOCK_SIZE_M", meta=True)
57
+ BLOCK_SIZE_N = Symbol("BLOCK_SIZE_N", meta=True)
58
+ BLOCK_SIZE_K = Symbol("BLOCK_SIZE_K", meta=True)
59
+
60
+ a_tiled = Tensor(2).tile((BLOCK_SIZE_M, BLOCK_SIZE_K)).tile((1, -1))
61
+ b_tiled = Tensor(2).tile((BLOCK_SIZE_K, BLOCK_SIZE_N)).tile((-1, 1))
62
+ c_tiled = Tensor(2).tile((BLOCK_SIZE_M, BLOCK_SIZE_N))
63
+
64
+ a_tiled = a_tiled.expand((-1, c_tiled.shape[1]))
65
+ b_tiled = b_tiled.expand((c_tiled.shape[0], -1))
66
+
67
+ @ninetoothed.jit
68
+ def matmul_kernel(a: a_tiled, b: b_tiled, c: c_tiled):
69
+ accumulator = ninetoothed.language.zeros(
70
+ c.shape, dtype=ninetoothed.language.float32
71
+ )
72
+ for k in range(a.shape[1]):
73
+ accumulator = ninetoothed.language.dot(a[0, k], b[k, 0], accumulator)
74
+ c = accumulator.to(ninetoothed.language.float16)
75
+ ```
76
+
77
+ For matrix multiplication, we also have three tensor parameters, but the tiling method is more complex than vector addition. We denote the three matrices as $A$, $B$, and $C$, where $A$ and $B$ are inputs, and $C$ is the output. Tiling $C$ is simple; we just need to divide it into blocks of size `(BLOCK_SIZE_M, BLOCK_SIZE_N)` by rows and columns. Once each block computes its result, the entire $C$ is computed. However, how should we tile $A$ and $B$? The answer is to introduce another meta-parameter `BLOCK_SIZE_K`. This way, we can divide $A$ into blocks of size `(BLOCK_SIZE_M, BLOCK_SIZE_K)` and $B$ into blocks of size `(BLOCK_SIZE_K, BLOCK_SIZE_N)`. However, for matrix multiplication, $A$ and $B$ do not correspond block by block; each row of $A$ needs to correspond to each column of $B$. Therefore, we need to further `tile` $A$ and $B$ by rows and columns, respectively. Up to this point, we have a set of row blocks of $A$ and column blocks of $B$. However, each row block of $A$ must correspond to every column block of $B$. This is where `expand` comes in. We `expand` the row blocks of $A$ along the columns to the number of columns of $C$ and the column blocks of $B$ along the rows to the number of rows of $C$. This way, we successfully tile $A$, $B$, and $C$.
78
+
79
+ With tiling done, the rest is simple. In the function body, we define an `accumulator` to accumulate intermediate results. We then iterate through the corresponding row blocks of $A$ and column blocks of B, multiplying them and accumulating the results in `accumulator`. Finally, we place the `accumulator` in the corresponding block of $C$. Since each block of the parameter tensors undergoes this operation, the multiplication is completed for the whole tensors as well.
@@ -0,0 +1,10 @@
1
+ ninetoothed/__init__.py,sha256=T5UJXlC-wbo8JKPbLUNT65Kccp12xP52WFV5FsugETI,147
2
+ ninetoothed/jit.py,sha256=DdRdZ7DhfZwJeS7AcO_RhD9TZcCebKI55V4_6UHs3bo,10523
3
+ ninetoothed/language.py,sha256=cSuTgi5OwmLFy-dy_AHGZzRm18wz01ByHQ2vioP1vTg,437
4
+ ninetoothed/symbol.py,sha256=8BI4ekeLuUdHTEREvMMlAzwrJ93pqiCdSHGc38clBFA,3034
5
+ ninetoothed/tensor.py,sha256=o_HLEuaBzojmbMLnbPGLcw4iqBI34TNdES3YLTagztE,4590
6
+ ninetoothed/torchifier.py,sha256=JmIVQE8r0zr_RLExsRDOGNsMu0F7v6J_o22aWqlw81k,841
7
+ ninetoothed-0.1.1.dist-info/METADATA,sha256=1Nv6Xcz7CrpEUrzAYH93bYVX8GfPtHwzj4yofeaoJro,5422
8
+ ninetoothed-0.1.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
9
+ ninetoothed-0.1.1.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
10
+ ninetoothed-0.1.1.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: ninetoothed
3
- Version: 0.1.0
4
- Summary: A domain-specific language based on Triton but providing higher-level abstraction.
5
- Project-URL: Homepage, https://github.com/InfiniTensor/ninetoothed
6
- Project-URL: Issues, https://github.com/InfiniTensor/ninetoothed/issues
7
- Author-email: Jiacheng Huang <huangjiacheng0709@outlook.com>
8
- License-File: LICENSE
9
- Classifier: License :: OSI Approved :: Apache Software License
10
- Classifier: Operating System :: OS Independent
11
- Classifier: Programming Language :: Python :: 3
12
- Requires-Python: >=3.10
13
- Description-Content-Type: text/markdown
14
-
15
- # Nine-Toothed
16
-
17
- A domain-specific language based on Triton but providing higher-level abstraction.
18
-
19
- **Read this in other languages: [English](README.md), [简体中文](docs/README.zh.md).**
@@ -1,10 +0,0 @@
1
- ninetoothed/__init__.py,sha256=T5UJXlC-wbo8JKPbLUNT65Kccp12xP52WFV5FsugETI,147
2
- ninetoothed/jit.py,sha256=mnBtsrD84usfYEozAclKBqW3Rrl1OEAolhsKRvrOTKU,9735
3
- ninetoothed/language.py,sha256=cSuTgi5OwmLFy-dy_AHGZzRm18wz01ByHQ2vioP1vTg,437
4
- ninetoothed/symbol.py,sha256=8BI4ekeLuUdHTEREvMMlAzwrJ93pqiCdSHGc38clBFA,3034
5
- ninetoothed/tensor.py,sha256=RMHgADBTdj5Q18Ttre4baq6tG_mqC4VrSn0AV6BL6VQ,4610
6
- ninetoothed/torchifier.py,sha256=JmIVQE8r0zr_RLExsRDOGNsMu0F7v6J_o22aWqlw81k,841
7
- ninetoothed-0.1.0.dist-info/METADATA,sha256=uM1Bs_zmjwgGtWJMBKejFRyiC0jO209PHS33btFMTGA,783
8
- ninetoothed-0.1.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
9
- ninetoothed-0.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
10
- ninetoothed-0.1.0.dist-info/RECORD,,