lucid-dl 2.10.0__tar.gz → 2.11.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.
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/PKG-INFO +15 -4
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/README.md +14 -3
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/__init__.py +1 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_tensor/tensor.py +3 -104
- lucid_dl-2.11.0/lucid/autograd/__init__.py +219 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/types.py +15 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid_dl.egg-info/PKG-INFO +15 -4
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid_dl.egg-info/SOURCES.txt +1 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/setup.py +1 -1
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/LICENSE +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_backend/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_backend/conv.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_backend/core.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_backend/metal.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_backend/pool.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_func/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_func/bfunc.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_func/gfunc.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_func/ufunc.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_fusion/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_fusion/base.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_fusion/func.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_tensor/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_tensor/tensor_ops.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_util/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/_util/func.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/data/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/data/_base.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/data/_util.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/datasets/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/datasets/_base.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/datasets/cifar.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/datasets/mnist.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/einops/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/einops/_func.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/error.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/linalg/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/linalg/_func.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/alex.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/coatnet.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/convnext.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/crossvit.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/cspnet.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/cvt.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/dense.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/efficient.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/efficientformer.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/inception.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/inception_next.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/inception_res.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/lenet.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/maxvit.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/mobile.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/pvt.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/resnest.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/resnet.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/resnext.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/senet.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/sknet.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/swin.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/vgg.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/vit.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/xception.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imgclf/zfnet.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imggen/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imggen/ddpm.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/imggen/vae.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/detr.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/efficientdet.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/fast_rcnn.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/faster_rcnn.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/rcnn.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/util.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/yolo/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/yolo/yolo_v1.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/yolo/yolo_v2.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/yolo/yolo_v3.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/objdet/yolo/yolo_v4.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/seq2seq/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/seq2seq/transformer.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/models/util.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_activation.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_attention.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_conv.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_drop.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_linear.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_loss.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_norm.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_pool.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_spatial.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/functional/_util.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/fused.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/init/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/init/_dist.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/module.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/activation.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/attention.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/conv.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/drop.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/einops.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/linear.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/loss.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/norm.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/pool.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/rnn.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/sparse.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/transformer.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/modules/vision.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/parameter.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/nn/util.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/_base.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/ada.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/adam.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/lr_scheduler/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/lr_scheduler/_base.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/lr_scheduler/_schedulers.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/prop.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/optim/sgd.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/port.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/random/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/random/_func.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/transforms/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/transforms/_base.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/transforms/image.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/visual/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/visual/graph.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/weights/__init__.py +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid/weights/__init__.pyi +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid_dl.egg-info/dependency_links.txt +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid_dl.egg-info/requires.txt +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/lucid_dl.egg-info/top_level.txt +0 -0
- {lucid_dl-2.10.0 → lucid_dl-2.11.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lucid-dl
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.11.0
|
|
4
4
|
Summary: Lumerico's Comprehensive Interface for Deep Learning
|
|
5
5
|
Home-page: https://github.com/ChanLumerico/lucid
|
|
6
6
|
Author: ChanLumerico
|
|
@@ -28,9 +28,9 @@ Dynamic: summary
|
|
|
28
28
|
|
|
29
29
|
# Lucid² 💎
|
|
30
30
|
|
|
31
|
-

|
|
32
|
+

|
|
33
|
+
[](https://pepy.tech/projects/lucid-dl)
|
|
34
34
|

|
|
35
35
|

|
|
36
36
|

|
|
@@ -50,6 +50,17 @@ Whether you're a student, educator, or an advanced researcher seeking to demysti
|
|
|
50
50
|
|
|
51
51
|
- Now supports [**`Safetensors`**](https://github.com/huggingface/safetensors) for Lucid neural module porting along with the legacy `.lcd` format
|
|
52
52
|
|
|
53
|
+
- Branched a Stand-alone Autograd Engine as `lucid.autograd`
|
|
54
|
+
|
|
55
|
+
- Provides a generalized API of computing gradients:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import lucid.autograd as autograd
|
|
59
|
+
x = lucid.Tensor([1., 2.], requires_grad=True)
|
|
60
|
+
y = (x ** 2).sum()
|
|
61
|
+
autograd.grad(y, x) # ∂y/∂x
|
|
62
|
+
```
|
|
63
|
+
|
|
53
64
|
- Introduced **Backward Fusion** for CPU execution:
|
|
54
65
|
- Automatically fuses selected operation patterns during backpropagation to reduce graph overhead
|
|
55
66
|
- Supports identity/unary fusion (e.g. `log∘exp`, double negation, and view-like ops such as reshape/squeeze)
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Lucid² 💎
|
|
2
2
|
|
|
3
|
-

|
|
4
|
+

|
|
5
|
+
[](https://pepy.tech/projects/lucid-dl)
|
|
6
6
|

|
|
7
7
|

|
|
8
8
|

|
|
@@ -22,6 +22,17 @@ Whether you're a student, educator, or an advanced researcher seeking to demysti
|
|
|
22
22
|
|
|
23
23
|
- Now supports [**`Safetensors`**](https://github.com/huggingface/safetensors) for Lucid neural module porting along with the legacy `.lcd` format
|
|
24
24
|
|
|
25
|
+
- Branched a Stand-alone Autograd Engine as `lucid.autograd`
|
|
26
|
+
|
|
27
|
+
- Provides a generalized API of computing gradients:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import lucid.autograd as autograd
|
|
31
|
+
x = lucid.Tensor([1., 2.], requires_grad=True)
|
|
32
|
+
y = (x ** 2).sum()
|
|
33
|
+
autograd.grad(y, x) # ∂y/∂x
|
|
34
|
+
```
|
|
35
|
+
|
|
25
36
|
- Introduced **Backward Fusion** for CPU execution:
|
|
26
37
|
- Automatically fuses selected operation patterns during backpropagation to reduce graph overhead
|
|
27
38
|
- Supports identity/unary fusion (e.g. `log∘exp`, double negation, and view-like ops such as reshape/squeeze)
|
|
@@ -140,110 +140,9 @@ class Tensor(_TensorBase):
|
|
|
140
140
|
return self
|
|
141
141
|
|
|
142
142
|
def backward(self, retain_grad: bool = False, retain_graph: bool = False) -> None:
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
)
|
|
147
|
-
visited = set()
|
|
148
|
-
topo_order: list[Self] = []
|
|
149
|
-
stack = [self]
|
|
150
|
-
ops_to_clear = set()
|
|
151
|
-
|
|
152
|
-
while stack:
|
|
153
|
-
tensor = stack[-1]
|
|
154
|
-
if tensor in visited:
|
|
155
|
-
stack.pop()
|
|
156
|
-
topo_order.append(tensor)
|
|
157
|
-
continue
|
|
158
|
-
|
|
159
|
-
visited.add(tensor)
|
|
160
|
-
for parent in tensor._prev:
|
|
161
|
-
if parent not in visited:
|
|
162
|
-
stack.append(parent)
|
|
163
|
-
|
|
164
|
-
if lucid.ENABLE_FUSION and self.is_cpu():
|
|
165
|
-
self._try_backward_fusion(topo_order)
|
|
166
|
-
|
|
167
|
-
for tensor in reversed(topo_order):
|
|
168
|
-
try:
|
|
169
|
-
tensor._backward_op()
|
|
170
|
-
except Exception as e:
|
|
171
|
-
raise lucid.BackwardError(shape=tensor.shape, op=tensor._op) from e
|
|
172
|
-
|
|
173
|
-
for hook in tensor._backward_hooks:
|
|
174
|
-
hook(tensor, tensor.grad)
|
|
175
|
-
|
|
176
|
-
if tensor._op is not None:
|
|
177
|
-
ops_to_clear.add(tensor._op)
|
|
178
|
-
|
|
179
|
-
if not (tensor.is_leaf or retain_grad or tensor.keep_grad):
|
|
180
|
-
tensor.grad = None
|
|
181
|
-
|
|
182
|
-
if not retain_graph:
|
|
183
|
-
for tensor in topo_order:
|
|
184
|
-
tensor.clear_node()
|
|
185
|
-
for op in ops_to_clear:
|
|
186
|
-
try:
|
|
187
|
-
op.clear()
|
|
188
|
-
except Exception:
|
|
189
|
-
try:
|
|
190
|
-
op.result = None
|
|
191
|
-
except Exception:
|
|
192
|
-
pass
|
|
193
|
-
|
|
194
|
-
def _try_backward_fusion(self, topo_order: list[Self]) -> None:
|
|
195
|
-
consumer_of: dict[int, Self] = {}
|
|
196
|
-
multi_consumer: set[int] = set()
|
|
197
|
-
|
|
198
|
-
for consumer in topo_order:
|
|
199
|
-
for parent in consumer._prev:
|
|
200
|
-
pid = id(parent)
|
|
201
|
-
if pid in multi_consumer:
|
|
202
|
-
continue
|
|
203
|
-
|
|
204
|
-
prev_consumer = consumer_of.get(pid)
|
|
205
|
-
if prev_consumer is None:
|
|
206
|
-
consumer_of[pid] = consumer
|
|
207
|
-
else:
|
|
208
|
-
multi_consumer.add(pid)
|
|
209
|
-
consumer_of.pop(pid, None)
|
|
210
|
-
|
|
211
|
-
if not consumer_of:
|
|
212
|
-
return
|
|
213
|
-
|
|
214
|
-
from lucid._fusion import match_fusion_table
|
|
215
|
-
|
|
216
|
-
for pid, v in list(consumer_of.items()):
|
|
217
|
-
p = next((t for t in v._prev if id(t) == pid), None)
|
|
218
|
-
if p is None:
|
|
219
|
-
continue
|
|
220
|
-
if p._op is None or v._op is None:
|
|
221
|
-
continue
|
|
222
|
-
|
|
223
|
-
fused_backward_op = match_fusion_table(p._op, v._op)
|
|
224
|
-
if fused_backward_op is None:
|
|
225
|
-
continue
|
|
226
|
-
if v.size < fused_backward_op.heuristic_thresh:
|
|
227
|
-
continue
|
|
228
|
-
|
|
229
|
-
# NOTE (fusion limitation): --- IGNORE ---
|
|
230
|
-
# TEMP: only fuse simple unary chains p -> v.
|
|
231
|
-
# If v has multiple parents (e.g., binary ops), a fused grad func would
|
|
232
|
-
# need to account for all inputs; skip for now.
|
|
233
|
-
if len(v._prev) != 1 or v._prev[0] is not p:
|
|
234
|
-
continue
|
|
235
|
-
|
|
236
|
-
p_parents = tuple(p._prev)
|
|
237
|
-
v._prev.remove(p)
|
|
238
|
-
v._prev.extend(p_parents)
|
|
239
|
-
p.clear_node(clear_op=False)
|
|
240
|
-
|
|
241
|
-
v._backward_op.override_tensor_refs(tuple(weakref.ref(t) for t in v._prev))
|
|
242
|
-
v._backward_op.override_grad_func(
|
|
243
|
-
fused_backward_op.get_fused_grad_func(
|
|
244
|
-
inputs=p_parents, results=v, device=v.device
|
|
245
|
-
)
|
|
246
|
-
)
|
|
143
|
+
import lucid.autograd as autograd
|
|
144
|
+
|
|
145
|
+
autograd.backward(self, retain_grad=retain_grad, retain_graph=retain_graph)
|
|
247
146
|
|
|
248
147
|
def register_hook(self, hook: _HookType) -> Callable:
|
|
249
148
|
self._backward_hooks.append(hook)
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
from typing import Iterable, Sequence
|
|
2
|
+
import weakref
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from lucid._backend.metal import mx
|
|
7
|
+
from lucid.error import BackwardError
|
|
8
|
+
from lucid.types import _MLXArray, _NumPyArray, _TensorLike, _Scalar, _Gradient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
__all__ = ["grad", "backward"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _as_tuple(value: _TensorLike | Sequence[_TensorLike]) -> tuple[_TensorLike, ...]:
|
|
15
|
+
if isinstance(value, (tuple, list)):
|
|
16
|
+
return tuple(value)
|
|
17
|
+
return (value,)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _coerce_grad_output(
|
|
21
|
+
output: _TensorLike, grad_output: _TensorLike | _Gradient | _Scalar
|
|
22
|
+
) -> _Gradient:
|
|
23
|
+
if grad_output is None:
|
|
24
|
+
if output.is_cpu():
|
|
25
|
+
return np.ones_like(output.data)
|
|
26
|
+
return mx.ones_like(output.data)
|
|
27
|
+
|
|
28
|
+
if isinstance(grad_output, _TensorLike):
|
|
29
|
+
grad_output = grad_output.data
|
|
30
|
+
|
|
31
|
+
if isinstance(grad_output, _NumPyArray):
|
|
32
|
+
if output.is_gpu():
|
|
33
|
+
grad_output = mx.array(grad_output)
|
|
34
|
+
return grad_output
|
|
35
|
+
|
|
36
|
+
if isinstance(grad_output, _MLXArray):
|
|
37
|
+
if output.is_cpu():
|
|
38
|
+
grad_output = np.array(grad_output)
|
|
39
|
+
return grad_output
|
|
40
|
+
|
|
41
|
+
if output.is_cpu():
|
|
42
|
+
return np.ones_like(output.data) * grad_output
|
|
43
|
+
return mx.ones_like(output.data) * grad_output
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def grad(
|
|
47
|
+
outputs: _TensorLike | Iterable[_TensorLike],
|
|
48
|
+
inputs: _TensorLike | Iterable[_TensorLike],
|
|
49
|
+
grad_outputs: _TensorLike | Iterable[_TensorLike] | Iterable[_Scalar] | None = None,
|
|
50
|
+
retain_graph: bool = False,
|
|
51
|
+
allow_unused: bool = False,
|
|
52
|
+
) -> tuple[_Gradient, ...] | _Gradient:
|
|
53
|
+
out_tensors = _as_tuple(outputs)
|
|
54
|
+
in_tensors = _as_tuple(inputs)
|
|
55
|
+
|
|
56
|
+
if grad_outputs is None:
|
|
57
|
+
grad_outs = (None,) * len(out_tensors)
|
|
58
|
+
else:
|
|
59
|
+
grad_outs = _as_tuple(grad_outputs)
|
|
60
|
+
if len(grad_outs) != len(out_tensors):
|
|
61
|
+
raise ValueError("grad_outputs length must match outputs length.")
|
|
62
|
+
|
|
63
|
+
for tensor in out_tensors:
|
|
64
|
+
if not isinstance(tensor, _TensorLike):
|
|
65
|
+
raise TypeError("All outputs must be _TensorLike instances.")
|
|
66
|
+
|
|
67
|
+
for tensor in in_tensors:
|
|
68
|
+
if not isinstance(tensor, _TensorLike):
|
|
69
|
+
raise TypeError("All inputs must be _TensorLike instances.")
|
|
70
|
+
|
|
71
|
+
prev_grads = {tensor: tensor.grad for tensor in in_tensors}
|
|
72
|
+
prev_out_grads = {tensor: tensor.grad for tensor in out_tensors}
|
|
73
|
+
prev_keep = {tensor: tensor.keep_grad for tensor in in_tensors}
|
|
74
|
+
|
|
75
|
+
for tensor in in_tensors:
|
|
76
|
+
tensor.grad = None
|
|
77
|
+
tensor.keep_grad = True
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
for i, (output, grad_output) in enumerate(zip(out_tensors, grad_outs)):
|
|
81
|
+
if not output.requires_grad:
|
|
82
|
+
if allow_unused:
|
|
83
|
+
continue
|
|
84
|
+
raise RuntimeError("All outputs must require gradients.")
|
|
85
|
+
|
|
86
|
+
coerced = _coerce_grad_output(output, grad_output)
|
|
87
|
+
if coerced.shape != output.shape:
|
|
88
|
+
raise ValueError("grad_output shape must match output shape.")
|
|
89
|
+
|
|
90
|
+
output.grad = coerced
|
|
91
|
+
output.backward(
|
|
92
|
+
retain_grad=True,
|
|
93
|
+
retain_graph=(i < len(out_tensors) - 1) or retain_graph,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
grads = tuple(tensor.grad for tensor in in_tensors)
|
|
97
|
+
if not allow_unused and any(grad is None for grad in grads):
|
|
98
|
+
raise RuntimeError(
|
|
99
|
+
"Some inputs did not receive gradients. Set allow_unused=True."
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
if len(grads) == 1:
|
|
103
|
+
return grads[0]
|
|
104
|
+
return grads
|
|
105
|
+
finally:
|
|
106
|
+
for tensor, grad in prev_out_grads.items():
|
|
107
|
+
tensor.grad = grad
|
|
108
|
+
for tensor in in_tensors:
|
|
109
|
+
tensor.grad = prev_grads[tensor]
|
|
110
|
+
tensor.keep_grad = prev_keep[tensor]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def backward(
|
|
114
|
+
tensor: _TensorLike, retain_grad: bool = False, retain_graph: bool = False
|
|
115
|
+
) -> None:
|
|
116
|
+
if tensor.grad is None:
|
|
117
|
+
tensor.grad = (
|
|
118
|
+
np.ones_like(tensor.data) if tensor.is_cpu() else mx.ones_like(tensor.data)
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
visited = set()
|
|
122
|
+
topo_order: list[_TensorLike] = []
|
|
123
|
+
stack = [tensor]
|
|
124
|
+
ops_to_clear = set()
|
|
125
|
+
|
|
126
|
+
while stack:
|
|
127
|
+
node = stack[-1]
|
|
128
|
+
if node in visited:
|
|
129
|
+
stack.pop()
|
|
130
|
+
topo_order.append(node)
|
|
131
|
+
continue
|
|
132
|
+
|
|
133
|
+
visited.add(node)
|
|
134
|
+
for parent in node._prev:
|
|
135
|
+
if parent not in visited:
|
|
136
|
+
stack.append(parent)
|
|
137
|
+
|
|
138
|
+
from lucid._fusion import ENABLE_FUSION
|
|
139
|
+
|
|
140
|
+
if ENABLE_FUSION and tensor.is_cpu():
|
|
141
|
+
_try_backward_fusion(topo_order)
|
|
142
|
+
|
|
143
|
+
for node in reversed(topo_order):
|
|
144
|
+
try:
|
|
145
|
+
node._backward_op()
|
|
146
|
+
except Exception as e:
|
|
147
|
+
raise BackwardError(shape=node.shape, op=node._op) from e
|
|
148
|
+
|
|
149
|
+
for hook in node._backward_hooks:
|
|
150
|
+
hook(node, node.grad)
|
|
151
|
+
|
|
152
|
+
if node._op is not None:
|
|
153
|
+
ops_to_clear.add(node._op)
|
|
154
|
+
|
|
155
|
+
if not (node.is_leaf or retain_grad or node.keep_grad):
|
|
156
|
+
node.grad = None
|
|
157
|
+
|
|
158
|
+
if not retain_graph:
|
|
159
|
+
for node in topo_order:
|
|
160
|
+
node.clear_node()
|
|
161
|
+
for op in ops_to_clear:
|
|
162
|
+
try:
|
|
163
|
+
op.clear()
|
|
164
|
+
except Exception:
|
|
165
|
+
try:
|
|
166
|
+
op.result = None
|
|
167
|
+
except Exception:
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _try_backward_fusion(topo_order: list[_TensorLike]) -> None:
|
|
172
|
+
from lucid._fusion import match_fusion_table
|
|
173
|
+
|
|
174
|
+
consumer_of: dict[int, _TensorLike] = {}
|
|
175
|
+
multi_consumer: set[int] = set()
|
|
176
|
+
|
|
177
|
+
for consumer in topo_order:
|
|
178
|
+
for parent in consumer._prev:
|
|
179
|
+
pid = id(parent)
|
|
180
|
+
if pid in multi_consumer:
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
prev_consumer = consumer_of.get(pid)
|
|
184
|
+
if prev_consumer is None:
|
|
185
|
+
consumer_of[pid] = consumer
|
|
186
|
+
else:
|
|
187
|
+
multi_consumer.add(pid)
|
|
188
|
+
consumer_of.pop(pid, None)
|
|
189
|
+
|
|
190
|
+
if not consumer_of:
|
|
191
|
+
return
|
|
192
|
+
|
|
193
|
+
for pid, v in list(consumer_of.items()):
|
|
194
|
+
p = next((t for t in v._prev if id(t) == pid), None)
|
|
195
|
+
if p is None:
|
|
196
|
+
continue
|
|
197
|
+
if p._op is None or v._op is None:
|
|
198
|
+
continue
|
|
199
|
+
|
|
200
|
+
fused_backward_op = match_fusion_table(p._op, v._op)
|
|
201
|
+
if fused_backward_op is None:
|
|
202
|
+
continue
|
|
203
|
+
if v.size < fused_backward_op.heuristic_thresh:
|
|
204
|
+
continue
|
|
205
|
+
|
|
206
|
+
if len(v._prev) != 1 or v._prev[0] is not p:
|
|
207
|
+
continue
|
|
208
|
+
|
|
209
|
+
p_parents = tuple(p._prev)
|
|
210
|
+
v._prev.remove(p)
|
|
211
|
+
v._prev.extend(p_parents)
|
|
212
|
+
p.clear_node(clear_op=False)
|
|
213
|
+
|
|
214
|
+
v._backward_op.override_tensor_refs(tuple(weakref.ref(t) for t in v._prev))
|
|
215
|
+
v._backward_op.override_grad_func(
|
|
216
|
+
fused_backward_op.get_fused_grad_func(
|
|
217
|
+
inputs=p_parents, results=v, device=v.device
|
|
218
|
+
)
|
|
219
|
+
)
|
|
@@ -46,15 +46,30 @@ class _TensorLike(Protocol):
|
|
|
46
46
|
device: _DeviceType
|
|
47
47
|
shape: Any
|
|
48
48
|
data: Any
|
|
49
|
+
grad: Any
|
|
50
|
+
keep_grad: bool
|
|
51
|
+
is_leaf: bool
|
|
52
|
+
size: Any
|
|
49
53
|
|
|
50
54
|
_op: object | None
|
|
51
55
|
_prev: list[_TensorLike]
|
|
52
56
|
_backward_op: Any
|
|
57
|
+
_backward_hooks: Any
|
|
53
58
|
|
|
54
59
|
def to(self, device: _DeviceType) -> None: ...
|
|
55
60
|
|
|
56
61
|
def free(self) -> None: ...
|
|
57
62
|
|
|
63
|
+
def is_cpu(self) -> bool: ...
|
|
64
|
+
|
|
65
|
+
def is_gpu(self) -> bool: ...
|
|
66
|
+
|
|
67
|
+
def clear_node(self, clear_op: bool = True) -> None: ...
|
|
68
|
+
|
|
69
|
+
def backward(
|
|
70
|
+
self, retain_grad: bool = False, retain_graph: bool = False
|
|
71
|
+
) -> None: ...
|
|
72
|
+
|
|
58
73
|
|
|
59
74
|
class Numeric:
|
|
60
75
|
def __init__(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lucid-dl
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.11.0
|
|
4
4
|
Summary: Lumerico's Comprehensive Interface for Deep Learning
|
|
5
5
|
Home-page: https://github.com/ChanLumerico/lucid
|
|
6
6
|
Author: ChanLumerico
|
|
@@ -28,9 +28,9 @@ Dynamic: summary
|
|
|
28
28
|
|
|
29
29
|
# Lucid² 💎
|
|
30
30
|
|
|
31
|
-

|
|
32
|
+

|
|
33
|
+
[](https://pepy.tech/projects/lucid-dl)
|
|
34
34
|

|
|
35
35
|

|
|
36
36
|

|
|
@@ -50,6 +50,17 @@ Whether you're a student, educator, or an advanced researcher seeking to demysti
|
|
|
50
50
|
|
|
51
51
|
- Now supports [**`Safetensors`**](https://github.com/huggingface/safetensors) for Lucid neural module porting along with the legacy `.lcd` format
|
|
52
52
|
|
|
53
|
+
- Branched a Stand-alone Autograd Engine as `lucid.autograd`
|
|
54
|
+
|
|
55
|
+
- Provides a generalized API of computing gradients:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import lucid.autograd as autograd
|
|
59
|
+
x = lucid.Tensor([1., 2.], requires_grad=True)
|
|
60
|
+
y = (x ** 2).sum()
|
|
61
|
+
autograd.grad(y, x) # ∂y/∂x
|
|
62
|
+
```
|
|
63
|
+
|
|
53
64
|
- Introduced **Backward Fusion** for CPU execution:
|
|
54
65
|
- Automatically fuses selected operation patterns during backpropagation to reduce graph overhead
|
|
55
66
|
- Supports identity/unary fusion (e.g. `log∘exp`, double negation, and view-like ops such as reshape/squeeze)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|