PyTorch and TensorFlow Interoperability
Safe GPU memory sharing between Epochly and deep learning frameworks.
Overview
Epochly provides different levels of integration with PyTorch and TensorFlow to safely share GPU memory.
Framework Support Levels
| Framework | Support Tier | Capabilities |
|---|---|---|
| PyTorch | Tier 2: Coordination | Zero-copy tensor sharing via DLPack, memory budget coordination |
| TensorFlow | Tier 1: Detection | Runtime detection, memory configuration guidance |
PyTorch Integration
Automatic Detection
Epochly automatically detects if PyTorch is active and coordinates GPU memory usage.
import epochly# Check if PyTorch is activeif epochly.is_pytorch_active():print("PyTorch detected - GPU memory coordination active")# Get PyTorch memory infopytorch_memory = epochly.get_pytorch_memory_usage()print(f"PyTorch using: {pytorch_memory / 1e9:.2f} GB")
Zero-Copy Tensor Sharing via DLPack
Use the PyTorch coordinator for safe zero-copy tensor transfers between PyTorch and CuPy.
import epochlyimport torchimport numpy as np# Get the PyTorch coordinatorcoordinator = epochly.get_pytorch_coordinator()@epochly.optimize(level=4) # GPU accelerationdef process_with_pytorch_integration(pytorch_tensor):"""Safe GPU memory sharing with PyTorch"""# Convert PyTorch tensor to CuPy array (zero-copy via DLPack)cupy_array = coordinator.safe_tensor_to_cupy(pytorch_tensor)# Perform operations on GPUresult = cupy_array ** 2 + np.sin(cupy_array)# Convert back to PyTorch tensor (zero-copy)output_tensor = coordinator.safe_cupy_to_tensor(result)return output_tensor# Create PyTorch tensor on GPUx = torch.randn(1000, 1000, device='cuda')# Process with Epochly (shares GPU memory safely)result = process_with_pytorch_integration(x)print(f"Result shape: {result.shape}")print(f"Result device: {result.device}")
Memory Budget Coordination
Coordinate GPU memory allocation between PyTorch and Epochly.
import epochlyimport torch# Configure memory budgetcoordinator = epochly.get_pytorch_coordinator()# Get current memory usagepytorch_mem = coordinator.get_memory_usage()total_gpu_mem = torch.cuda.get_device_properties(0).total_memoryprint(f"PyTorch memory: {pytorch_mem / 1e9:.2f} GB")print(f"Total GPU memory: {total_gpu_mem / 1e9:.2f} GB")# Coordinate memory budgetsavailable_for_epochly = total_gpu_mem - pytorch_memcoordinator.coordinate_memory_budget(available_for_epochly)print(f"Epochly can use up to: {available_for_epochly / 1e9:.2f} GB")
Safety Gates - Mandatory Synchronization
The coordinator enforces synchronization to prevent race conditions.
import epochlyimport torchcoordinator = epochly.get_pytorch_coordinator()@epochly.optimize(level=4)def safe_mixed_processing(pytorch_tensor):"""Mandatory synchronization prevents race conditions"""# 1. Convert to CuPy (automatic sync)cupy_array = coordinator.safe_tensor_to_cupy(pytorch_tensor)# 2. Process with Epochly on GPUprocessed = cupy_array * 2 + 1# 3. Convert back to PyTorch (automatic sync)result_tensor = coordinator.safe_cupy_to_tensor(processed)# Synchronization is enforced at conversion boundaries# No manual torch.cuda.synchronize() neededreturn result_tensorx = torch.randn(5000, 5000, device='cuda')result = safe_mixed_processing(x)
What Epochly Does NOT Do
Important: Epochly does not re-parallelize PyTorch operations because they already release the GIL.
import epochlyimport torch# NO BENEFIT: PyTorch operations already release GIL@epochly.optimize(level=3)def unnecessary_optimization(tensor):"""PyTorch ops don't benefit from Level 3"""# These already release GIL and use optimized librariesreturn torch.matmul(tensor, tensor.T)# BENEFIT: Custom Python logic with PyTorch data@epochly.optimize(level=3)def beneficial_optimization(tensors):"""Level 3 helps with Python logic, not tensor ops"""results = []for tensor in tensors:# Python loop overhead is reducedresult = tensor.cpu().numpy()results.append(result.sum())return results# BEST: Use coordinator for GPU memory sharing@epochly.optimize(level=4)def best_practice(pytorch_tensor):"""Use Level 4 with coordinator for GPU sharing"""coordinator = epochly.get_pytorch_coordinator()cupy_array = coordinator.safe_tensor_to_cupy(pytorch_tensor)# Now use Epochly's GPU operationsreturn cupy_array ** 2
TensorFlow Integration
CRITICAL WARNING: Memory Pre-allocation
TensorFlow pre-allocates ALL GPU memory by default! This prevents Epochly from using the GPU.
# WARNING: This will allocate ALL GPU memory to TensorFlowimport tensorflow as tfimport epochly# TensorFlow has taken all GPU memory# Epochly Level 4 will fail with OOM error
Required Configuration - Set Memory Growth
You MUST call set_memory_growth() BEFORE any TensorFlow operations.
import tensorflow as tf# CORRECT: Configure BEFORE importing Epochly or creating tensorsgpus = tf.config.list_physical_devices('GPU')if gpus:try:# Enable memory growth for all GPUsfor gpu in gpus:tf.config.experimental.set_memory_growth(gpu, True)print("TensorFlow memory growth enabled")except RuntimeError as e:print(f"Memory growth must be set before GPUs are initialized: {e}")# Now safe to use Epochly with GPUimport epochly@epochly.optimize(level=4)def process_with_tensorflow_coexistence():# Epochly can now allocate GPU memoryreturn cupy.random.rand(1000, 1000)
Import Order Diagram
CORRECT Import Order:
1. Import TensorFlowimport tensorflow as tf2. Configure Memory Growthtf.config.experimental.set_memory_growth(gpu, True)3. Import Epochlyimport epochly4. Use Both Safelytf.keras.Model(...)epochly.optimize(level=4)
INCORRECT Import Order:
1. Import TensorFlowimport tensorflow as tf2. Create TensorFlow Tensorx = tf.constant([1, 2, 3])(GPU memory allocated!)3. Try to Set Memory Growthset_memory_growth(gpu, True)ERROR: Too late!
Alternative: Limit TensorFlow Memory
If you can't use memory growth, explicitly limit TensorFlow's GPU memory.
import tensorflow as tf# Limit TensorFlow to specific memory amount (e.g., 4GB)gpus = tf.config.list_physical_devices('GPU')if gpus:try:tf.config.set_logical_device_configuration(gpus[0],[tf.config.LogicalDeviceConfiguration(memory_limit=4096)] # 4GB)print("TensorFlow limited to 4GB")except RuntimeError as e:print(f"Virtual devices must be set before GPUs are initialized: {e}")# Now Epochly can use remaining GPU memoryimport epochlyepochly.configure(enhancement_level=4,gpu_memory_limit=4096 # Use remaining 4GB)
Mixed Workflows
PyTorch + Epochly GPU Workflow
import torchimport epochlyimport numpy as np# Get coordinatorcoordinator = epochly.get_pytorch_coordinator()def mixed_pytorch_epochly_workflow():"""Complete workflow mixing PyTorch and Epochly on GPU"""# 1. Create data with PyTorchpytorch_data = torch.randn(10000, 512, device='cuda')# 2. Process with Epochly Level 4 (zero-copy transfer)@epochly.optimize(level=4)def epochly_preprocessing(tensor):# Convert to CuPy (zero-copy via DLPack)cupy_array = coordinator.safe_tensor_to_cupy(tensor)# Perform operations on GPUnormalized = (cupy_array - cupy_array.mean()) / cupy_array.std()# Convert back to PyTorchreturn coordinator.safe_cupy_to_tensor(normalized)preprocessed = epochly_preprocessing(pytorch_data)# 3. Train with PyTorchmodel = torch.nn.Linear(512, 10).cuda()optimizer = torch.optim.Adam(model.parameters())output = model(preprocessed)loss = output.mean()loss.backward()optimizer.step()# 4. Post-process predictions with Epochly@epochly.optimize(level=4)def epochly_postprocessing(predictions):cupy_pred = coordinator.safe_tensor_to_cupy(predictions)# Custom GPU operationssoftmax = np.exp(cupy_pred) / np.exp(cupy_pred).sum(axis=1, keepdims=True)return coordinator.safe_cupy_to_tensor(softmax)with torch.no_grad():predictions = model(preprocessed)final = epochly_postprocessing(predictions)return finalresult = mixed_pytorch_epochly_workflow()print(f"Final result shape: {result.shape}")
TensorFlow + NumPy Workflow
import tensorflow as tfimport epochlyimport numpy as np# Configure TensorFlow FIRSTgpus = tf.config.list_physical_devices('GPU')if gpus:for gpu in gpus:tf.config.experimental.set_memory_growth(gpu, True)def mixed_tensorflow_epochly_workflow():"""Mix TensorFlow and Epochly (CPU-based)"""# 1. Prepare data with Epochly (Level 3 for CPU parallelism)@epochly.optimize(level=3)def prepare_data(file_paths):data = []for path in file_paths:arr = np.load(path)arr = (arr - arr.mean()) / arr.std()data.append(arr)return np.stack(data)# Prepare datasetfile_paths = [f'data_{i}.npy' for i in range(100)]data = prepare_data(file_paths)# 2. Train with TensorFlowmodel = tf.keras.Sequential([tf.keras.layers.Dense(128, activation='relu'),tf.keras.layers.Dense(10)])model.compile(optimizer='adam', loss='mse')labels = np.random.rand(len(data), 10)model.fit(data, labels, epochs=5)# 3. Post-process predictions with Epochly@epochly.optimize(level=3)def post_process(predictions):# Custom NumPy operations in parallelresults = []for pred in predictions:result = pred ** 2 + np.sin(pred)results.append(result)return np.array(results)predictions = model.predict(data)final = post_process(predictions)return finalresult = mixed_tensorflow_epochly_workflow()
Troubleshooting
Common Errors and Solutions
Error: CUDA out of memory with TensorFlow
# Problem: TensorFlow allocated all GPU memoryRuntimeError: CUDA out of memory# Solution: Set memory growth BEFORE any TF operationsimport tensorflow as tfgpus = tf.config.list_physical_devices('GPU')for gpu in gpus:tf.config.experimental.set_memory_growth(gpu, True)
Error: Coordinator not available
# Problem: Trying to get coordinator when PyTorch not detectedAttributeError: PyTorch coordinator not available# Solution: Check if PyTorch is active firstimport epochlyif epochly.is_pytorch_active():coordinator = epochly.get_pytorch_coordinator()else:print("PyTorch not detected")
Error: RuntimeError setting memory growth
# Problem: Tried to set memory growth after GPU initializationRuntimeError: Virtual devices must be set before GPUs have been initialized# Solution: Import and configure TensorFlow FIRSTimport tensorflow as tf# Configure IMMEDIATELY after import, before ANY operationsgpus = tf.config.list_physical_devices('GPU')for gpu in gpus:tf.config.experimental.set_memory_growth(gpu, True)# Only NOW import other librariesimport epochly
Debug GPU Memory Issues
import epochlyimport torchimport tensorflow as tfdef debug_gpu_memory():"""Debug GPU memory allocation"""# Check PyTorch memoryif torch.cuda.is_available():pytorch_mem = torch.cuda.memory_allocated() / 1e9pytorch_reserved = torch.cuda.memory_reserved() / 1e9print(f"PyTorch allocated: {pytorch_mem:.2f} GB")print(f"PyTorch reserved: {pytorch_reserved:.2f} GB")# Check TensorFlow memorygpus = tf.config.list_physical_devices('GPU')if gpus:print(f"TensorFlow GPUs: {len(gpus)}")for i, gpu in enumerate(gpus):print(f"GPU {i}: {gpu.name}")# Check Epochly statusstatus = epochly.get_status()print(f"Epochly GPU available: {status.get('gpu_available', False)}")print(f"Epochly Level: {status.get('enhancement_level')}")debug_gpu_memory()
Best Practices
PyTorch-Specific Tips
- Always use the coordinator for GPU tensors
```python
coordinator = epochly.get_pytorch_coordinator()
cupy_array = coordinator.safe_tensor_to_cupy(tensor)
```
- Don't optimize PyTorch native operations
```python
# No benefit
@epochly.optimize(level=3)
def bad():
return torch.matmul(a, b)
# Optimize Python logic
@epochly.optimize(level=3)
def good():
return [process(x) for x in data]
```
- Coordinate memory budgets for large models
```python
coordinator = epochly.get_pytorch_coordinator()
available = total_gpu_mem - pytorch_mem
coordinator.coordinate_memory_budget(available)
```
TensorFlow-Specific Tips
- Always configure memory growth first
```python
# Do this at the very top of your script
import tensorflow as tf
gpus = tf.config.list_physical_devices('GPU')
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
```
- Use Epochly for data preprocessing, not TF ops
```python
# ✅ Good: Preprocess with Epochly
@epochly.optimize(level=3)
def preprocess(files):
return [load_and_process(f) for f in files]
# Use preprocessed data with TensorFlow
data = preprocess(files)
model.fit(data, labels)
```
- Consider CPU-only Epochly for TensorFlow workflows
```python
# TensorFlow uses GPU, Epochly uses CPU parallelism
epochly.configure(enhancement_level=3) # Level 3, not 4
```