从零开始手写机器学习框架:我的深度学习之旅——核心原理解密与手写实现
一、引言:为什么选择“从零开始”?
在深度学习领域,TensorFlow、PyTorch 等框架已经非常成熟,但“从零开始手写机器学习框架:我的深度学习之旅”不仅是技术的修炼,更是对底层原理的彻底掌握。本文将带你从张量(Tensor)开始,手写一个支持自动求导(Autograd)和神经网络训练的微型框架,真正理解深度学习背后的运行机制。
二、关键概念与核心技巧
1. 张量(Tensor)
张量是深度学习的基本数据结构,类似于 NumPy 的多维数组,但支持自动求导。
2. 计算图(Computational Graph)
每个张量操作都会构建一个计算图,用于反向传播时计算梯度。
3. 自动求导(Autograd)
通过链式法则自动计算每个参数的梯度,是框架的核心能力。
4. 模块化设计(Module)
神经网络由多个层(Layer)组成,每层实现前向传播和反向传播。
三、应用场景
- 教学演示:帮助学生理解深度学习底层原理
- 快速原型验证:在嵌入式设备或边缘计算中部署轻量级框架
- 自定义算子:研究新型激活函数或优化器
四、详细代码案例分析:手写 Autograd 系统
以下是一个简化版的 Autograd 系统,支持张量基本运算与反向传播。
import numpy as npclass Tensor:def __init__(self, data, requires_grad=False):self.data = np.array(data, dtype=np.float32)self.grad = Noneself.requires_grad = requires_gradself._backward = lambda: Noneself._prev = set()def __repr__(self):return f"Tensor({self.data}, grad={self.grad})"def backward(self, grad=None):if grad is None:grad = np.ones_like(self.data)self.grad = gradtopo = []visited = set()def build_topo(v):if v not in visited:visited.add(v)for child in v._prev:build_topo(child)topo.append(v)build_topo(self)for v in reversed(topo):v._backward()def __add__(self, other):other = other if isinstance(other, Tensor) else Tensor(other)out = Tensor(self.data + other.data, requires_grad=self.requires_grad or other.requires_grad)def _backward():if self.requires_grad:self.grad = (self.grad or 0) + out.gradif other.requires_grad:other.grad = (other.grad or 0) + out.gradout._backward = _backwardout._prev = {self, other}return outdef __mul__(self, other):other = other if isinstance(other, Tensor) else Tensor(other)out = Tensor(self.data * other.data, requires_grad=self.requires_grad or other.requires_grad)def _backward():if self.requires_grad:self.grad = (self.grad or 0) + other.data * out.gradif other.requires_grad:other.grad = (other.grad or 0) + self.data * out.gradout._backward = _backwardout._prev = {self, other}return outdef relu(self):out = Tensor(np.maximum(0, self.data), requires_grad=self.requires_grad)def _backward():if self.requires_grad:self.grad = (self.grad or 0) + (out.data > 0) * out.gradout._backward = _backwardout._prev = {self}return out
代码分析(重点)
这段代码的核心是构建一个支持自动求导的张量系统,我们逐段解析:
Tensor 类初始化
data
存储实际数值,grad
存储梯度,requires_grad
控制是否参与反向传播。_backward
是一个函数,用于在反向传播时计算梯度。_prev
是一个集合,记录当前张量依赖的前驱张量,用于构建计算图。
backward 方法
- 使用拓扑排序(Topological Sort)确保梯度按正确顺序传播。
- 从输出张量开始,逐步调用每个张量的
_backward
函数,完成梯度回传。
运算符重载(add 和 mul)
- 每次运算都会创建一个新的 Tensor,并定义其
_backward
方法。 - 在
_backward
中,根据链式法则将梯度分配到操作数上。 - 例如,
a + b
的梯度是out.grad
直接传递给a
和b
。
- 每次运算都会创建一个新的 Tensor,并定义其
ReLU 激活函数
- 前向传播使用
np.maximum(0, x)
。 - 反向传播时,只有当输入大于 0 时才传递梯度,否则为 0。
- 前向传播使用
这个系统虽然简单,但已经具备了自动求导的核心机制,可以支持后续的神经网络训练。
五、未来发展趋势
- 向 GPU 加速扩展:引入 CUDA 支持,实现张量并行计算
- 支持高阶导数:为 Meta-Learning、二阶优化提供基础
- 图优化与编译器:结合 MLIR、XLA 等技术实现计算图优化
- 自动微分与符号微分融合:提升训练效率与数值稳定性