gradix 0.1.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.
gradix-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gradix contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
gradix-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,312 @@
1
+ Metadata-Version: 2.4
2
+ Name: gradix
3
+ Version: 0.1.0
4
+ Summary: A lightweight NumPy-based automatic differentiation and deep learning library
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: numpy>=1.24
10
+ Requires-Dist: graphviz>=0.20
11
+ Requires-Dist: matplotlib>=3.8
12
+ Provides-Extra: gpu
13
+ Requires-Dist: cupy-cuda12x>=12; extra == "gpu"
14
+ Provides-Extra: all
15
+ Requires-Dist: cupy-cuda12x>=12; extra == "all"
16
+ Requires-Dist: graphviz>=0.20; extra == "all"
17
+ Requires-Dist: matplotlib>=3.8; extra == "all"
18
+ Dynamic: license-file
19
+
20
+ # Gradix
21
+
22
+ Gradix is a small, educational deep-learning engine built around a `Tensor` class and automatic differentiation. It lets you compose tensor operations, build neural-network layers, calculate gradients with `backward()`, and update parameters with SGD.
23
+
24
+ The project is intentionally compact and is useful for learning how computation graphs and training loops fit together. It is not a drop-in replacement for PyTorch or another production deep-learning framework.
25
+
26
+ ## What You Can Do
27
+
28
+ - Create tensors and combine them with arithmetic, matrix multiplication, reductions, and activations.
29
+ - Track operations in a computation graph and calculate gradients with backpropagation.
30
+ - Build models with `Linear` and `Conv2D` modules.
31
+ - Calculate classification loss with `cross_entropy` and update parameters with `SGD`.
32
+ - Visualize a tensor's computation graph with Graphviz.
33
+
34
+ ## Install
35
+
36
+ Gradix requires Python 3.10 or newer. Install the published package and its required Python dependencies with:
37
+
38
+ ```bash
39
+ pip install gradix
40
+ ```
41
+
42
+ The base installation includes NumPy, the Python Graphviz binding, and Matplotlib. Graph rendering also requires the Graphviz system executable (`dot`), which must be installed separately through your operating system's package manager.
43
+
44
+ For example, on Ubuntu or Debian:
45
+
46
+ ```bash
47
+ sudo apt install graphviz
48
+ ```
49
+
50
+ CuPy is optional. The `gpu` extra currently requests the CUDA 12.x CuPy build:
51
+
52
+ ```bash
53
+ pip install "gradix[gpu]"
54
+ ```
55
+
56
+ You also need a compatible NVIDIA driver and CUDA setup. CPU usage is the recommended path for the current version; CUDA support is experimental, and some operations, particularly Conv2D's patch-index creation, still use NumPy internally.
57
+
58
+ ### Install From a Local Checkout
59
+
60
+ When working in a clone of this repository, install the current source in editable mode:
61
+
62
+ ```bash
63
+ python -m pip install -e .
64
+ ```
65
+
66
+ This makes `import gradix` work from that Python environment without adding `src` to `sys.path` manually. In Jupyter, choose the same environment as the notebook kernel.
67
+
68
+ ## Your First Tensor
69
+
70
+ ```python
71
+ from gradix import Tensor
72
+
73
+ left = Tensor([1.0, 2.0, 3.0], requires_grad=True, name="left input")
74
+ right = Tensor([4.0, 5.0, 6.0], requires_grad=True, name="right input")
75
+
76
+ result = (left * right).sum()
77
+ result.backward()
78
+
79
+ print(result.data) # 32.0
80
+ print(left.grad) # [4. 5. 6.]
81
+ print(right.grad) # [1. 2. 3.]
82
+ ```
83
+
84
+ `requires_grad=True` asks Gradix to track operations that contribute to that tensor. Calling `backward()` on a result propagates its gradient backward through those operations. Gradients are stored in each participating tensor's `.grad` attribute.
85
+
86
+ Tensor names can be assigned at construction or afterward. Any non-`None` value is converted to a string:
87
+
88
+ ```python
89
+ image = Tensor([0.0, 1.0], name=1)
90
+ image.name = 2.5
91
+ assert image.name == "2.5"
92
+ ```
93
+
94
+ ## Public Imports
95
+
96
+ Gradix re-exports common classes at convenient package levels:
97
+
98
+ ```python
99
+ from gradix import Tensor
100
+ from gradix.nn import Linear, Conv2D, cross_entropy, SGD
101
+ from gradix.nn.modules import Module, Linear, Conv2D, Upsample
102
+ from gradix.nn.loss import cross_entropy
103
+ from gradix.nn.optim import SGD
104
+ ```
105
+
106
+ ## How Backpropagation Flows
107
+
108
+ Each operation creates a result tensor that remembers its input tensors and a local backward function. For example, matrix multiplication records its operands. When `backward()` is called, Gradix traverses the graph and applies those local derivatives from the output toward the inputs.
109
+
110
+ ```mermaid
111
+ flowchart LR
112
+ A[Input a] --> M[Multiply]
113
+ B[Input b] --> M
114
+ M --> S[Sum]
115
+ S --> L[Scalar loss]
116
+ L -->|backward| S
117
+ S --> M
118
+ M --> GA[Gradient for a]
119
+ M --> GB[Gradient for b]
120
+ ```
121
+
122
+ The core idea in code is:
123
+
124
+ ```python
125
+ prediction = model(batch)
126
+ loss = cross_entropy(prediction, targets)
127
+ optimizer.zero_grad()
128
+ loss.backward()
129
+ optimizer.step()
130
+ ```
131
+
132
+ `zero_grad()` clears gradients from the previous batch. `backward()` calculates gradients for this batch. `step()` uses those gradients to update parameters.
133
+
134
+ ## Visualize a Computation Graph
135
+
136
+ The graph examples in `demos/digraph_test.ipynb` build longer expressions and ask Graphviz to display their operation dependencies. Here is a smaller version:
137
+
138
+ ```python
139
+ from gradix import Tensor
140
+ from gradix.utils import visualize_computation_graph
141
+
142
+ a = Tensor(1.0, requires_grad=True, name="a")
143
+ b = Tensor(2.0, requires_grad=True, name="b")
144
+ c = Tensor(3.0, requires_grad=True, name="c")
145
+
146
+ result = (a + b) * c
147
+ result.backward()
148
+
149
+ graph = visualize_computation_graph(
150
+ result,
151
+ filename="example_graph",
152
+ c_view_options=["data", "grad"],
153
+ )
154
+ graph
155
+ ```
156
+
157
+ Each box represents a tensor and each ellipse represents an operation. Edges connect an operation to its result and its inputs. Tensor names, shapes, scalar data, and scalar gradients can help identify nodes. Graphviz's `dot` executable must be installed for rendering.
158
+
159
+ The attention-style example in `demos/digraph_test.ipynb` follows this flow:
160
+
161
+ 1. Create input and weight tensors for query, key, value, and projection operations.
162
+ 2. Compute query-key scores with matrix multiplication and a transpose.
163
+ 3. Apply a numerically stabilized softmax using max, exponentiation, and sum.
164
+ 4. Multiply attention weights by values, then apply a projection.
165
+ 5. Add a residual connection and normalize using mean and variance operations.
166
+ 6. Pass through a small MLP, combine the residual output, reduce to a scalar loss, and visualize the full graph.
167
+
168
+ The notebook also builds a recurrent, gated sequence example. Each time-step appends more operations to the same graph through the hidden state; reducing the final hidden state to a scalar and visualizing it shows how dependencies span time steps.
169
+
170
+ `demos/demo.ipynb` contains a smaller arithmetic graph. The corresponding examples are notebooks, so run cells from top to bottom after installing Gradix and Graphviz.
171
+
172
+ ## Define a Model
173
+
174
+ Models subclass `Module`, implement `forward`, and return all trainable tensors from `parameters`. The `Linear` layer accepts a batch whose last dimension matches `in_features`.
175
+
176
+ ```python
177
+ from gradix.nn.modules import Linear, Module
178
+
179
+
180
+ class SmallClassifier(Module):
181
+ def __init__(self):
182
+ self.hidden = Linear(784, 128, bias=True)
183
+ self.output = Linear(128, 10, bias=True)
184
+
185
+ def parameters(self):
186
+ return self.hidden.parameters() + self.output.parameters()
187
+
188
+ def forward(self, x):
189
+ x = x.reshape(x.shape[0], 784)
190
+ x = self.hidden(x).relu()
191
+ return self.output(x)
192
+ ```
193
+
194
+ The MNIST examples in `demos/MnistModel.py` show two model shapes:
195
+
196
+ - `MNISTModel`: flatten each 28-by-28 image, apply a 784-to-128 linear layer with ReLU, then produce 10 class scores.
197
+ - `MNISTConvModel`: reshape to `(batch, 1, 28, 28)`, apply three Conv2D layers with ReLU, flatten the result, and produce 10 class scores.
198
+
199
+ The convolutional model's `parameters()` method combines the parameters from each child layer. Gradix modules do not currently automatically register nested modules, so a custom model should explicitly return its parameters as above.
200
+
201
+ ## Train a Model
202
+
203
+ Gradix's `cross_entropy` expects logits shaped `(batch, classes)` and integer class labels in a target tensor. The targets do not need gradients. This self-contained example demonstrates the same batch flow used in `demos/train.ipynb` without downloading a dataset:
204
+
205
+ ```python
206
+ import numpy as np
207
+
208
+ from gradix import Tensor
209
+ from gradix.nn.loss import cross_entropy
210
+ from gradix.nn.modules import Linear, Module
211
+ from gradix.nn.optim import SGD
212
+
213
+
214
+ class TinyClassifier(Module):
215
+ def __init__(self):
216
+ self.layer = Linear(2, 2, bias=True)
217
+
218
+ def parameters(self):
219
+ return self.layer.parameters()
220
+
221
+ def forward(self, x):
222
+ return self.layer(x)
223
+
224
+
225
+ x = Tensor(np.array([[1, 0], [0, 1], [1, 1], [0, 0]], dtype=np.float32))
226
+ targets = Tensor(np.array([0, 1, 0, 1]))
227
+
228
+ model = TinyClassifier()
229
+ optimizer = SGD(model.parameters(), lr=0.1)
230
+
231
+ for step in range(20):
232
+ logits = model(x)
233
+ loss = cross_entropy(logits, targets)
234
+
235
+ optimizer.zero_grad()
236
+ loss.backward()
237
+ optimizer.step()
238
+
239
+ print(f"step {step + 1}: loss={float(loss.data):.4f}")
240
+ ```
241
+
242
+ In each step, the model produces one score per class, cross-entropy compares those scores with the labels, and backpropagation computes parameter gradients. SGD then updates the parameters. This is a minimal educational loop; it does not include features such as batching helpers, schedulers, regularization, checkpointing, or automatic device placement.
243
+
244
+ ## MNIST Notebook Workflow
245
+
246
+ `demos/train.ipynb` demonstrates the larger workflow:
247
+
248
+ 1. Load MNIST with scikit-learn's `fetch_openml` and split pixels and labels into training, validation, and test sets.
249
+ 2. Convert pixel arrays to `float32`, scale pixels into the 0-to-1 range, and convert labels to integers.
250
+ 3. Create `MNISTModel` or `MNISTConvModel`, then pass `model.parameters()` to `SGD`.
251
+ 4. Iterate over mini-batches. For each batch, create input and target tensors, run the model, calculate cross-entropy, clear gradients, call `backward()`, and update parameters.
252
+ 5. Calculate validation loss without calling `backward()`, then evaluate on the test data after training.
253
+ 6. Plot training and validation loss with Matplotlib and optionally visualize the model's graph.
254
+
255
+ The notebook uses additional packages for the example workflow. Install them in the notebook's Python environment if they are not already present:
256
+
257
+ ```bash
258
+ python -m pip install scikit-learn tqdm
259
+ ```
260
+
261
+ Matplotlib is already a required Gradix dependency. Fetching MNIST requires an internet connection the first time. Training the full dataset, particularly with the pure-Python Conv2D implementation, may take a while.
262
+
263
+ ## API at a Glance
264
+
265
+ | API | Purpose |
266
+ | --- | --- |
267
+ | `Tensor(data, requires_grad=False, name=None)` | Store array data and optionally track gradients. |
268
+ | `tensor.backward()` | Compute gradients from a scalar result back through its graph. |
269
+ | `tensor.zero_grad()` | Clear gradients in the tensor's graph. |
270
+ | `Module` | Base class for models with `forward()` and `parameters()`. |
271
+ | `Linear(in_features, out_features, bias=False)` | Fully connected transformation. |
272
+ | `Conv2D(in_channels, out_channels, kernel, stride=1, padding=0, use_bias=False)` | Two-dimensional convolution. |
273
+ | `cross_entropy(logits, targets)` | Mean multiclass cross-entropy for integer class labels. |
274
+ | `SGD(parameters, lr=0.001)` | Basic stochastic gradient descent optimizer. |
275
+ | `visualize_computation_graph(tensor, ...)` | Return or render the tensor's operation graph. |
276
+
277
+ ## Project Layout
278
+
279
+ ```text
280
+ src/gradix/ Library implementation
281
+ tensor.py Tensor and automatic differentiation
282
+ nn/ Functions, modules, losses, and optimizer
283
+ demos/MnistModel.py Example fully connected and convolutional models
284
+ demos/demo.ipynb Small tensor and graph examples
285
+ demos/digraph_test.ipynb Attention-style and recurrent graph examples
286
+ demos/train.ipynb MNIST data preparation, training, and evaluation
287
+ tests/test_conv2d.py Conv2D comparison against PyTorch
288
+ ```
289
+
290
+ ## Development Checks
291
+
292
+ Install the project and run the Conv2D comparison from the repository root:
293
+
294
+ ```bash
295
+ python -m pip install -e .
296
+ python -m pip install torch
297
+ PYTHONPATH=src python tests/test_conv2d.py
298
+ ```
299
+
300
+ The test uses PyTorch only as a reference implementation. The library itself does not depend on PyTorch.
301
+
302
+ ## Current Limitations
303
+
304
+ - Gradix is educational software and implements a small subset of tensor and neural-network functionality.
305
+ - CPU execution is the most suitable current path. CUDA support is experimental; Conv2D currently constructs some intermediate indices with NumPy and has not been validated on a real CUDA device.
306
+ - Models explicitly implement `parameters()`; nested layers are not automatically discovered.
307
+ - Dataset loading and notebook conveniences such as scikit-learn and tqdm are separate from the core package dependencies.
308
+ - The Graphviz Python package does not include the Graphviz system executable.
309
+
310
+ ## License
311
+
312
+ See [LICENSE](LICENSE).
gradix-0.1.0/README.md ADDED
@@ -0,0 +1,293 @@
1
+ # Gradix
2
+
3
+ Gradix is a small, educational deep-learning engine built around a `Tensor` class and automatic differentiation. It lets you compose tensor operations, build neural-network layers, calculate gradients with `backward()`, and update parameters with SGD.
4
+
5
+ The project is intentionally compact and is useful for learning how computation graphs and training loops fit together. It is not a drop-in replacement for PyTorch or another production deep-learning framework.
6
+
7
+ ## What You Can Do
8
+
9
+ - Create tensors and combine them with arithmetic, matrix multiplication, reductions, and activations.
10
+ - Track operations in a computation graph and calculate gradients with backpropagation.
11
+ - Build models with `Linear` and `Conv2D` modules.
12
+ - Calculate classification loss with `cross_entropy` and update parameters with `SGD`.
13
+ - Visualize a tensor's computation graph with Graphviz.
14
+
15
+ ## Install
16
+
17
+ Gradix requires Python 3.10 or newer. Install the published package and its required Python dependencies with:
18
+
19
+ ```bash
20
+ pip install gradix
21
+ ```
22
+
23
+ The base installation includes NumPy, the Python Graphviz binding, and Matplotlib. Graph rendering also requires the Graphviz system executable (`dot`), which must be installed separately through your operating system's package manager.
24
+
25
+ For example, on Ubuntu or Debian:
26
+
27
+ ```bash
28
+ sudo apt install graphviz
29
+ ```
30
+
31
+ CuPy is optional. The `gpu` extra currently requests the CUDA 12.x CuPy build:
32
+
33
+ ```bash
34
+ pip install "gradix[gpu]"
35
+ ```
36
+
37
+ You also need a compatible NVIDIA driver and CUDA setup. CPU usage is the recommended path for the current version; CUDA support is experimental, and some operations, particularly Conv2D's patch-index creation, still use NumPy internally.
38
+
39
+ ### Install From a Local Checkout
40
+
41
+ When working in a clone of this repository, install the current source in editable mode:
42
+
43
+ ```bash
44
+ python -m pip install -e .
45
+ ```
46
+
47
+ This makes `import gradix` work from that Python environment without adding `src` to `sys.path` manually. In Jupyter, choose the same environment as the notebook kernel.
48
+
49
+ ## Your First Tensor
50
+
51
+ ```python
52
+ from gradix import Tensor
53
+
54
+ left = Tensor([1.0, 2.0, 3.0], requires_grad=True, name="left input")
55
+ right = Tensor([4.0, 5.0, 6.0], requires_grad=True, name="right input")
56
+
57
+ result = (left * right).sum()
58
+ result.backward()
59
+
60
+ print(result.data) # 32.0
61
+ print(left.grad) # [4. 5. 6.]
62
+ print(right.grad) # [1. 2. 3.]
63
+ ```
64
+
65
+ `requires_grad=True` asks Gradix to track operations that contribute to that tensor. Calling `backward()` on a result propagates its gradient backward through those operations. Gradients are stored in each participating tensor's `.grad` attribute.
66
+
67
+ Tensor names can be assigned at construction or afterward. Any non-`None` value is converted to a string:
68
+
69
+ ```python
70
+ image = Tensor([0.0, 1.0], name=1)
71
+ image.name = 2.5
72
+ assert image.name == "2.5"
73
+ ```
74
+
75
+ ## Public Imports
76
+
77
+ Gradix re-exports common classes at convenient package levels:
78
+
79
+ ```python
80
+ from gradix import Tensor
81
+ from gradix.nn import Linear, Conv2D, cross_entropy, SGD
82
+ from gradix.nn.modules import Module, Linear, Conv2D, Upsample
83
+ from gradix.nn.loss import cross_entropy
84
+ from gradix.nn.optim import SGD
85
+ ```
86
+
87
+ ## How Backpropagation Flows
88
+
89
+ Each operation creates a result tensor that remembers its input tensors and a local backward function. For example, matrix multiplication records its operands. When `backward()` is called, Gradix traverses the graph and applies those local derivatives from the output toward the inputs.
90
+
91
+ ```mermaid
92
+ flowchart LR
93
+ A[Input a] --> M[Multiply]
94
+ B[Input b] --> M
95
+ M --> S[Sum]
96
+ S --> L[Scalar loss]
97
+ L -->|backward| S
98
+ S --> M
99
+ M --> GA[Gradient for a]
100
+ M --> GB[Gradient for b]
101
+ ```
102
+
103
+ The core idea in code is:
104
+
105
+ ```python
106
+ prediction = model(batch)
107
+ loss = cross_entropy(prediction, targets)
108
+ optimizer.zero_grad()
109
+ loss.backward()
110
+ optimizer.step()
111
+ ```
112
+
113
+ `zero_grad()` clears gradients from the previous batch. `backward()` calculates gradients for this batch. `step()` uses those gradients to update parameters.
114
+
115
+ ## Visualize a Computation Graph
116
+
117
+ The graph examples in `demos/digraph_test.ipynb` build longer expressions and ask Graphviz to display their operation dependencies. Here is a smaller version:
118
+
119
+ ```python
120
+ from gradix import Tensor
121
+ from gradix.utils import visualize_computation_graph
122
+
123
+ a = Tensor(1.0, requires_grad=True, name="a")
124
+ b = Tensor(2.0, requires_grad=True, name="b")
125
+ c = Tensor(3.0, requires_grad=True, name="c")
126
+
127
+ result = (a + b) * c
128
+ result.backward()
129
+
130
+ graph = visualize_computation_graph(
131
+ result,
132
+ filename="example_graph",
133
+ c_view_options=["data", "grad"],
134
+ )
135
+ graph
136
+ ```
137
+
138
+ Each box represents a tensor and each ellipse represents an operation. Edges connect an operation to its result and its inputs. Tensor names, shapes, scalar data, and scalar gradients can help identify nodes. Graphviz's `dot` executable must be installed for rendering.
139
+
140
+ The attention-style example in `demos/digraph_test.ipynb` follows this flow:
141
+
142
+ 1. Create input and weight tensors for query, key, value, and projection operations.
143
+ 2. Compute query-key scores with matrix multiplication and a transpose.
144
+ 3. Apply a numerically stabilized softmax using max, exponentiation, and sum.
145
+ 4. Multiply attention weights by values, then apply a projection.
146
+ 5. Add a residual connection and normalize using mean and variance operations.
147
+ 6. Pass through a small MLP, combine the residual output, reduce to a scalar loss, and visualize the full graph.
148
+
149
+ The notebook also builds a recurrent, gated sequence example. Each time-step appends more operations to the same graph through the hidden state; reducing the final hidden state to a scalar and visualizing it shows how dependencies span time steps.
150
+
151
+ `demos/demo.ipynb` contains a smaller arithmetic graph. The corresponding examples are notebooks, so run cells from top to bottom after installing Gradix and Graphviz.
152
+
153
+ ## Define a Model
154
+
155
+ Models subclass `Module`, implement `forward`, and return all trainable tensors from `parameters`. The `Linear` layer accepts a batch whose last dimension matches `in_features`.
156
+
157
+ ```python
158
+ from gradix.nn.modules import Linear, Module
159
+
160
+
161
+ class SmallClassifier(Module):
162
+ def __init__(self):
163
+ self.hidden = Linear(784, 128, bias=True)
164
+ self.output = Linear(128, 10, bias=True)
165
+
166
+ def parameters(self):
167
+ return self.hidden.parameters() + self.output.parameters()
168
+
169
+ def forward(self, x):
170
+ x = x.reshape(x.shape[0], 784)
171
+ x = self.hidden(x).relu()
172
+ return self.output(x)
173
+ ```
174
+
175
+ The MNIST examples in `demos/MnistModel.py` show two model shapes:
176
+
177
+ - `MNISTModel`: flatten each 28-by-28 image, apply a 784-to-128 linear layer with ReLU, then produce 10 class scores.
178
+ - `MNISTConvModel`: reshape to `(batch, 1, 28, 28)`, apply three Conv2D layers with ReLU, flatten the result, and produce 10 class scores.
179
+
180
+ The convolutional model's `parameters()` method combines the parameters from each child layer. Gradix modules do not currently automatically register nested modules, so a custom model should explicitly return its parameters as above.
181
+
182
+ ## Train a Model
183
+
184
+ Gradix's `cross_entropy` expects logits shaped `(batch, classes)` and integer class labels in a target tensor. The targets do not need gradients. This self-contained example demonstrates the same batch flow used in `demos/train.ipynb` without downloading a dataset:
185
+
186
+ ```python
187
+ import numpy as np
188
+
189
+ from gradix import Tensor
190
+ from gradix.nn.loss import cross_entropy
191
+ from gradix.nn.modules import Linear, Module
192
+ from gradix.nn.optim import SGD
193
+
194
+
195
+ class TinyClassifier(Module):
196
+ def __init__(self):
197
+ self.layer = Linear(2, 2, bias=True)
198
+
199
+ def parameters(self):
200
+ return self.layer.parameters()
201
+
202
+ def forward(self, x):
203
+ return self.layer(x)
204
+
205
+
206
+ x = Tensor(np.array([[1, 0], [0, 1], [1, 1], [0, 0]], dtype=np.float32))
207
+ targets = Tensor(np.array([0, 1, 0, 1]))
208
+
209
+ model = TinyClassifier()
210
+ optimizer = SGD(model.parameters(), lr=0.1)
211
+
212
+ for step in range(20):
213
+ logits = model(x)
214
+ loss = cross_entropy(logits, targets)
215
+
216
+ optimizer.zero_grad()
217
+ loss.backward()
218
+ optimizer.step()
219
+
220
+ print(f"step {step + 1}: loss={float(loss.data):.4f}")
221
+ ```
222
+
223
+ In each step, the model produces one score per class, cross-entropy compares those scores with the labels, and backpropagation computes parameter gradients. SGD then updates the parameters. This is a minimal educational loop; it does not include features such as batching helpers, schedulers, regularization, checkpointing, or automatic device placement.
224
+
225
+ ## MNIST Notebook Workflow
226
+
227
+ `demos/train.ipynb` demonstrates the larger workflow:
228
+
229
+ 1. Load MNIST with scikit-learn's `fetch_openml` and split pixels and labels into training, validation, and test sets.
230
+ 2. Convert pixel arrays to `float32`, scale pixels into the 0-to-1 range, and convert labels to integers.
231
+ 3. Create `MNISTModel` or `MNISTConvModel`, then pass `model.parameters()` to `SGD`.
232
+ 4. Iterate over mini-batches. For each batch, create input and target tensors, run the model, calculate cross-entropy, clear gradients, call `backward()`, and update parameters.
233
+ 5. Calculate validation loss without calling `backward()`, then evaluate on the test data after training.
234
+ 6. Plot training and validation loss with Matplotlib and optionally visualize the model's graph.
235
+
236
+ The notebook uses additional packages for the example workflow. Install them in the notebook's Python environment if they are not already present:
237
+
238
+ ```bash
239
+ python -m pip install scikit-learn tqdm
240
+ ```
241
+
242
+ Matplotlib is already a required Gradix dependency. Fetching MNIST requires an internet connection the first time. Training the full dataset, particularly with the pure-Python Conv2D implementation, may take a while.
243
+
244
+ ## API at a Glance
245
+
246
+ | API | Purpose |
247
+ | --- | --- |
248
+ | `Tensor(data, requires_grad=False, name=None)` | Store array data and optionally track gradients. |
249
+ | `tensor.backward()` | Compute gradients from a scalar result back through its graph. |
250
+ | `tensor.zero_grad()` | Clear gradients in the tensor's graph. |
251
+ | `Module` | Base class for models with `forward()` and `parameters()`. |
252
+ | `Linear(in_features, out_features, bias=False)` | Fully connected transformation. |
253
+ | `Conv2D(in_channels, out_channels, kernel, stride=1, padding=0, use_bias=False)` | Two-dimensional convolution. |
254
+ | `cross_entropy(logits, targets)` | Mean multiclass cross-entropy for integer class labels. |
255
+ | `SGD(parameters, lr=0.001)` | Basic stochastic gradient descent optimizer. |
256
+ | `visualize_computation_graph(tensor, ...)` | Return or render the tensor's operation graph. |
257
+
258
+ ## Project Layout
259
+
260
+ ```text
261
+ src/gradix/ Library implementation
262
+ tensor.py Tensor and automatic differentiation
263
+ nn/ Functions, modules, losses, and optimizer
264
+ demos/MnistModel.py Example fully connected and convolutional models
265
+ demos/demo.ipynb Small tensor and graph examples
266
+ demos/digraph_test.ipynb Attention-style and recurrent graph examples
267
+ demos/train.ipynb MNIST data preparation, training, and evaluation
268
+ tests/test_conv2d.py Conv2D comparison against PyTorch
269
+ ```
270
+
271
+ ## Development Checks
272
+
273
+ Install the project and run the Conv2D comparison from the repository root:
274
+
275
+ ```bash
276
+ python -m pip install -e .
277
+ python -m pip install torch
278
+ PYTHONPATH=src python tests/test_conv2d.py
279
+ ```
280
+
281
+ The test uses PyTorch only as a reference implementation. The library itself does not depend on PyTorch.
282
+
283
+ ## Current Limitations
284
+
285
+ - Gradix is educational software and implements a small subset of tensor and neural-network functionality.
286
+ - CPU execution is the most suitable current path. CUDA support is experimental; Conv2D currently constructs some intermediate indices with NumPy and has not been validated on a real CUDA device.
287
+ - Models explicitly implement `parameters()`; nested layers are not automatically discovered.
288
+ - Dataset loading and notebook conveniences such as scikit-learn and tqdm are separate from the core package dependencies.
289
+ - The Graphviz Python package does not include the Graphviz system executable.
290
+
291
+ ## License
292
+
293
+ See [LICENSE](LICENSE).
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "gradix"
7
+ version = "0.1.0"
8
+ description = "A lightweight NumPy-based automatic differentiation and deep learning library"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.10"
12
+ dependencies = [
13
+ "numpy>=1.24",
14
+ "graphviz>=0.20",
15
+ "matplotlib>=3.8",
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ gpu = ["cupy-cuda12x>=12"]
20
+ all = ["cupy-cuda12x>=12", "graphviz>=0.20", "matplotlib>=3.8"]
21
+
22
+ [tool.setuptools]
23
+ package-dir = {"" = "src"}
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["src"]
27
+ include = ["gradix*"]
gradix-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,35 @@
1
+ import numpy as np
2
+
3
+ try:
4
+ import cupy as cp
5
+ import cupyx
6
+ except ImportError:
7
+ cp = None
8
+ cupyx = None
9
+
10
+ GPU_AVAILABLE = cp is not None and cp.cuda.is_available() and cp.cuda.runtime.getDeviceCount() > 0
11
+ DEVICE = 'cuda' if GPU_AVAILABLE else 'cpu'
12
+
13
+ #dtypes
14
+ float32 = np.float32
15
+ float64 = np.float64
16
+ float16 = np.float16
17
+ int32 = np.int32
18
+ int64 = np.int64
19
+ bool_ = np.bool_
20
+
21
+ from .tensor import Tensor
22
+ from . import nn
23
+
24
+ __all__ = [
25
+ "Tensor",
26
+ "nn",
27
+ "GPU_AVAILABLE",
28
+ "DEVICE",
29
+ "float32",
30
+ "float64",
31
+ "float16",
32
+ "int32",
33
+ "int64",
34
+ "bool_",
35
+ ]