Contributing Guide
Thank you for your interest in contributing to torchvision-customizer! This guide will help you get started.
Getting Started
Fork the repository on GitHub
Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/torchvision-customizer.git
cd torchvision-customizer
Create a virtual environment:
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
Install in development mode:
pip install -e ".[dev]"
Create a branch for your changes:
git checkout -b feature/your-feature-name
Development Workflow
Code Style
We use Black for code formatting:
black torchvision_customizer/
black tests/
Type Checking
We use mypy for type hints:
mypy torchvision_customizer/
Linting
We use flake8 for linting:
flake8 torchvision_customizer/ tests/
Testing
Run tests before committing:
pytest tests/ -v
pytest tests/ --cov=torchvision_customizer # With coverage
Pre-commit Checks
Run all checks:
black --check torchvision_customizer/
mypy torchvision_customizer/
flake8 torchvision_customizer/ tests/
pytest tests/ -v
Adding Features
Follow Test-Driven Development (TDD):
# tests/test_new_feature.py
import pytest
import torch
from torchvision_customizer import NewFeature
def test_new_feature_basic():
feature = NewFeature()
assert feature is not None
def test_new_feature_forward():
feature = NewFeature(input_dim=64, output_dim=128)
x = torch.randn(1, 64, 224, 224)
y = feature(x)
assert y.shape == (1, 128, 224, 224)
Add your implementation:
# torchvision_customizer/blocks/new_feature.py
import torch.nn as nn
from typing import Optional
class NewFeature(nn.Module):
"""
Description of your feature.
Args:
input_dim: Number of input channels
output_dim: Number of output channels
...
"""
def __init__(
self,
input_dim: int,
output_dim: int,
**kwargs
) -> None:
super().__init__()
# Implementation here
def forward(self, x):
# Forward pass implementation
return x
Test edge cases and normal cases:
def test_new_feature_edge_case():
feature = NewFeature(1, 1)
x = torch.randn(1, 1, 1, 1)
y = feature(x)
assert y.shape == (1, 1, 1, 1)
def test_new_feature_batch():
feature = NewFeature(64, 128)
x = torch.randn(32, 64, 224, 224)
y = feature(x)
assert y.shape == (32, 128, 224, 224)
Document your feature:
class NewFeature(nn.Module):
"""
Brief description.
Longer description with details about what this feature does,
when to use it, and key characteristics.
Args:
input_dim (int): Number of input channels
output_dim (int): Number of output channels
kernel_size (int, optional): Kernel size. Default: 3
stride (int, optional): Stride. Default: 1
padding (int, optional): Padding. Default: 1
activation (str, optional): Activation function. Default: 'relu'
Returns:
Tensor: Output tensor of shape (B, output_dim, H, W)
Raises:
ValueError: If input_dim or output_dim is invalid
Example:
>>> feature = NewFeature(64, 128)
>>> x = torch.randn(1, 64, 224, 224)
>>> y = feature(x)
>>> print(y.shape)
torch.Size([1, 128, 224, 224])
"""
Ensure all tests pass:
pytest tests/ -v
pytest tests/test_new_feature.py -v
Push to your fork and create a pull request:
git push origin feature/your-feature-name
Commit Message Guidelines
Use clear, descriptive commit messages:
Good:
Add SEBlock with channel attention mechanism
- Implement Squeeze-and-Excitation block
- Add comprehensive tests (10 test cases)
- Add examples and documentation
- Fixes #42
Avoid:
Update code
Fix bug
Changes
Code Review Process
Automated Checks: GitHub Actions runs tests automatically
Code Review: Maintainers review your code
Revisions: Update code based on feedback
Merge: Once approved, your code is merged
Review Criteria
✅ All tests pass
✅ Code follows style guidelines
✅ Type hints are complete
✅ Documentation is clear
✅ No breaking changes (unless major version)
✅ Includes tests for new features
Reporting Issues
When reporting bugs, include:
Description: What’s the problem?
Reproduction: How to reproduce it?
Environment: - Python version - PyTorch version - OS
Expected vs Actual: What should happen vs what actually happens?
Example Issue:
Title: ResidualBlock fails with stride=2 and downsample=False
Description:
ResidualBlock produces shape mismatch when stride=2 and downsample=False
Reproduction:
>>> from torchvision_customizer.blocks import ResidualBlock
>>> import torch
>>> block = ResidualBlock(64, 64, stride=2, downsample=False)
>>> x = torch.randn(1, 64, 224, 224)
>>> y = block(x) # RuntimeError: size mismatch
Environment:
- Python 3.13
- PyTorch 2.9.1
- Ubuntu 22.04
Expected:
Output shape should be (1, 64, 112, 112)
Actual:
RuntimeError: size mismatch: expected tensor of shape [1, 64, 112, 112]
Documentation Standards
All docstrings must follow Google style:
def function_name(
param1: int,
param2: str,
param3: Optional[float] = None
) -> Tuple[int, str]:
"""
One-line summary.
Longer description explaining what the function does,
including any important details or caveats.
Args:
param1: Description of param1
param2: Description of param2
param3: Optional description. Default is None
Returns:
Description of return value
Raises:
ValueError: When this error occurs
TypeError: When this error occurs
Example:
>>> result = function_name(1, "test")
>>> print(result)
(1, 'test')
Note:
Important notes about usage or behavior
"""
Testing Standards
All new code must include tests:
import pytest
import torch
from torchvision_customizer import MyFeature
class TestMyFeature:
@pytest.fixture
def feature(self):
return MyFeature(input_dim=64, output_dim=128)
def test_initialization(self, feature):
assert feature is not None
def test_forward_shape(self, feature):
x = torch.randn(1, 64, 224, 224)
y = feature(x)
assert y.shape == (1, 128, 224, 224)
def test_batch_processing(self, feature):
x = torch.randn(32, 64, 224, 224)
y = feature(x)
assert y.shape == (32, 128, 224, 224)
def test_gradient_flow(self, feature):
x = torch.randn(1, 64, 224, 224, requires_grad=True)
y = feature(x)
loss = y.sum()
loss.backward()
assert x.grad is not None
Minimum 90% code coverage
All new code must have tests
Edge cases must be covered
Check coverage:
pytest tests/ --cov=torchvision_customizer --cov-report=html
Performance Considerations
When adding features:
Benchmark: Measure performance impact
Optimize: Use efficient implementations
Document: Note any performance characteristics
Example benchmark:
import time
import torch
from torchvision_customizer import MyFeature
feature = MyFeature()
x = torch.randn(100, 64, 224, 224)
start = time.time()
for _ in range(10):
_ = feature(x)
elapsed = time.time() - start
print(f"Average time: {elapsed / 10:.4f}s")
CI/CD Pipeline
Automated checks on every pull request:
Tests: pytest with coverage
Linting: flake8 and pylint
Type Checking: mypy
Code Formatting: black
Documentation: sphinx build
All checks must pass before merging.
Resources
Style Guide: PEP 8
Type Hints: PEP 484
Documentation: Google Style Guide
Testing: pytest documentation
Git Workflow: GitHub Flow
Questions?
Check existing issues/PRs
Read API documentation
Look at examples
Open a discussion
Thank you for contributing!