Files
TinyTorch/modules/source/01_tensor/tensor_dev.ipynb
Vijay Janapa Reddi eafbb4ac8d Fix comprehensive testing and module exports
🔧 TESTING INFRASTRUCTURE FIXES:
- Fixed pytest configuration (removed duplicate timeout)
- Exported all modules to tinytorch package using nbdev
- Converted .py files to .ipynb for proper NBDev processing
- Fixed import issues in test files with fallback strategies

📊 TESTING RESULTS:
- 145 tests passing, 15 failing, 16 skipped
- Major improvement from previous import errors
- All modules now properly exported and testable
- Analysis tool working correctly on all modules

🎯 MODULE QUALITY STATUS:
- Most modules: Grade C, Scaffolding 3/5
- 01_tensor: Grade C, Scaffolding 2/5 (needs improvement)
- 07_autograd: Grade D, Scaffolding 2/5 (needs improvement)
- Overall: Functional but needs educational enhancement

 RESOLVED ISSUES:
- All import errors resolved
- NBDev export process working
- Test infrastructure functional
- Analysis tools operational

🚀 READY FOR NEXT PHASE: Professional report cards and improvements
2025-07-13 09:20:32 -04:00

1853 lines
76 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"cells": [
{
"cell_type": "markdown",
"id": "d889922d",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"# Module 1: Tensor - Core Data Structure\n",
"\n",
"Welcome to the Tensor module! This is where TinyTorch really begins. You'll implement the fundamental data structure that powers all ML systems.\n",
"\n",
"## Learning Goals\n",
"- Understand tensors as N-dimensional arrays with ML-specific operations\n",
"- Implement a complete Tensor class with arithmetic operations\n",
"- Handle shape management, data types, and memory layout\n",
"- Build the foundation for neural networks and automatic differentiation\n",
"- Master the NBGrader workflow with comprehensive testing\n",
"\n",
"## Build → Use → Understand\n",
"1. **Build**: Create the Tensor class with core operations\n",
"2. **Use**: Perform tensor arithmetic and transformations\n",
"3. **Understand**: How tensors form the foundation of ML systems"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4a146c17",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "tensor-imports",
"locked": false,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"#| default_exp core.tensor\n",
"\n",
"#| export\n",
"import numpy as np\n",
"import sys\n",
"from typing import Union, List, Tuple, Optional, Any"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bcebdf84",
"metadata": {
"nbgrader": {
"grade": false,
"grade_id": "tensor-setup",
"locked": false,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"print(\"🔥 TinyTorch Tensor Module\")\n",
"print(f\"NumPy version: {np.__version__}\")\n",
"print(f\"Python version: {sys.version_info.major}.{sys.version_info.minor}\")\n",
"print(\"Ready to build tensors!\")"
]
},
{
"cell_type": "markdown",
"id": "ab96dce5",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## 📦 Where This Code Lives in the Final Package\n",
"\n",
"**Learning Side:** You work in `modules/source/01_tensor/tensor_dev.py` \n",
"**Building Side:** Code exports to `tinytorch.core.tensor`\n",
"\n",
"```python\n",
"# Final package structure:\n",
"from tinytorch.core.tensor import Tensor # The foundation of everything!\n",
"from tinytorch.core.activations import ReLU, Sigmoid, Tanh\n",
"from tinytorch.core.layers import Dense, Conv2D\n",
"```\n",
"\n",
"**Why this matters:**\n",
"- **Learning:** Focused modules for deep understanding\n",
"- **Production:** Proper organization like PyTorch's `torch.Tensor`\n",
"- **Consistency:** All tensor operations live together in `core.tensor`\n",
"- **Foundation:** Every other module depends on Tensor"
]
},
{
"cell_type": "markdown",
"id": "7f474d65",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## Step 1: What is a Tensor?\n",
"\n",
"### Definition\n",
"A **tensor** is an N-dimensional array with ML-specific operations. Think of it as a container that can hold data in multiple dimensions:\n",
"\n",
"- **Scalar** (0D): A single number - `5.0`\n",
"- **Vector** (1D): A list of numbers - `[1, 2, 3]` \n",
"- **Matrix** (2D): A 2D array - `[[1, 2], [3, 4]]`\n",
"- **Higher dimensions**: 3D, 4D, etc. for images, video, batches\n",
"\n",
"### The Mathematical Foundation: From Scalars to Tensors\n",
"Understanding tensors requires building from mathematical fundamentals:\n",
"\n",
"#### **Scalars (Rank 0)**\n",
"- **Definition**: A single number with no direction\n",
"- **Examples**: Temperature (25°C), mass (5.2 kg), probability (0.7)\n",
"- **Operations**: Addition, multiplication, comparison\n",
"- **ML Context**: Loss values, learning rates, regularization parameters\n",
"\n",
"#### **Vectors (Rank 1)**\n",
"- **Definition**: An ordered list of numbers with direction and magnitude\n",
"- **Examples**: Position [x, y, z], RGB color [255, 128, 0], word embedding [0.1, -0.5, 0.8]\n",
"- **Operations**: Dot product, cross product, norm calculation\n",
"- **ML Context**: Feature vectors, gradients, model parameters\n",
"\n",
"#### **Matrices (Rank 2)**\n",
"- **Definition**: A 2D array organizing data in rows and columns\n",
"- **Examples**: Image (height × width), weight matrix (input × output), covariance matrix\n",
"- **Operations**: Matrix multiplication, transpose, inverse, eigendecomposition\n",
"- **ML Context**: Linear layer weights, attention matrices, batch data\n",
"\n",
"#### **Higher-Order Tensors (Rank 3+)**\n",
"- **Definition**: Multi-dimensional arrays extending matrices\n",
"- **Examples**: \n",
" - **3D**: Video frames (time × height × width), RGB images (height × width × channels)\n",
" - **4D**: Image batches (batch × height × width × channels)\n",
" - **5D**: Video batches (batch × time × height × width × channels)\n",
"- **Operations**: Tensor products, contractions, decompositions\n",
"- **ML Context**: Convolutional features, RNN states, transformer attention\n",
"\n",
"### Why Tensors Matter in ML: The Computational Foundation\n",
"\n",
"#### **1. Unified Data Representation**\n",
"Tensors provide a consistent way to represent all ML data:\n",
"```python\n",
"# All of these are tensors with different shapes\n",
"scalar_loss = Tensor(0.5) # Shape: ()\n",
"feature_vector = Tensor([1, 2, 3]) # Shape: (3,)\n",
"weight_matrix = Tensor([[1, 2], [3, 4]]) # Shape: (2, 2)\n",
"image_batch = Tensor(np.random.rand(32, 224, 224, 3)) # Shape: (32, 224, 224, 3)\n",
"```\n",
"\n",
"#### **2. Efficient Batch Processing**\n",
"ML systems process multiple samples simultaneously:\n",
"```python\n",
"# Instead of processing one image at a time:\n",
"for image in images:\n",
" result = model(image) # Slow: 1000 separate operations\n",
"\n",
"# Process entire batch at once:\n",
"batch_result = model(image_batch) # Fast: 1 vectorized operation\n",
"```\n",
"\n",
"#### **3. Hardware Acceleration**\n",
"Modern hardware (GPUs, TPUs) excels at tensor operations:\n",
"- **Parallel processing**: Multiple operations simultaneously\n",
"- **Vectorization**: SIMD (Single Instruction, Multiple Data) operations\n",
"- **Memory optimization**: Contiguous memory layout for cache efficiency\n",
"\n",
"#### **4. Automatic Differentiation**\n",
"Tensors enable gradient computation through computational graphs:\n",
"```python\n",
"# Each tensor operation creates a node in the computation graph\n",
"x = Tensor([1, 2, 3])\n",
"y = x * 2 # Node: multiplication\n",
"z = y + 1 # Node: addition\n",
"loss = z.sum() # Node: summation\n",
"# Gradients flow backward through this graph\n",
"```\n",
"\n",
"### Real-World Examples: Tensors in Action\n",
"\n",
"#### **Computer Vision**\n",
"- **Grayscale image**: 2D tensor `(height, width)` - `(28, 28)` for MNIST\n",
"- **Color image**: 3D tensor `(height, width, channels)` - `(224, 224, 3)` for RGB\n",
"- **Image batch**: 4D tensor `(batch, height, width, channels)` - `(32, 224, 224, 3)`\n",
"- **Video**: 5D tensor `(batch, time, height, width, channels)`\n",
"\n",
"#### **Natural Language Processing**\n",
"- **Word embedding**: 1D tensor `(embedding_dim,)` - `(300,)` for Word2Vec\n",
"- **Sentence**: 2D tensor `(sequence_length, embedding_dim)` - `(50, 768)` for BERT\n",
"- **Batch of sentences**: 3D tensor `(batch, sequence_length, embedding_dim)`\n",
"\n",
"#### **Audio Processing**\n",
"- **Audio signal**: 1D tensor `(time_steps,)` - `(16000,)` for 1 second at 16kHz\n",
"- **Spectrogram**: 2D tensor `(time_frames, frequency_bins)`\n",
"- **Batch of audio**: 3D tensor `(batch, time_steps, features)`\n",
"\n",
"#### **Time Series**\n",
"- **Single series**: 2D tensor `(time_steps, features)`\n",
"- **Multiple series**: 3D tensor `(batch, time_steps, features)`\n",
"- **Multivariate forecasting**: 4D tensor `(batch, time_steps, features, predictions)`\n",
"\n",
"### Why Not Just Use NumPy?\n",
"\n",
"While we use NumPy internally, our Tensor class adds ML-specific functionality:\n",
"\n",
"#### **1. ML-Specific Operations**\n",
"- **Gradient tracking**: For automatic differentiation (coming in Module 7)\n",
"- **GPU support**: For hardware acceleration (future extension)\n",
"- **Broadcasting semantics**: ML-friendly dimension handling\n",
"\n",
"#### **2. Consistent API**\n",
"- **Type safety**: Predictable behavior across operations\n",
"- **Error checking**: Clear error messages for debugging\n",
"- **Integration**: Seamless work with other TinyTorch components\n",
"\n",
"#### **3. Educational Value**\n",
"- **Conceptual clarity**: Understand what tensors really are\n",
"- **Implementation insight**: See how frameworks work internally\n",
"- **Debugging skills**: Trace through tensor operations step by step\n",
"\n",
"#### **4. Extensibility**\n",
"- **Future features**: Ready for gradients, GPU, distributed computing\n",
"- **Customization**: Add domain-specific operations\n",
"- **Optimization**: Profile and optimize specific use cases\n",
"\n",
"### Performance Considerations: Building Efficient Tensors\n",
"\n",
"#### **Memory Layout**\n",
"- **Contiguous arrays**: Better cache locality and performance\n",
"- **Data types**: `float32` vs `float64` trade-offs\n",
"- **Memory sharing**: Avoid unnecessary copies\n",
"\n",
"#### **Vectorization**\n",
"- **SIMD operations**: Single Instruction, Multiple Data\n",
"- **Broadcasting**: Efficient operations on different shapes\n",
"- **Batch operations**: Process multiple samples simultaneously\n",
"\n",
"#### **Numerical Stability**\n",
"- **Precision**: Balancing speed and accuracy\n",
"- **Overflow/underflow**: Handling extreme values\n",
"- **Gradient flow**: Maintaining numerical stability for training\n",
"\n",
"Let's start building our tensor foundation!"
]
},
{
"cell_type": "markdown",
"id": "1cba0ba4",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## 🧠 The Mathematical Foundation\n",
"\n",
"### Linear Algebra Refresher\n",
"Tensors are generalizations of scalars, vectors, and matrices:\n",
"\n",
"```\n",
"Scalar (0D): 5\n",
"Vector (1D): [1, 2, 3]\n",
"Matrix (2D): [[1, 2], [3, 4]]\n",
"Tensor (3D): [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]\n",
"```\n",
"\n",
"### Why This Matters for Neural Networks\n",
"- **Forward Pass**: Matrix multiplication between layers\n",
"- **Batch Processing**: Multiple samples processed simultaneously\n",
"- **Convolutions**: 3D operations on image data\n",
"- **Gradients**: Derivatives computed across all dimensions\n",
"\n",
"### Connection to Real ML Systems\n",
"Every major ML framework uses tensors:\n",
"- **PyTorch**: `torch.Tensor`\n",
"- **TensorFlow**: `tf.Tensor`\n",
"- **JAX**: `jax.numpy.ndarray`\n",
"- **TinyTorch**: `tinytorch.core.tensor.Tensor` (what we're building!)\n",
"\n",
"### Performance Considerations\n",
"- **Memory Layout**: Contiguous arrays for cache efficiency\n",
"- **Vectorization**: SIMD operations for speed\n",
"- **Broadcasting**: Efficient operations on different shapes\n",
"- **Type Consistency**: Avoiding unnecessary conversions"
]
},
{
"cell_type": "markdown",
"id": "0b755b99",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
},
"source": [
"## Step 2: The Tensor Class Foundation\n",
"\n",
"### Core Concept: Wrapping NumPy with ML Intelligence\n",
"Our Tensor class wraps NumPy arrays with ML-specific functionality. This design pattern is used by all major ML frameworks:\n",
"\n",
"- **PyTorch**: `torch.Tensor` wraps ATen (C++ tensor library)\n",
"- **TensorFlow**: `tf.Tensor` wraps Eigen (C++ linear algebra library)\n",
"- **JAX**: `jax.numpy.ndarray` wraps XLA (Google's linear algebra compiler)\n",
"- **TinyTorch**: `Tensor` wraps NumPy (Python's numerical computing library)\n",
"\n",
"### Design Requirements Analysis\n",
"\n",
"#### **1. Input Flexibility**\n",
"Our tensor must handle diverse input types:\n",
"```python\n",
"# Scalars (Python numbers)\n",
"t1 = Tensor(5) # int → numpy array\n",
"t2 = Tensor(3.14) # float → numpy array\n",
"\n",
"# Lists (Python sequences)\n",
"t3 = Tensor([1, 2, 3]) # list → numpy array\n",
"t4 = Tensor([[1, 2], [3, 4]]) # nested list → 2D array\n",
"\n",
"# NumPy arrays (existing arrays)\n",
"t5 = Tensor(np.array([1, 2, 3])) # array → tensor wrapper\n",
"```\n",
"\n",
"#### **2. Type Management**\n",
"ML systems need consistent, predictable types:\n",
"- **Default behavior**: Auto-detect appropriate types\n",
"- **Explicit control**: Allow manual type specification\n",
"- **Performance optimization**: Prefer `float32` over `float64`\n",
"- **Memory efficiency**: Use appropriate precision\n",
"\n",
"#### **3. Property Access**\n",
"Essential tensor properties for ML operations:\n",
"- **Shape**: Dimensions for compatibility checking\n",
"- **Size**: Total elements for memory estimation\n",
"- **Data type**: For numerical computation planning\n",
"- **Data access**: For integration with other libraries\n",
"\n",
"#### **4. Arithmetic Operations**\n",
"Support for mathematical operations:\n",
"- **Element-wise**: Addition, multiplication, subtraction, division\n",
"- **Broadcasting**: Operations on different shapes\n",
"- **Type promotion**: Consistent result types\n",
"- **Error handling**: Clear messages for incompatible operations\n",
"\n",
"### Implementation Strategy\n",
"\n",
"#### **Memory Management**\n",
"- **Copy vs. Reference**: When to copy data vs. share memory\n",
"- **Type conversion**: Efficient dtype changes\n",
"- **Contiguous layout**: Ensure optimal memory access patterns\n",
"\n",
"#### **Error Handling**\n",
"- **Input validation**: Check for valid input types\n",
"- **Shape compatibility**: Verify operations are mathematically valid\n",
"- **Informative messages**: Help users debug issues quickly\n",
"\n",
"#### **Performance Optimization**\n",
"- **Lazy evaluation**: Defer expensive operations when possible\n",
"- **Vectorization**: Use NumPy's optimized operations\n",
"- **Memory reuse**: Minimize unnecessary allocations\n",
"\n",
"### Learning Objectives for Implementation\n",
"\n",
"By implementing this Tensor class, you'll learn:\n",
"1. **Wrapper pattern**: How to extend existing libraries\n",
"2. **Type system design**: Managing data types in numerical computing\n",
"3. **API design**: Creating intuitive, consistent interfaces\n",
"4. **Performance considerations**: Balancing flexibility and speed\n",
"5. **Error handling**: Providing helpful feedback to users\n",
"\n",
"Let's implement our tensor foundation!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8e4f7ece",
"metadata": {
"lines_to_next_cell": 1,
"nbgrader": {
"grade": false,
"grade_id": "tensor-class",
"locked": false,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"#| export\n",
"class Tensor:\n",
" \"\"\"\n",
" TinyTorch Tensor: N-dimensional array with ML operations.\n",
" \n",
" The fundamental data structure for all TinyTorch operations.\n",
" Wraps NumPy arrays with ML-specific functionality.\n",
" \"\"\"\n",
" \n",
" def __init__(self, data: Union[int, float, List, np.ndarray], dtype: Optional[str] = None):\n",
" \"\"\"\n",
" Create a new tensor from data.\n",
" \n",
" Args:\n",
" data: Input data (scalar, list, or numpy array)\n",
" dtype: Data type ('float32', 'int32', etc.). Defaults to auto-detect.\n",
" \n",
" TODO: Implement tensor creation with proper type handling.\n",
" \n",
" STEP-BY-STEP:\n",
" 1. Check if data is a scalar (int/float) - convert to numpy array\n",
" 2. Check if data is a list - convert to numpy array \n",
" 3. Check if data is already a numpy array - use as-is\n",
" 4. Apply dtype conversion if specified\n",
" 5. Store the result in self._data\n",
" \n",
" EXAMPLE:\n",
" Tensor(5) → stores np.array(5)\n",
" Tensor([1, 2, 3]) → stores np.array([1, 2, 3])\n",
" Tensor(np.array([1, 2, 3])) → stores the array directly\n",
" \n",
" HINTS:\n",
" - Use isinstance() to check data types\n",
" - Use np.array() for conversion\n",
" - Handle dtype parameter for type conversion\n",
" - Store the array in self._data\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" # Convert input to numpy array\n",
" if isinstance(data, (int, float, np.number)):\n",
" # Handle Python and NumPy scalars\n",
" if dtype is None:\n",
" # Auto-detect type: int for integers, float32 for floats\n",
" if isinstance(data, int) or (isinstance(data, np.number) and np.issubdtype(type(data), np.integer)):\n",
" dtype = 'int32'\n",
" else:\n",
" dtype = 'float32'\n",
" self._data = np.array(data, dtype=dtype)\n",
" elif isinstance(data, list):\n",
" # Let NumPy auto-detect type, then convert if needed\n",
" temp_array = np.array(data)\n",
" if dtype is None:\n",
" # Use NumPy's auto-detected type, but prefer float32 for floats\n",
" if temp_array.dtype == np.float64:\n",
" dtype = 'float32'\n",
" else:\n",
" dtype = str(temp_array.dtype)\n",
" self._data = np.array(data, dtype=dtype)\n",
" elif isinstance(data, np.ndarray):\n",
" # Already a numpy array\n",
" if dtype is None:\n",
" # Keep existing dtype, but prefer float32 for float64\n",
" if data.dtype == np.float64:\n",
" dtype = 'float32'\n",
" else:\n",
" dtype = str(data.dtype)\n",
" self._data = data.astype(dtype) if dtype != data.dtype else data.copy()\n",
" else:\n",
" # Try to convert unknown types\n",
" self._data = np.array(data, dtype=dtype)\n",
" ### END SOLUTION\n",
"\n",
" @property\n",
" def data(self) -> np.ndarray:\n",
" \"\"\"\n",
" Access underlying numpy array.\n",
" \n",
" TODO: Return the stored numpy array.\n",
" \n",
" HINT: Return self._data (the array you stored in __init__)\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" return self._data\n",
" ### END SOLUTION\n",
" \n",
" @property\n",
" def shape(self) -> Tuple[int, ...]:\n",
" \"\"\"\n",
" Get tensor shape.\n",
" \n",
" TODO: Return the shape of the stored numpy array.\n",
" \n",
" HINT: Use .shape attribute of the numpy array\n",
" EXAMPLE: Tensor([1, 2, 3]).shape should return (3,)\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" return self._data.shape\n",
" ### END SOLUTION\n",
" \n",
" @property\n",
" def size(self) -> int:\n",
" \"\"\"\n",
" Get total number of elements.\n",
" \n",
" TODO: Return the total number of elements in the tensor.\n",
" \n",
" HINT: Use .size attribute of the numpy array\n",
" EXAMPLE: Tensor([1, 2, 3]).size should return 3\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" return self._data.size\n",
" ### END SOLUTION\n",
" \n",
" @property\n",
" def dtype(self) -> np.dtype:\n",
" \"\"\"\n",
" Get data type as numpy dtype.\n",
" \n",
" TODO: Return the data type of the stored numpy array.\n",
" \n",
" HINT: Use .dtype attribute of the numpy array\n",
" EXAMPLE: Tensor([1, 2, 3]).dtype should return dtype('int32')\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" return self._data.dtype\n",
" ### END SOLUTION\n",
" \n",
" def __repr__(self) -> str:\n",
" \"\"\"\n",
" String representation.\n",
" \n",
" TODO: Create a clear string representation of the tensor.\n",
" \n",
" APPROACH:\n",
" 1. Convert the numpy array to a list for readable output\n",
" 2. Include the shape and dtype information\n",
" 3. Format: \"Tensor([data], shape=shape, dtype=dtype)\"\n",
" \n",
" EXAMPLE:\n",
" Tensor([1, 2, 3]) → \"Tensor([1, 2, 3], shape=(3,), dtype=int32)\"\n",
" \n",
" HINTS:\n",
" - Use .tolist() to convert numpy array to list\n",
" - Include shape and dtype information\n",
" - Keep format consistent and readable\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" return f\"Tensor({self._data.tolist()}, shape={self.shape}, dtype={self.dtype})\"\n",
" ### END SOLUTION\n",
"\n",
" def add(self, other: 'Tensor') -> 'Tensor':\n",
" \"\"\"\n",
" Add two tensors element-wise.\n",
" \n",
" TODO: Implement tensor addition.\n",
" \n",
" APPROACH:\n",
" 1. Add the numpy arrays using +\n",
" 2. Return a new Tensor with the result\n",
" 3. Handle broadcasting automatically\n",
" \n",
" EXAMPLE:\n",
" Tensor([1, 2]) + Tensor([3, 4]) → Tensor([4, 6])\n",
" \n",
" HINTS:\n",
" - Use self._data + other._data\n",
" - Return Tensor(result)\n",
" - NumPy handles broadcasting automatically\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" result = self._data + other._data\n",
" return Tensor(result)\n",
" ### END SOLUTION\n",
"\n",
" def multiply(self, other: 'Tensor') -> 'Tensor':\n",
" \"\"\"\n",
" Multiply two tensors element-wise.\n",
" \n",
" TODO: Implement tensor multiplication.\n",
" \n",
" APPROACH:\n",
" 1. Multiply the numpy arrays using *\n",
" 2. Return a new Tensor with the result\n",
" 3. Handle broadcasting automatically\n",
" \n",
" EXAMPLE:\n",
" Tensor([1, 2]) * Tensor([3, 4]) → Tensor([3, 8])\n",
" \n",
" HINTS:\n",
" - Use self._data * other._data\n",
" - Return Tensor(result)\n",
" - This is element-wise, not matrix multiplication\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" result = self._data * other._data\n",
" return Tensor(result)\n",
" ### END SOLUTION\n",
"\n",
" def __add__(self, other: Union['Tensor', int, float]) -> 'Tensor':\n",
" \"\"\"\n",
" Addition operator: tensor + other\n",
" \n",
" TODO: Implement + operator for tensors.\n",
" \n",
" APPROACH:\n",
" 1. If other is a Tensor, use tensor addition\n",
" 2. If other is a scalar, convert to Tensor first\n",
" 3. Return the result\n",
" \n",
" EXAMPLE:\n",
" Tensor([1, 2]) + Tensor([3, 4]) → Tensor([4, 6])\n",
" Tensor([1, 2]) + 5 → Tensor([6, 7])\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" if isinstance(other, Tensor):\n",
" return self.add(other)\n",
" else:\n",
" return self.add(Tensor(other))\n",
" ### END SOLUTION\n",
"\n",
" def __mul__(self, other: Union['Tensor', int, float]) -> 'Tensor':\n",
" \"\"\"\n",
" Multiplication operator: tensor * other\n",
" \n",
" TODO: Implement * operator for tensors.\n",
" \n",
" APPROACH:\n",
" 1. If other is a Tensor, use tensor multiplication\n",
" 2. If other is a scalar, convert to Tensor first\n",
" 3. Return the result\n",
" \n",
" EXAMPLE:\n",
" Tensor([1, 2]) * Tensor([3, 4]) → Tensor([3, 8])\n",
" Tensor([1, 2]) * 3 → Tensor([3, 6])\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" if isinstance(other, Tensor):\n",
" return self.multiply(other)\n",
" else:\n",
" return self.multiply(Tensor(other))\n",
" ### END SOLUTION\n",
"\n",
" def __sub__(self, other: Union['Tensor', int, float]) -> 'Tensor':\n",
" \"\"\"\n",
" Subtraction operator: tensor - other\n",
" \n",
" TODO: Implement - operator for tensors.\n",
" \n",
" APPROACH:\n",
" 1. Convert other to Tensor if needed\n",
" 2. Subtract using numpy arrays\n",
" 3. Return new Tensor with result\n",
" \n",
" EXAMPLE:\n",
" Tensor([5, 6]) - Tensor([1, 2]) → Tensor([4, 4])\n",
" Tensor([5, 6]) - 1 → Tensor([4, 5])\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" if isinstance(other, Tensor):\n",
" result = self._data - other._data\n",
" else:\n",
" result = self._data - other\n",
" return Tensor(result)\n",
" ### END SOLUTION\n",
"\n",
" def __truediv__(self, other: Union['Tensor', int, float]) -> 'Tensor':\n",
" \"\"\"\n",
" Division operator: tensor / other\n",
" \n",
" TODO: Implement / operator for tensors.\n",
" \n",
" APPROACH:\n",
" 1. Convert other to Tensor if needed\n",
" 2. Divide using numpy arrays\n",
" 3. Return new Tensor with result\n",
" \n",
" EXAMPLE:\n",
" Tensor([6, 8]) / Tensor([2, 4]) → Tensor([3, 2])\n",
" Tensor([6, 8]) / 2 → Tensor([3, 4])\n",
" \"\"\"\n",
" ### BEGIN SOLUTION\n",
" if isinstance(other, Tensor):\n",
" result = self._data / other._data\n",
" else:\n",
" result = self._data / other\n",
" return Tensor(result)\n",
" ### END SOLUTION"
]
},
{
"cell_type": "markdown",
"id": "087dce88",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"### 🧪 Unit Test: Tensor Creation\n",
"\n",
"Let's test your tensor creation implementation right away! This gives you immediate feedback on whether your `__init__` method works correctly.\n",
"\n",
"**This is a unit test** - it tests one specific function (tensor creation) in isolation."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6530d563",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-creation-immediate",
"locked": true,
"points": 5,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"# Test tensor creation immediately after implementation\n",
"print(\"🔬 Unit Test: Tensor Creation...\")\n",
"\n",
"# Test basic tensor creation\n",
"try:\n",
" # Test scalar\n",
" scalar = Tensor(5.0)\n",
" assert hasattr(scalar, '_data'), \"Tensor should have _data attribute\"\n",
" assert scalar._data.shape == (), f\"Scalar should have shape (), got {scalar._data.shape}\"\n",
" print(\"✅ Scalar creation works\")\n",
" \n",
" # Test vector\n",
" vector = Tensor([1, 2, 3])\n",
" assert vector._data.shape == (3,), f\"Vector should have shape (3,), got {vector._data.shape}\"\n",
" print(\"✅ Vector creation works\")\n",
" \n",
" # Test matrix\n",
" matrix = Tensor([[1, 2], [3, 4]])\n",
" assert matrix._data.shape == (2, 2), f\"Matrix should have shape (2, 2), got {matrix._data.shape}\"\n",
" print(\"✅ Matrix creation works\")\n",
" \n",
" print(\"📈 Progress: Tensor Creation ✓\")\n",
" \n",
"except Exception as e:\n",
" print(f\"❌ Tensor creation test failed: {e}\")\n",
" raise\n",
"\n",
"print(\"🎯 Tensor creation behavior:\")\n",
"print(\" Converts data to NumPy arrays\")\n",
"print(\" Preserves shape and data type\")\n",
"print(\" Stores in _data attribute\")"
]
},
{
"cell_type": "markdown",
"id": "9f5392ac",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"### 🧪 Unit Test: Tensor Properties\n",
"\n",
"Now let's test that your tensor properties work correctly. This tests the @property methods you implemented.\n",
"\n",
"**This is a unit test** - it tests specific properties (shape, size, dtype, data) in isolation."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7a21015c",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-properties-immediate",
"locked": true,
"points": 5,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"# Test tensor properties immediately after implementation\n",
"print(\"🔬 Unit Test: Tensor Properties...\")\n",
"\n",
"# Test properties with simple examples\n",
"try:\n",
" # Test with a simple matrix\n",
" tensor = Tensor([[1, 2, 3], [4, 5, 6]])\n",
" \n",
" # Test shape property\n",
" assert tensor.shape == (2, 3), f\"Shape should be (2, 3), got {tensor.shape}\"\n",
" print(\"✅ Shape property works\")\n",
" \n",
" # Test size property\n",
" assert tensor.size == 6, f\"Size should be 6, got {tensor.size}\"\n",
" print(\"✅ Size property works\")\n",
" \n",
" # Test data property\n",
" assert np.array_equal(tensor.data, np.array([[1, 2, 3], [4, 5, 6]])), \"Data property should return numpy array\"\n",
" print(\"✅ Data property works\")\n",
" \n",
" # Test dtype property\n",
" assert tensor.dtype in [np.int32, np.int64], f\"Dtype should be int32 or int64, got {tensor.dtype}\"\n",
" print(\"✅ Dtype property works\")\n",
" \n",
" print(\"📈 Progress: Tensor Properties ✓\")\n",
" \n",
"except Exception as e:\n",
" print(f\"❌ Tensor properties test failed: {e}\")\n",
" raise\n",
"\n",
"print(\"🎯 Tensor properties behavior:\")\n",
"print(\" shape: Returns tuple of dimensions\")\n",
"print(\" size: Returns total number of elements\")\n",
"print(\" data: Returns underlying NumPy array\")\n",
"print(\" dtype: Returns NumPy data type\")"
]
},
{
"cell_type": "markdown",
"id": "38be4d01",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"### 🧪 Unit Test: Tensor Arithmetic\n",
"\n",
"Let's test your tensor arithmetic operations. This tests the __add__, __mul__, __sub__, __truediv__ methods.\n",
"\n",
"**This is a unit test** - it tests specific arithmetic operations in isolation."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6049f928",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-arithmetic-immediate",
"locked": true,
"points": 5,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"# Test tensor arithmetic immediately after implementation\n",
"print(\"🔬 Unit Test: Tensor Arithmetic...\")\n",
"\n",
"# Test basic arithmetic with simple examples\n",
"try:\n",
" # Test addition\n",
" a = Tensor([1, 2, 3])\n",
" b = Tensor([4, 5, 6])\n",
" result = a + b\n",
" expected = np.array([5, 7, 9])\n",
" assert np.array_equal(result.data, expected), f\"Addition failed: expected {expected}, got {result.data}\"\n",
" print(\"✅ Addition works\")\n",
" \n",
" # Test scalar addition\n",
" result_scalar = a + 10\n",
" expected_scalar = np.array([11, 12, 13])\n",
" assert np.array_equal(result_scalar.data, expected_scalar), f\"Scalar addition failed: expected {expected_scalar}, got {result_scalar.data}\"\n",
" print(\"✅ Scalar addition works\")\n",
" \n",
" # Test multiplication\n",
" result_mul = a * b\n",
" expected_mul = np.array([4, 10, 18])\n",
" assert np.array_equal(result_mul.data, expected_mul), f\"Multiplication failed: expected {expected_mul}, got {result_mul.data}\"\n",
" print(\"✅ Multiplication works\")\n",
" \n",
" # Test scalar multiplication\n",
" result_scalar_mul = a * 2\n",
" expected_scalar_mul = np.array([2, 4, 6])\n",
" assert np.array_equal(result_scalar_mul.data, expected_scalar_mul), f\"Scalar multiplication failed: expected {expected_scalar_mul}, got {result_scalar_mul.data}\"\n",
" print(\"✅ Scalar multiplication works\")\n",
" \n",
" print(\"📈 Progress: Tensor Arithmetic ✓\")\n",
" \n",
"except Exception as e:\n",
" print(f\"❌ Tensor arithmetic test failed: {e}\")\n",
" raise\n",
"\n",
"print(\"🎯 Tensor arithmetic behavior:\")\n",
"print(\" Element-wise operations on tensors\")\n",
"print(\" Broadcasting with scalars\")\n",
"print(\" Returns new Tensor objects\")"
]
},
{
"cell_type": "markdown",
"id": "1c166248",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
},
"source": [
"### 🧪 Comprehensive Test: Tensor Creation\n",
"\n",
"Let's thoroughly test your tensor creation to make sure it handles all the cases you'll encounter in ML.\n",
"This tests the foundation of everything else we'll build."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "71cac50f",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-creation-comprehensive",
"locked": true,
"points": 15,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"def test_tensor_creation_comprehensive():\n",
" \"\"\"Comprehensive test of tensor creation with all data types and shapes.\"\"\"\n",
" print(\"🔬 Testing comprehensive tensor creation...\")\n",
" \n",
" tests_passed = 0\n",
" total_tests = 8\n",
" \n",
" # Test 1: Scalar creation (0D tensor)\n",
" try:\n",
" scalar_int = Tensor(42)\n",
" scalar_float = Tensor(3.14)\n",
" scalar_zero = Tensor(0)\n",
" \n",
" assert hasattr(scalar_int, '_data'), \"Tensor should have _data attribute\"\n",
" assert scalar_int._data.shape == (), f\"Scalar should have shape (), got {scalar_int._data.shape}\"\n",
" assert scalar_float._data.shape == (), f\"Float scalar should have shape (), got {scalar_float._data.shape}\"\n",
" assert scalar_zero._data.shape == (), f\"Zero scalar should have shape (), got {scalar_zero._data.shape}\"\n",
" \n",
" print(\"✅ Scalar creation: integers, floats, and zero\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Scalar creation failed: {e}\")\n",
" \n",
" # Test 2: Vector creation (1D tensor)\n",
" try:\n",
" vector_int = Tensor([1, 2, 3, 4, 5])\n",
" vector_float = Tensor([1.0, 2.5, 3.7])\n",
" vector_single = Tensor([42])\n",
" vector_empty = Tensor([])\n",
" \n",
" assert vector_int._data.shape == (5,), f\"Int vector should have shape (5,), got {vector_int._data.shape}\"\n",
" assert vector_float._data.shape == (3,), f\"Float vector should have shape (3,), got {vector_float._data.shape}\"\n",
" assert vector_single._data.shape == (1,), f\"Single element vector should have shape (1,), got {vector_single._data.shape}\"\n",
" assert vector_empty._data.shape == (0,), f\"Empty vector should have shape (0,), got {vector_empty._data.shape}\"\n",
" \n",
" print(\"✅ Vector creation: integers, floats, single element, and empty\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Vector creation failed: {e}\")\n",
" \n",
" # Test 3: Matrix creation (2D tensor)\n",
" try:\n",
" matrix_2x2 = Tensor([[1, 2], [3, 4]])\n",
" matrix_3x2 = Tensor([[1, 2], [3, 4], [5, 6]])\n",
" matrix_1x3 = Tensor([[1, 2, 3]])\n",
" \n",
" assert matrix_2x2._data.shape == (2, 2), f\"2x2 matrix should have shape (2, 2), got {matrix_2x2._data.shape}\"\n",
" assert matrix_3x2._data.shape == (3, 2), f\"3x2 matrix should have shape (3, 2), got {matrix_3x2._data.shape}\"\n",
" assert matrix_1x3._data.shape == (1, 3), f\"1x3 matrix should have shape (1, 3), got {matrix_1x3._data.shape}\"\n",
" \n",
" print(\"✅ Matrix creation: 2x2, 3x2, and 1x3 matrices\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Matrix creation failed: {e}\")\n",
" \n",
" # Test 4: Data type handling\n",
" try:\n",
" int_tensor = Tensor([1, 2, 3])\n",
" float_tensor = Tensor([1.0, 2.0, 3.0])\n",
" mixed_tensor = Tensor([1, 2.5, 3]) # Should convert to float\n",
" \n",
" # Check that data types are reasonable\n",
" assert int_tensor._data.dtype in [np.int32, np.int64], f\"Int tensor has unexpected dtype: {int_tensor._data.dtype}\"\n",
" assert float_tensor._data.dtype in [np.float32, np.float64], f\"Float tensor has unexpected dtype: {float_tensor._data.dtype}\"\n",
" assert mixed_tensor._data.dtype in [np.float32, np.float64], f\"Mixed tensor should be float, got: {mixed_tensor._data.dtype}\"\n",
" \n",
" print(\"✅ Data type handling: integers, floats, and mixed types\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Data type handling failed: {e}\")\n",
" \n",
" # Test 5: NumPy array input\n",
" try:\n",
" np_array = np.array([1, 2, 3, 4])\n",
" tensor_from_np = Tensor(np_array)\n",
" \n",
" assert tensor_from_np._data.shape == (4,), f\"Tensor from NumPy should have shape (4,), got {tensor_from_np._data.shape}\"\n",
" assert np.array_equal(tensor_from_np._data, np_array), \"Tensor from NumPy should preserve data\"\n",
" \n",
" print(\"✅ NumPy array input: conversion works correctly\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ NumPy array input failed: {e}\")\n",
" \n",
" # Test 6: Large tensor creation\n",
" try:\n",
" large_tensor = Tensor(list(range(1000)))\n",
" assert large_tensor._data.shape == (1000,), f\"Large tensor should have shape (1000,), got {large_tensor._data.shape}\"\n",
" assert large_tensor._data[0] == 0, \"Large tensor should start with 0\"\n",
" assert large_tensor._data[-1] == 999, \"Large tensor should end with 999\"\n",
" \n",
" print(\"✅ Large tensor creation: 1000 elements\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Large tensor creation failed: {e}\")\n",
" \n",
" # Test 7: Negative numbers\n",
" try:\n",
" negative_tensor = Tensor([-1, -2, -3])\n",
" mixed_signs = Tensor([-1, 0, 1])\n",
" \n",
" assert negative_tensor._data.shape == (3,), f\"Negative tensor should have shape (3,), got {negative_tensor._data.shape}\"\n",
" assert np.array_equal(negative_tensor._data, np.array([-1, -2, -3])), \"Negative numbers should be preserved\"\n",
" assert np.array_equal(mixed_signs._data, np.array([-1, 0, 1])), \"Mixed signs should be preserved\"\n",
" \n",
" print(\"✅ Negative numbers: handled correctly\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Negative numbers failed: {e}\")\n",
" \n",
" # Test 8: Edge cases\n",
" try:\n",
" # Very large numbers\n",
" big_tensor = Tensor([1e6, 1e-6])\n",
" assert big_tensor._data.shape == (2,), \"Big numbers tensor should have correct shape\"\n",
" \n",
" # Zero tensor\n",
" zero_tensor = Tensor([0, 0, 0])\n",
" assert np.all(zero_tensor._data == 0), \"Zero tensor should contain all zeros\"\n",
" \n",
" print(\"✅ Edge cases: large numbers and zeros\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Edge cases failed: {e}\")\n",
" \n",
" # Results summary\n",
" print(f\"\\n📊 Tensor Creation Results: {tests_passed}/{total_tests} tests passed\")\n",
" \n",
" if tests_passed == total_tests:\n",
" print(\"🎉 All tensor creation tests passed! Your Tensor class can handle:\")\n",
" print(\" • Scalars, vectors, and matrices\")\n",
" print(\" • Different data types (int, float)\")\n",
" print(\" • NumPy arrays\")\n",
" print(\" • Large tensors and edge cases\")\n",
" print(\"📈 Progress: Tensor Creation ✓\")\n",
" return True\n",
" else:\n",
" print(\"⚠️ Some tensor creation tests failed. Common issues:\")\n",
" print(\" • Check your __init__ method implementation\")\n",
" print(\" • Make sure you're storing data in self._data\")\n",
" print(\" • Verify NumPy array conversion works correctly\")\n",
" print(\" • Test with different input types (int, float, list, np.array)\")\n",
" return False\n",
"\n",
"# Run the comprehensive test\n",
"success = test_tensor_creation_comprehensive()"
]
},
{
"cell_type": "markdown",
"id": "e9fef08c",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
},
"source": [
"### 🧪 Comprehensive Test: Tensor Properties\n",
"\n",
"Now let's test all the properties your tensor should have. These properties are essential for ML operations."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "61017a82",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-properties-comprehensive",
"locked": true,
"points": 15,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"def test_tensor_properties_comprehensive():\n",
" \"\"\"Comprehensive test of tensor properties (shape, size, dtype, data access).\"\"\"\n",
" print(\"🔬 Testing comprehensive tensor properties...\")\n",
" \n",
" tests_passed = 0\n",
" total_tests = 6\n",
" \n",
" # Test 1: Shape property\n",
" try:\n",
" scalar = Tensor(5.0)\n",
" vector = Tensor([1, 2, 3])\n",
" matrix = Tensor([[1, 2], [3, 4]])\n",
" tensor_3d = Tensor([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])\n",
" \n",
" assert scalar.shape == (), f\"Scalar shape should be (), got {scalar.shape}\"\n",
" assert vector.shape == (3,), f\"Vector shape should be (3,), got {vector.shape}\"\n",
" assert matrix.shape == (2, 2), f\"Matrix shape should be (2, 2), got {matrix.shape}\"\n",
" assert tensor_3d.shape == (2, 2, 2), f\"3D tensor shape should be (2, 2, 2), got {tensor_3d.shape}\"\n",
" \n",
" print(\"✅ Shape property: scalar, vector, matrix, and 3D tensor\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Shape property failed: {e}\")\n",
" \n",
" # Test 2: Size property\n",
" try:\n",
" scalar = Tensor(5.0)\n",
" vector = Tensor([1, 2, 3])\n",
" matrix = Tensor([[1, 2], [3, 4]])\n",
" empty = Tensor([])\n",
" \n",
" assert scalar.size == 1, f\"Scalar size should be 1, got {scalar.size}\"\n",
" assert vector.size == 3, f\"Vector size should be 3, got {vector.size}\"\n",
" assert matrix.size == 4, f\"Matrix size should be 4, got {matrix.size}\"\n",
" assert empty.size == 0, f\"Empty tensor size should be 0, got {empty.size}\"\n",
" \n",
" print(\"✅ Size property: scalar, vector, matrix, and empty tensor\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Size property failed: {e}\")\n",
" \n",
" # Test 3: Data type property\n",
" try:\n",
" int_tensor = Tensor([1, 2, 3])\n",
" float_tensor = Tensor([1.0, 2.0, 3.0])\n",
" \n",
" # Check that dtype is accessible and reasonable\n",
" assert hasattr(int_tensor, 'dtype'), \"Tensor should have dtype property\"\n",
" assert hasattr(float_tensor, 'dtype'), \"Tensor should have dtype property\"\n",
" \n",
" # Data types should be NumPy dtypes\n",
" assert isinstance(int_tensor.dtype, np.dtype), f\"dtype should be np.dtype, got {type(int_tensor.dtype)}\"\n",
" assert isinstance(float_tensor.dtype, np.dtype), f\"dtype should be np.dtype, got {type(float_tensor.dtype)}\"\n",
" \n",
" print(f\"✅ Data type property: int tensor is {int_tensor.dtype}, float tensor is {float_tensor.dtype}\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Data type property failed: {e}\")\n",
" \n",
" # Test 4: Data access property\n",
" try:\n",
" scalar = Tensor(5.0)\n",
" vector = Tensor([1, 2, 3])\n",
" matrix = Tensor([[1, 2], [3, 4]])\n",
" \n",
" # Test data access\n",
" assert hasattr(scalar, 'data'), \"Tensor should have data property\"\n",
" assert hasattr(vector, 'data'), \"Tensor should have data property\"\n",
" assert hasattr(matrix, 'data'), \"Tensor should have data property\"\n",
" \n",
" # Test data content\n",
" assert scalar.data.item() == 5.0, f\"Scalar data should be 5.0, got {scalar.data.item()}\"\n",
" assert np.array_equal(vector.data, np.array([1, 2, 3])), \"Vector data mismatch\"\n",
" assert np.array_equal(matrix.data, np.array([[1, 2], [3, 4]])), \"Matrix data mismatch\"\n",
" \n",
" print(\"✅ Data access: scalar, vector, and matrix data retrieval\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Data access failed: {e}\")\n",
" \n",
" # Test 5: String representation\n",
" try:\n",
" scalar = Tensor(5.0)\n",
" vector = Tensor([1, 2, 3])\n",
" \n",
" # Test that __repr__ works\n",
" scalar_str = str(scalar)\n",
" vector_str = str(vector)\n",
" \n",
" assert isinstance(scalar_str, str), \"Tensor string representation should be a string\"\n",
" assert isinstance(vector_str, str), \"Tensor string representation should be a string\"\n",
" assert len(scalar_str) > 0, \"Tensor string representation should not be empty\"\n",
" assert len(vector_str) > 0, \"Tensor string representation should not be empty\"\n",
" \n",
" print(f\"✅ String representation: scalar={scalar_str[:50]}{'...' if len(scalar_str) > 50 else ''}\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ String representation failed: {e}\")\n",
" \n",
" # Test 6: Property consistency\n",
" try:\n",
" test_cases = [\n",
" Tensor(42),\n",
" Tensor([1, 2, 3, 4, 5]),\n",
" Tensor([[1, 2, 3], [4, 5, 6]]),\n",
" Tensor([])\n",
" ]\n",
" \n",
" for i, tensor in enumerate(test_cases):\n",
" # Size should equal product of shape\n",
" expected_size = np.prod(tensor.shape) if tensor.shape else 1\n",
" assert tensor.size == expected_size, f\"Test case {i}: size {tensor.size} doesn't match shape {tensor.shape}\"\n",
" \n",
" # Data shape should match tensor shape\n",
" assert tensor.data.shape == tensor.shape, f\"Test case {i}: data shape {tensor.data.shape} doesn't match tensor shape {tensor.shape}\"\n",
" \n",
" print(\"✅ Property consistency: size matches shape, data shape matches tensor shape\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Property consistency failed: {e}\")\n",
" \n",
" # Results summary\n",
" print(f\"\\n📊 Tensor Properties Results: {tests_passed}/{total_tests} tests passed\")\n",
" \n",
" if tests_passed == total_tests:\n",
" print(\"🎉 All tensor property tests passed! Your tensor has:\")\n",
" print(\" • Correct shape property for all dimensions\")\n",
" print(\" • Accurate size calculation\")\n",
" print(\" • Proper data type handling\")\n",
" print(\" • Working data access\")\n",
" print(\" • Good string representation\")\n",
" print(\"📈 Progress: Tensor Creation ✓, Properties ✓\")\n",
" return True\n",
" else:\n",
" print(\"⚠️ Some property tests failed. Common issues:\")\n",
" print(\" • Check your @property decorators\")\n",
" print(\" • Verify shape returns self._data.shape\")\n",
" print(\" • Make sure size returns self._data.size\")\n",
" print(\" • Ensure dtype returns self._data.dtype\")\n",
" print(\" • Test your __repr__ method\")\n",
" return False\n",
"\n",
"# Run the comprehensive test\n",
"success = test_tensor_properties_comprehensive() and success"
]
},
{
"cell_type": "markdown",
"id": "8467b780",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
},
"source": [
"### 🧪 Comprehensive Test: Tensor Arithmetic\n",
"\n",
"Let's test all arithmetic operations. These are the foundation of neural network computations!"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3883fcf9",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-arithmetic-comprehensive",
"locked": true,
"points": 20,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"def test_tensor_arithmetic_comprehensive():\n",
" \"\"\"Comprehensive test of tensor arithmetic operations.\"\"\"\n",
" print(\"🔬 Testing comprehensive tensor arithmetic...\")\n",
" \n",
" tests_passed = 0\n",
" total_tests = 8\n",
" \n",
" # Test 1: Basic addition method\n",
" try:\n",
" a = Tensor([1, 2, 3])\n",
" b = Tensor([4, 5, 6])\n",
" c = a.add(b)\n",
" \n",
" expected = np.array([5, 7, 9])\n",
" assert np.array_equal(c.data, expected), f\"Addition method failed: expected {expected}, got {c.data}\"\n",
" assert isinstance(c, Tensor), \"Addition should return a Tensor\"\n",
" \n",
" print(f\"✅ Addition method: {a.data} + {b.data} = {c.data}\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Addition method failed: {e}\")\n",
" \n",
" # Test 2: Basic multiplication method\n",
" try:\n",
" a = Tensor([1, 2, 3])\n",
" b = Tensor([4, 5, 6])\n",
" c = a.multiply(b)\n",
" \n",
" expected = np.array([4, 10, 18])\n",
" assert np.array_equal(c.data, expected), f\"Multiplication method failed: expected {expected}, got {c.data}\"\n",
" assert isinstance(c, Tensor), \"Multiplication should return a Tensor\"\n",
" \n",
" print(f\"✅ Multiplication method: {a.data} * {b.data} = {c.data}\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Multiplication method failed: {e}\")\n",
" \n",
" # Test 3: Addition operator (+)\n",
" try:\n",
" a = Tensor([1, 2, 3])\n",
" b = Tensor([4, 5, 6])\n",
" c = a + b\n",
" \n",
" expected = np.array([5, 7, 9])\n",
" assert np.array_equal(c.data, expected), f\"+ operator failed: expected {expected}, got {c.data}\"\n",
" assert isinstance(c, Tensor), \"+ operator should return a Tensor\"\n",
" \n",
" print(f\"✅ + operator: {a.data} + {b.data} = {c.data}\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ + operator failed: {e}\")\n",
" \n",
" # Test 4: Multiplication operator (*)\n",
" try:\n",
" a = Tensor([1, 2, 3])\n",
" b = Tensor([4, 5, 6])\n",
" c = a * b\n",
" \n",
" expected = np.array([4, 10, 18])\n",
" assert np.array_equal(c.data, expected), f\"* operator failed: expected {expected}, got {c.data}\"\n",
" assert isinstance(c, Tensor), \"* operator should return a Tensor\"\n",
" \n",
" print(f\"✅ * operator: {a.data} * {b.data} = {c.data}\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ * operator failed: {e}\")\n",
" \n",
" # Test 5: Subtraction operator (-)\n",
" try:\n",
" a = Tensor([1, 2, 3])\n",
" b = Tensor([4, 5, 6])\n",
" c = b - a\n",
" \n",
" expected = np.array([3, 3, 3])\n",
" assert np.array_equal(c.data, expected), f\"- operator failed: expected {expected}, got {c.data}\"\n",
" assert isinstance(c, Tensor), \"- operator should return a Tensor\"\n",
" \n",
" print(f\"✅ - operator: {b.data} - {a.data} = {c.data}\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ - operator failed: {e}\")\n",
" \n",
" # Test 6: Division operator (/)\n",
" try:\n",
" a = Tensor([1, 2, 4])\n",
" b = Tensor([2, 4, 8])\n",
" c = b / a\n",
" \n",
" expected = np.array([2.0, 2.0, 2.0])\n",
" assert np.allclose(c.data, expected), f\"/ operator failed: expected {expected}, got {c.data}\"\n",
" assert isinstance(c, Tensor), \"/ operator should return a Tensor\"\n",
" \n",
" print(f\"✅ / operator: {b.data} / {a.data} = {c.data}\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ / operator failed: {e}\")\n",
" \n",
" # Test 7: Scalar operations\n",
" try:\n",
" a = Tensor([1, 2, 3])\n",
" \n",
" # Addition with scalar\n",
" b = a + 10\n",
" expected_add = np.array([11, 12, 13])\n",
" assert np.array_equal(b.data, expected_add), f\"Scalar addition failed: expected {expected_add}, got {b.data}\"\n",
" \n",
" # Multiplication with scalar\n",
" c = a * 2\n",
" expected_mul = np.array([2, 4, 6])\n",
" assert np.array_equal(c.data, expected_mul), f\"Scalar multiplication failed: expected {expected_mul}, got {c.data}\"\n",
" \n",
" # Subtraction with scalar\n",
" d = a - 1\n",
" expected_sub = np.array([0, 1, 2])\n",
" assert np.array_equal(d.data, expected_sub), f\"Scalar subtraction failed: expected {expected_sub}, got {d.data}\"\n",
" \n",
" # Division with scalar\n",
" e = a / 2\n",
" expected_div = np.array([0.5, 1.0, 1.5])\n",
" assert np.allclose(e.data, expected_div), f\"Scalar division failed: expected {expected_div}, got {e.data}\"\n",
" \n",
" print(f\"✅ Scalar operations: +10, *2, -1, /2 all work correctly\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Scalar operations failed: {e}\")\n",
" \n",
" # Test 8: Matrix operations\n",
" try:\n",
" matrix_a = Tensor([[1, 2], [3, 4]])\n",
" matrix_b = Tensor([[5, 6], [7, 8]])\n",
" \n",
" # Matrix addition\n",
" c = matrix_a + matrix_b\n",
" expected = np.array([[6, 8], [10, 12]])\n",
" assert np.array_equal(c.data, expected), f\"Matrix addition failed: expected {expected}, got {c.data}\"\n",
" assert c.shape == (2, 2), f\"Matrix addition should preserve shape, got {c.shape}\"\n",
" \n",
" # Matrix multiplication (element-wise)\n",
" d = matrix_a * matrix_b\n",
" expected_mul = np.array([[5, 12], [21, 32]])\n",
" assert np.array_equal(d.data, expected_mul), f\"Matrix multiplication failed: expected {expected_mul}, got {d.data}\"\n",
" \n",
" print(f\"✅ Matrix operations: 2x2 matrix addition and multiplication\")\n",
" tests_passed += 1\n",
" except Exception as e:\n",
" print(f\"❌ Matrix operations failed: {e}\")\n",
" \n",
" # Results summary\n",
" print(f\"\\n📊 Tensor Arithmetic Results: {tests_passed}/{total_tests} tests passed\")\n",
" \n",
" if tests_passed == total_tests:\n",
" print(\"🎉 All tensor arithmetic tests passed! Your tensor supports:\")\n",
" print(\" • Basic methods: add(), multiply()\")\n",
" print(\" • Python operators: +, -, *, /\")\n",
" print(\" • Scalar operations: tensor + number\")\n",
" print(\" • Matrix operations: element-wise operations\")\n",
" print(\"📈 Progress: Tensor Creation ✓, Properties ✓, Arithmetic ✓\")\n",
" return True\n",
" else:\n",
" print(\"⚠️ Some arithmetic tests failed. Common issues:\")\n",
" print(\" • Check your add() and multiply() methods\")\n",
" print(\" • Verify operator overloading (__add__, __mul__, __sub__, __truediv__)\")\n",
" print(\" • Make sure scalar operations work (convert scalar to Tensor)\")\n",
" print(\" • Test with different tensor shapes\")\n",
" return False\n",
"\n",
"# Run the comprehensive test\n",
"success = test_tensor_arithmetic_comprehensive() and success"
]
},
{
"cell_type": "markdown",
"id": "fe61e372",
"metadata": {
"cell_marker": "\"\"\"",
"lines_to_next_cell": 1
},
"source": [
"### 🧪 Final Integration Test: Real ML Scenario\n",
"\n",
"Let's test your tensor with a realistic machine learning scenario to make sure everything works together."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b5650653",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-integration",
"locked": true,
"points": 10,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"def test_tensor_integration():\n",
" \"\"\"Integration test with realistic ML scenario.\"\"\"\n",
" print(\"🔬 Testing tensor integration with ML scenario...\")\n",
" \n",
" try:\n",
" print(\"🧠 Simulating a simple neural network forward pass...\")\n",
" \n",
" # Simulate input data (batch of 2 samples, 3 features each)\n",
" X = Tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])\n",
" print(f\"📊 Input data shape: {X.shape}\")\n",
" \n",
" # Simulate weights (3 input features, 2 output neurons)\n",
" W = Tensor([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]])\n",
" print(f\"🎯 Weights shape: {W.shape}\")\n",
" \n",
" # Simulate bias (2 output neurons)\n",
" b = Tensor([0.1, 0.2])\n",
" print(f\"⚖️ Bias shape: {b.shape}\")\n",
" \n",
" # Simple linear transformation: y = X * W + b\n",
" # Note: This is a simplified version - real matrix multiplication would be different\n",
" # But we can test element-wise operations\n",
" \n",
" # Test that we can do basic operations needed for ML\n",
" sample = Tensor([1.0, 2.0, 3.0]) # Single sample\n",
" weight_col = Tensor([0.1, 0.3, 0.5]) # First column of weights\n",
" \n",
" # Compute dot product manually using element-wise operations\n",
" products = sample * weight_col # Element-wise multiplication\n",
" print(f\"✅ Element-wise multiplication works: {products.data}\")\n",
" \n",
" # Test addition for bias\n",
" result = products + Tensor([0.1, 0.1, 0.1])\n",
" print(f\"✅ Bias addition works: {result.data}\")\n",
" \n",
" # Test with different shapes\n",
" matrix_a = Tensor([[1, 2], [3, 4]])\n",
" matrix_b = Tensor([[0.1, 0.2], [0.3, 0.4]])\n",
" matrix_result = matrix_a * matrix_b\n",
" print(f\"✅ Matrix operations work: {matrix_result.data}\")\n",
" \n",
" # Test scalar operations (common in ML)\n",
" scaled = sample * 0.5 # Learning rate scaling\n",
" print(f\"✅ Scalar scaling works: {scaled.data}\")\n",
" \n",
" # Test normalization-like operations\n",
" mean_val = Tensor([2.0, 2.0, 2.0]) # Simulate mean\n",
" normalized = sample - mean_val\n",
" print(f\"✅ Mean subtraction works: {normalized.data}\")\n",
" \n",
" print(\"\\n🎉 Integration test passed! Your tensor class can handle:\")\n",
" print(\" • Multi-dimensional data (batches, features)\")\n",
" print(\" • Element-wise operations needed for ML\")\n",
" print(\" • Scalar operations (learning rates, normalization)\")\n",
" print(\" • Matrix operations (weights, transformations)\")\n",
" print(\"📈 Progress: All tensor functionality ✓\")\n",
" print(\"🚀 Ready for neural network layers!\")\n",
" \n",
" return True\n",
" \n",
" except Exception as e:\n",
" print(f\"❌ Integration test failed: {e}\")\n",
" print(\"\\n💡 This suggests an issue with:\")\n",
" print(\" • Basic tensor operations not working together\")\n",
" print(\" • Shape handling problems\")\n",
" print(\" • Arithmetic operation implementation\")\n",
" print(\" • Check your tensor creation and arithmetic methods\")\n",
" return False\n",
"\n",
"# Run the integration test\n",
"success = test_tensor_integration() and success\n",
"\n",
"# Print final summary\n",
"print(f\"\\n{'='*60}\")\n",
"print(\"🎯 TENSOR MODULE TESTING COMPLETE\")\n",
"print(f\"{'='*60}\")\n",
"\n",
"if success:\n",
" print(\"🎉 CONGRATULATIONS! All tensor tests passed!\")\n",
" print(\"\\n✅ Your Tensor class successfully implements:\")\n",
" print(\" • Comprehensive tensor creation (scalars, vectors, matrices)\")\n",
" print(\" • All essential properties (shape, size, dtype, data access)\")\n",
" print(\" • Complete arithmetic operations (methods and operators)\")\n",
" print(\" • Scalar and matrix operations\")\n",
" print(\" • Real ML scenario compatibility\")\n",
" print(\"\\n🚀 You're ready to move to the next module!\")\n",
" print(\"📈 Final Progress: Tensor Module ✓ COMPLETE\")\n",
"else:\n",
" print(\"⚠️ Some tests failed. Please review the error messages above.\")\n",
" print(\"\\n🔧 To fix issues:\")\n",
" print(\" 1. Check the specific test that failed\")\n",
" print(\" 2. Review the error message and hints\")\n",
" print(\" 3. Fix your implementation\")\n",
" print(\" 4. Re-run the notebook cells\")\n",
" print(\"\\n💪 Don't give up! Debugging is part of learning.\")"
]
},
{
"cell_type": "markdown",
"id": "9287bb44",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## Step 3: Tensor Arithmetic Operations\n",
"\n",
"### Why Arithmetic Matters\n",
"Tensor arithmetic is the foundation of all neural network operations:\n",
"- **Forward pass**: Matrix multiplications and additions\n",
"- **Activation functions**: Element-wise operations\n",
"- **Loss computation**: Differences and squares\n",
"- **Gradient computation**: Chain rule applications\n",
"\n",
"### Operations We'll Implement\n",
"- **Addition**: Element-wise addition of tensors\n",
"- **Multiplication**: Element-wise multiplication\n",
"- **Python operators**: `+`, `-`, `*`, `/` for natural syntax\n",
"- **Broadcasting**: Handle different shapes automatically"
]
},
{
"cell_type": "markdown",
"id": "a5c68c19",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## Step 3: Tensor Arithmetic Methods\n",
"\n",
"The arithmetic methods are now part of the Tensor class above. Let's test them!"
]
},
{
"cell_type": "markdown",
"id": "b8d0e58f",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## Step 4: Python Operator Overloading\n",
"\n",
"### Why Operator Overloading?\n",
"Python's magic methods allow us to use natural syntax:\n",
"- `a + b` instead of `a.add(b)`\n",
"- `a * b` instead of `a.multiply(b)`\n",
"- `a - b` for subtraction\n",
"- `a / b` for division\n",
"\n",
"This makes tensor operations feel natural and readable."
]
},
{
"cell_type": "markdown",
"id": "2fb25e3c",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## Step 4: Operator Overloading\n",
"\n",
"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`."
]
},
{
"cell_type": "markdown",
"id": "1ce7233e",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"### 🧪 Test Your Tensor Implementation\n",
"\n",
"Once you implement the Tensor class above, run these cells to test your implementation:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e45b9b7d",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-creation",
"locked": true,
"points": 25,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"# Test tensor creation and properties\n",
"print(\"Testing tensor creation...\")\n",
"\n",
"# Test scalar creation\n",
"scalar = Tensor(5.0)\n",
"assert scalar.shape == (), f\"Scalar shape should be (), got {scalar.shape}\"\n",
"assert scalar.size == 1, f\"Scalar size should be 1, got {scalar.size}\"\n",
"assert scalar.data.item() == 5.0, f\"Scalar value should be 5.0, got {scalar.data.item()}\"\n",
"\n",
"# Test vector creation\n",
"vector = Tensor([1, 2, 3])\n",
"assert vector.shape == (3,), f\"Vector shape should be (3,), got {vector.shape}\"\n",
"assert vector.size == 3, f\"Vector size should be 3, got {vector.size}\"\n",
"assert np.array_equal(vector.data, np.array([1, 2, 3])), \"Vector data mismatch\"\n",
"\n",
"# Test matrix creation\n",
"matrix = Tensor([[1, 2], [3, 4]])\n",
"assert matrix.shape == (2, 2), f\"Matrix shape should be (2, 2), got {matrix.shape}\"\n",
"assert matrix.size == 4, f\"Matrix size should be 4, got {matrix.size}\"\n",
"assert np.array_equal(matrix.data, np.array([[1, 2], [3, 4]])), \"Matrix data mismatch\"\n",
"\n",
"# Test dtype handling\n",
"float_tensor = Tensor([1.0, 2.0, 3.0])\n",
"assert float_tensor.dtype == np.float32, f\"Float tensor dtype should be float32, got {float_tensor.dtype}\"\n",
"\n",
"int_tensor = Tensor([1, 2, 3])\n",
"# Note: NumPy may default to int64 on some systems, so we check for integer types\n",
"assert int_tensor.dtype in [np.int32, np.int64], f\"Int tensor dtype should be int32 or int64, got {int_tensor.dtype}\"\n",
"\n",
"print(\"✅ Tensor creation tests passed!\")\n",
"print(f\"✅ Scalar: {scalar}\")\n",
"print(f\"✅ Vector: {vector}\")\n",
"print(f\"✅ Matrix: {matrix}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "01b4a2ba",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-arithmetic",
"locked": true,
"points": 25,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"# Test tensor arithmetic operations\n",
"print(\"Testing tensor arithmetic...\")\n",
"\n",
"# Test addition\n",
"a = Tensor([1, 2, 3])\n",
"b = Tensor([4, 5, 6])\n",
"c = a + b\n",
"expected = np.array([5, 7, 9])\n",
"assert np.array_equal(c.data, expected), f\"Addition failed: expected {expected}, got {c.data}\"\n",
"\n",
"# Test multiplication\n",
"d = a * b\n",
"expected = np.array([4, 10, 18])\n",
"assert np.array_equal(d.data, expected), f\"Multiplication failed: expected {expected}, got {d.data}\"\n",
"\n",
"# Test subtraction\n",
"e = b - a\n",
"expected = np.array([3, 3, 3])\n",
"assert np.array_equal(e.data, expected), f\"Subtraction failed: expected {expected}, got {e.data}\"\n",
"\n",
"# Test division\n",
"f = b / a\n",
"expected = np.array([4.0, 2.5, 2.0])\n",
"assert np.allclose(f.data, expected), f\"Division failed: expected {expected}, got {f.data}\"\n",
"\n",
"# Test scalar operations\n",
"g = a + 10\n",
"expected = np.array([11, 12, 13])\n",
"assert np.array_equal(g.data, expected), f\"Scalar addition failed: expected {expected}, got {g.data}\"\n",
"\n",
"h = a * 2\n",
"expected = np.array([2, 4, 6])\n",
"assert np.array_equal(h.data, expected), f\"Scalar multiplication failed: expected {expected}, got {h.data}\"\n",
"\n",
"print(\"✅ Tensor arithmetic tests passed!\")\n",
"print(f\"✅ Addition: {a} + {b} = {c}\")\n",
"print(f\"✅ Multiplication: {a} * {b} = {d}\")\n",
"print(f\"✅ Subtraction: {b} - {a} = {e}\")\n",
"print(f\"✅ Division: {b} / {a} = {f}\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d268a516",
"metadata": {
"nbgrader": {
"grade": true,
"grade_id": "test-tensor-broadcasting",
"locked": true,
"points": 25,
"schema_version": 3,
"solution": false,
"task": false
}
},
"outputs": [],
"source": [
"# Test tensor broadcasting\n",
"print(\"Testing tensor broadcasting...\")\n",
"\n",
"# Test scalar broadcasting\n",
"matrix = Tensor([[1, 2], [3, 4]])\n",
"scalar = Tensor(10)\n",
"result = matrix + scalar\n",
"expected = np.array([[11, 12], [13, 14]])\n",
"assert np.array_equal(result.data, expected), f\"Scalar broadcasting failed: expected {expected}, got {result.data}\"\n",
"\n",
"# Test vector broadcasting\n",
"vector = Tensor([1, 2])\n",
"result = matrix + vector\n",
"expected = np.array([[2, 4], [4, 6]])\n",
"assert np.array_equal(result.data, expected), f\"Vector broadcasting failed: expected {expected}, got {result.data}\"\n",
"\n",
"# Test different shapes\n",
"a = Tensor([[1], [2], [3]]) # (3, 1)\n",
"b = Tensor([10, 20]) # (2,)\n",
"result = a + b\n",
"expected = np.array([[11, 21], [12, 22], [13, 23]])\n",
"assert np.array_equal(result.data, expected), f\"Shape broadcasting failed: expected {expected}, got {result.data}\"\n",
"\n",
"print(\"✅ Tensor broadcasting tests passed!\")\n",
"print(f\"✅ Matrix + Scalar: {matrix} + {scalar} = {result}\")\n",
"print(f\"✅ Broadcasting works correctly!\")"
]
},
{
"cell_type": "markdown",
"id": "57b99fdc",
"metadata": {
"cell_marker": "\"\"\""
},
"source": [
"## 🎯 Module Summary\n",
"\n",
"Congratulations! You've successfully implemented the core Tensor class for TinyTorch:\n",
"\n",
"### What You've Accomplished\n",
"✅ **Tensor Creation**: Handle scalars, vectors, matrices, and higher-dimensional arrays \n",
"✅ **Data Types**: Proper dtype handling with auto-detection and conversion \n",
"✅ **Properties**: Shape, size, dtype, and data access \n",
"✅ **Arithmetic**: Addition, multiplication, subtraction, division \n",
"✅ **Operators**: Natural Python syntax with `+`, `-`, `*`, `/` \n",
"✅ **Broadcasting**: Automatic shape compatibility like NumPy \n",
"\n",
"### Key Concepts You've Learned\n",
"- **Tensors** are the fundamental data structure for ML systems\n",
"- **NumPy backend** provides efficient computation with ML-friendly API\n",
"- **Operator overloading** makes tensor operations feel natural\n",
"- **Broadcasting** enables flexible operations between different shapes\n",
"- **Type safety** ensures consistent behavior across operations\n",
"\n",
"### Next Steps\n",
"1. **Export your code**: `tito package nbdev --export 01_tensor`\n",
"2. **Test your implementation**: `tito module test 01_tensor`\n",
"3. **Use your tensors**: \n",
" ```python\n",
" from tinytorch.core.tensor import Tensor\n",
" t = Tensor([1, 2, 3])\n",
" print(t + 5) # Your tensor in action!\n",
" ```\n",
"4. **Move to Module 2**: Start building activation functions!\n",
"\n",
"**Ready for the next challenge?** Let's add the mathematical functions that make neural networks powerful!"
]
}
],
"metadata": {
"jupytext": {
"main_language": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}