gpuarray 0.1.0__tar.gz → 0.3.0__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.
- {gpuarray-0.1.0 → gpuarray-0.3.0}/PKG-INFO +1 -1
- {gpuarray-0.1.0 → gpuarray-0.3.0}/gpuarray/__init__.py +14 -0
- gpuarray-0.3.0/gpuarray/api.py +182 -0
- gpuarray-0.3.0/gpuarray/core.py +737 -0
- gpuarray-0.3.0/gpuarray/shaders.py +881 -0
- {gpuarray-0.1.0 → gpuarray-0.3.0}/gpuarray.egg-info/PKG-INFO +1 -1
- {gpuarray-0.1.0 → gpuarray-0.3.0}/pyproject.toml +1 -1
- gpuarray-0.3.0/tests/test_core.py +559 -0
- gpuarray-0.1.0/gpuarray/api.py +0 -99
- gpuarray-0.1.0/gpuarray/core.py +0 -402
- gpuarray-0.1.0/gpuarray/shaders.py +0 -426
- gpuarray-0.1.0/tests/test_core.py +0 -227
- {gpuarray-0.1.0 → gpuarray-0.3.0}/README.md +0 -0
- {gpuarray-0.1.0 → gpuarray-0.3.0}/gpuarray/device.py +0 -0
- {gpuarray-0.1.0 → gpuarray-0.3.0}/gpuarray.egg-info/SOURCES.txt +0 -0
- {gpuarray-0.1.0 → gpuarray-0.3.0}/gpuarray.egg-info/dependency_links.txt +0 -0
- {gpuarray-0.1.0 → gpuarray-0.3.0}/gpuarray.egg-info/requires.txt +0 -0
- {gpuarray-0.1.0 → gpuarray-0.3.0}/gpuarray.egg-info/top_level.txt +0 -0
- {gpuarray-0.1.0 → gpuarray-0.3.0}/setup.cfg +0 -0
|
@@ -20,6 +20,13 @@ from .api import (
|
|
|
20
20
|
relu,
|
|
21
21
|
sigmoid,
|
|
22
22
|
tanh,
|
|
23
|
+
where,
|
|
24
|
+
clip,
|
|
25
|
+
argmax,
|
|
26
|
+
argmin,
|
|
27
|
+
concatenate,
|
|
28
|
+
stack,
|
|
29
|
+
random,
|
|
23
30
|
)
|
|
24
31
|
|
|
25
32
|
__version__ = "0.1.0"
|
|
@@ -44,4 +51,11 @@ __all__ = [
|
|
|
44
51
|
"relu",
|
|
45
52
|
"sigmoid",
|
|
46
53
|
"tanh",
|
|
54
|
+
"where",
|
|
55
|
+
"clip",
|
|
56
|
+
"argmax",
|
|
57
|
+
"argmin",
|
|
58
|
+
"concatenate",
|
|
59
|
+
"stack",
|
|
60
|
+
"random",
|
|
47
61
|
]
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""NumPy-compatible module-level functions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Sequence
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from .core import GPUArray, _from_numpy, matmul as _matmul
|
|
10
|
+
from . import shaders
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# ----- creation functions -----
|
|
14
|
+
|
|
15
|
+
def array(data) -> GPUArray:
|
|
16
|
+
"""Create a GPUArray from a list, nested list, or numpy array."""
|
|
17
|
+
if isinstance(data, GPUArray):
|
|
18
|
+
return data
|
|
19
|
+
arr = np.asarray(data, dtype=np.float32)
|
|
20
|
+
if arr.ndim == 0:
|
|
21
|
+
arr = arr.reshape((1,))
|
|
22
|
+
return _from_numpy(arr)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def zeros(shape) -> GPUArray:
|
|
26
|
+
if isinstance(shape, int):
|
|
27
|
+
shape = (shape,)
|
|
28
|
+
return _from_numpy(np.zeros(shape, dtype=np.float32))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def ones(shape) -> GPUArray:
|
|
32
|
+
if isinstance(shape, int):
|
|
33
|
+
shape = (shape,)
|
|
34
|
+
return _from_numpy(np.ones(shape, dtype=np.float32))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def arange(start, stop=None, step=1) -> GPUArray:
|
|
38
|
+
if stop is None:
|
|
39
|
+
stop = start
|
|
40
|
+
start = 0
|
|
41
|
+
return _from_numpy(np.arange(start, stop, step, dtype=np.float32))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def linspace(start, stop, num=50) -> GPUArray:
|
|
45
|
+
return _from_numpy(np.linspace(start, stop, num, dtype=np.float32))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ----- operations -----
|
|
49
|
+
|
|
50
|
+
def dot(a: GPUArray, b: GPUArray):
|
|
51
|
+
return a.dot(b)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def matmul(a: GPUArray, b: GPUArray) -> GPUArray:
|
|
55
|
+
return _matmul(a, b)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def sum(a: GPUArray) -> float:
|
|
59
|
+
return a.sum()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def mean(a: GPUArray) -> float:
|
|
63
|
+
return a.mean()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def exp(a: GPUArray) -> GPUArray:
|
|
67
|
+
return a._run_unary_op(shaders.EXP_SHADER)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def log(a: GPUArray) -> GPUArray:
|
|
71
|
+
return a._run_unary_op(shaders.LOG_SHADER)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def sqrt(a: GPUArray) -> GPUArray:
|
|
75
|
+
return a._run_unary_op(shaders.SQRT_SHADER)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def abs(a: GPUArray) -> GPUArray:
|
|
79
|
+
return a._run_unary_op(shaders.ABS_SHADER)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def max(a: GPUArray) -> float:
|
|
83
|
+
return a.max()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def min(a: GPUArray) -> float:
|
|
87
|
+
return a.min()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def relu(a: GPUArray) -> GPUArray:
|
|
91
|
+
return a._run_unary_op(shaders.RELU_SHADER)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def sigmoid(a: GPUArray) -> GPUArray:
|
|
95
|
+
return a._run_unary_op(shaders.SIGMOID_SHADER)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def tanh(a: GPUArray) -> GPUArray:
|
|
99
|
+
return a._run_unary_op(shaders.TANH_SHADER)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# ----- new operations -----
|
|
103
|
+
|
|
104
|
+
def where(condition: GPUArray, x: GPUArray, y: GPUArray) -> GPUArray:
|
|
105
|
+
"""Conditional select: where condition is 1.0, pick x; else pick y."""
|
|
106
|
+
import wgpu
|
|
107
|
+
from .device import get_device
|
|
108
|
+
from .core import _get_pipeline
|
|
109
|
+
|
|
110
|
+
assert condition.size == x.size == y.size
|
|
111
|
+
device = get_device()
|
|
112
|
+
_, pipeline = _get_pipeline(shaders.WHERE_SHADER)
|
|
113
|
+
|
|
114
|
+
out_buf = device.create_buffer(
|
|
115
|
+
size=condition.size * 4,
|
|
116
|
+
usage=wgpu.BufferUsage.STORAGE | wgpu.BufferUsage.COPY_SRC | wgpu.BufferUsage.COPY_DST,
|
|
117
|
+
)
|
|
118
|
+
bind_group = device.create_bind_group(
|
|
119
|
+
layout=pipeline.get_bind_group_layout(0),
|
|
120
|
+
entries=[
|
|
121
|
+
{"binding": 0, "resource": {"buffer": condition._buffer, "offset": 0, "size": condition.size * 4}},
|
|
122
|
+
{"binding": 1, "resource": {"buffer": x._buffer, "offset": 0, "size": x.size * 4}},
|
|
123
|
+
{"binding": 2, "resource": {"buffer": y._buffer, "offset": 0, "size": y.size * 4}},
|
|
124
|
+
{"binding": 3, "resource": {"buffer": out_buf, "offset": 0, "size": condition.size * 4}},
|
|
125
|
+
],
|
|
126
|
+
)
|
|
127
|
+
import math
|
|
128
|
+
n_workgroups = math.ceil(condition.size / 256)
|
|
129
|
+
encoder = device.create_command_encoder()
|
|
130
|
+
pass_enc = encoder.begin_compute_pass()
|
|
131
|
+
pass_enc.set_pipeline(pipeline)
|
|
132
|
+
pass_enc.set_bind_group(0, bind_group)
|
|
133
|
+
pass_enc.dispatch_workgroups(n_workgroups)
|
|
134
|
+
pass_enc.end()
|
|
135
|
+
device.queue.submit([encoder.finish()])
|
|
136
|
+
return GPUArray(out_buf, condition._shape)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def clip(a: GPUArray, min_val: float, max_val: float) -> GPUArray:
|
|
140
|
+
"""Clamp values to [min_val, max_val]."""
|
|
141
|
+
return a.clip(min_val, max_val)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def argmax(a: GPUArray) -> int:
|
|
145
|
+
"""Return index of maximum value."""
|
|
146
|
+
return a.argmax()
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def argmin(a: GPUArray) -> int:
|
|
150
|
+
"""Return index of minimum value."""
|
|
151
|
+
return a.argmin()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def concatenate(arrays, axis: int = 0) -> GPUArray:
|
|
155
|
+
"""Join arrays along an axis (CPU-side, creates new GPU buffer)."""
|
|
156
|
+
np_arrays = [a.to_numpy() for a in arrays]
|
|
157
|
+
result = np.concatenate(np_arrays, axis=axis)
|
|
158
|
+
return _from_numpy(result)
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def stack(arrays, axis: int = 0) -> GPUArray:
|
|
162
|
+
"""Stack arrays along a new axis (CPU-side, creates new GPU buffer)."""
|
|
163
|
+
np_arrays = [a.to_numpy() for a in arrays]
|
|
164
|
+
result = np.stack(np_arrays, axis=axis)
|
|
165
|
+
return _from_numpy(result)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ----- random submodule -----
|
|
169
|
+
|
|
170
|
+
class _Random:
|
|
171
|
+
"""Random array generation (CPU-side, uploaded to GPU)."""
|
|
172
|
+
|
|
173
|
+
def rand(self, *shape) -> GPUArray:
|
|
174
|
+
"""Uniform random values in [0, 1)."""
|
|
175
|
+
return _from_numpy(np.random.rand(*shape).astype(np.float32))
|
|
176
|
+
|
|
177
|
+
def randn(self, *shape) -> GPUArray:
|
|
178
|
+
"""Standard normal random values."""
|
|
179
|
+
return _from_numpy(np.random.randn(*shape).astype(np.float32))
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
random = _Random()
|