Documentation

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

FrameworkSupport TierCapabilities
PyTorchTier 2: CoordinationZero-copy tensor sharing via DLPack, memory budget coordination
TensorFlowTier 1: DetectionRuntime 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 active
if epochly.is_pytorch_active():
print("PyTorch detected - GPU memory coordination active")
# Get PyTorch memory info
pytorch_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 epochly
import torch
import numpy as np
# Get the PyTorch coordinator
coordinator = epochly.get_pytorch_coordinator()
@epochly.optimize(level=4) # GPU acceleration
def 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 GPU
result = 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 GPU
x = 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 epochly
import torch
# Configure memory budget
coordinator = epochly.get_pytorch_coordinator()
# Get current memory usage
pytorch_mem = coordinator.get_memory_usage()
total_gpu_mem = torch.cuda.get_device_properties(0).total_memory
print(f"PyTorch memory: {pytorch_mem / 1e9:.2f} GB")
print(f"Total GPU memory: {total_gpu_mem / 1e9:.2f} GB")
# Coordinate memory budgets
available_for_epochly = total_gpu_mem - pytorch_mem
coordinator.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 epochly
import torch
coordinator = 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 GPU
processed = 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() needed
return result_tensor
x = 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 epochly
import 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 libraries
return 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 reduced
result = 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 operations
return 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 TensorFlow
import tensorflow as tf
import 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 tensors
gpus = tf.config.list_physical_devices('GPU')
if gpus:
try:
# Enable memory growth for all GPUs
for 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 GPU
import epochly
@epochly.optimize(level=4)
def process_with_tensorflow_coexistence():
# Epochly can now allocate GPU memory
return cupy.random.rand(1000, 1000)

Import Order Diagram

CORRECT Import Order:

1. Import TensorFlow
import tensorflow as tf
2. Configure Memory Growth
tf.config.experimental.set_memory_growth(gpu, True)
3. Import Epochly
import epochly
4. Use Both Safely
tf.keras.Model(...)
epochly.optimize(level=4)

INCORRECT Import Order:

1. Import TensorFlow
import tensorflow as tf
2. Create TensorFlow Tensor
x = tf.constant([1, 2, 3])
(GPU memory allocated!)
3. Try to Set Memory Growth
set_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 memory
import epochly
epochly.configure(
enhancement_level=4,
gpu_memory_limit=4096 # Use remaining 4GB
)

Mixed Workflows

PyTorch + Epochly GPU Workflow

import torch
import epochly
import numpy as np
# Get coordinator
coordinator = epochly.get_pytorch_coordinator()
def mixed_pytorch_epochly_workflow():
"""Complete workflow mixing PyTorch and Epochly on GPU"""
# 1. Create data with PyTorch
pytorch_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 GPU
normalized = (cupy_array - cupy_array.mean()) / cupy_array.std()
# Convert back to PyTorch
return coordinator.safe_cupy_to_tensor(normalized)
preprocessed = epochly_preprocessing(pytorch_data)
# 3. Train with PyTorch
model = 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 operations
softmax = 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 final
result = mixed_pytorch_epochly_workflow()
print(f"Final result shape: {result.shape}")

TensorFlow + NumPy Workflow

import tensorflow as tf
import epochly
import numpy as np
# Configure TensorFlow FIRST
gpus = 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 dataset
file_paths = [f'data_{i}.npy' for i in range(100)]
data = prepare_data(file_paths)
# 2. Train with TensorFlow
model = 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 parallel
results = []
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 final
result = mixed_tensorflow_epochly_workflow()

Troubleshooting

Common Errors and Solutions

Error: CUDA out of memory with TensorFlow

# Problem: TensorFlow allocated all GPU memory
RuntimeError: CUDA out of memory
# Solution: Set memory growth BEFORE any TF operations
import tensorflow as tf
gpus = 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 detected
AttributeError: PyTorch coordinator not available
# Solution: Check if PyTorch is active first
import epochly
if 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 initialization
RuntimeError: Virtual devices must be set before GPUs have been initialized
# Solution: Import and configure TensorFlow FIRST
import tensorflow as tf
# Configure IMMEDIATELY after import, before ANY operations
gpus = tf.config.list_physical_devices('GPU')
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
# Only NOW import other libraries
import epochly

Debug GPU Memory Issues

import epochly
import torch
import tensorflow as tf
def debug_gpu_memory():
"""Debug GPU memory allocation"""
# Check PyTorch memory
if torch.cuda.is_available():
pytorch_mem = torch.cuda.memory_allocated() / 1e9
pytorch_reserved = torch.cuda.memory_reserved() / 1e9
print(f"PyTorch allocated: {pytorch_mem:.2f} GB")
print(f"PyTorch reserved: {pytorch_reserved:.2f} GB")
# Check TensorFlow memory
gpus = 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 status
status = 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

  1. Always use the coordinator for GPU tensors

```python

coordinator = epochly.get_pytorch_coordinator()

cupy_array = coordinator.safe_tensor_to_cupy(tensor)

```

  1. 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]

```

  1. 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

  1. 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)

```

  1. 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)

```

  1. Consider CPU-only Epochly for TensorFlow workflows

```python

# TensorFlow uses GPU, Epochly uses CPU parallelism

epochly.configure(enhancement_level=3) # Level 3, not 4

```