一、引言:为什么选择“从零开始”?

在深度学习领域,TensorFlow、PyTorch 等框架已经非常成熟,但“从零开始手写机器学习框架:我的深度学习之旅”不仅是技术的修炼,更是对底层原理的彻底掌握。本文将带你从张量(Tensor)开始,手写一个支持自动求导(Autograd)和神经网络训练的微型框架,真正理解深度学习背后的运行机制。


二、关键概念与核心技巧

1. 张量(Tensor)

张量是深度学习的基本数据结构,类似于 NumPy 的多维数组,但支持自动求导。

2. 计算图(Computational Graph)

每个张量操作都会构建一个计算图,用于反向传播时计算梯度。

3. 自动求导(Autograd)

通过链式法则自动计算每个参数的梯度,是框架的核心能力。

4. 模块化设计(Module)

神经网络由多个层(Layer)组成,每层实现前向传播和反向传播。


三、应用场景

  • 教学演示:帮助学生理解深度学习底层原理
  • 快速原型验证:在嵌入式设备或边缘计算中部署轻量级框架
  • 自定义算子:研究新型激活函数或优化器

四、详细代码案例分析:手写 Autograd 系统

以下是一个简化版的 Autograd 系统,支持张量基本运算与反向传播。

import numpy as np

class Tensor:
    def __init__(self, data, requires_grad=False):
        self.data = np.array(data, dtype=np.float32)
        self.grad = None
        self.requires_grad = requires_grad
        self._backward = lambda: None
        self._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 = grad
        topo = []
        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.grad
            if other.requires_grad:
                other.grad = (other.grad or 0) + out.grad
        out._backward = _backward
        out._prev = {self, other}
        return out

    def __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.grad
            if other.requires_grad:
                other.grad = (other.grad or 0) + self.data * out.grad
        out._backward = _backward
        out._prev = {self, other}
        return out

    def 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.grad
        out._backward = _backward
        out._prev = {self}
        return out
代码分析(重点)

这段代码的核心是构建一个支持自动求导的张量系统,我们逐段解析:

  1. Tensor 类初始化

    • data 存储实际数值,grad 存储梯度,requires_grad 控制是否参与反向传播。
    • _backward 是一个函数,用于在反向传播时计算梯度。
    • _prev 是一个集合,记录当前张量依赖的前驱张量,用于构建计算图。
  2. backward 方法

    • 使用拓扑排序(Topological Sort)确保梯度按正确顺序传播。
    • 从输出张量开始,逐步调用每个张量的 _backward 函数,完成梯度回传。
  3. 运算符重载(add 和 mul

    • 每次运算都会创建一个新的 Tensor,并定义其 _backward 方法。
    • 在 _backward 中,根据链式法则将梯度分配到操作数上。
    • 例如,a + b 的梯度是 out.grad 直接传递给 a 和 b
  4. ReLU 激活函数

    • 前向传播使用 np.maximum(0, x)
    • 反向传播时,只有当输入大于 0 时才传递梯度,否则为 0。

这个系统虽然简单,但已经具备了自动求导的核心机制,可以支持后续的神经网络训练。


五、未来发展趋势

  1. 向 GPU 加速扩展:引入 CUDA 支持,实现张量并行计算
  2. 支持高阶导数:为 Meta-Learning、二阶优化提供基础
  3. 图优化与编译器:结合 MLIR、XLA 等技术实现计算图优化
  4. 自动微分与符号微分融合:提升训练效率与数值稳定性
Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐