- Moved tools/py_to_notebook.py to bin/py_to_notebook.py - Updated tito.py to reference the new location - Made py_to_notebook.py executable for direct invocation - Removed empty tools/ directory - Updated documentation to reflect new location - All tools now consolidated in bin/ directory for consistency Benefits: - Conventional organization (bin/ for executables) - Can invoke tools directly: ./bin/py_to_notebook.py - Cleaner project structure - Consistent with other tools (tito.py, generate_student_notebooks.py)
8.5 KiB
📖 TinyTorch Module Development Guide
A complete guide for creating educational modules that automatically generate student exercise versions.
🎯 Philosophy
Write once, teach everywhere. Create complete, working implementations with embedded pedagogical markers that automatically generate student exercise notebooks.
🏗️ Module Development Workflow
Step 1: Plan the Learning Journey
Before coding, decide:
- What should students implement? (core learning objectives)
- What should be provided? (utilities, complex setup, advanced features)
- What's the difficulty progression? (easy → medium → hard)
Step 2: Write Complete Implementation
Create modules/{module}/{module}_dev.py with:
# %% [markdown]
# # Module Title: Learning Objectives
#
# Brief description of what students will build and learn.
# %%
#| keep_imports
import numpy as np
from typing import Union, List
# %%
# Complete working implementation with markers...
Step 3: Add Pedagogical Markers
Mark what students should implement vs. what to provide.
Step 4: Convert and Generate
# Convert Python to notebook
python bin/tito.py notebooks --module {module}
# Generate student version
python3 bin/generate_student_notebooks.py --module {module}
🏷️ Marker System
Exercise Markers
#| exercise_start
#| difficulty: easy|medium|hard
#| hint: Helpful guidance without giving away the solution
#| hint: Multiple hints allowed for complex methods
#| solution_test: What students should verify after implementation
def method_to_implement(self, params):
"""Complete function signature and docstring."""
# Full working implementation
return result
#| exercise_end
Preservation Markers
#| keep_imports
import statements # Preserved in student version
#| keep_complete
def utility_method(self):
"""Keep entire implementation - too complex/not educational."""
return complex_implementation()
#| remove_cell
# This entire cell removed from student version
instructor_only_code()
🎨 Difficulty System
Use visual indicators that students immediately understand:
-
🟢 Easy (5-10 min): Basic implementation, clear patterns
- Constructor with simple type conversion
- Property getters
- Basic arithmetic operations
-
🟡 Medium (10-20 min): Moderate complexity, some edge cases
- Methods with conditional logic
- Shape manipulation
- Error handling
-
🔴 Hard (20+ min): Complex logic, multiple concepts
- Broadcasting operations
- Advanced algorithms
- Integration between components
📋 What Students Should Implement vs. Receive
✅ Students Implement (Active Learning)
- Core functionality: Main learning objectives
- Basic operations: Addition, multiplication, etc.
- Essential properties: Shape, size, dtype
- Error handling: Type checking, validation
- Simple algorithms: Reshape, transpose, reductions
🎁 Students Receive (Focus on Learning Goals)
- Complex setup code: Initialization boilerplate
- Utility functions: String formatting, type checking helpers
- Advanced features: GPU support, optimization, broadcasting
- Infrastructure: Test frameworks, import statements
- Edge case handling: Complex error messages, corner cases
📝 Writing Guidelines
Function Structure
Always provide complete signatures and docstrings:
#| exercise_start
#| difficulty: medium
#| hint: Use numpy broadcasting for element-wise operations
#| solution_test: Result should be same shape as inputs
def __add__(self, other: Union['Tensor', int, float]) -> 'Tensor':
"""
Add this tensor with another tensor or scalar.
Args:
other: Another Tensor or scalar value
Returns:
Tensor: New tensor with element-wise addition result
Raises:
TypeError: If other is not a compatible type
"""
if isinstance(other, Tensor):
return Tensor(self._data + other._data)
else:
return Tensor(self._data + other)
#| exercise_end
Hint Guidelines
- Be helpful, not prescriptive: Guide thinking, don't give code
- Progressive disclosure: Start general, get more specific
- Reference relevant concepts: "Use numpy broadcasting", "Check instance type"
Good hints:
#| hint: Convert input to numpy array for consistent handling
#| hint: Use isinstance() to check if input is a Tensor or scalar
#| hint: Remember to return a new Tensor object, not numpy array
Bad hints:
#| hint: Write: return Tensor(self._data + other._data) # Too specific!
#| hint: Add the data # Too vague!
Solution Tests
Help students verify their implementation:
#| solution_test: Tensor([1,2]) + Tensor([3,4]) should equal Tensor([4,6])
#| solution_test: Tensor([1,2]) + 5 should equal Tensor([6,7])
#| solution_test: Result should be a Tensor object, not numpy array
🗂️ Module Structure
modules/{module}/
├── {module}_dev.py # 🔧 Complete implementation (instructor)
├── {module}_dev.ipynb # 📓 Generated from .py file
├── {module}_dev_student.ipynb # 🎓 Auto-generated exercise version
├── test_{module}.py # 🧪 Comprehensive test suite
├── check_{module}.py # ✅ Manual verification script
└── README.md # 📖 Module overview and setup
🎯 Module Examples
Easy Module (Tensor Basics)
Students implement:
- 🟢 Constructor (
__init__) - 🟢 Properties (
shape,size,dtype) - 🟢 Basic arithmetic (
__add__,__sub__) - 🟡 Utilities (
reshape,transpose)
Medium Module (Autograd)
Students implement:
- 🟡 Forward pass computation
- 🟡 Gradient accumulation
- 🔴 Backward pass algorithm
- 🔴 Chain rule application
Hard Module (Neural Networks)
Students implement:
- 🟡 Layer forward pass
- 🔴 Loss computation
- 🔴 Backpropagation
- 🔴 Parameter updates
🛠️ Development Tools
Convert Python to Notebook
python bin/tito.py notebooks --module {module}
Generate Student Version
python bin/generate_student_notebooks.py --module {module}
Test Complete Workflow
# Test instructor version
cd modules/{module}
jupyter lab {module}_dev.ipynb
# Test student version
jupyter lab {module}_dev_student.ipynb
# Verify exports work
python bin/tito.py sync --module {module}
python bin/tito.py test --module {module}
✅ Quality Checklist
Before releasing a module:
Instructor Version:
- Complete implementation works and passes all tests
- All methods have proper type hints and docstrings
- Markers are correctly placed and consistent
- Code follows TinyTorch style guidelines
Student Version:
- Generated notebook preserves function signatures
- Hints are helpful but not prescriptive
- Difficulty progression makes sense
- Tests provide clear verification guidance
- Students can run and get feedback immediately
Integration:
- Module exports correctly to tinytorch package
- Tests pass with student implementation stubs
- README explains module purpose and workflow
- Follows established module naming conventions
💡 Best Practices
For Instructors
- Start with learning goals: What should students understand after this module?
- Write complete first: Get the full solution working before adding markers
- Think like a student: What would be confusing? What needs guidance?
- Test the student path: Try implementing following your own hints
For Markers
- Be consistent: Use same difficulty criteria across modules
- Progressive complexity: Easy concepts early, hard concepts later
- Meaningful hints: Guide understanding, not just implementation
- Clear boundaries: Be explicit about what students implement vs. receive
For Generator
- Preserve signatures: Students need to know the interface
- Keep docstrings: Essential for understanding purpose
- Clean output: Remove implementation but keep structure
- Test guidance: Help students verify their work
🔄 Iteration and Improvement
After teaching with a module:
- Collect feedback: What confused students? What was too easy/hard?
- Update markers: Adjust difficulty, improve hints
- Refine scope: Move methods between implement/provide categories
- Share learnings: Update this guide with discoveries
Remember: The goal is active learning through hands-on implementation, not just demonstration!