mirror of
https://github.com/MLSysBook/TinyTorch.git
synced 2026-05-01 02:17:33 -05:00
MAJOR: Implement beautiful module progression through strategic reordering
This commit implements the pedagogically optimal "inevitable discovery" module progression based on expert validation and educational design principles. ## Module Reordering Summary **Previous Order (Problems)**: - 05_losses → 06_autograd → 07_dataloader → 08_optimizers → 09_spatial → 10_training - Issues: Autograd before optimizers, DataLoader before training, scattered dependencies **New Order (Beautiful Progression)**: - 05_losses → 06_optimizers → 07_autograd → 08_training → 09_spatial → 10_dataloader - Benefits: Each module creates inevitable need for the next ## Pedagogical Flow Achieved **05_losses** → "Need systematic weight updates" → **06_optimizers** **06_optimizers** → "Need automatic gradients" → **07_autograd** **07_autograd** → "Need systematic training" → **08_training** **08_training** → "MLPs hit limits on images" → **09_spatial** **09_spatial** → "Training is too slow" → **10_dataloader** ## Technical Changes ### Module Directory Renaming - `06_autograd` → `07_autograd` - `07_dataloader` → `10_dataloader` - `08_optimizers` → `06_optimizers` - `10_training` → `08_training` - `09_spatial` → `09_spatial` (no change) ### System Integration Updates - **MODULE_TO_CHECKPOINT mapping**: Updated in tito/commands/export.py - **Test directories**: Renamed module_XX directories to match new numbers - **Documentation**: Updated all references in MD files and agent configurations - **CLI integration**: Updated next-steps suggestions for proper flow ### Agent Configuration Updates - **Quality Assurance**: Updated module audit status with new numbers - **Module Developer**: Updated work tracking with new sequence - **Documentation**: Updated MASTER_PLAN_OF_RECORD.md with beautiful progression ## Educational Benefits 1. **Inevitable Discovery**: Each module naturally leads to the next 2. **Cognitive Load**: Concepts introduced exactly when needed 3. **Motivation**: Students understand WHY each tool is necessary 4. **Synthesis**: Everything flows toward complete ML systems understanding 5. **Professional Alignment**: Matches real ML engineering workflows ## Quality Assurance - ✅ All CLI commands still function - ✅ Checkpoint system mappings updated - ✅ Documentation consistency maintained - ✅ Test directory structure aligned - ✅ Agent configurations synchronized **Impact**: This reordering transforms TinyTorch from a collection of modules into a coherent educational journey where each step naturally motivates the next, creating optimal conditions for deep learning systems understanding.
This commit is contained in:
270
tests/module_07/test_cnn_pipeline_integration.py
Normal file
270
tests/module_07/test_cnn_pipeline_integration.py
Normal file
@@ -0,0 +1,270 @@
|
||||
"""
|
||||
Integration Tests - CNN Pipeline
|
||||
|
||||
Tests real integration between CNN operations, activations, and layers.
|
||||
Moved from inline tests because it's true cross-module integration testing.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
import numpy as np
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add the project root to the path
|
||||
project_root = Path(__file__).parent.parent.parent
|
||||
sys.path.insert(0, str(project_root))
|
||||
|
||||
# Import REAL TinyTorch components
|
||||
try:
|
||||
from tinytorch.core.tensor import Tensor
|
||||
from tinytorch.core.cnn import Conv2D, flatten
|
||||
from tinytorch.core.activations import ReLU, Sigmoid, Tanh, Softmax
|
||||
from tinytorch.core.layers import Dense
|
||||
except ImportError:
|
||||
# Fallback for development
|
||||
sys.path.append(str(project_root / "modules" / "source" / "01_tensor"))
|
||||
sys.path.append(str(project_root / "modules" / "source" / "02_activations"))
|
||||
sys.path.append(str(project_root / "modules" / "source" / "03_layers"))
|
||||
sys.path.append(str(project_root / "modules" / "source" / "05_cnn"))
|
||||
|
||||
from tensor_dev import Tensor
|
||||
from activations_dev import ReLU, Sigmoid, Tanh, Softmax
|
||||
from layers_dev import Dense
|
||||
from cnn_dev import Conv2D, flatten
|
||||
|
||||
|
||||
class TestCNNPipelineIntegration:
|
||||
"""Test CNN pipeline integration with activations and layers."""
|
||||
|
||||
def test_cnn_pipeline_integration(self):
|
||||
"""Test CNN pipeline integration with complete workflow."""
|
||||
print("🔬 Integration Test: CNN Pipeline...")
|
||||
|
||||
# Test complete CNN pipeline
|
||||
input_image = Tensor(np.random.randn(8, 8))
|
||||
|
||||
# Build CNN pipeline
|
||||
conv = Conv2D(kernel_size=(3, 3))
|
||||
conv_output = conv(input_image)
|
||||
flattened = flatten(conv_output)
|
||||
|
||||
# Test shapes
|
||||
assert conv_output.shape == (6, 6), "Conv output should be correct"
|
||||
assert flattened.shape == (1, 36), "Flatten output should be correct"
|
||||
|
||||
# Test with activation and dense layers
|
||||
relu = ReLU()
|
||||
dense = Dense(input_size=36, output_size=10)
|
||||
|
||||
activated = relu(conv_output)
|
||||
final_flat = flatten(activated)
|
||||
predictions = dense(final_flat)
|
||||
|
||||
assert predictions.shape == (1, 10), "Final predictions should be correct shape"
|
||||
|
||||
print("✅ CNN pipeline integration works correctly")
|
||||
|
||||
def test_cnn_with_different_activations(self):
|
||||
"""Test CNN pipeline with different activation functions."""
|
||||
activations = [
|
||||
("ReLU", ReLU()),
|
||||
("Sigmoid", Sigmoid()),
|
||||
("Tanh", Tanh())
|
||||
]
|
||||
|
||||
input_image = Tensor(np.random.randn(6, 6))
|
||||
|
||||
for name, activation in activations:
|
||||
# CNN pipeline with specific activation
|
||||
conv = Conv2D(kernel_size=(2, 2))
|
||||
conv_output = conv(input_image)
|
||||
|
||||
# Apply activation
|
||||
activated = activation(conv_output)
|
||||
|
||||
# Flatten and classify
|
||||
flattened = flatten(activated)
|
||||
dense = Dense(input_size=25, output_size=5)
|
||||
predictions = dense(flattened)
|
||||
|
||||
# Verify integration
|
||||
assert isinstance(predictions, Tensor), f"CNN-{name} pipeline should return Tensor"
|
||||
assert predictions.shape == (1, 5), f"CNN-{name} pipeline should have correct shape"
|
||||
assert not np.any(np.isnan(predictions.data)), f"CNN-{name} pipeline should not produce NaN"
|
||||
|
||||
def test_deep_cnn_pipeline(self):
|
||||
"""Test deeper CNN pipeline with multiple layers."""
|
||||
# Create deeper pipeline
|
||||
input_image = Tensor(np.random.randn(10, 10))
|
||||
|
||||
# Stage 1: First convolution
|
||||
conv1 = Conv2D(kernel_size=(3, 3))
|
||||
conv1_output = conv1(input_image) # 10x10 -> 8x8
|
||||
relu1 = ReLU()
|
||||
activated1 = relu1(conv1_output)
|
||||
|
||||
# Stage 2: Second convolution
|
||||
conv2 = Conv2D(kernel_size=(3, 3))
|
||||
conv2_output = conv2(activated1) # 8x8 -> 6x6
|
||||
relu2 = ReLU()
|
||||
activated2 = relu2(conv2_output)
|
||||
|
||||
# Stage 3: Final classification
|
||||
flattened = flatten(activated2) # 6x6 -> 36
|
||||
dense = Dense(input_size=36, output_size=3)
|
||||
predictions = dense(flattened)
|
||||
|
||||
# Verify deep pipeline
|
||||
assert isinstance(predictions, Tensor), "Deep CNN pipeline should return Tensor"
|
||||
assert predictions.shape == (1, 3), "Deep CNN pipeline should have correct shape"
|
||||
assert not np.any(np.isnan(predictions.data)), "Deep CNN pipeline should not produce NaN"
|
||||
|
||||
# Verify intermediate shapes
|
||||
assert conv1_output.shape == (8, 8), "First conv should produce 8x8"
|
||||
assert conv2_output.shape == (6, 6), "Second conv should produce 6x6"
|
||||
assert flattened.shape == (1, 36), "Flatten should produce 36 features"
|
||||
|
||||
def test_cnn_with_softmax_output(self):
|
||||
"""Test CNN pipeline with softmax output for classification."""
|
||||
input_image = Tensor(np.random.randn(5, 5))
|
||||
|
||||
# Build classification pipeline
|
||||
conv = Conv2D(kernel_size=(2, 2))
|
||||
conv_output = conv(input_image) # 5x5 -> 4x4
|
||||
|
||||
relu = ReLU()
|
||||
activated = relu(conv_output)
|
||||
|
||||
flattened = flatten(activated) # 4x4 -> 16
|
||||
dense = Dense(input_size=16, output_size=3)
|
||||
dense_output = dense(flattened)
|
||||
|
||||
softmax = Softmax()
|
||||
predictions = softmax(dense_output)
|
||||
|
||||
# Verify classification pipeline
|
||||
assert isinstance(predictions, Tensor), "Classification pipeline should return Tensor"
|
||||
assert predictions.shape == (1, 3), "Classification should have 3 class outputs"
|
||||
|
||||
# Verify softmax properties
|
||||
probabilities = predictions.data[0]
|
||||
assert np.all(probabilities > 0), "Softmax should produce positive probabilities"
|
||||
assert np.isclose(np.sum(probabilities), 1.0), "Softmax should sum to 1"
|
||||
|
||||
def test_cnn_batch_processing_integration(self):
|
||||
"""Test CNN pipeline with batch processing integration."""
|
||||
# Create batch of images
|
||||
batch_size = 3
|
||||
batch_images = []
|
||||
for _ in range(batch_size):
|
||||
batch_images.append(Tensor(np.random.randn(4, 4)))
|
||||
|
||||
# Process each image through the pipeline
|
||||
predictions = []
|
||||
for image in batch_images:
|
||||
# CNN pipeline
|
||||
conv = Conv2D(kernel_size=(2, 2))
|
||||
conv_output = conv(image) # 4x4 -> 3x3
|
||||
|
||||
relu = ReLU()
|
||||
activated = relu(conv_output)
|
||||
|
||||
flattened = flatten(activated) # 3x3 -> 9
|
||||
dense = Dense(input_size=9, output_size=2)
|
||||
prediction = dense(flattened)
|
||||
|
||||
predictions.append(prediction)
|
||||
|
||||
# Verify batch processing
|
||||
assert len(predictions) == batch_size, "Should process all images in batch"
|
||||
for i, pred in enumerate(predictions):
|
||||
assert isinstance(pred, Tensor), f"Batch item {i} should return Tensor"
|
||||
assert pred.shape == (1, 2), f"Batch item {i} should have correct shape"
|
||||
assert not np.any(np.isnan(pred.data)), f"Batch item {i} should not produce NaN"
|
||||
|
||||
def test_cnn_pipeline_numerical_stability(self):
|
||||
"""Test CNN pipeline numerical stability with edge cases."""
|
||||
# Test with very small values
|
||||
small_image = Tensor(np.random.randn(3, 3) * 0.001)
|
||||
|
||||
conv = Conv2D(kernel_size=(2, 2))
|
||||
conv_output = conv(small_image)
|
||||
|
||||
relu = ReLU()
|
||||
activated = relu(conv_output)
|
||||
|
||||
flattened = flatten(activated)
|
||||
dense = Dense(input_size=4, output_size=1)
|
||||
output = dense(flattened)
|
||||
|
||||
# Should handle small values without numerical issues
|
||||
assert isinstance(output, Tensor), "Should handle small values"
|
||||
assert output.shape == (1, 1), "Should maintain correct shape"
|
||||
assert not np.any(np.isnan(output.data)), "Should not produce NaN with small values"
|
||||
|
||||
# Test with larger values
|
||||
large_image = Tensor(np.random.randn(3, 3) * 10.0)
|
||||
|
||||
conv = Conv2D(kernel_size=(2, 2))
|
||||
conv_output = conv(large_image)
|
||||
|
||||
relu = ReLU()
|
||||
activated = relu(conv_output)
|
||||
|
||||
flattened = flatten(activated)
|
||||
dense = Dense(input_size=4, output_size=1)
|
||||
output = dense(flattened)
|
||||
|
||||
# Should handle large values without overflow
|
||||
assert isinstance(output, Tensor), "Should handle large values"
|
||||
assert output.shape == (1, 1), "Should maintain correct shape"
|
||||
assert not np.any(np.isnan(output.data)), "Should not produce NaN with large values"
|
||||
assert not np.any(np.isinf(output.data)), "Should not produce Inf with large values"
|
||||
|
||||
|
||||
def test_integration_summary():
|
||||
"""Summary test demonstrating complete CNN pipeline integration."""
|
||||
print("🎯 Integration Summary: CNN Pipeline")
|
||||
print("=" * 50)
|
||||
|
||||
# Create realistic CNN pipeline
|
||||
print("🏗️ Building CNN pipeline...")
|
||||
input_image = Tensor(np.random.randn(8, 8))
|
||||
|
||||
# Stage 1: Feature extraction
|
||||
conv = Conv2D(kernel_size=(3, 3))
|
||||
features = conv(input_image) # 8x8 -> 6x6
|
||||
|
||||
# Stage 2: Nonlinear activation
|
||||
relu = ReLU()
|
||||
activated = relu(features)
|
||||
|
||||
# Stage 3: Prepare for classification
|
||||
flattened = flatten(activated) # 6x6 -> 36
|
||||
|
||||
# Stage 4: Classification
|
||||
classifier = Dense(input_size=36, output_size=3)
|
||||
raw_predictions = classifier(flattened)
|
||||
|
||||
# Stage 5: Probability distribution
|
||||
softmax = Softmax()
|
||||
predictions = softmax(raw_predictions)
|
||||
|
||||
# Verify complete pipeline
|
||||
assert isinstance(predictions, Tensor), "Complete pipeline should return Tensor"
|
||||
assert predictions.shape == (1, 3), "Complete pipeline should produce 3 class probabilities"
|
||||
|
||||
probabilities = predictions.data[0]
|
||||
assert np.all(probabilities > 0), "Should produce positive probabilities"
|
||||
assert np.isclose(np.sum(probabilities), 1.0), "Should sum to 1.0"
|
||||
|
||||
print("✅ CNN pipeline integration successful!")
|
||||
print(f" Input: {input_image.shape} -> Features: {features.shape}")
|
||||
print(f" Activated: {activated.shape} -> Flattened: {flattened.shape}")
|
||||
print(f" Raw predictions: {raw_predictions.shape} -> Final: {predictions.shape}")
|
||||
print(" Components: CNN → Activation → Flatten → Dense → Softmax")
|
||||
print("🎉 Ready for real computer vision applications!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_integration_summary()
|
||||
Reference in New Issue
Block a user