从零实现神经网络:深入理解深度学习本质

深度学习看似神秘,但当我们揭开它的面纱,会发现其核心原理其实非常直观。本文将通过从零实现一个简单的神经网络,带你深入理解深度学习的本质。

神经网络的核心组件

在我们开始编码之前,先来回顾一下神经网络的基本构成:

  • 层(Layers):数据处理的模块,将输入映射到输出
  • 损失函数(Loss Function):衡量预测值与真实值的差距
  • 优化器(Optimizer):根据损失值更新模型权重
  • 训练循环(Training Loop):重复训练直到模型收敛

从零实现神经网络

1. 自定义Dense层

import tensorflow as tf
import numpy as np
import math

class NaiveDense:
    def __init__(self, input_size, output_size, activation):
        # Xavier初始化权重,提高训练稳定性
        initial_w = tf.random.uniform(
            shape=(input_size, output_size),
            minval=-0.5, maxval=0.5
        ) / np.sqrt(input_size)
        self.W = tf.Variable(initial_w, name="weights")
        
        # 零初始化偏置
        self.b = tf.Variable(tf.zeros((output_size,)), name="bias")
        self.activation = activation

    def __call__(self, inputs):
        # 前向传播:output = activation(W @ input + b)
        z = tf.matmul(inputs, self.W) + self.b
        return self.activation(z) if self.activation else z

    @property
    def weights(self):
        return [self.W, self.b]

这个简单的Dense层实现了神经网络的核心计算:output = activation(dot(W, input) + b)

2. 构建Sequential模型

class NaiveSequential:
    def __init__(self, layers):
        self.layers = layers

    def __call__(self, inputs):
        x = inputs
        for layer in self.layers:
            x = layer(x)
        return x

    @property
    def weights(self):
        weights = []
        for layer in self.layers:
            weights += layer.weights
        return weights

Sequential模型将多个层串联起来,形成一个完整的数据处理流水线。

3. 数据批量生成器

class BatchGenerator:
    def __init__(self, images, labels, batch_size=128):
        assert len(images) == len(labels)
        self.images = images
        self.labels = labels
        self.batch_size = batch_size
        self.num_batches = math.ceil(len(images) / batch_size)
        self._index = 0

    def next(self):
        start = self._index
        end = min(self._index + self.batch_size, len(self.images))
        images_batch = self.images[start:end]
        labels_batch = self.labels[start:end]
        self._index = (self._index + self.batch_size) % len(self.images)
        return images_batch, labels_batch

批量生成器负责将训练数据分成小批量,这对于内存效率和训练稳定性至关重要。

4. 核心训练步骤

def one_training_step(model, images_batch, labels_batch):
    with tf.GradientTape() as tape:
        # 前向传播计算预测值
        predictions = model(images_batch)
        
        # 计算损失值
        per_sample_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(
            labels=labels_batch,
            logits=predictions
        )
        loss = tf.reduce_mean(per_sample_loss)
    
    # 反向传播计算梯度
    gradients = tape.gradient(loss, model.weights)
    
    # 更新权重(随机梯度下降)
    learning_rate = 1e-3
    for g, w in zip(gradients, model.weights):
        w.assign_sub(g * learning_rate)
    
    return loss

这是整个训练过程的核心,包含四个关键步骤:

  1. 前向传播计算预测值
  2. 计算损失值
  3. 反向传播计算梯度
  4. 更新模型权重

5. 完整训练循环

def fit(model, images, labels, epochs, batch_size=128):
    for epoch in range(epochs):
        print(f"\nEpoch {epoch + 1}/{epochs}")
        batch_generator = BatchGenerator(images, labels, batch_size)
        
        for batch_idx in range(batch_generator.num_batches):
            images_batch, labels_batch = batch_generator.next()
            loss = one_training_step(model, images_batch, labels_batch)
            
            if batch_idx % 100 == 0:
                print(f"  Batch {batch_idx}/{batch_generator.num_batches} - Loss: {loss:.4f}")

训练循环重复执行训练步骤,直到模型收敛。

实际运行结果

当我们运行这个完整的神经网络时,可以看到训练过程:

开始训练...

Epoch 1/5
  Batch 0/469 - Loss: 2.3009
  Batch 100/469 - Loss: 2.2955
  Batch 200/469 - Loss: 2.2915
  ...

Epoch 5/5
  Batch 0/469 - Loss: 2.1199
  Batch 100/469 - Loss: 2.1352
  ...

评估模型...
测试集准确率: 0.6788

关键理解点

  1. 前向传播:数据从输入层流向输出层,每一层都对数据进行变换
  2. 损失计算:衡量模型预测与真实标签的差距
  3. 反向传播:通过链式法则计算损失对每个权重的梯度
  4. 权重更新:沿着梯度反方向微调权重,减少损失

为什么需要理解底层原理?

虽然Keras等高级框架让深度学习变得简单,但理解底层原理有重要价值:

  • 调试能力:当模型不收敛时,知道底层原理能帮助你快速定位问题
  • 定制化:可以自定义层、损失函数或优化器来满足特殊需求
  • 优化性能:理解计算图有助于模型和训练过程的优化
  • 创新能力:为基础研究和新算法开发打下基础

总结

通过从零实现神经网络,我们揭开了深度学习的神秘面纱。虽然实际应用中我们通常使用高级框架,但这种底层理解让我们能够更好地使用这些工具,并在遇到问题时知道如何解决。

深度学习的核心思想其实很简单:通过大量的简单变换(层)组合成复杂的函数,然后通过梯度下降不断优化这个函数的参数,使其能够从数据中学习到有用的模式。

记住:理解原理不是为了重复造轮子,而是为了在需要时能够制造更好的轮子。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐