mirror of
https://github.com/MLSysBook/TinyTorch.git
synced 2026-03-26 10:02:19 -05:00
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.
270 lines
10 KiB
Python
270 lines
10 KiB
Python
"""
|
|
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() |