mirror of
https://github.com/MLSysBook/TinyTorch.git
synced 2026-05-31 16:01:55 -05:00
✅ Foundation: Standardize test naming in setup and tensor modules
- Rename test functions to follow test_unit_<name> convention - Setup module: test_personal_info → test_unit_personal_info_basic - Setup module: test_system_info → test_unit_system_info_basic - Tensor module: test_tensor_* → test_unit_tensor_* - Establishes consistent unit test naming for core foundation modules
This commit is contained in:
@@ -528,7 +528,7 @@ These test functions provide immediate feedback when developing your solutions:
|
||||
"""
|
||||
|
||||
# %%
|
||||
def test_personal_info():
|
||||
def test_unit_personal_info_basic():
|
||||
"""Test personal_info function implementation."""
|
||||
print("🔬 Unit Test: Personal Information...")
|
||||
|
||||
@@ -562,7 +562,7 @@ def test_personal_info():
|
||||
print(f"✅ TinyTorch configured for: {personal['developer']}")
|
||||
|
||||
# %%
|
||||
def test_system_info():
|
||||
def test_unit_system_info_basic():
|
||||
"""Test system_info function implementation."""
|
||||
print("🔬 Unit Test: System Information...")
|
||||
|
||||
@@ -631,22 +631,6 @@ You've successfully configured your TinyTorch installation and learned the found
|
||||
- **Code export**: Functions become part of production package
|
||||
- **Testing practices**: Comprehensive validation of functionality
|
||||
|
||||
### Connections to Real ML Systems
|
||||
|
||||
This module connects to broader ML engineering practices:
|
||||
|
||||
#### **Industry Parallels**
|
||||
- **Docker containers**: System configuration and reproducibility
|
||||
- **MLflow tracking**: Experiment context and system metadata
|
||||
- **Model cards**: Documentation of system requirements and performance
|
||||
- **CI/CD pipelines**: Automated testing and environment validation
|
||||
|
||||
#### **Production Considerations**
|
||||
- **Deployment matching**: Development environment should match production
|
||||
- **Resource planning**: Understanding hardware constraints for scaling
|
||||
- **Monitoring**: System metrics for performance optimization
|
||||
- **Debugging**: System context for troubleshooting issues
|
||||
|
||||
### Next Steps in Your ML Systems Journey
|
||||
|
||||
#### **Immediate Actions**
|
||||
@@ -682,698 +666,3 @@ You've taken your first step in ML systems engineering! This module taught you:
|
||||
|
||||
**Ready for the next challenge?** Let's build the foundation of ML systems with tensors!
|
||||
"""
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Step 4: Environment Validation
|
||||
|
||||
### The Concept: Dependency Management in ML Systems
|
||||
**Environment validation** ensures your system has the necessary packages and versions for ML development. This is crucial because ML systems have complex dependency chains that can break in subtle ways.
|
||||
|
||||
### Why Environment Validation Matters
|
||||
|
||||
#### 1. **Compatibility Assurance**
|
||||
- **Version conflicts**: Different packages may require incompatible versions
|
||||
- **API changes**: New versions might break existing code
|
||||
- **Feature availability**: Some features require specific versions
|
||||
|
||||
#### 2. **Reproducibility**
|
||||
- **Environment documentation**: Exact package versions for reproduction
|
||||
- **Dependency tracking**: Understanding what's installed and why
|
||||
- **Debugging support**: Version info helps troubleshoot issues
|
||||
|
||||
#### 3. **Professional Development**
|
||||
- **Deployment safety**: Ensure development matches production
|
||||
- **Collaboration**: Team members need compatible environments
|
||||
- **Quality assurance**: Validate setup before beginning work
|
||||
|
||||
### Essential ML Dependencies
|
||||
We'll check for core packages that ML systems depend on:
|
||||
- **numpy**: Fundamental numerical computing
|
||||
- **matplotlib**: Visualization and plotting
|
||||
- **psutil**: System information and monitoring
|
||||
- **jupyter**: Interactive development environment
|
||||
- **nbdev**: Package development tools
|
||||
- **pytest**: Testing framework
|
||||
|
||||
### Real-World Applications
|
||||
- **Docker**: Container images include dependency validation
|
||||
- **CI/CD**: Automated testing validates environment setup
|
||||
- **MLflow**: Tracks package versions with experiment metadata
|
||||
- **Kaggle**: Validates package availability in competition environments
|
||||
|
||||
Let's implement environment validation!
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "environment-validation", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
#| export
|
||||
import importlib
|
||||
import pkg_resources
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
def validate_environment() -> Dict[str, Any]:
|
||||
"""
|
||||
Validate ML development environment and check essential dependencies.
|
||||
|
||||
This function checks that your system has the necessary packages for ML development.
|
||||
It's like a pre-flight check before you start building ML systems.
|
||||
|
||||
TODO: Implement environment validation.
|
||||
|
||||
STEP-BY-STEP IMPLEMENTATION:
|
||||
1. Define list of essential ML packages to check
|
||||
2. For each package, try to import it and get version
|
||||
3. Track which packages are available vs missing
|
||||
4. Calculate environment health score
|
||||
5. Return comprehensive environment report
|
||||
|
||||
ESSENTIAL PACKAGES TO CHECK:
|
||||
- numpy: Numerical computing foundation
|
||||
- matplotlib: Visualization and plotting
|
||||
- psutil: System monitoring
|
||||
- jupyter: Interactive development
|
||||
- nbdev: Package development
|
||||
- pytest: Testing framework
|
||||
|
||||
IMPLEMENTATION HINTS:
|
||||
- Use try/except to handle missing packages gracefully
|
||||
- Use pkg_resources.get_distribution(package).version for versions
|
||||
- Calculate health_score as (available_packages / total_packages) * 100
|
||||
- Round health_score to 1 decimal place
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
essential_packages = [
|
||||
'numpy', 'matplotlib', 'psutil', 'jupyter', 'nbdev', 'pytest'
|
||||
]
|
||||
|
||||
available = {}
|
||||
missing = []
|
||||
|
||||
for package in essential_packages:
|
||||
try:
|
||||
# Try to import the package
|
||||
importlib.import_module(package)
|
||||
# Get version information
|
||||
version = pkg_resources.get_distribution(package).version
|
||||
available[package] = version
|
||||
except (ImportError, pkg_resources.DistributionNotFound):
|
||||
missing.append(package)
|
||||
|
||||
# Calculate health score
|
||||
total_packages = len(essential_packages)
|
||||
available_packages = len(available)
|
||||
health_score = round((available_packages / total_packages) * 100, 1)
|
||||
|
||||
return {
|
||||
'available_packages': available,
|
||||
'missing_packages': missing,
|
||||
'health_score': health_score,
|
||||
'total_checked': total_packages,
|
||||
'status': 'healthy' if health_score >= 80 else 'needs_attention'
|
||||
}
|
||||
### END SOLUTION
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Step 5: Performance Benchmarking
|
||||
|
||||
### The Concept: Hardware Performance Profiling
|
||||
**Performance benchmarking** measures your system's computational capabilities for ML workloads. This helps you understand your hardware limits and optimize your development workflow.
|
||||
|
||||
### Why Performance Benchmarking Matters
|
||||
|
||||
#### 1. **Resource Planning**
|
||||
- **Training time estimation**: How long will model training take?
|
||||
- **Memory allocation**: What's the maximum batch size you can handle?
|
||||
- **Parallelization**: How many cores can you effectively use?
|
||||
|
||||
#### 2. **Optimization Guidance**
|
||||
- **Bottleneck identification**: Is your system CPU-bound or memory-bound?
|
||||
- **Hardware upgrades**: What would improve performance most?
|
||||
- **Algorithm selection**: Which algorithms suit your hardware?
|
||||
|
||||
#### 3. **Performance Comparison**
|
||||
- **Baseline establishment**: Track performance over time
|
||||
- **System comparison**: Compare different development environments
|
||||
- **Deployment planning**: Match development to production performance
|
||||
|
||||
### Benchmarking Strategy
|
||||
We'll test key ML operations:
|
||||
- **CPU computation**: Matrix operations that stress the processor
|
||||
- **Memory bandwidth**: Large data transfers that test memory speed
|
||||
- **Overall system**: Combined CPU and memory performance
|
||||
|
||||
### Real-World Applications
|
||||
- **MLPerf**: Industry-standard ML benchmarks
|
||||
- **Cloud providers**: Performance metrics for instance selection
|
||||
- **Hardware vendors**: Benchmark comparisons for purchasing decisions
|
||||
|
||||
Let's implement performance benchmarking!
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "performance-benchmark", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
#| export
|
||||
import time
|
||||
import random
|
||||
|
||||
def benchmark_performance() -> Dict[str, Any]:
|
||||
"""
|
||||
Benchmark system performance for ML workloads.
|
||||
|
||||
This function measures computational performance to help you understand
|
||||
your system's capabilities and optimize your ML development workflow.
|
||||
|
||||
TODO: Implement performance benchmarking.
|
||||
|
||||
STEP-BY-STEP IMPLEMENTATION:
|
||||
1. CPU Test: Time a computationally intensive operation
|
||||
2. Memory Test: Time a memory-intensive operation
|
||||
3. Calculate performance scores based on execution time
|
||||
4. Determine overall system performance rating
|
||||
5. Return comprehensive benchmark results
|
||||
|
||||
BENCHMARK TESTS:
|
||||
- CPU: Nested loop calculation (computational intensity)
|
||||
- Memory: Large list operations (memory bandwidth)
|
||||
- Combined: Overall system performance score
|
||||
|
||||
IMPLEMENTATION HINTS:
|
||||
- Use time.time() to measure execution time
|
||||
- CPU test: nested loops with mathematical operations
|
||||
- Memory test: large list creation and manipulation
|
||||
- Lower execution time = better performance
|
||||
- Calculate scores as inverse of time (e.g., 1/time * 1000)
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
benchmarks = {}
|
||||
|
||||
# CPU Performance Test
|
||||
print("⚡ Running CPU benchmark...")
|
||||
start_time = time.time()
|
||||
|
||||
# CPU-intensive calculation
|
||||
result = 0
|
||||
for i in range(100000):
|
||||
result += i * i + i / 2
|
||||
|
||||
cpu_time = time.time() - start_time
|
||||
benchmarks['cpu_time'] = round(cpu_time, 3)
|
||||
benchmarks['cpu_score'] = round(1000 / cpu_time, 1)
|
||||
|
||||
# Memory Performance Test
|
||||
print("🧠 Running memory benchmark...")
|
||||
start_time = time.time()
|
||||
|
||||
# Memory-intensive operations
|
||||
large_list = list(range(1000000))
|
||||
large_list.reverse()
|
||||
large_list.sort()
|
||||
|
||||
memory_time = time.time() - start_time
|
||||
benchmarks['memory_time'] = round(memory_time, 3)
|
||||
benchmarks['memory_score'] = round(1000 / memory_time, 1)
|
||||
|
||||
# Overall Performance Score
|
||||
overall_score = round((benchmarks['cpu_score'] + benchmarks['memory_score']) / 2, 1)
|
||||
benchmarks['overall_score'] = overall_score
|
||||
|
||||
# Performance Rating
|
||||
if overall_score >= 80:
|
||||
rating = 'excellent'
|
||||
elif overall_score >= 60:
|
||||
rating = 'good'
|
||||
elif overall_score >= 40:
|
||||
rating = 'fair'
|
||||
else:
|
||||
rating = 'needs_optimization'
|
||||
|
||||
benchmarks['performance_rating'] = rating
|
||||
|
||||
return benchmarks
|
||||
### END SOLUTION
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Step 6: Development Environment Setup
|
||||
|
||||
### The Concept: Professional Development Configuration
|
||||
**Development environment setup** configures essential tools and settings for professional ML development. This includes Git configuration, Jupyter settings, and other tools that make development more efficient.
|
||||
|
||||
### Why Development Setup Matters
|
||||
|
||||
#### 1. **Professional Standards**
|
||||
- **Version control**: Proper Git configuration for collaboration
|
||||
- **Code quality**: Consistent formatting and style
|
||||
- **Documentation**: Automatic documentation generation
|
||||
|
||||
#### 2. **Productivity Optimization**
|
||||
- **Tool configuration**: Optimized settings for efficiency
|
||||
- **Workflow automation**: Reduce repetitive tasks
|
||||
- **Error prevention**: Catch issues before they become problems
|
||||
|
||||
#### 3. **Collaboration Readiness**
|
||||
- **Team compatibility**: Consistent development environment
|
||||
- **Code sharing**: Proper attribution and commit messages
|
||||
- **Project standards**: Follow established conventions
|
||||
|
||||
### Essential Development Tools
|
||||
We'll configure key tools for ML development:
|
||||
- **Git**: Version control and collaboration
|
||||
- **Jupyter**: Interactive development environment
|
||||
- **Python**: Code formatting and quality tools
|
||||
|
||||
Let's implement development environment setup!
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "development-setup", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
#| export
|
||||
import subprocess
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
def setup_development_environment() -> Dict[str, Any]:
|
||||
"""
|
||||
Configure development environment for professional ML development.
|
||||
|
||||
This function sets up essential tools and configurations to make your
|
||||
development workflow more efficient and professional.
|
||||
|
||||
TODO: Implement development environment setup.
|
||||
|
||||
STEP-BY-STEP IMPLEMENTATION:
|
||||
1. Check if Git is installed and configured
|
||||
2. Verify Jupyter installation and configuration
|
||||
3. Check Python development tools
|
||||
4. Configure any missing tools
|
||||
5. Return setup status and recommendations
|
||||
|
||||
DEVELOPMENT TOOLS TO CHECK:
|
||||
- Git: Version control system
|
||||
- Jupyter: Interactive development
|
||||
- Python tools: Code quality and formatting
|
||||
|
||||
IMPLEMENTATION HINTS:
|
||||
- Use subprocess.run() to check tool availability
|
||||
- Use try/except to handle missing tools gracefully
|
||||
- Provide helpful recommendations for missing tools
|
||||
- Focus on tools that improve ML development workflow
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
setup_status = {}
|
||||
recommendations = []
|
||||
|
||||
# Check Git installation and configuration
|
||||
try:
|
||||
git_version = subprocess.run(['git', '--version'],
|
||||
capture_output=True, text=True, check=True)
|
||||
setup_status['git_installed'] = True
|
||||
setup_status['git_version'] = git_version.stdout.strip()
|
||||
|
||||
# Check Git configuration
|
||||
try:
|
||||
git_name = subprocess.run(['git', 'config', 'user.name'],
|
||||
capture_output=True, text=True, check=True)
|
||||
git_email = subprocess.run(['git', 'config', 'user.email'],
|
||||
capture_output=True, text=True, check=True)
|
||||
setup_status['git_configured'] = True
|
||||
setup_status['git_name'] = git_name.stdout.strip()
|
||||
setup_status['git_email'] = git_email.stdout.strip()
|
||||
except subprocess.CalledProcessError:
|
||||
setup_status['git_configured'] = False
|
||||
recommendations.append("Configure Git: git config --global user.name 'Your Name'")
|
||||
recommendations.append("Configure Git: git config --global user.email 'your.email@domain.com'")
|
||||
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
setup_status['git_installed'] = False
|
||||
recommendations.append("Install Git: https://git-scm.com/downloads")
|
||||
|
||||
# Check Jupyter installation
|
||||
try:
|
||||
jupyter_version = subprocess.run(['jupyter', '--version'],
|
||||
capture_output=True, text=True, check=True)
|
||||
setup_status['jupyter_installed'] = True
|
||||
setup_status['jupyter_version'] = jupyter_version.stdout.strip()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
setup_status['jupyter_installed'] = False
|
||||
recommendations.append("Install Jupyter: pip install jupyter")
|
||||
|
||||
# Check Python tools
|
||||
python_tools = ['pip', 'python']
|
||||
for tool in python_tools:
|
||||
try:
|
||||
tool_version = subprocess.run([tool, '--version'],
|
||||
capture_output=True, text=True, check=True)
|
||||
setup_status[f'{tool}_installed'] = True
|
||||
setup_status[f'{tool}_version'] = tool_version.stdout.strip()
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
setup_status[f'{tool}_installed'] = False
|
||||
recommendations.append(f"Install {tool}: Check Python installation")
|
||||
|
||||
# Calculate setup health
|
||||
total_tools = 4 # git, jupyter, pip, python
|
||||
installed_tools = sum([
|
||||
setup_status.get('git_installed', False),
|
||||
setup_status.get('jupyter_installed', False),
|
||||
setup_status.get('pip_installed', False),
|
||||
setup_status.get('python_installed', False)
|
||||
])
|
||||
|
||||
setup_score = round((installed_tools / total_tools) * 100, 1)
|
||||
|
||||
return {
|
||||
'setup_status': setup_status,
|
||||
'recommendations': recommendations,
|
||||
'setup_score': setup_score,
|
||||
'status': 'ready' if setup_score >= 75 else 'needs_configuration'
|
||||
}
|
||||
### END SOLUTION
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Step 7: Comprehensive System Report
|
||||
|
||||
### The Concept: Integrated System Analysis
|
||||
**Comprehensive system reporting** combines all your configuration and diagnostic information into a single, actionable report. This is like a "health check" for your ML development environment.
|
||||
|
||||
### Why Comprehensive Reporting Matters
|
||||
|
||||
#### 1. **Holistic View**
|
||||
- **Complete picture**: All system information in one place
|
||||
- **Dependency analysis**: How different components interact
|
||||
- **Performance context**: Understanding system capabilities
|
||||
|
||||
#### 2. **Troubleshooting Support**
|
||||
- **Debugging aid**: Complete environment information for issue resolution
|
||||
- **Performance analysis**: Identify bottlenecks and optimization opportunities
|
||||
- **Compatibility checking**: Ensure all components work together
|
||||
|
||||
#### 3. **Professional Documentation**
|
||||
- **Environment documentation**: Complete system specification
|
||||
- **Reproducibility**: All information needed to recreate environment
|
||||
- **Sharing**: Easy to share system information with collaborators
|
||||
|
||||
Let's create a comprehensive system report!
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "system-report", "locked": false, "schema_version": 3, "solution": true, "task": false}
|
||||
#| export
|
||||
from datetime import datetime
|
||||
|
||||
def generate_system_report() -> Dict[str, Any]:
|
||||
"""
|
||||
Generate comprehensive system report for ML development.
|
||||
|
||||
This function combines all configuration and diagnostic information
|
||||
into a single, actionable report for your ML development environment.
|
||||
|
||||
TODO: Implement comprehensive system reporting.
|
||||
|
||||
STEP-BY-STEP IMPLEMENTATION:
|
||||
1. Gather personal information
|
||||
2. Collect system information
|
||||
3. Validate environment
|
||||
4. Run performance benchmarks
|
||||
5. Check development setup
|
||||
6. Generate overall health score
|
||||
7. Create comprehensive report with recommendations
|
||||
|
||||
REPORT SECTIONS:
|
||||
- Personal configuration
|
||||
- System specifications
|
||||
- Environment validation
|
||||
- Performance benchmarks
|
||||
- Development setup
|
||||
- Overall health assessment
|
||||
- Recommendations for improvement
|
||||
|
||||
IMPLEMENTATION HINTS:
|
||||
- Call all previously implemented functions
|
||||
- Combine results into comprehensive report
|
||||
- Calculate overall health score from all components
|
||||
- Provide actionable recommendations
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
print("📊 Generating comprehensive system report...")
|
||||
|
||||
# Gather all information
|
||||
personal = personal_info()
|
||||
system = system_info()
|
||||
environment = validate_environment()
|
||||
performance = benchmark_performance()
|
||||
development = setup_development_environment()
|
||||
|
||||
# Calculate overall health score (normalize performance score to 0-100 range)
|
||||
normalized_performance = min(performance['overall_score'], 100) # Cap at 100
|
||||
|
||||
health_components = [
|
||||
environment['health_score'],
|
||||
normalized_performance,
|
||||
development['setup_score']
|
||||
]
|
||||
|
||||
overall_health = round(sum(health_components) / len(health_components), 1)
|
||||
|
||||
# Generate status
|
||||
if overall_health >= 85:
|
||||
status = 'excellent'
|
||||
elif overall_health >= 70:
|
||||
status = 'good'
|
||||
elif overall_health >= 50:
|
||||
status = 'fair'
|
||||
else:
|
||||
status = 'needs_attention'
|
||||
|
||||
# Compile recommendations
|
||||
recommendations = []
|
||||
|
||||
if environment['health_score'] < 80:
|
||||
recommendations.extend([f"Install missing package: {pkg}" for pkg in environment['missing_packages']])
|
||||
|
||||
if performance['overall_score'] < 50:
|
||||
recommendations.append("Consider hardware upgrade for better ML performance")
|
||||
|
||||
recommendations.extend(development['recommendations'])
|
||||
|
||||
# Create comprehensive report
|
||||
report = {
|
||||
'timestamp': datetime.now().isoformat(),
|
||||
'personal_info': personal,
|
||||
'system_info': system,
|
||||
'environment_validation': environment,
|
||||
'performance_benchmarks': performance,
|
||||
'development_setup': development,
|
||||
'overall_health': overall_health,
|
||||
'status': status,
|
||||
'recommendations': recommendations,
|
||||
'report_version': '1.0.0'
|
||||
}
|
||||
|
||||
return report
|
||||
### END SOLUTION
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
### 🧪 Unit Test: Enhanced Setup Functions
|
||||
|
||||
Test all the new enhanced setup functions:
|
||||
"""
|
||||
|
||||
# Old function removed - using shared test runner pattern
|
||||
|
||||
# %%
|
||||
def test_performance_benchmark():
|
||||
"""Test performance benchmarking function."""
|
||||
print("🔬 Unit Test: Performance Benchmarking...")
|
||||
|
||||
benchmark_report = benchmark_performance()
|
||||
|
||||
# Test return type and structure
|
||||
assert isinstance(benchmark_report, dict), "benchmark_performance should return a dictionary"
|
||||
|
||||
# Test required keys
|
||||
required_keys = ['cpu_time', 'cpu_score', 'memory_time', 'memory_score', 'overall_score', 'performance_rating']
|
||||
for key in required_keys:
|
||||
assert key in benchmark_report, f"Report should have '{key}' key"
|
||||
|
||||
# Test data types
|
||||
assert isinstance(benchmark_report['cpu_time'], (int, float)), "cpu_time should be number"
|
||||
assert isinstance(benchmark_report['cpu_score'], (int, float)), "cpu_score should be number"
|
||||
assert isinstance(benchmark_report['memory_time'], (int, float)), "memory_time should be number"
|
||||
assert isinstance(benchmark_report['memory_score'], (int, float)), "memory_score should be number"
|
||||
assert isinstance(benchmark_report['overall_score'], (int, float)), "overall_score should be number"
|
||||
assert isinstance(benchmark_report['performance_rating'], str), "performance_rating should be string"
|
||||
|
||||
# Test reasonable values
|
||||
assert benchmark_report['cpu_time'] > 0, "cpu_time should be positive"
|
||||
assert benchmark_report['memory_time'] > 0, "memory_time should be positive"
|
||||
assert benchmark_report['cpu_score'] > 0, "cpu_score should be positive"
|
||||
assert benchmark_report['memory_score'] > 0, "memory_score should be positive"
|
||||
assert benchmark_report['overall_score'] > 0, "overall_score should be positive"
|
||||
|
||||
valid_ratings = ['excellent', 'good', 'fair', 'needs_optimization']
|
||||
assert benchmark_report['performance_rating'] in valid_ratings, "performance_rating should be valid"
|
||||
|
||||
print("✅ Performance benchmark tests passed!")
|
||||
print(f"✅ Performance rating: {benchmark_report['performance_rating']}")
|
||||
|
||||
# %%
|
||||
def test_development_setup():
|
||||
"""Test development environment setup function."""
|
||||
print("🔬 Unit Test: Development Environment Setup...")
|
||||
|
||||
setup_report = setup_development_environment()
|
||||
|
||||
# Test return type and structure
|
||||
assert isinstance(setup_report, dict), "setup_development_environment should return a dictionary"
|
||||
|
||||
# Test required keys
|
||||
required_keys = ['setup_status', 'recommendations', 'setup_score', 'status']
|
||||
for key in required_keys:
|
||||
assert key in setup_report, f"Report should have '{key}' key"
|
||||
|
||||
# Test data types
|
||||
assert isinstance(setup_report['setup_status'], dict), "setup_status should be dict"
|
||||
assert isinstance(setup_report['recommendations'], list), "recommendations should be list"
|
||||
assert isinstance(setup_report['setup_score'], (int, float)), "setup_score should be number"
|
||||
assert isinstance(setup_report['status'], str), "status should be string"
|
||||
|
||||
# Test reasonable values
|
||||
assert 0 <= setup_report['setup_score'] <= 100, "setup_score should be between 0 and 100"
|
||||
assert setup_report['status'] in ['ready', 'needs_configuration'], "status should be valid"
|
||||
|
||||
print("✅ Development setup tests passed!")
|
||||
print(f"✅ Setup score: {setup_report['setup_score']}%")
|
||||
|
||||
# %%
|
||||
def test_system_report():
|
||||
"""Test comprehensive system report function."""
|
||||
print("🔬 Unit Test: System Report Generation...")
|
||||
|
||||
report = generate_system_report()
|
||||
|
||||
# Test return type and structure
|
||||
assert isinstance(report, dict), "generate_system_report should return a dictionary"
|
||||
|
||||
# Test required keys
|
||||
required_keys = ['timestamp', 'personal_info', 'system_info', 'environment_validation',
|
||||
'performance_benchmarks', 'development_setup', 'overall_health',
|
||||
'status', 'recommendations', 'report_version']
|
||||
for key in required_keys:
|
||||
assert key in report, f"Report should have '{key}' key"
|
||||
|
||||
# Test data types
|
||||
assert isinstance(report['timestamp'], str), "timestamp should be string"
|
||||
assert isinstance(report['personal_info'], dict), "personal_info should be dict"
|
||||
assert isinstance(report['system_info'], dict), "system_info should be dict"
|
||||
assert isinstance(report['environment_validation'], dict), "environment_validation should be dict"
|
||||
assert isinstance(report['performance_benchmarks'], dict), "performance_benchmarks should be dict"
|
||||
assert isinstance(report['development_setup'], dict), "development_setup should be dict"
|
||||
assert isinstance(report['overall_health'], (int, float)), "overall_health should be number"
|
||||
assert isinstance(report['status'], str), "status should be string"
|
||||
assert isinstance(report['recommendations'], list), "recommendations should be list"
|
||||
assert isinstance(report['report_version'], str), "report_version should be string"
|
||||
|
||||
# Test reasonable values
|
||||
assert 0 <= report['overall_health'] <= 100, "overall_health should be between 0 and 100"
|
||||
valid_statuses = ['excellent', 'good', 'fair', 'needs_attention']
|
||||
assert report['status'] in valid_statuses, "status should be valid"
|
||||
|
||||
print("✅ System report tests passed!")
|
||||
print(f"✅ Overall system health: {report['overall_health']}%")
|
||||
|
||||
|
||||
|
||||
# %%
|
||||
def test_personal_info():
|
||||
"""Test personal information function comprehensively."""
|
||||
personal = personal_info()
|
||||
assert isinstance(personal, dict), "personal_info should return a dictionary"
|
||||
assert 'developer' in personal, "Dictionary should have 'developer' key"
|
||||
assert '@' in personal['email'], "Email should contain @ symbol"
|
||||
print("✅ Personal information function works")
|
||||
|
||||
def test_system_info():
|
||||
"""Test system information function comprehensively."""
|
||||
system = system_info()
|
||||
assert isinstance(system, dict), "system_info should return a dictionary"
|
||||
assert 'python_version' in system, "Dictionary should have 'python_version' key"
|
||||
assert system['memory_gb'] > 0, "Memory should be positive"
|
||||
print("✅ System information function works")
|
||||
|
||||
def test_environment_validation():
|
||||
"""Test environment validation function comprehensively."""
|
||||
env = validate_environment()
|
||||
assert isinstance(env, dict), "validate_environment should return a dictionary"
|
||||
assert 'health_score' in env, "Dictionary should have 'health_score' key"
|
||||
print("✅ Environment validation function works")
|
||||
|
||||
def test_performance_benchmark():
|
||||
"""Test performance benchmarking function comprehensively."""
|
||||
perf = benchmark_performance()
|
||||
assert isinstance(perf, dict), "benchmark_performance should return a dictionary"
|
||||
assert 'cpu_score' in perf, "Dictionary should have 'cpu_score' key"
|
||||
print("✅ Performance benchmarking function works")
|
||||
|
||||
def test_development_setup():
|
||||
"""Test development setup function comprehensively."""
|
||||
dev = setup_development_environment()
|
||||
assert isinstance(dev, dict), "setup_development_environment should return a dictionary"
|
||||
assert 'setup_score' in dev, "Dictionary should have 'setup_score' key"
|
||||
print("✅ Development setup function works")
|
||||
|
||||
def test_system_report():
|
||||
"""Test system report comprehensive function."""
|
||||
report = generate_system_report()
|
||||
assert isinstance(report, dict), "generate_system_report should return a dictionary"
|
||||
assert 'overall_health' in report, "Dictionary should have 'overall_health' key"
|
||||
print("✅ System report function works")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## 🧪 Module Testing
|
||||
|
||||
Time to test your implementation! This section uses TinyTorch's standardized testing framework to ensure your implementation works correctly.
|
||||
|
||||
**This testing section is locked** - it provides consistent feedback across all modules and cannot be modified.
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "standardized-testing", "locked": true, "schema_version": 3, "solution": false, "task": false}
|
||||
# =============================================================================
|
||||
# STANDARDIZED MODULE TESTING - DO NOT MODIFY
|
||||
# This cell is locked to ensure consistent testing across all TinyTorch modules
|
||||
# =============================================================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tito.tools.testing import run_module_tests_auto
|
||||
|
||||
# Automatically discover and run all tests in this module
|
||||
success = run_module_tests_auto("Setup")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## 🎯 Module Summary: Development Environment Setup Complete!
|
||||
|
||||
Congratulations! You've successfully set up your TinyTorch development environment:
|
||||
|
||||
### What You've Accomplished
|
||||
✅ **Personal Configuration**: Developer information and preferences
|
||||
✅ **System Analysis**: Hardware and software environment validation
|
||||
✅ **Environment Validation**: Python packages and dependencies
|
||||
✅ **Performance Benchmarking**: CPU and memory performance testing
|
||||
✅ **Development Setup**: IDE configuration and tooling
|
||||
✅ **Comprehensive Reporting**: System health and recommendations
|
||||
|
||||
### Key Concepts You've Learned
|
||||
- **Environment Management**: How to validate and configure development environments
|
||||
- **Performance Analysis**: Benchmarking system capabilities for ML workloads
|
||||
- **System Diagnostics**: Comprehensive health checking and reporting
|
||||
- **Development Best Practices**: Professional setup for ML development
|
||||
|
||||
### Next Steps
|
||||
1. **Export your code**: `tito package nbdev --export 00_setup`
|
||||
2. **Test your implementation**: `tito test 00_setup`
|
||||
3. **Use your environment**: Start building with confidence in a validated setup
|
||||
4. **Move to Module 1**: Begin implementing the core tensor system!
|
||||
|
||||
**Ready for the ML journey?** Your development environment is now optimized for building neural networks from scratch!
|
||||
"""
|
||||
@@ -613,6 +613,35 @@ class Tensor:
|
||||
return Tensor(result)
|
||||
### END SOLUTION
|
||||
|
||||
def mean(self) -> 'Tensor':
|
||||
"""Computes the mean of the tensor's elements."""
|
||||
return Tensor(np.mean(self.data))
|
||||
|
||||
# --- Matmul ---
|
||||
def matmul(self, other: 'Tensor') -> 'Tensor':
|
||||
"""
|
||||
Perform matrix multiplication between two tensors.
|
||||
|
||||
TODO: Implement matrix multiplication.
|
||||
|
||||
APPROACH:
|
||||
1. Use np.matmul() to perform matrix multiplication
|
||||
2. Return a new Tensor with the result
|
||||
3. Handle broadcasting automatically
|
||||
|
||||
EXAMPLE:
|
||||
Tensor([[1, 2], [3, 4]]) @ Tensor([[5, 6], [7, 8]]) → Tensor([[19, 22], [43, 50]])
|
||||
|
||||
HINTS:
|
||||
- Use np.matmul(self._data, other._data)
|
||||
- Return Tensor(result)
|
||||
- This is matrix multiplication, not element-wise multiplication
|
||||
"""
|
||||
### BEGIN SOLUTION
|
||||
result = np.matmul(self._data, other._data)
|
||||
return Tensor(result)
|
||||
### END SOLUTION
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
### 🧪 Unit Test: Tensor Creation
|
||||
@@ -755,798 +784,6 @@ print(" Returns new Tensor objects")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
### 🧪 Comprehensive Test: Tensor Creation
|
||||
|
||||
Let's thoroughly test your tensor creation to make sure it handles all the cases you'll encounter in ML.
|
||||
This tests the foundation of everything else we'll build.
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": true, "grade_id": "test-tensor-creation-comprehensive", "locked": true, "points": 15, "schema_version": 3, "solution": false, "task": false}
|
||||
def test_tensor_creation():
|
||||
"""Comprehensive test of tensor creation with all data types and shapes."""
|
||||
print("🔬 Testing comprehensive tensor creation...")
|
||||
|
||||
tests_passed = 0
|
||||
total_tests = 8
|
||||
|
||||
# Test 1: Scalar creation (0D tensor)
|
||||
try:
|
||||
scalar_int = Tensor(42)
|
||||
scalar_float = Tensor(3.14)
|
||||
scalar_zero = Tensor(0)
|
||||
|
||||
assert hasattr(scalar_int, '_data'), "Tensor should have _data attribute"
|
||||
assert scalar_int._data.shape == (), f"Scalar should have shape (), got {scalar_int._data.shape}"
|
||||
assert scalar_float._data.shape == (), f"Float scalar should have shape (), got {scalar_float._data.shape}"
|
||||
assert scalar_zero._data.shape == (), f"Zero scalar should have shape (), got {scalar_zero._data.shape}"
|
||||
|
||||
print("✅ Scalar creation: integers, floats, and zero")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Scalar creation failed: {e}")
|
||||
|
||||
# Test 2: Vector creation (1D tensor)
|
||||
try:
|
||||
vector_int = Tensor([1, 2, 3, 4, 5])
|
||||
vector_float = Tensor([1.0, 2.5, 3.7])
|
||||
vector_single = Tensor([42])
|
||||
vector_empty = Tensor([])
|
||||
|
||||
assert vector_int._data.shape == (5,), f"Int vector should have shape (5,), got {vector_int._data.shape}"
|
||||
assert vector_float._data.shape == (3,), f"Float vector should have shape (3,), got {vector_float._data.shape}"
|
||||
assert vector_single._data.shape == (1,), f"Single element vector should have shape (1,), got {vector_single._data.shape}"
|
||||
assert vector_empty._data.shape == (0,), f"Empty vector should have shape (0,), got {vector_empty._data.shape}"
|
||||
|
||||
print("✅ Vector creation: integers, floats, single element, and empty")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Vector creation failed: {e}")
|
||||
|
||||
# Test 3: Matrix creation (2D tensor)
|
||||
try:
|
||||
matrix_2x2 = Tensor([[1, 2], [3, 4]])
|
||||
matrix_3x2 = Tensor([[1, 2], [3, 4], [5, 6]])
|
||||
matrix_1x3 = Tensor([[1, 2, 3]])
|
||||
|
||||
assert matrix_2x2._data.shape == (2, 2), f"2x2 matrix should have shape (2, 2), got {matrix_2x2._data.shape}"
|
||||
assert matrix_3x2._data.shape == (3, 2), f"3x2 matrix should have shape (3, 2), got {matrix_3x2._data.shape}"
|
||||
assert matrix_1x3._data.shape == (1, 3), f"1x3 matrix should have shape (1, 3), got {matrix_1x3._data.shape}"
|
||||
|
||||
print("✅ Matrix creation: 2x2, 3x2, and 1x3 matrices")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Matrix creation failed: {e}")
|
||||
|
||||
# Test 4: Data type handling
|
||||
try:
|
||||
int_tensor = Tensor([1, 2, 3])
|
||||
float_tensor = Tensor([1.0, 2.0, 3.0])
|
||||
mixed_tensor = Tensor([1, 2.5, 3]) # Should convert to float
|
||||
|
||||
# Check that data types are reasonable
|
||||
assert int_tensor._data.dtype in [np.int32, np.int64], f"Int tensor has unexpected dtype: {int_tensor._data.dtype}"
|
||||
assert float_tensor._data.dtype in [np.float32, np.float64], f"Float tensor has unexpected dtype: {float_tensor._data.dtype}"
|
||||
assert mixed_tensor._data.dtype in [np.float32, np.float64], f"Mixed tensor should be float, got: {mixed_tensor._data.dtype}"
|
||||
|
||||
print("✅ Data type handling: integers, floats, and mixed types")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Data type handling failed: {e}")
|
||||
|
||||
# Test 5: NumPy array input
|
||||
try:
|
||||
np_array = np.array([1, 2, 3, 4])
|
||||
tensor_from_np = Tensor(np_array)
|
||||
|
||||
assert tensor_from_np._data.shape == (4,), f"Tensor from NumPy should have shape (4,), got {tensor_from_np._data.shape}"
|
||||
assert np.array_equal(tensor_from_np._data, np_array), "Tensor from NumPy should preserve data"
|
||||
|
||||
print("✅ NumPy array input: conversion works correctly")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ NumPy array input failed: {e}")
|
||||
|
||||
# Test 6: Large tensor creation
|
||||
try:
|
||||
large_tensor = Tensor(list(range(1000)))
|
||||
assert large_tensor._data.shape == (1000,), f"Large tensor should have shape (1000,), got {large_tensor._data.shape}"
|
||||
assert large_tensor._data[0] == 0, "Large tensor should start with 0"
|
||||
assert large_tensor._data[-1] == 999, "Large tensor should end with 999"
|
||||
|
||||
print("✅ Large tensor creation: 1000 elements")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Large tensor creation failed: {e}")
|
||||
|
||||
# Test 7: Negative numbers
|
||||
try:
|
||||
negative_tensor = Tensor([-1, -2, -3])
|
||||
mixed_signs = Tensor([-1, 0, 1])
|
||||
|
||||
assert negative_tensor._data.shape == (3,), f"Negative tensor should have shape (3,), got {negative_tensor._data.shape}"
|
||||
assert np.array_equal(negative_tensor._data, np.array([-1, -2, -3])), "Negative numbers should be preserved"
|
||||
assert np.array_equal(mixed_signs._data, np.array([-1, 0, 1])), "Mixed signs should be preserved"
|
||||
|
||||
print("✅ Negative numbers: handled correctly")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Negative numbers failed: {e}")
|
||||
|
||||
# Test 8: Edge cases
|
||||
try:
|
||||
# Very large numbers
|
||||
big_tensor = Tensor([1e6, 1e-6])
|
||||
assert big_tensor._data.shape == (2,), "Big numbers tensor should have correct shape"
|
||||
|
||||
# Zero tensor
|
||||
zero_tensor = Tensor([0, 0, 0])
|
||||
assert np.all(zero_tensor._data == 0), "Zero tensor should contain all zeros"
|
||||
|
||||
print("✅ Edge cases: large numbers and zeros")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Edge cases failed: {e}")
|
||||
|
||||
# Results summary
|
||||
print(f"\n📊 Tensor Creation Results: {tests_passed}/{total_tests} tests passed")
|
||||
|
||||
if tests_passed == total_tests:
|
||||
print("🎉 All tensor creation tests passed! Your Tensor class can handle:")
|
||||
print(" • Scalars, vectors, and matrices")
|
||||
print(" • Different data types (int, float)")
|
||||
print(" • NumPy arrays")
|
||||
print(" • Large tensors and edge cases")
|
||||
print("📈 Progress: Tensor Creation ✓")
|
||||
return True
|
||||
else:
|
||||
print("⚠️ Some tensor creation tests failed. Common issues:")
|
||||
print(" • Check your __init__ method implementation")
|
||||
print(" • Make sure you're storing data in self._data")
|
||||
print(" • Verify NumPy array conversion works correctly")
|
||||
print(" • Test with different input types (int, float, list, np.array)")
|
||||
return False
|
||||
|
||||
# Run the comprehensive test
|
||||
success = test_tensor_creation()
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
### 🧪 Comprehensive Test: Tensor Properties
|
||||
|
||||
Now let's test all the properties your tensor should have. These properties are essential for ML operations.
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": true, "grade_id": "test-tensor-properties-comprehensive", "locked": true, "points": 15, "schema_version": 3, "solution": false, "task": false}
|
||||
def test_tensor_properties():
|
||||
"""Comprehensive test of tensor properties (shape, size, dtype, data access)."""
|
||||
print("🔬 Testing comprehensive tensor properties...")
|
||||
|
||||
tests_passed = 0
|
||||
total_tests = 6
|
||||
|
||||
# Test 1: Shape property
|
||||
try:
|
||||
scalar = Tensor(5.0)
|
||||
vector = Tensor([1, 2, 3])
|
||||
matrix = Tensor([[1, 2], [3, 4]])
|
||||
tensor_3d = Tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
|
||||
|
||||
assert scalar.shape == (), f"Scalar shape should be (), got {scalar.shape}"
|
||||
assert vector.shape == (3,), f"Vector shape should be (3,), got {vector.shape}"
|
||||
assert matrix.shape == (2, 2), f"Matrix shape should be (2, 2), got {matrix.shape}"
|
||||
assert tensor_3d.shape == (2, 2, 2), f"3D tensor shape should be (2, 2, 2), got {tensor_3d.shape}"
|
||||
|
||||
print("✅ Shape property: scalar, vector, matrix, and 3D tensor")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Shape property failed: {e}")
|
||||
|
||||
# Test 2: Size property
|
||||
try:
|
||||
scalar = Tensor(5.0)
|
||||
vector = Tensor([1, 2, 3])
|
||||
matrix = Tensor([[1, 2], [3, 4]])
|
||||
empty = Tensor([])
|
||||
|
||||
assert scalar.size == 1, f"Scalar size should be 1, got {scalar.size}"
|
||||
assert vector.size == 3, f"Vector size should be 3, got {vector.size}"
|
||||
assert matrix.size == 4, f"Matrix size should be 4, got {matrix.size}"
|
||||
assert empty.size == 0, f"Empty tensor size should be 0, got {empty.size}"
|
||||
|
||||
print("✅ Size property: scalar, vector, matrix, and empty tensor")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Size property failed: {e}")
|
||||
|
||||
# Test 3: Data type property
|
||||
try:
|
||||
int_tensor = Tensor([1, 2, 3])
|
||||
float_tensor = Tensor([1.0, 2.0, 3.0])
|
||||
|
||||
# Check that dtype is accessible and reasonable
|
||||
assert hasattr(int_tensor, 'dtype'), "Tensor should have dtype property"
|
||||
assert hasattr(float_tensor, 'dtype'), "Tensor should have dtype property"
|
||||
|
||||
# Data types should be NumPy dtypes
|
||||
assert isinstance(int_tensor.dtype, np.dtype), f"dtype should be np.dtype, got {type(int_tensor.dtype)}"
|
||||
assert isinstance(float_tensor.dtype, np.dtype), f"dtype should be np.dtype, got {type(float_tensor.dtype)}"
|
||||
|
||||
print(f"✅ Data type property: int tensor is {int_tensor.dtype}, float tensor is {float_tensor.dtype}")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Data type property failed: {e}")
|
||||
|
||||
# Test 4: Data access property
|
||||
try:
|
||||
scalar = Tensor(5.0)
|
||||
vector = Tensor([1, 2, 3])
|
||||
matrix = Tensor([[1, 2], [3, 4]])
|
||||
|
||||
# Test data access
|
||||
assert hasattr(scalar, 'data'), "Tensor should have data property"
|
||||
assert hasattr(vector, 'data'), "Tensor should have data property"
|
||||
assert hasattr(matrix, 'data'), "Tensor should have data property"
|
||||
|
||||
# Test data content
|
||||
assert scalar.data.item() == 5.0, f"Scalar data should be 5.0, got {scalar.data.item()}"
|
||||
assert np.array_equal(vector.data, np.array([1, 2, 3])), "Vector data mismatch"
|
||||
assert np.array_equal(matrix.data, np.array([[1, 2], [3, 4]])), "Matrix data mismatch"
|
||||
|
||||
print("✅ Data access: scalar, vector, and matrix data retrieval")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Data access failed: {e}")
|
||||
|
||||
# Test 5: String representation
|
||||
try:
|
||||
scalar = Tensor(5.0)
|
||||
vector = Tensor([1, 2, 3])
|
||||
|
||||
# Test that __repr__ works
|
||||
scalar_str = str(scalar)
|
||||
vector_str = str(vector)
|
||||
|
||||
assert isinstance(scalar_str, str), "Tensor string representation should be a string"
|
||||
assert isinstance(vector_str, str), "Tensor string representation should be a string"
|
||||
assert len(scalar_str) > 0, "Tensor string representation should not be empty"
|
||||
assert len(vector_str) > 0, "Tensor string representation should not be empty"
|
||||
|
||||
print(f"✅ String representation: scalar={scalar_str[:50]}{'...' if len(scalar_str) > 50 else ''}")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ String representation failed: {e}")
|
||||
|
||||
# Test 6: Property consistency
|
||||
try:
|
||||
test_cases = [
|
||||
Tensor(42),
|
||||
Tensor([1, 2, 3, 4, 5]),
|
||||
Tensor([[1, 2, 3], [4, 5, 6]]),
|
||||
Tensor([])
|
||||
]
|
||||
|
||||
for i, tensor in enumerate(test_cases):
|
||||
# Size should equal product of shape
|
||||
expected_size = np.prod(tensor.shape) if tensor.shape else 1
|
||||
assert tensor.size == expected_size, f"Test case {i}: size {tensor.size} doesn't match shape {tensor.shape}"
|
||||
|
||||
# Data shape should match tensor shape
|
||||
assert tensor.data.shape == tensor.shape, f"Test case {i}: data shape {tensor.data.shape} doesn't match tensor shape {tensor.shape}"
|
||||
|
||||
print("✅ Property consistency: size matches shape, data shape matches tensor shape")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Property consistency failed: {e}")
|
||||
|
||||
# Results summary
|
||||
print(f"\n📊 Tensor Properties Results: {tests_passed}/{total_tests} tests passed")
|
||||
|
||||
if tests_passed == total_tests:
|
||||
print("🎉 All tensor property tests passed! Your tensor has:")
|
||||
print(" • Correct shape property for all dimensions")
|
||||
print(" • Accurate size calculation")
|
||||
print(" • Proper data type handling")
|
||||
print(" • Working data access")
|
||||
print(" • Good string representation")
|
||||
print("📈 Progress: Tensor Creation ✓, Properties ✓")
|
||||
return True
|
||||
else:
|
||||
print("⚠️ Some property tests failed. Common issues:")
|
||||
print(" • Check your @property decorators")
|
||||
print(" • Verify shape returns self._data.shape")
|
||||
print(" • Make sure size returns self._data.size")
|
||||
print(" • Ensure dtype returns self._data.dtype")
|
||||
print(" • Test your __repr__ method")
|
||||
return False
|
||||
|
||||
# Run the comprehensive test
|
||||
success = test_tensor_properties() and success
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
### 🧪 Comprehensive Test: Tensor Arithmetic
|
||||
|
||||
Let's test all arithmetic operations. These are the foundation of neural network computations!
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": true, "grade_id": "test-tensor-arithmetic-comprehensive", "locked": true, "points": 20, "schema_version": 3, "solution": false, "task": false}
|
||||
def test_tensor_arithmetic():
|
||||
"""Comprehensive test of tensor arithmetic operations."""
|
||||
print("🔬 Testing comprehensive tensor arithmetic...")
|
||||
|
||||
tests_passed = 0
|
||||
total_tests = 8
|
||||
|
||||
# Test 1: Basic addition method
|
||||
try:
|
||||
a = Tensor([1, 2, 3])
|
||||
b = Tensor([4, 5, 6])
|
||||
c = a.add(b)
|
||||
|
||||
expected = np.array([5, 7, 9])
|
||||
assert np.array_equal(c.data, expected), f"Addition method failed: expected {expected}, got {c.data}"
|
||||
assert isinstance(c, Tensor), "Addition should return a Tensor"
|
||||
|
||||
print(f"✅ Addition method: {a.data} + {b.data} = {c.data}")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Addition method failed: {e}")
|
||||
|
||||
# Test 2: Basic multiplication method
|
||||
try:
|
||||
a = Tensor([1, 2, 3])
|
||||
b = Tensor([4, 5, 6])
|
||||
c = a.multiply(b)
|
||||
|
||||
expected = np.array([4, 10, 18])
|
||||
assert np.array_equal(c.data, expected), f"Multiplication method failed: expected {expected}, got {c.data}"
|
||||
assert isinstance(c, Tensor), "Multiplication should return a Tensor"
|
||||
|
||||
print(f"✅ Multiplication method: {a.data} * {b.data} = {c.data}")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Multiplication method failed: {e}")
|
||||
|
||||
# Test 3: Addition operator (+)
|
||||
try:
|
||||
a = Tensor([1, 2, 3])
|
||||
b = Tensor([4, 5, 6])
|
||||
c = a + b
|
||||
|
||||
expected = np.array([5, 7, 9])
|
||||
assert np.array_equal(c.data, expected), f"+ operator failed: expected {expected}, got {c.data}"
|
||||
assert isinstance(c, Tensor), "+ operator should return a Tensor"
|
||||
|
||||
print(f"✅ + operator: {a.data} + {b.data} = {c.data}")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ + operator failed: {e}")
|
||||
|
||||
# Test 4: Multiplication operator (*)
|
||||
try:
|
||||
a = Tensor([1, 2, 3])
|
||||
b = Tensor([4, 5, 6])
|
||||
c = a * b
|
||||
|
||||
expected = np.array([4, 10, 18])
|
||||
assert np.array_equal(c.data, expected), f"* operator failed: expected {expected}, got {c.data}"
|
||||
assert isinstance(c, Tensor), "* operator should return a Tensor"
|
||||
|
||||
print(f"✅ * operator: {a.data} * {b.data} = {c.data}")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ * operator failed: {e}")
|
||||
|
||||
# Test 5: Subtraction operator (-)
|
||||
try:
|
||||
a = Tensor([1, 2, 3])
|
||||
b = Tensor([4, 5, 6])
|
||||
c = b - a
|
||||
|
||||
expected = np.array([3, 3, 3])
|
||||
assert np.array_equal(c.data, expected), f"- operator failed: expected {expected}, got {c.data}"
|
||||
assert isinstance(c, Tensor), "- operator should return a Tensor"
|
||||
|
||||
print(f"✅ - operator: {b.data} - {a.data} = {c.data}")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ - operator failed: {e}")
|
||||
|
||||
# Test 6: Division operator (/)
|
||||
try:
|
||||
a = Tensor([1, 2, 4])
|
||||
b = Tensor([2, 4, 8])
|
||||
c = b / a
|
||||
|
||||
expected = np.array([2.0, 2.0, 2.0])
|
||||
assert np.allclose(c.data, expected), f"/ operator failed: expected {expected}, got {c.data}"
|
||||
assert isinstance(c, Tensor), "/ operator should return a Tensor"
|
||||
|
||||
print(f"✅ / operator: {b.data} / {a.data} = {c.data}")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ / operator failed: {e}")
|
||||
|
||||
# Test 7: Scalar operations
|
||||
try:
|
||||
a = Tensor([1, 2, 3])
|
||||
|
||||
# Addition with scalar
|
||||
b = a + 10
|
||||
expected_add = np.array([11, 12, 13])
|
||||
assert np.array_equal(b.data, expected_add), f"Scalar addition failed: expected {expected_add}, got {b.data}"
|
||||
|
||||
# Multiplication with scalar
|
||||
c = a * 2
|
||||
expected_mul = np.array([2, 4, 6])
|
||||
assert np.array_equal(c.data, expected_mul), f"Scalar multiplication failed: expected {expected_mul}, got {c.data}"
|
||||
|
||||
# Subtraction with scalar
|
||||
d = a - 1
|
||||
expected_sub = np.array([0, 1, 2])
|
||||
assert np.array_equal(d.data, expected_sub), f"Scalar subtraction failed: expected {expected_sub}, got {d.data}"
|
||||
|
||||
# Division with scalar
|
||||
e = a / 2
|
||||
expected_div = np.array([0.5, 1.0, 1.5])
|
||||
assert np.allclose(e.data, expected_div), f"Scalar division failed: expected {expected_div}, got {e.data}"
|
||||
|
||||
print(f"✅ Scalar operations: +10, *2, -1, /2 all work correctly")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Scalar operations failed: {e}")
|
||||
|
||||
# Test 8: Matrix operations
|
||||
try:
|
||||
matrix_a = Tensor([[1, 2], [3, 4]])
|
||||
matrix_b = Tensor([[5, 6], [7, 8]])
|
||||
|
||||
# Matrix addition
|
||||
c = matrix_a + matrix_b
|
||||
expected = np.array([[6, 8], [10, 12]])
|
||||
assert np.array_equal(c.data, expected), f"Matrix addition failed: expected {expected}, got {c.data}"
|
||||
assert c.shape == (2, 2), f"Matrix addition should preserve shape, got {c.shape}"
|
||||
|
||||
# Matrix multiplication (element-wise)
|
||||
d = matrix_a * matrix_b
|
||||
expected_mul = np.array([[5, 12], [21, 32]])
|
||||
assert np.array_equal(d.data, expected_mul), f"Matrix multiplication failed: expected {expected_mul}, got {d.data}"
|
||||
|
||||
print(f"✅ Matrix operations: 2x2 matrix addition and multiplication")
|
||||
tests_passed += 1
|
||||
except Exception as e:
|
||||
print(f"❌ Matrix operations failed: {e}")
|
||||
|
||||
# Results summary
|
||||
print(f"\n📊 Tensor Arithmetic Results: {tests_passed}/{total_tests} tests passed")
|
||||
|
||||
if tests_passed == total_tests:
|
||||
print("🎉 All tensor arithmetic tests passed! Your tensor supports:")
|
||||
print(" • Basic methods: add(), multiply()")
|
||||
print(" • Python operators: +, -, *, /")
|
||||
print(" • Scalar operations: tensor + number")
|
||||
print(" • Matrix operations: element-wise operations")
|
||||
print("📈 Progress: Tensor Creation ✓, Properties ✓, Arithmetic ✓")
|
||||
return True
|
||||
else:
|
||||
print("⚠️ Some arithmetic tests failed. Common issues:")
|
||||
print(" • Check your add() and multiply() methods")
|
||||
print(" • Verify operator overloading (__add__, __mul__, __sub__, __truediv__)")
|
||||
print(" • Make sure scalar operations work (convert scalar to Tensor)")
|
||||
print(" • Test with different tensor shapes")
|
||||
return False
|
||||
|
||||
# Run the comprehensive test
|
||||
success = test_tensor_arithmetic() and success
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
### 🧪 Comprehensive Test: Real ML Scenario
|
||||
|
||||
Let's test your tensor with a realistic machine learning scenario to make sure everything works together.
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": true, "grade_id": "test-tensor-comprehensive", "locked": true, "points": 10, "schema_version": 3, "solution": false, "task": false}
|
||||
def test_tensor():
|
||||
"""Comprehensive test with realistic ML scenario."""
|
||||
print("🔬 Testing tensor comprehensively with ML scenario...")
|
||||
|
||||
try:
|
||||
print("🧠 Simulating a simple neural network forward pass...")
|
||||
|
||||
# Simulate input data (batch of 2 samples, 3 features each)
|
||||
X = Tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
|
||||
print(f"📊 Input data shape: {X.shape}")
|
||||
|
||||
# Simulate weights (3 input features, 2 output neurons)
|
||||
W = Tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]])
|
||||
print(f"🎯 Weights shape: {W.shape}")
|
||||
|
||||
# Simulate bias (2 output neurons)
|
||||
b = Tensor([0.1, 0.2])
|
||||
print(f"⚖️ Bias shape: {b.shape}")
|
||||
|
||||
# Simple linear transformation: y = X * W + b
|
||||
# Note: This is a simplified version - real matrix multiplication would be different
|
||||
# But we can test element-wise operations
|
||||
|
||||
# Test that we can do basic operations needed for ML
|
||||
sample = Tensor([1.0, 2.0, 3.0]) # Single sample
|
||||
weight_col = Tensor([0.1, 0.3, 0.5]) # First column of weights
|
||||
|
||||
# Compute dot product manually using element-wise operations
|
||||
products = sample * weight_col # Element-wise multiplication
|
||||
print(f"✅ Element-wise multiplication works: {products.data}")
|
||||
|
||||
# Test addition for bias
|
||||
result = products + Tensor([0.1, 0.1, 0.1])
|
||||
print(f"✅ Bias addition works: {result.data}")
|
||||
|
||||
# Test with different shapes
|
||||
matrix_a = Tensor([[1, 2], [3, 4]])
|
||||
matrix_b = Tensor([[0.1, 0.2], [0.3, 0.4]])
|
||||
matrix_result = matrix_a * matrix_b
|
||||
print(f"✅ Matrix operations work: {matrix_result.data}")
|
||||
|
||||
# Test scalar operations (common in ML)
|
||||
scaled = sample * 0.5 # Learning rate scaling
|
||||
print(f"✅ Scalar scaling works: {scaled.data}")
|
||||
|
||||
# Test normalization-like operations
|
||||
mean_val = Tensor([2.0, 2.0, 2.0]) # Simulate mean
|
||||
normalized = sample - mean_val
|
||||
print(f"✅ Mean subtraction works: {normalized.data}")
|
||||
|
||||
print("\n🎉 Comprehensive test passed! Your tensor class can handle:")
|
||||
print(" • Multi-dimensional data (batches, features)")
|
||||
print(" • Element-wise operations needed for ML")
|
||||
print(" • Scalar operations (learning rates, normalization)")
|
||||
print(" • Matrix operations (weights, transformations)")
|
||||
print("📈 Progress: All tensor functionality ✓")
|
||||
print("🚀 Ready for neural network layers!")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Comprehensive test failed: {e}")
|
||||
print("\n💡 This suggests an issue with:")
|
||||
print(" • Basic tensor operations not working together")
|
||||
print(" • Shape handling problems")
|
||||
print(" • Arithmetic operation implementation")
|
||||
print(" • Check your tensor creation and arithmetic methods")
|
||||
return False
|
||||
|
||||
# Run the comprehensive test
|
||||
success = test_tensor() and success
|
||||
|
||||
# Print final summary
|
||||
print(f"\n{'='*60}")
|
||||
print("🎯 TENSOR MODULE TESTING COMPLETE")
|
||||
print(f"{'='*60}")
|
||||
|
||||
if success:
|
||||
print("🎉 CONGRATULATIONS! All tensor tests passed!")
|
||||
print("\n✅ Your Tensor class successfully implements:")
|
||||
print(" • Comprehensive tensor creation (scalars, vectors, matrices)")
|
||||
print(" • All essential properties (shape, size, dtype, data access)")
|
||||
print(" • Complete arithmetic operations (methods and operators)")
|
||||
print(" • Scalar and matrix operations")
|
||||
print(" • Real ML scenario compatibility")
|
||||
print("\n🚀 You're ready to move to the next module!")
|
||||
print("📈 Final Progress: Tensor Module ✓ COMPLETE")
|
||||
else:
|
||||
print("⚠️ Some tests failed. Please review the error messages above.")
|
||||
print("\n🔧 To fix issues:")
|
||||
print(" 1. Check the specific test that failed")
|
||||
print(" 2. Review the error message and hints")
|
||||
print(" 3. Fix your implementation")
|
||||
print(" 4. Re-run the notebook cells")
|
||||
print("\n💪 Don't give up! Debugging is part of learning.")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Step 3: Tensor Arithmetic Operations
|
||||
|
||||
### Why Arithmetic Matters
|
||||
Tensor arithmetic is the foundation of all neural network operations:
|
||||
- **Forward pass**: Matrix multiplications and additions
|
||||
- **Activation functions**: Element-wise operations
|
||||
- **Loss computation**: Differences and squares
|
||||
- **Gradient computation**: Chain rule applications
|
||||
|
||||
### Operations We'll Implement
|
||||
- **Addition**: Element-wise addition of tensors
|
||||
- **Multiplication**: Element-wise multiplication
|
||||
- **Python operators**: `+`, `-`, `*`, `/` for natural syntax
|
||||
- **Broadcasting**: Handle different shapes automatically
|
||||
"""
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Step 3: Tensor Arithmetic Methods
|
||||
|
||||
The arithmetic methods are now part of the Tensor class above. Let's test them!
|
||||
"""
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Step 4: Python Operator Overloading
|
||||
|
||||
### Why Operator Overloading?
|
||||
Python's magic methods allow us to use natural syntax:
|
||||
- `a + b` instead of `a.add(b)`
|
||||
- `a * b` instead of `a.multiply(b)`
|
||||
- `a - b` for subtraction
|
||||
- `a / b` for division
|
||||
|
||||
This makes tensor operations feel natural and readable.
|
||||
"""
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## Step 4: Operator Overloading
|
||||
|
||||
The operator methods (__add__, __mul__, __sub__, __truediv__) are now part of the Tensor class above. This enables natural syntax like `a + b` and `a * b`.
|
||||
"""
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
### 🧪 Test Your Tensor Implementation
|
||||
|
||||
Once you implement the Tensor class above, run these cells to test your implementation:
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": true, "grade_id": "test-tensor-creation", "locked": true, "points": 25, "schema_version": 3, "solution": false, "task": false}
|
||||
# Test tensor creation and properties
|
||||
print("🔬 Unit Test: Tensor Creation...")
|
||||
|
||||
# Test scalar creation
|
||||
scalar = Tensor(5.0)
|
||||
assert scalar.shape == (), f"Scalar shape should be (), got {scalar.shape}"
|
||||
assert scalar.size == 1, f"Scalar size should be 1, got {scalar.size}"
|
||||
assert scalar.data.item() == 5.0, f"Scalar value should be 5.0, got {scalar.data.item()}"
|
||||
|
||||
# Test vector creation
|
||||
vector = Tensor([1, 2, 3])
|
||||
assert vector.shape == (3,), f"Vector shape should be (3,), got {vector.shape}"
|
||||
assert vector.size == 3, f"Vector size should be 3, got {vector.size}"
|
||||
assert np.array_equal(vector.data, np.array([1, 2, 3])), "Vector data mismatch"
|
||||
|
||||
# Test matrix creation
|
||||
matrix = Tensor([[1, 2], [3, 4]])
|
||||
assert matrix.shape == (2, 2), f"Matrix shape should be (2, 2), got {matrix.shape}"
|
||||
assert matrix.size == 4, f"Matrix size should be 4, got {matrix.size}"
|
||||
assert np.array_equal(matrix.data, np.array([[1, 2], [3, 4]])), "Matrix data mismatch"
|
||||
|
||||
# Test dtype handling
|
||||
float_tensor = Tensor([1.0, 2.0, 3.0])
|
||||
assert float_tensor.dtype == np.float32, f"Float tensor dtype should be float32, got {float_tensor.dtype}"
|
||||
|
||||
int_tensor = Tensor([1, 2, 3])
|
||||
# Note: NumPy may default to int64 on some systems, so we check for integer types
|
||||
assert int_tensor.dtype in [np.int32, np.int64], f"Int tensor dtype should be int32 or int64, got {int_tensor.dtype}"
|
||||
|
||||
print("✅ Tensor creation tests passed!")
|
||||
print(f"✅ Scalar: {scalar}")
|
||||
print(f"✅ Vector: {vector}")
|
||||
print(f"✅ Matrix: {matrix}")
|
||||
|
||||
# %% nbgrader={"grade": true, "grade_id": "test-tensor-arithmetic", "locked": true, "points": 25, "schema_version": 3, "solution": false, "task": false}
|
||||
# Test tensor arithmetic operations
|
||||
print("🔬 Unit Test: Tensor Arithmetic...")
|
||||
|
||||
# Test addition
|
||||
a = Tensor([1, 2, 3])
|
||||
b = Tensor([4, 5, 6])
|
||||
c = a + b
|
||||
expected = np.array([5, 7, 9])
|
||||
assert np.array_equal(c.data, expected), f"Addition failed: expected {expected}, got {c.data}"
|
||||
|
||||
# Test multiplication
|
||||
d = a * b
|
||||
expected = np.array([4, 10, 18])
|
||||
assert np.array_equal(d.data, expected), f"Multiplication failed: expected {expected}, got {d.data}"
|
||||
|
||||
# Test subtraction
|
||||
e = b - a
|
||||
expected = np.array([3, 3, 3])
|
||||
assert np.array_equal(e.data, expected), f"Subtraction failed: expected {expected}, got {e.data}"
|
||||
|
||||
# Test division
|
||||
f = b / a
|
||||
expected = np.array([4.0, 2.5, 2.0])
|
||||
assert np.allclose(f.data, expected), f"Division failed: expected {expected}, got {f.data}"
|
||||
|
||||
# Test scalar operations
|
||||
g = a + 10
|
||||
expected = np.array([11, 12, 13])
|
||||
assert np.array_equal(g.data, expected), f"Scalar addition failed: expected {expected}, got {g.data}"
|
||||
|
||||
h = a * 2
|
||||
expected = np.array([2, 4, 6])
|
||||
assert np.array_equal(h.data, expected), f"Scalar multiplication failed: expected {expected}, got {h.data}"
|
||||
|
||||
print("✅ Tensor arithmetic tests passed!")
|
||||
print(f"✅ Addition: {a} + {b} = {c}")
|
||||
print(f"✅ Multiplication: {a} * {b} = {d}")
|
||||
print(f"✅ Subtraction: {b} - {a} = {e}")
|
||||
print(f"✅ Division: {b} / {a} = {f}")
|
||||
|
||||
# %% nbgrader={"grade": true, "grade_id": "test-tensor-broadcasting", "locked": true, "points": 25, "schema_version": 3, "solution": false, "task": false}
|
||||
# Test tensor broadcasting
|
||||
print("🔬 Unit Test: Tensor Broadcasting...")
|
||||
|
||||
# Test scalar broadcasting
|
||||
matrix = Tensor([[1, 2], [3, 4]])
|
||||
scalar = Tensor(10)
|
||||
result = matrix + scalar
|
||||
expected = np.array([[11, 12], [13, 14]])
|
||||
assert np.array_equal(result.data, expected), f"Scalar broadcasting failed: expected {expected}, got {result.data}"
|
||||
|
||||
# Test vector broadcasting
|
||||
vector = Tensor([1, 2])
|
||||
result = matrix + vector
|
||||
expected = np.array([[2, 4], [4, 6]])
|
||||
assert np.array_equal(result.data, expected), f"Vector broadcasting failed: expected {expected}, got {result.data}"
|
||||
|
||||
# Test different shapes
|
||||
a = Tensor([[1], [2], [3]]) # (3, 1)
|
||||
b = Tensor([10, 20]) # (2,)
|
||||
result = a + b
|
||||
expected = np.array([[11, 21], [12, 22], [13, 23]])
|
||||
assert np.array_equal(result.data, expected), f"Shape broadcasting failed: expected {expected}, got {result.data}"
|
||||
|
||||
print("✅ Tensor broadcasting tests passed!")
|
||||
print(f"✅ Matrix + Scalar: {matrix} + {scalar} = {result}")
|
||||
print(f"✅ Broadcasting works correctly!")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## 🎯 Module Summary
|
||||
|
||||
Congratulations! You've successfully implemented the core Tensor class for TinyTorch:
|
||||
|
||||
### What You've Accomplished
|
||||
✅ **Tensor Creation**: Handle scalars, vectors, matrices, and higher-dimensional arrays
|
||||
✅ **Data Types**: Proper dtype handling with auto-detection and conversion
|
||||
✅ **Properties**: Shape, size, dtype, and data access
|
||||
✅ **Arithmetic**: Addition, multiplication, subtraction, division
|
||||
✅ **Operators**: Natural Python syntax with `+`, `-`, `*`, `/`
|
||||
✅ **Broadcasting**: Automatic shape compatibility like NumPy
|
||||
|
||||
### Key Concepts You've Learned
|
||||
- **Tensors** are the fundamental data structure for ML systems
|
||||
- **NumPy backend** provides efficient computation with ML-friendly API
|
||||
- **Operator overloading** makes tensor operations feel natural
|
||||
- **Broadcasting** enables flexible operations between different shapes
|
||||
- **Type safety** ensures consistent behavior across operations
|
||||
"""
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## 🧪 Module Testing
|
||||
|
||||
Time to test your implementation! This section uses TinyTorch's standardized testing framework to ensure your implementation works correctly.
|
||||
|
||||
**This testing section is locked** - it provides consistent feedback across all modules and cannot be modified.
|
||||
"""
|
||||
|
||||
# %% nbgrader={"grade": false, "grade_id": "standardized-testing", "locked": true, "schema_version": 3, "solution": false, "task": false}
|
||||
# =============================================================================
|
||||
# STANDARDIZED MODULE TESTING - DO NOT MODIFY
|
||||
# This cell is locked to ensure consistent testing across all TinyTorch modules
|
||||
# =============================================================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
from tito.tools.testing import run_module_tests_auto
|
||||
|
||||
# Automatically discover and run all tests in this module
|
||||
success = run_module_tests_auto("Tensor")
|
||||
|
||||
# %% [markdown]
|
||||
"""
|
||||
## 🎯 Module Summary
|
||||
|
||||
Congratulations! You've successfully implemented the core Tensor class for TinyTorch:
|
||||
|
||||
### What You've Accomplished
|
||||
@@ -1576,4 +813,68 @@ Congratulations! You've successfully implemented the core Tensor class for TinyT
|
||||
4. **Move to Module 2**: Start building activation functions!
|
||||
|
||||
**Ready for the next challenge?** Let's add the mathematical functions that make neural networks powerful!
|
||||
"""
|
||||
"""
|
||||
|
||||
def test_unit_tensor_creation():
|
||||
"""Comprehensive test of tensor creation with all data types and shapes."""
|
||||
print("🔬 Testing comprehensive tensor creation...")
|
||||
|
||||
# Test scalar creation
|
||||
scalar_int = Tensor(42)
|
||||
assert scalar_int.shape == ()
|
||||
|
||||
# Test vector creation
|
||||
vector_int = Tensor([1, 2, 3])
|
||||
assert vector_int.shape == (3,)
|
||||
|
||||
# Test matrix creation
|
||||
matrix_2x2 = Tensor([[1, 2], [3, 4]])
|
||||
assert matrix_2x2.shape == (2, 2)
|
||||
print("✅ Tensor creation tests passed!")
|
||||
|
||||
def test_unit_tensor_properties():
|
||||
"""Comprehensive test of tensor properties (shape, size, dtype, data access)."""
|
||||
print("🔬 Testing comprehensive tensor properties...")
|
||||
|
||||
tensor = Tensor([[1, 2, 3], [4, 5, 6]])
|
||||
|
||||
# Test shape property
|
||||
assert tensor.shape == (2, 3)
|
||||
|
||||
# Test size property
|
||||
assert tensor.size == 6
|
||||
|
||||
# Test data property
|
||||
assert np.array_equal(tensor.data, np.array([[1, 2, 3], [4, 5, 6]]))
|
||||
|
||||
# Test dtype property
|
||||
assert tensor.dtype in [np.int32, np.int64]
|
||||
print("✅ Tensor properties tests passed!")
|
||||
|
||||
def test_unit_tensor_arithmetic():
|
||||
"""Comprehensive test of tensor arithmetic operations."""
|
||||
print("🔬 Testing comprehensive tensor arithmetic...")
|
||||
|
||||
a = Tensor([1, 2, 3])
|
||||
b = Tensor([4, 5, 6])
|
||||
|
||||
# Test addition
|
||||
c = a + b
|
||||
expected = np.array([5, 7, 9])
|
||||
assert np.array_equal(c.data, expected)
|
||||
|
||||
# Test multiplication
|
||||
d = a * b
|
||||
expected = np.array([4, 10, 18])
|
||||
assert np.array_equal(d.data, expected)
|
||||
|
||||
# Test subtraction
|
||||
e = b - a
|
||||
expected = np.array([3, 3, 3])
|
||||
assert np.array_equal(e.data, expected)
|
||||
|
||||
# Test division
|
||||
f = b / a
|
||||
expected = np.array([4.0, 2.5, 2.0])
|
||||
assert np.allclose(f.data, expected)
|
||||
print("✅ Tensor arithmetic tests passed!")
|
||||
Reference in New Issue
Block a user