从零实现神经网络:深入理解深度学习本质
Xavier初始化权重,提高训练稳定性# 零初始化偏置# 前向传播:output = activation(W @ input + b)@property。通过从零实现神经网络,我们揭开了深度学习的神秘面纱。虽然实际应用中我们通常使用高级框架,但这种底层理解让我们能够更好地使用这些工具,并在遇到问题时知道如何解决。深度学习的核心思想其实很简单:通过大量的简单变换(层)组合成复杂的函数,然后通过梯度
从零实现神经网络:深入理解深度学习本质
深度学习看似神秘,但当我们揭开它的面纱,会发现其核心原理其实非常直观。本文将通过从零实现一个简单的神经网络,带你深入理解深度学习的本质。
神经网络的核心组件
在我们开始编码之前,先来回顾一下神经网络的基本构成:
- 层(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
这是整个训练过程的核心,包含四个关键步骤:
- 前向传播计算预测值
- 计算损失值
- 反向传播计算梯度
- 更新模型权重
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
关键理解点
- 前向传播:数据从输入层流向输出层,每一层都对数据进行变换
- 损失计算:衡量模型预测与真实标签的差距
- 反向传播:通过链式法则计算损失对每个权重的梯度
- 权重更新:沿着梯度反方向微调权重,减少损失
为什么需要理解底层原理?
虽然Keras等高级框架让深度学习变得简单,但理解底层原理有重要价值:
- 调试能力:当模型不收敛时,知道底层原理能帮助你快速定位问题
- 定制化:可以自定义层、损失函数或优化器来满足特殊需求
- 优化性能:理解计算图有助于模型和训练过程的优化
- 创新能力:为基础研究和新算法开发打下基础
总结
通过从零实现神经网络,我们揭开了深度学习的神秘面纱。虽然实际应用中我们通常使用高级框架,但这种底层理解让我们能够更好地使用这些工具,并在遇到问题时知道如何解决。
深度学习的核心思想其实很简单:通过大量的简单变换(层)组合成复杂的函数,然后通过梯度下降不断优化这个函数的参数,使其能够从数据中学习到有用的模式。
记住:理解原理不是为了重复造轮子,而是为了在需要时能够制造更好的轮子。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)