openarchx 0.1.0__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.
Files changed (43) hide show
  1. openarchx/__init__.py +11 -0
  2. openarchx/core/tensor.py +179 -0
  3. openarchx/cuda/__init__.py +27 -0
  4. openarchx/cuda/cuda_ops.py +296 -0
  5. openarchx/layers/activations.py +63 -0
  6. openarchx/layers/base.py +40 -0
  7. openarchx/layers/cnn.py +145 -0
  8. openarchx/layers/transformer.py +131 -0
  9. openarchx/nn/__init__.py +26 -0
  10. openarchx/nn/activations.py +127 -0
  11. openarchx/nn/containers.py +174 -0
  12. openarchx/nn/dropout.py +121 -0
  13. openarchx/nn/layers.py +338 -0
  14. openarchx/nn/losses.py +156 -0
  15. openarchx/nn/module.py +18 -0
  16. openarchx/nn/padding.py +120 -0
  17. openarchx/nn/pooling.py +318 -0
  18. openarchx/nn/rnn.py +226 -0
  19. openarchx/nn/transformers.py +187 -0
  20. openarchx/optimizers/adam.py +49 -0
  21. openarchx/optimizers/adaptive.py +63 -0
  22. openarchx/optimizers/base.py +24 -0
  23. openarchx/optimizers/modern.py +98 -0
  24. openarchx/optimizers/optx.py +91 -0
  25. openarchx/optimizers/sgd.py +63 -0
  26. openarchx/quantum/circuit.py +92 -0
  27. openarchx/quantum/gates.py +126 -0
  28. openarchx/utils/__init__.py +50 -0
  29. openarchx/utils/data.py +229 -0
  30. openarchx/utils/huggingface.py +288 -0
  31. openarchx/utils/losses.py +21 -0
  32. openarchx/utils/model_io.py +553 -0
  33. openarchx/utils/pytorch.py +420 -0
  34. openarchx/utils/tensorflow.py +467 -0
  35. openarchx/utils/transforms.py +259 -0
  36. openarchx-0.1.0.dist-info/METADATA +180 -0
  37. openarchx-0.1.0.dist-info/RECORD +43 -0
  38. openarchx-0.1.0.dist-info/WHEEL +5 -0
  39. openarchx-0.1.0.dist-info/licenses/LICENSE +21 -0
  40. openarchx-0.1.0.dist-info/top_level.txt +2 -0
  41. tests/__init__.py +1 -0
  42. tests/test_cuda_ops.py +205 -0
  43. tests/test_integrations.py +236 -0
@@ -0,0 +1,420 @@
1
+ """
2
+ PyTorch Integration Utilities for OpenArchX.
3
+
4
+ This module provides conversion and adapter utilities for using PyTorch models
5
+ and datasets with OpenArchX. These utilities are completely optional and do not
6
+ affect OpenArchX's core functionality, which remains independent from external libraries.
7
+ """
8
+
9
+ import numpy as np
10
+ import importlib.util
11
+ from ..core.tensor import Tensor
12
+
13
+
14
+ class PyTorchModelAdapter:
15
+ """Adapter for using PyTorch models with OpenArchX."""
16
+
17
+ def __init__(self, torch_model, device=None):
18
+ """
19
+ Initialize a PyTorch model adapter.
20
+
21
+ Args:
22
+ torch_model: A PyTorch nn.Module model.
23
+ device: The device to run the model on ('cpu', 'cuda', etc.).
24
+ """
25
+ # Check if torch is installed
26
+ if importlib.util.find_spec("torch") is None:
27
+ raise ImportError("PyTorch is required. Install with 'pip install torch'")
28
+
29
+ import torch
30
+
31
+ self.model = torch_model
32
+
33
+ # Handle device placement
34
+ if device is None:
35
+ device = "cuda" if torch.cuda.is_available() else "cpu"
36
+ self.device = torch.device(device)
37
+ self.model.to(self.device)
38
+ self.model.eval() # Set to evaluation mode
39
+
40
+ def __call__(self, inputs, **kwargs):
41
+ """
42
+ Process inputs through the PyTorch model.
43
+
44
+ Args:
45
+ inputs: Input data, can be numpy arrays, lists, or OpenArchX Tensors.
46
+ **kwargs: Additional arguments to pass to the model.
47
+
48
+ Returns:
49
+ OpenArchX Tensor containing the model output.
50
+ """
51
+ import torch
52
+
53
+ # Convert inputs to torch tensors
54
+ if isinstance(inputs, Tensor):
55
+ inputs = inputs.data
56
+
57
+ if isinstance(inputs, np.ndarray):
58
+ inputs = torch.tensor(inputs, dtype=torch.float32, device=self.device)
59
+ elif isinstance(inputs, list):
60
+ inputs = torch.tensor(np.array(inputs), dtype=torch.float32, device=self.device)
61
+ elif not isinstance(inputs, torch.Tensor):
62
+ raise TypeError(f"Unsupported input type: {type(inputs)}")
63
+
64
+ # If inputs is already a torch tensor, ensure it's on the right device
65
+ if isinstance(inputs, torch.Tensor) and inputs.device != self.device:
66
+ inputs = inputs.to(self.device)
67
+
68
+ # Forward pass with gradient tracking disabled
69
+ with torch.no_grad():
70
+ outputs = self.model(inputs, **kwargs)
71
+
72
+ # Convert output to numpy and then to Tensor
73
+ if isinstance(outputs, torch.Tensor):
74
+ return Tensor(outputs.detach().cpu().numpy())
75
+ elif isinstance(outputs, (tuple, list)):
76
+ return tuple(Tensor(output.detach().cpu().numpy()) for output in outputs
77
+ if isinstance(output, torch.Tensor))
78
+ elif isinstance(outputs, dict):
79
+ return {k: Tensor(v.detach().cpu().numpy()) if isinstance(v, torch.Tensor) else v
80
+ for k, v in outputs.items()}
81
+ else:
82
+ return outputs
83
+
84
+
85
+ class PyTorchDatasetConverter:
86
+ """Utility for converting between PyTorch and OpenArchX datasets."""
87
+
88
+ @staticmethod
89
+ def to_openarchx_dataset(torch_dataset, transform=None):
90
+ """
91
+ Convert a PyTorch Dataset to an OpenArchX Dataset.
92
+
93
+ Args:
94
+ torch_dataset: A PyTorch Dataset instance.
95
+ transform: Optional transform to apply to the data.
96
+
97
+ Returns:
98
+ An OpenArchX Dataset.
99
+ """
100
+ from .data import Dataset
101
+
102
+ # Check if torch is installed
103
+ if importlib.util.find_spec("torch") is None:
104
+ raise ImportError("PyTorch is required. Install with 'pip install torch'")
105
+
106
+ class OpenArchXDatasetFromPyTorch(Dataset):
107
+ def __init__(self, torch_dataset, transform=None):
108
+ self.torch_dataset = torch_dataset
109
+ self.transform = transform
110
+
111
+ def __len__(self):
112
+ return len(self.torch_dataset)
113
+
114
+ def __getitem__(self, idx):
115
+ data = self.torch_dataset[idx]
116
+
117
+ # Handle different return types from PyTorch dataset
118
+ if isinstance(data, tuple) and len(data) == 2:
119
+ # Standard (input, target) format
120
+ features, target = data
121
+
122
+ # Convert PyTorch tensors to numpy arrays
123
+ if hasattr(features, 'numpy'):
124
+ features = features.numpy()
125
+ if hasattr(target, 'numpy'):
126
+ target = target.numpy()
127
+
128
+ # Apply transform if provided
129
+ if self.transform:
130
+ features = self.transform(features)
131
+
132
+ return features, target
133
+ else:
134
+ # Generic handling for other formats
135
+ if hasattr(data, 'numpy'):
136
+ data = data.numpy()
137
+ return data
138
+
139
+ return OpenArchXDatasetFromPyTorch(torch_dataset, transform)
140
+
141
+ @staticmethod
142
+ def from_openarchx_dataset(ox_dataset, tensor_dtype=None):
143
+ """
144
+ Convert an OpenArchX Dataset to a PyTorch Dataset.
145
+
146
+ Args:
147
+ ox_dataset: An OpenArchX Dataset instance.
148
+ tensor_dtype: Optional dtype for the PyTorch tensors.
149
+
150
+ Returns:
151
+ A PyTorch Dataset.
152
+ """
153
+ # Check if torch is installed
154
+ if importlib.util.find_spec("torch") is None:
155
+ raise ImportError("PyTorch is required. Install with 'pip install torch'")
156
+
157
+ import torch
158
+ from torch.utils.data import Dataset as TorchDataset
159
+
160
+ class PyTorchDatasetFromOpenArchX(TorchDataset):
161
+ def __init__(self, ox_dataset, tensor_dtype=None):
162
+ self.ox_dataset = ox_dataset
163
+ self.tensor_dtype = tensor_dtype or torch.float32
164
+
165
+ def __len__(self):
166
+ return len(self.ox_dataset)
167
+
168
+ def __getitem__(self, idx):
169
+ data = self.ox_dataset[idx]
170
+
171
+ # Handle different return types from OpenArchX dataset
172
+ if isinstance(data, tuple) and len(data) == 2:
173
+ # Standard (input, target) format
174
+ features, target = data
175
+
176
+ # Convert to PyTorch tensors
177
+ if isinstance(features, Tensor):
178
+ features = torch.tensor(features.data, dtype=self.tensor_dtype)
179
+ elif isinstance(features, np.ndarray):
180
+ features = torch.tensor(features, dtype=self.tensor_dtype)
181
+
182
+ if isinstance(target, Tensor):
183
+ target = torch.tensor(target.data, dtype=self.tensor_dtype)
184
+ elif isinstance(target, np.ndarray):
185
+ target = torch.tensor(target, dtype=self.tensor_dtype)
186
+
187
+ return features, target
188
+ else:
189
+ # Generic handling for other formats
190
+ if isinstance(data, Tensor):
191
+ return torch.tensor(data.data, dtype=self.tensor_dtype)
192
+ elif isinstance(data, np.ndarray):
193
+ return torch.tensor(data, dtype=self.tensor_dtype)
194
+ return data
195
+
196
+ return PyTorchDatasetFromOpenArchX(ox_dataset, tensor_dtype)
197
+
198
+
199
+ class PyTorchModelConverter:
200
+ """Utility for converting PyTorch models to OpenArchX architecture."""
201
+
202
+ @staticmethod
203
+ def convert_model(torch_model, input_shape=None, framework_dependence=False):
204
+ """
205
+ Convert a PyTorch model to an OpenArchX model.
206
+
207
+ Args:
208
+ torch_model: A PyTorch nn.Module model.
209
+ input_shape: The shape of the input tensor (excluding batch dimension).
210
+ framework_dependence: If True, the resulting model will still rely on PyTorch
211
+ for forward passes. If False, it will be converted to
212
+ pure OpenArchX layers.
213
+
214
+ Returns:
215
+ An OpenArchX model.
216
+ """
217
+ # Check if torch is installed
218
+ if importlib.util.find_spec("torch") is None:
219
+ raise ImportError("PyTorch is required. Install with 'pip install torch'")
220
+
221
+ import torch
222
+ import torch.nn as nn
223
+ from ..nn.base import Layer, Model
224
+ from ..nn.layers import Dense, Conv2D, MaxPool2D, Flatten, Dropout
225
+
226
+ if framework_dependence:
227
+ # Create a wrapper around the PyTorch model
228
+ class PyTorchWrappedModel(Model):
229
+ def __init__(self, torch_model):
230
+ super().__init__()
231
+ self.torch_model = torch_model
232
+ self.torch_model.eval() # Set to evaluation mode
233
+
234
+ def forward(self, x):
235
+ # Convert OpenArchX Tensor to PyTorch tensor
236
+ if isinstance(x, Tensor):
237
+ x_torch = torch.tensor(x.data, dtype=torch.float32)
238
+ else:
239
+ x_torch = torch.tensor(x, dtype=torch.float32)
240
+
241
+ # Forward pass with gradient tracking disabled
242
+ with torch.no_grad():
243
+ output = self.torch_model(x_torch)
244
+
245
+ # Convert back to OpenArchX Tensor
246
+ if isinstance(output, torch.Tensor):
247
+ return Tensor(output.numpy())
248
+ else:
249
+ return output
250
+
251
+ return PyTorchWrappedModel(torch_model)
252
+
253
+ else:
254
+ # Convert to pure OpenArchX model by translating each layer
255
+ class OpenArchXModelFromPyTorch(Model):
256
+ def __init__(self, torch_model, input_shape):
257
+ super().__init__()
258
+ self.layers = []
259
+
260
+ # We need sample input to trace through the PyTorch model
261
+ if input_shape is None:
262
+ raise ValueError("input_shape must be provided for full conversion")
263
+
264
+ # Create a sample input tensor to trace the model
265
+ sample_input = torch.zeros((1,) + input_shape)
266
+
267
+ # Collect layer information
268
+ layer_info = []
269
+
270
+ def hook_fn(module, input, output):
271
+ layer_info.append({
272
+ 'module': module,
273
+ 'input_shape': [tuple(t.shape) for t in input if isinstance(t, torch.Tensor)],
274
+ 'output_shape': output.shape if isinstance(output, torch.Tensor)
275
+ else [t.shape for t in output if isinstance(t, torch.Tensor)]
276
+ })
277
+
278
+ # Register hooks
279
+ hooks = []
280
+ for name, module in torch_model.named_modules():
281
+ if isinstance(module, (nn.Linear, nn.Conv2d, nn.MaxPool2d, nn.Flatten, nn.Dropout)):
282
+ hooks.append(module.register_forward_hook(hook_fn))
283
+
284
+ # Forward pass to activate hooks
285
+ with torch.no_grad():
286
+ torch_model(sample_input)
287
+
288
+ # Remove hooks
289
+ for hook in hooks:
290
+ hook.remove()
291
+
292
+ # Convert each layer
293
+ for info in layer_info:
294
+ module = info['module']
295
+ if isinstance(module, nn.Linear):
296
+ layer = Dense(module.out_features)
297
+ # Set weights and biases
298
+ layer.weights = Tensor(module.weight.detach().numpy().T)
299
+ if module.bias is not None:
300
+ layer.bias = Tensor(module.bias.detach().numpy())
301
+ self.layers.append(layer)
302
+
303
+ elif isinstance(module, nn.Conv2d):
304
+ layer = Conv2D(
305
+ filters=module.out_channels,
306
+ kernel_size=module.kernel_size,
307
+ strides=module.stride,
308
+ padding=module.padding
309
+ )
310
+ # Set weights and biases
311
+ layer.kernels = Tensor(module.weight.detach().numpy())
312
+ if module.bias is not None:
313
+ layer.bias = Tensor(module.bias.detach().numpy())
314
+ self.layers.append(layer)
315
+
316
+ elif isinstance(module, nn.MaxPool2d):
317
+ layer = MaxPool2D(
318
+ pool_size=module.kernel_size,
319
+ strides=module.stride,
320
+ padding=module.padding
321
+ )
322
+ self.layers.append(layer)
323
+
324
+ elif isinstance(module, nn.Flatten):
325
+ layer = Flatten()
326
+ self.layers.append(layer)
327
+
328
+ elif isinstance(module, nn.Dropout):
329
+ layer = Dropout(rate=module.p)
330
+ self.layers.append(layer)
331
+
332
+ def forward(self, x):
333
+ for layer in self.layers:
334
+ x = layer(x)
335
+ return x
336
+
337
+ return OpenArchXModelFromPyTorch(torch_model, input_shape)
338
+
339
+
340
+ # Convenience functions
341
+
342
+ def get_pytorch_model_adapter(torch_model, device=None):
343
+ """
344
+ Helper function to get a PyTorch model adapter.
345
+
346
+ Args:
347
+ torch_model: A PyTorch nn.Module model.
348
+ device: The device to run the model on.
349
+
350
+ Returns:
351
+ A PyTorchModelAdapter instance.
352
+ """
353
+ return PyTorchModelAdapter(torch_model, device)
354
+
355
+
356
+ def convert_to_pytorch_dataset(ox_dataset, tensor_dtype=None):
357
+ """
358
+ Convert an OpenArchX Dataset to a PyTorch Dataset.
359
+
360
+ Args:
361
+ ox_dataset: An OpenArchX Dataset instance.
362
+ tensor_dtype: Optional dtype for the PyTorch tensors.
363
+
364
+ Returns:
365
+ A PyTorch Dataset.
366
+ """
367
+ return PyTorchDatasetConverter.from_openarchx_dataset(ox_dataset, tensor_dtype)
368
+
369
+
370
+ def convert_from_pytorch_dataset(torch_dataset, transform=None):
371
+ """
372
+ Convert a PyTorch Dataset to an OpenArchX Dataset.
373
+
374
+ Args:
375
+ torch_dataset: A PyTorch Dataset instance.
376
+ transform: Optional transform to apply to the data.
377
+
378
+ Returns:
379
+ An OpenArchX Dataset.
380
+ """
381
+ return PyTorchDatasetConverter.to_openarchx_dataset(torch_dataset, transform)
382
+
383
+
384
+ def convert_pytorch_model(torch_model, input_shape=None, framework_dependence=False):
385
+ """
386
+ Convert a PyTorch model to an OpenArchX model.
387
+
388
+ Args:
389
+ torch_model: A PyTorch nn.Module model.
390
+ input_shape: The shape of the input tensor (excluding batch dimension).
391
+ framework_dependence: If True, the resulting model will still rely on PyTorch.
392
+ If False, it will be converted to pure OpenArchX layers.
393
+
394
+ Returns:
395
+ An OpenArchX model.
396
+ """
397
+ return PyTorchModelConverter.convert_model(torch_model, input_shape, framework_dependence)
398
+
399
+
400
+ def extract_pytorch_weights(torch_model):
401
+ """
402
+ Extract weights from a PyTorch model.
403
+
404
+ Args:
405
+ torch_model: A PyTorch nn.Module model.
406
+
407
+ Returns:
408
+ Dictionary mapping parameter names to OpenArchX Tensors.
409
+ """
410
+ # Check if torch is installed
411
+ if importlib.util.find_spec("torch") is None:
412
+ raise ImportError("PyTorch is required. Install with 'pip install torch'")
413
+
414
+ weights_dict = {}
415
+
416
+ # Iterate through named parameters
417
+ for name, param in torch_model.named_parameters():
418
+ weights_dict[name] = Tensor(param.detach().cpu().numpy())
419
+
420
+ return weights_dict