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.
- openarchx/__init__.py +11 -0
- openarchx/core/tensor.py +179 -0
- openarchx/cuda/__init__.py +27 -0
- openarchx/cuda/cuda_ops.py +296 -0
- openarchx/layers/activations.py +63 -0
- openarchx/layers/base.py +40 -0
- openarchx/layers/cnn.py +145 -0
- openarchx/layers/transformer.py +131 -0
- openarchx/nn/__init__.py +26 -0
- openarchx/nn/activations.py +127 -0
- openarchx/nn/containers.py +174 -0
- openarchx/nn/dropout.py +121 -0
- openarchx/nn/layers.py +338 -0
- openarchx/nn/losses.py +156 -0
- openarchx/nn/module.py +18 -0
- openarchx/nn/padding.py +120 -0
- openarchx/nn/pooling.py +318 -0
- openarchx/nn/rnn.py +226 -0
- openarchx/nn/transformers.py +187 -0
- openarchx/optimizers/adam.py +49 -0
- openarchx/optimizers/adaptive.py +63 -0
- openarchx/optimizers/base.py +24 -0
- openarchx/optimizers/modern.py +98 -0
- openarchx/optimizers/optx.py +91 -0
- openarchx/optimizers/sgd.py +63 -0
- openarchx/quantum/circuit.py +92 -0
- openarchx/quantum/gates.py +126 -0
- openarchx/utils/__init__.py +50 -0
- openarchx/utils/data.py +229 -0
- openarchx/utils/huggingface.py +288 -0
- openarchx/utils/losses.py +21 -0
- openarchx/utils/model_io.py +553 -0
- openarchx/utils/pytorch.py +420 -0
- openarchx/utils/tensorflow.py +467 -0
- openarchx/utils/transforms.py +259 -0
- openarchx-0.1.0.dist-info/METADATA +180 -0
- openarchx-0.1.0.dist-info/RECORD +43 -0
- openarchx-0.1.0.dist-info/WHEEL +5 -0
- openarchx-0.1.0.dist-info/licenses/LICENSE +21 -0
- openarchx-0.1.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +1 -0
- tests/test_cuda_ops.py +205 -0
- tests/test_integrations.py +236 -0
@@ -0,0 +1,467 @@
|
|
1
|
+
"""
|
2
|
+
TensorFlow Integration Utilities for OpenArchX.
|
3
|
+
|
4
|
+
This module provides conversion and adapter utilities for using TensorFlow 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 TensorFlowModelAdapter:
|
15
|
+
"""Adapter for using TensorFlow models with OpenArchX."""
|
16
|
+
|
17
|
+
def __init__(self, tf_model, device=None):
|
18
|
+
"""
|
19
|
+
Initialize a TensorFlow model adapter.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
tf_model: A TensorFlow/Keras model.
|
23
|
+
device: The device to run the model on ('/CPU:0', '/GPU:0', etc.).
|
24
|
+
"""
|
25
|
+
# Check if tensorflow is installed
|
26
|
+
if importlib.util.find_spec("tensorflow") is None:
|
27
|
+
raise ImportError("TensorFlow is required. Install with 'pip install tensorflow'")
|
28
|
+
|
29
|
+
import tensorflow as tf
|
30
|
+
|
31
|
+
self.model = tf_model
|
32
|
+
|
33
|
+
# Handle device placement
|
34
|
+
if device is not None:
|
35
|
+
with tf.device(device):
|
36
|
+
# Create a duplicate model on the specified device
|
37
|
+
self.model = tf.keras.models.clone_model(tf_model)
|
38
|
+
self.model.set_weights(tf_model.get_weights())
|
39
|
+
|
40
|
+
def __call__(self, inputs, **kwargs):
|
41
|
+
"""
|
42
|
+
Process inputs through the TensorFlow 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 tensorflow as tf
|
52
|
+
|
53
|
+
# Convert inputs to tf tensors
|
54
|
+
if isinstance(inputs, Tensor):
|
55
|
+
inputs = inputs.data
|
56
|
+
|
57
|
+
if isinstance(inputs, np.ndarray):
|
58
|
+
inputs = tf.convert_to_tensor(inputs, dtype=tf.float32)
|
59
|
+
elif isinstance(inputs, list):
|
60
|
+
inputs = tf.convert_to_tensor(np.array(inputs), dtype=tf.float32)
|
61
|
+
elif not isinstance(inputs, tf.Tensor):
|
62
|
+
raise TypeError(f"Unsupported input type: {type(inputs)}")
|
63
|
+
|
64
|
+
# Forward pass
|
65
|
+
outputs = self.model(inputs, training=False, **kwargs)
|
66
|
+
|
67
|
+
# Convert output to numpy and then to Tensor
|
68
|
+
if isinstance(outputs, tf.Tensor):
|
69
|
+
return Tensor(outputs.numpy())
|
70
|
+
elif isinstance(outputs, (tuple, list)):
|
71
|
+
return tuple(Tensor(output.numpy()) for output in outputs
|
72
|
+
if isinstance(output, tf.Tensor))
|
73
|
+
elif isinstance(outputs, dict):
|
74
|
+
return {k: Tensor(v.numpy()) if isinstance(v, tf.Tensor) else v
|
75
|
+
for k, v in outputs.items()}
|
76
|
+
else:
|
77
|
+
return outputs
|
78
|
+
|
79
|
+
|
80
|
+
class TensorFlowDatasetConverter:
|
81
|
+
"""Utility for converting between TensorFlow and OpenArchX datasets."""
|
82
|
+
|
83
|
+
@staticmethod
|
84
|
+
def to_openarchx_dataset(tf_dataset, transform=None):
|
85
|
+
"""
|
86
|
+
Convert a TensorFlow Dataset to an OpenArchX Dataset.
|
87
|
+
|
88
|
+
Args:
|
89
|
+
tf_dataset: A TensorFlow tf.data.Dataset instance.
|
90
|
+
transform: Optional transform to apply to the data.
|
91
|
+
|
92
|
+
Returns:
|
93
|
+
An OpenArchX Dataset.
|
94
|
+
"""
|
95
|
+
from .data import Dataset
|
96
|
+
|
97
|
+
# Check if tensorflow is installed
|
98
|
+
if importlib.util.find_spec("tensorflow") is None:
|
99
|
+
raise ImportError("TensorFlow is required. Install with 'pip install tensorflow'")
|
100
|
+
|
101
|
+
import tensorflow as tf
|
102
|
+
|
103
|
+
class OpenArchXDatasetFromTensorFlow(Dataset):
|
104
|
+
def __init__(self, tf_dataset, transform=None):
|
105
|
+
self.tf_dataset = tf_dataset
|
106
|
+
self.transform = transform
|
107
|
+
|
108
|
+
# Convert tf.data.Dataset to a list for random access
|
109
|
+
self.data_list = list(tf_dataset.as_numpy_iterator())
|
110
|
+
|
111
|
+
def __len__(self):
|
112
|
+
return len(self.data_list)
|
113
|
+
|
114
|
+
def __getitem__(self, idx):
|
115
|
+
data = self.data_list[idx]
|
116
|
+
|
117
|
+
# Handle different return types from TensorFlow dataset
|
118
|
+
if isinstance(data, tuple) and len(data) == 2:
|
119
|
+
# Standard (input, target) format
|
120
|
+
features, target = data
|
121
|
+
|
122
|
+
# Apply transform if provided
|
123
|
+
if self.transform:
|
124
|
+
features = self.transform(features)
|
125
|
+
|
126
|
+
return features, target
|
127
|
+
else:
|
128
|
+
# Generic handling for other formats
|
129
|
+
return data
|
130
|
+
|
131
|
+
return OpenArchXDatasetFromTensorFlow(tf_dataset, transform)
|
132
|
+
|
133
|
+
@staticmethod
|
134
|
+
def from_openarchx_dataset(ox_dataset, tensor_dtype=None):
|
135
|
+
"""
|
136
|
+
Convert an OpenArchX Dataset to a TensorFlow Dataset.
|
137
|
+
|
138
|
+
Args:
|
139
|
+
ox_dataset: An OpenArchX Dataset instance.
|
140
|
+
tensor_dtype: Optional dtype for the TensorFlow tensors.
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
A TensorFlow tf.data.Dataset.
|
144
|
+
"""
|
145
|
+
# Check if tensorflow is installed
|
146
|
+
if importlib.util.find_spec("tensorflow") is None:
|
147
|
+
raise ImportError("TensorFlow is required. Install with 'pip install tensorflow'")
|
148
|
+
|
149
|
+
import tensorflow as tf
|
150
|
+
|
151
|
+
# Use a generator to create a tf.data.Dataset
|
152
|
+
def generator():
|
153
|
+
for i in range(len(ox_dataset)):
|
154
|
+
data = ox_dataset[i]
|
155
|
+
|
156
|
+
# Handle different return types from OpenArchX dataset
|
157
|
+
if isinstance(data, tuple) and len(data) == 2:
|
158
|
+
# Standard (input, target) format
|
159
|
+
features, target = data
|
160
|
+
|
161
|
+
# Convert to numpy if needed
|
162
|
+
if isinstance(features, Tensor):
|
163
|
+
features = features.data
|
164
|
+
if isinstance(target, Tensor):
|
165
|
+
target = target.data
|
166
|
+
|
167
|
+
yield features, target
|
168
|
+
else:
|
169
|
+
# Generic handling for other formats
|
170
|
+
if isinstance(data, Tensor):
|
171
|
+
yield data.data
|
172
|
+
else:
|
173
|
+
yield data
|
174
|
+
|
175
|
+
# Get the first element to determine shapes and types
|
176
|
+
sample = ox_dataset[0]
|
177
|
+
|
178
|
+
if isinstance(sample, tuple) and len(sample) == 2:
|
179
|
+
features, target = sample
|
180
|
+
feature_shape = features.shape if hasattr(features, 'shape') else None
|
181
|
+
target_shape = target.shape if hasattr(target, 'shape') else None
|
182
|
+
|
183
|
+
feature_dtype = tensor_dtype or tf.float32
|
184
|
+
target_dtype = tensor_dtype or tf.float32
|
185
|
+
|
186
|
+
return tf.data.Dataset.from_generator(
|
187
|
+
generator,
|
188
|
+
output_signature=(
|
189
|
+
tf.TensorSpec(shape=feature_shape, dtype=feature_dtype),
|
190
|
+
tf.TensorSpec(shape=target_shape, dtype=target_dtype)
|
191
|
+
)
|
192
|
+
)
|
193
|
+
else:
|
194
|
+
sample_shape = sample.shape if hasattr(sample, 'shape') else None
|
195
|
+
sample_dtype = tensor_dtype or tf.float32
|
196
|
+
|
197
|
+
return tf.data.Dataset.from_generator(
|
198
|
+
generator,
|
199
|
+
output_signature=tf.TensorSpec(shape=sample_shape, dtype=sample_dtype)
|
200
|
+
)
|
201
|
+
|
202
|
+
|
203
|
+
class TensorFlowModelConverter:
|
204
|
+
"""Utility for converting TensorFlow models to OpenArchX architecture."""
|
205
|
+
|
206
|
+
@staticmethod
|
207
|
+
def convert_model(tf_model, framework_dependence=False):
|
208
|
+
"""
|
209
|
+
Convert a TensorFlow/Keras model to an OpenArchX model.
|
210
|
+
|
211
|
+
Args:
|
212
|
+
tf_model: A TensorFlow/Keras model.
|
213
|
+
framework_dependence: If True, the resulting model will still rely on TensorFlow
|
214
|
+
for forward passes. If False, it will be converted to
|
215
|
+
pure OpenArchX layers.
|
216
|
+
|
217
|
+
Returns:
|
218
|
+
An OpenArchX model.
|
219
|
+
"""
|
220
|
+
# Check if tensorflow is installed
|
221
|
+
if importlib.util.find_spec("tensorflow") is None:
|
222
|
+
raise ImportError("TensorFlow is required. Install with 'pip install tensorflow'")
|
223
|
+
|
224
|
+
import tensorflow as tf
|
225
|
+
from ..nn.base import Layer, Model
|
226
|
+
from ..nn.layers import Dense, Conv2D, MaxPool2D, Flatten, Dropout
|
227
|
+
|
228
|
+
if framework_dependence:
|
229
|
+
# Create a wrapper around the TensorFlow model
|
230
|
+
class TensorFlowWrappedModel(Model):
|
231
|
+
def __init__(self, tf_model):
|
232
|
+
super().__init__()
|
233
|
+
self.tf_model = tf_model
|
234
|
+
|
235
|
+
def forward(self, x):
|
236
|
+
# Convert OpenArchX Tensor to TensorFlow tensor
|
237
|
+
if isinstance(x, Tensor):
|
238
|
+
x_tf = tf.convert_to_tensor(x.data, dtype=tf.float32)
|
239
|
+
else:
|
240
|
+
x_tf = tf.convert_to_tensor(x, dtype=tf.float32)
|
241
|
+
|
242
|
+
# Forward pass
|
243
|
+
output = self.tf_model(x_tf, training=False)
|
244
|
+
|
245
|
+
# Convert back to OpenArchX Tensor
|
246
|
+
if isinstance(output, tf.Tensor):
|
247
|
+
return Tensor(output.numpy())
|
248
|
+
else:
|
249
|
+
return output
|
250
|
+
|
251
|
+
return TensorFlowWrappedModel(tf_model)
|
252
|
+
|
253
|
+
else:
|
254
|
+
# Convert to pure OpenArchX model by translating each layer
|
255
|
+
class OpenArchXModelFromTensorFlow(Model):
|
256
|
+
def __init__(self, tf_model):
|
257
|
+
super().__init__()
|
258
|
+
self.layers = []
|
259
|
+
|
260
|
+
# Convert each layer
|
261
|
+
for layer in tf_model.layers:
|
262
|
+
# Dense (Fully Connected) layer
|
263
|
+
if isinstance(layer, tf.keras.layers.Dense):
|
264
|
+
ox_layer = Dense(layer.units)
|
265
|
+
# Set weights and biases
|
266
|
+
weights, bias = layer.get_weights()
|
267
|
+
ox_layer.weights = Tensor(weights)
|
268
|
+
ox_layer.bias = Tensor(bias)
|
269
|
+
self.layers.append(ox_layer)
|
270
|
+
|
271
|
+
# Convolutional layer
|
272
|
+
elif isinstance(layer, tf.keras.layers.Conv2D):
|
273
|
+
ox_layer = Conv2D(
|
274
|
+
filters=layer.filters,
|
275
|
+
kernel_size=layer.kernel_size,
|
276
|
+
strides=layer.strides,
|
277
|
+
padding='same' if layer.padding.lower() == 'same' else 'valid'
|
278
|
+
)
|
279
|
+
# Set weights and biases
|
280
|
+
weights, bias = layer.get_weights()
|
281
|
+
ox_layer.kernels = Tensor(weights)
|
282
|
+
ox_layer.bias = Tensor(bias)
|
283
|
+
self.layers.append(ox_layer)
|
284
|
+
|
285
|
+
# MaxPooling layer
|
286
|
+
elif isinstance(layer, tf.keras.layers.MaxPool2D):
|
287
|
+
ox_layer = MaxPool2D(
|
288
|
+
pool_size=layer.pool_size,
|
289
|
+
strides=layer.strides,
|
290
|
+
padding='same' if layer.padding.lower() == 'same' else 'valid'
|
291
|
+
)
|
292
|
+
self.layers.append(ox_layer)
|
293
|
+
|
294
|
+
# Flatten layer
|
295
|
+
elif isinstance(layer, tf.keras.layers.Flatten):
|
296
|
+
ox_layer = Flatten()
|
297
|
+
self.layers.append(ox_layer)
|
298
|
+
|
299
|
+
# Dropout layer
|
300
|
+
elif isinstance(layer, tf.keras.layers.Dropout):
|
301
|
+
ox_layer = Dropout(rate=layer.rate)
|
302
|
+
self.layers.append(ox_layer)
|
303
|
+
|
304
|
+
# Other layer types could be added as needed
|
305
|
+
else:
|
306
|
+
raise ValueError(f"Unsupported layer type: {type(layer).__name__}")
|
307
|
+
|
308
|
+
def forward(self, x):
|
309
|
+
for layer in self.layers:
|
310
|
+
x = layer(x)
|
311
|
+
return x
|
312
|
+
|
313
|
+
return OpenArchXModelFromTensorFlow(tf_model)
|
314
|
+
|
315
|
+
|
316
|
+
class ModelWeightsExtractor:
|
317
|
+
"""Utility for extracting weights from TensorFlow models for use in OpenArchX."""
|
318
|
+
|
319
|
+
@staticmethod
|
320
|
+
def extract_transformer_weights(tf_model, layer_mapping=None):
|
321
|
+
"""
|
322
|
+
Extract weights from a TensorFlow transformer model into a format usable by OpenArchX.
|
323
|
+
|
324
|
+
Args:
|
325
|
+
tf_model: A TensorFlow transformer model.
|
326
|
+
layer_mapping: Optional dictionary mapping TensorFlow layer names to
|
327
|
+
OpenArchX parameter names.
|
328
|
+
|
329
|
+
Returns:
|
330
|
+
Dictionary mapping OpenArchX parameter names to weights as Tensors.
|
331
|
+
"""
|
332
|
+
# Check if tensorflow is installed
|
333
|
+
if importlib.util.find_spec("tensorflow") is None:
|
334
|
+
raise ImportError("TensorFlow is required. Install with 'pip install tensorflow'")
|
335
|
+
|
336
|
+
# Default mapping for common transformer architectures
|
337
|
+
default_mapping = {
|
338
|
+
'embeddings': 'embedding',
|
339
|
+
'encoder': 'encoder',
|
340
|
+
'decoder': 'decoder',
|
341
|
+
'attention': 'attention',
|
342
|
+
'dense': 'linear',
|
343
|
+
'layer_norm': 'norm',
|
344
|
+
'kernel': 'weight',
|
345
|
+
'bias': 'bias'
|
346
|
+
}
|
347
|
+
|
348
|
+
mapping = default_mapping
|
349
|
+
if layer_mapping:
|
350
|
+
mapping.update(layer_mapping)
|
351
|
+
|
352
|
+
result = {}
|
353
|
+
|
354
|
+
# Process weights
|
355
|
+
for weight in tf_model.weights:
|
356
|
+
name = weight.name
|
357
|
+
value = weight.numpy()
|
358
|
+
|
359
|
+
# Transform the name according to the mapping
|
360
|
+
transformed_name = name
|
361
|
+
for tf_key, ox_key in mapping.items():
|
362
|
+
transformed_name = transformed_name.replace(tf_key, ox_key)
|
363
|
+
|
364
|
+
# Remove any TensorFlow-specific suffixes
|
365
|
+
transformed_name = transformed_name.replace(':0', '')
|
366
|
+
|
367
|
+
# Store the weight as a Tensor
|
368
|
+
result[transformed_name] = Tensor(value)
|
369
|
+
|
370
|
+
return result
|
371
|
+
|
372
|
+
|
373
|
+
# Convenience functions
|
374
|
+
|
375
|
+
def get_tensorflow_model_adapter(tf_model, device=None):
|
376
|
+
"""
|
377
|
+
Helper function to get a TensorFlow model adapter.
|
378
|
+
|
379
|
+
Args:
|
380
|
+
tf_model: A TensorFlow/Keras model.
|
381
|
+
device: The device to run the model on.
|
382
|
+
|
383
|
+
Returns:
|
384
|
+
A TensorFlowModelAdapter instance.
|
385
|
+
"""
|
386
|
+
return TensorFlowModelAdapter(tf_model, device)
|
387
|
+
|
388
|
+
|
389
|
+
def convert_to_tensorflow_dataset(ox_dataset, tensor_dtype=None):
|
390
|
+
"""
|
391
|
+
Convert an OpenArchX Dataset to a TensorFlow Dataset.
|
392
|
+
|
393
|
+
Args:
|
394
|
+
ox_dataset: An OpenArchX Dataset instance.
|
395
|
+
tensor_dtype: Optional dtype for the TensorFlow tensors.
|
396
|
+
|
397
|
+
Returns:
|
398
|
+
A TensorFlow Dataset.
|
399
|
+
"""
|
400
|
+
return TensorFlowDatasetConverter.from_openarchx_dataset(ox_dataset, tensor_dtype)
|
401
|
+
|
402
|
+
|
403
|
+
def convert_from_tensorflow_dataset(tf_dataset, transform=None):
|
404
|
+
"""
|
405
|
+
Convert a TensorFlow Dataset to an OpenArchX Dataset.
|
406
|
+
|
407
|
+
Args:
|
408
|
+
tf_dataset: A TensorFlow Dataset instance.
|
409
|
+
transform: Optional transform to apply to the data.
|
410
|
+
|
411
|
+
Returns:
|
412
|
+
An OpenArchX Dataset.
|
413
|
+
"""
|
414
|
+
return TensorFlowDatasetConverter.to_openarchx_dataset(tf_dataset, transform)
|
415
|
+
|
416
|
+
|
417
|
+
def convert_tensorflow_model(tf_model, framework_dependence=False):
|
418
|
+
"""
|
419
|
+
Convert a TensorFlow model to an OpenArchX model.
|
420
|
+
|
421
|
+
Args:
|
422
|
+
tf_model: A TensorFlow/Keras model.
|
423
|
+
framework_dependence: If True, the resulting model will still rely on TensorFlow.
|
424
|
+
If False, it will be converted to pure OpenArchX layers.
|
425
|
+
|
426
|
+
Returns:
|
427
|
+
An OpenArchX model.
|
428
|
+
"""
|
429
|
+
return TensorFlowModelConverter.convert_model(tf_model, framework_dependence)
|
430
|
+
|
431
|
+
|
432
|
+
def extract_tensorflow_weights(tf_model):
|
433
|
+
"""
|
434
|
+
Extract weights from a TensorFlow model.
|
435
|
+
|
436
|
+
Args:
|
437
|
+
tf_model: A TensorFlow model.
|
438
|
+
|
439
|
+
Returns:
|
440
|
+
Dictionary mapping parameter names to OpenArchX Tensors.
|
441
|
+
"""
|
442
|
+
# Check if tensorflow is installed
|
443
|
+
if importlib.util.find_spec("tensorflow") is None:
|
444
|
+
raise ImportError("TensorFlow is required. Install with 'pip install tensorflow'")
|
445
|
+
|
446
|
+
weights_dict = {}
|
447
|
+
|
448
|
+
# Extract weights from the model
|
449
|
+
for weight in tf_model.weights:
|
450
|
+
name = weight.name.replace(':0', '') # Remove TensorFlow-specific suffix
|
451
|
+
weights_dict[name] = Tensor(weight.numpy())
|
452
|
+
|
453
|
+
return weights_dict
|
454
|
+
|
455
|
+
|
456
|
+
def extract_transformer_weights(tf_model, layer_mapping=None):
|
457
|
+
"""
|
458
|
+
Extract weights from a TensorFlow transformer model for use in OpenArchX.
|
459
|
+
|
460
|
+
Args:
|
461
|
+
tf_model: A TensorFlow transformer model.
|
462
|
+
layer_mapping: Optional dictionary mapping TensorFlow layer names to OpenArchX names.
|
463
|
+
|
464
|
+
Returns:
|
465
|
+
Dictionary mapping OpenArchX parameter names to weights as Tensors.
|
466
|
+
"""
|
467
|
+
return ModelWeightsExtractor.extract_transformer_weights(tf_model, layer_mapping)
|