Skip to content

Commit

Permalink
Fix NetworkProfiler import and prepare for v0.2 release
Browse files Browse the repository at this point in the history
  • Loading branch information
MEHDI342 committed Oct 1, 2024
1 parent fc1cb62 commit dea7c05
Show file tree
Hide file tree
Showing 10 changed files with 456 additions and 149 deletions.
76 changes: 64 additions & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@ name: Memoraith CI

on:
push:
branches: [ main ]
branches: [ main, develop ]
pull_request:
branches: [ main ]
branches: [ main, develop ]

jobs:
build:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.7, 3.8, 3.9, '3.10']
python-version: [3.8, 3.9, '3.10']
fail-fast: false

steps:
- uses: actions/checkout@v2
Expand All @@ -22,15 +23,66 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
pip install tox tox-gh-actions
- name: Test with tox
run: tox
env:
PYTHON_VERSION: ${{ matrix.python-version }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
fail_ci_if_error: true

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install dependencies
run: |
pytest tests/
- name: Lint with flake8
python -m pip install --upgrade pip
pip install flake8 mypy
- name: Run linters
run: |
pip install flake8
flake8 .
- name: Check type hints with mypy
mypy memoraith
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install dependencies
run: |
pip install mypy
mypy memoraith/
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install sphinx sphinx-rtd-theme
- name: Build documentation
run: |
cd docs
make html
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/build/html

build:
needs: [test, lint, docs]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install pypa/build
run: python -m pip install build
- name: Build a binary wheel and a source tarball
run: python -m build --sdist --wheel --outdir dist/ .
65 changes: 37 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
# Memoraith

Memoraith is a lightweight model profiler for deep learning frameworks, designed to help you optimize your neural network models by providing detailed insights into their performance characteristics.
Memoraith is a cutting-edge, lightweight model profiler for deep learning frameworks, developed by Mehdi El Jouhfi. It's designed to revolutionize the optimization of neural network models by providing unparalleled insights into their performance characteristics.

## Features

- Supports PyTorch and TensorFlow models
- Profiles memory usage (CPU and GPU)
- Measures computation time for each layer
- Detects bottlenecks and anomalies
- Generates comprehensive reports with visualizations
- Provides real-time visualization capabilities
- Offers both programmatic and command-line interfaces
- Advanced support for PyTorch and TensorFlow models
- High-precision profiling of memory usage (CPU and GPU)
- Microsecond-accurate computation time measurement for each layer
- Sophisticated bottleneck and anomaly detection algorithms
- Generation of comprehensive, interactive reports with advanced visualizations
- Real-time visualization capabilities with minimal overhead
- Flexible programmatic and command-line interfaces

## Installation

You can install Memoraith using pip:
Install Memoraith using pip:

```bash
pip install memoraith
```

For GPU support, install with:
For GPU support and additional features:

```bash
pip install memoraith[gpu]
pip install memoraith[full]
```

## Quick Start

Here's a simple example of how to use Memoraith with a PyTorch model:
Here's an example of Memoraith in action with a PyTorch model:

```python
from memoraith import profile_model, set_output_path
Expand All @@ -37,56 +37,65 @@ import torch.nn as nn

set_output_path('profiling_results/')

class SimpleNet(nn.Module):
class AdvancedNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
self.fc = nn.Linear(10, 5)
super(AdvancedNet, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3, padding=1)
self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=1)
self.fc = nn.Linear(128 * 8 * 8, 10)

def forward(self, x):
x = torch.relu(self.conv1(x))
x = torch.relu(self.conv2(x))
x = x.view(x.size(0), -1)
return self.fc(x)

@profile_model(memory=True, computation=True, gpu=True)
@profile_model(memory=True, computation=True, gpu=True, network=True)
def train_model(model):
optimizer = torch.optim.Adam(model.parameters())
for _ in range(100):
input_data = torch.randn(32, 10)
input_data = torch.randn(32, 3, 32, 32)
output = model(input_data)
loss = output.sum()
loss.backward()
optimizer.step()

if __name__ == "__main__":
model = SimpleNet()
model = AdvancedNet()
train_model(model)
```

This will generate a profiling report in the 'profiling_results/' directory.
This will generate a comprehensive profiling report in the 'profiling_results/' directory.

## Documentation

For more detailed information on how to use Memoraith, please refer to our [documentation](https://memoraith.readthedocs.io).
For detailed information on Memoraith's advanced features, please refer to our [comprehensive documentation](https://memoraith.readthedocs.io).

## Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for more details.
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.

## License

Memoraith is released under the MIT License. See the [LICENSE](LICENSE) file for more details.

## Support

If you encounter any issues or have questions, please file an issue on the [GitHub issue tracker](https://github.com/yourusername/memoraith/issues).
If you encounter any issues or have questions, please file an issue on the [GitHub issue tracker](https://github.com/mehdi342/Memoraith/issues).

## Citing Memoraith

If you use Memoraith in your research, please cite it as follows:

```
```bibtex
@software{memoraith,
author = {Your Name},
title = {Memoraith: A Lightweight Model Profiler for Deep Learning},
year = {2023},
url = {https://github.com/yourusername/memoraith}
author = {El Jouhfi, Mehdi},
title = {Memoraith: Advanced Lightweight Model Profiler for Deep Learning},
year = {2024},
url = {https://github.com/mehdi342/Memoraith}
}
```
```

## Contact

For inquiries, please contact Mehdi El Jouhfi at midojouhfi@gmail.com.
3 changes: 2 additions & 1 deletion memoraith/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
from .profiler import profile_model, set_output_path
from .config import Config
from .exceptions import MemoraithError
from .visualization.real_time_visualizer import RealTimeVisualizer
from .visualization.real_time_visualizer import RealTimeVisualizer
from .network_profiler import NetworkProfiler
1 change: 1 addition & 0 deletions memoraith/data_collection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
from .gpu_memory import GPUMemoryTracker
from .time_tracking import TimeTracker
from .resource_lock import ResourceLock
from memoraith.data_collection.network_profiler import NetworkProfiler
135 changes: 67 additions & 68 deletions memoraith/profiler.py
Original file line number Diff line number Diff line change
@@ -1,81 +1,80 @@
import functools
from typing import Dict, Any
import logging
import asyncio
from typing import Callable, Any, Optional
from .config import config
from .logging_config import setup_logging
from .integration import get_framework_adapter
from .analysis import Analyzer
from .reporting import ReportGenerator
from .exceptions import MemoraithError
from .visualization.real_time_visualizer import RealTimeVisualizer
from memoraith.data_collection.cpu_memory import CPUMemoryTracker
from memoraith.data_collection.gpu_memory import GPUMemoryTracker
from memoraith.data_collection.time_tracking import TimeTracker
from memoraith.data_collection.network_profiler import NetworkProfiler

def profile_model(
memory: bool = True,
computation: bool = True,
gpu: bool = False,
save_report: bool = True,
report_format: str = 'html',
real_time_viz: bool = False
) -> Callable:
"""
Decorator to profile a model's training or inference function.
class ModelProfiler:
def __init__(self):
self.cpu_tracker = CPUMemoryTracker()
self.gpu_tracker = GPUMemoryTracker()
self.time_tracker = TimeTracker()
self.network_profiler = NetworkProfiler()
self.logger = logging.getLogger(__name__)

Args:
memory (bool): Enable memory profiling
computation (bool): Enable computation time profiling
gpu (bool): Enable GPU profiling
save_report (bool): Save the profiling report
report_format (str): Format of the saved report ('html' or 'pdf')
real_time_viz (bool): Enable real-time visualization
async def start_profiling(self):
self.logger.info("Starting model profiling")
await self.cpu_tracker.start()
if self.gpu_tracker:
await self.gpu_tracker.start()
self.time_tracker.start('training')
self.network_profiler.start()

Returns:
Callable: Decorated function
"""
def decorator(func: Callable) -> Callable:
@functools.wraps(func)
async def wrapper(*args: Any, **kwargs: Any) -> Any:
setup_logging(config.log_level)
logger = logging.getLogger('memoraith')
logger.info("Starting Memoraith Profiler...")
async def stop_profiling(self):
self.logger.info("Stopping model profiling")
cpu_memory = await self.cpu_tracker.get_peak_memory()
gpu_memory = await self.gpu_tracker.get_peak_memory() if self.gpu_tracker else None
duration = self.time_tracker.get_duration('training')
network_usage = self.network_profiler.stop()

config.enable_memory = memory
config.enable_time = computation
config.enable_gpu = gpu
profiling_results = {
'cpu_memory': cpu_memory,
'gpu_memory': gpu_memory,
'training_time': duration,
'network_usage': network_usage
}
self.logger.info(f"Profiling results: {profiling_results}")
return profiling_results

try:
model = kwargs.get('model') or args[0]
adapter = get_framework_adapter(model)
async def profile_step(self, step_name: str):
self.time_tracker.start(step_name)
cpu_memory_before = await self.cpu_tracker.get_current_memory()
gpu_memory_before = await self.gpu_tracker.get_current_memory() if self.gpu_tracker else None
network_usage_before = self.network_profiler.get_current_usage()

visualizer = RealTimeVisualizer() if real_time_viz else None
yield # Yield control to allow the step to execute

async with adapter:
if asyncio.iscoroutinefunction(func):
result = await func(*args, **kwargs)
else:
result = await asyncio.to_thread(func, *args, **kwargs)
cpu_memory_after = await self.cpu_tracker.get_current_memory()
gpu_memory_after = await self.gpu_tracker.get_current_memory() if self.gpu_tracker else None
network_usage_after = self.network_profiler.get_current_usage()
duration = self.time_tracker.stop(step_name)

if visualizer:
await visualizer.update(adapter.data)
step_profile = {
'name': step_name,
'duration': duration,
'cpu_memory_used': cpu_memory_after - cpu_memory_before,
'gpu_memory_used': gpu_memory_after - gpu_memory_before if gpu_memory_after and gpu_memory_before else None,
'network_sent': network_usage_after['bytes_sent'] - network_usage_before['bytes_sent'],
'network_recv': network_usage_after['bytes_recv'] - network_usage_before['bytes_recv'],
}

analysis_results = await Analyzer(adapter.data).run_analysis()
self.logger.info(f"Step profile for {step_name}: {step_profile}")
yield step_profile

if save_report:
await ReportGenerator(analysis_results).generate(format=report_format)
def get_summary(self) -> Dict[str, Any]:
return {
'total_time': self.time_tracker.get_total_duration(),
'peak_cpu_memory': self.cpu_tracker.get_peak_memory(),
'peak_gpu_memory': self.gpu_tracker.get_peak_memory() if self.gpu_tracker else None,
'average_network_usage': self.network_profiler.get_average_usage(),
}

logger.info("Memoraith Profiling Completed.")
return result

except MemoraithError as e:
logger.error(f"MemoraithError: {e}")
raise
except Exception as e:
logger.exception("An unexpected error occurred during profiling.")
raise

return wrapper
return decorator

def set_output_path(path: str) -> None:
"""Set the output path for profiling reports."""
config.set_output_path(path)
def reset(self):
self.cpu_tracker.reset()
if self.gpu_tracker:
self.gpu_tracker.reset()
self.time_tracker.reset()
self.network_profiler.reset()
self.logger.info("All profilers reset")
Loading

0 comments on commit dea7c05

Please sign in to comment.