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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gpuarray
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: NumPy-like GPU array library that works on every GPU — NVIDIA, AMD, Intel, Apple Silicon. No CUDA required.
5
5
  Author: Arnav Kewalram
6
6
  License: MIT
@@ -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()