共计 3609 个字符,预计需要花费 10 分钟才能阅读完成。
为什么需要神经网络?
神经网络是模仿人脑神经元连接方式的数学模型,在图像识别、自然语言处理等领域表现出色。比如支付宝的人脸识别、微信的语音转文字,背后都是神经网络在发挥作用。它能够自动从数据中学习特征,避免了传统算法需要手工设计特征的麻烦。

人工神经元模型
神经网络的基本单元是神经元,它的数学模型可以表示为:
$$z = w_1x_1 + w_2x_2 + … + w_nx_n + b$$
其中:
– $w_i$ 是权重(weight)
– $x_i$ 是输入(input)
– $b$ 是偏置(bias)
– $z$ 是加权和
然后通过激活函数 $\sigma(z)$ 得到神经元的输出。这个简单的模型却能组合出强大的表达能力。
前向传播过程
前向传播就是数据从输入层流向输出层的过程:
- 输入数据传入输入层
- 每一层计算加权和 $z = WX + b$
- 通过激活函数得到输出 $a = \sigma(z)$
- 输出传递到下一层作为输入
用 Python 实现前向传播:
import numpy as np
class NeuralNetwork:
def __init__(self, layers):
self.weights = [np.random.randn(y, x)
for x, y in zip(layers[:-1], layers[1:])]
self.biases = [np.random.randn(y, 1) for y in layers[1:]]
def forward(self, x):
for w, b in zip(self.weights, self.biases):
x = sigmoid(np.dot(w, x) + b)
return x
反向传播算法
反向传播 (BP) 是神经网络训练的核心,通过计算损失函数对各个参数的梯度来更新权重。推导过程需要用到链式法则:
- 计算输出层误差:$\delta^L = \nabla_a C \odot \sigma'(z^L)$
- 反向传播误差:$\delta^l = ((w^{l+1})^T \delta^{l+1}) \odot \sigma'(z^l)$
- 计算梯度:$\frac{\partial C}{\partial w^l} = \delta^l (a^{l-1})^T$
Python 实现反向传播:
def backprop(self, x, y):
# 前向传播
activation = x
activations = [x]
zs = []
for w, b in zip(self.weights, self.biases):
z = np.dot(w, activation) + b
zs.append(z)
activation = sigmoid(z)
activations.append(activation)
# 反向传播
delta = (activations[-1] - y) * sigmoid_prime(zs[-1])
nabla_w = [np.zeros(w.shape) for w in self.weights]
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w[-1] = np.dot(delta, activations[-2].T)
nabla_b[-1] = delta
for l in range(2, self.num_layers):
z = zs[-l]
sp = sigmoid_prime(z)
delta = np.dot(self.weights[-l+1].T, delta) * sp
nabla_w[-l] = np.dot(delta, activations[-l-1].T)
nabla_b[-l] = delta
return (nabla_w, nabla_b)
常用激活函数实现
激活函数引入非线性,使神经网络可以拟合任意函数。常见的三种激活函数:
- Sigmoid:$\sigma(z) = \frac{1}{1+e^{-z}}$
- 输出在 (0,1) 之间,适合二分类
-
容易导致梯度消失
-
Tanh:$tanh(z) = \frac{e^z – e^{-z}}{e^z + e^{-z}}$
- 输出在 (-1,1) 之间,中心对称
-
梯度消失问题比 Sigmoid 轻
-
ReLU:$ReLU(z) = max(0,z)$
- 计算简单,缓解梯度消失
- 可能出现神经元死亡
代码实现:
def sigmoid(z):
return 1.0/(1.0+np.exp(-z))
def sigmoid_prime(z):
return sigmoid(z)*(1-sigmoid(z))
def relu(z):
return np.maximum(0, z)
def relu_prime(z):
return (z > 0).astype(float)
优化算法实现
最简单的优化算法是随机梯度下降(SGD):
$$w \leftarrow w – \eta \frac{\partial C}{\partial w}$$
其中 $\eta$ 是学习率,控制参数更新步长。学习率太大可能导致震荡,太小则收敛慢。
Python 实现:
def SGD(self, training_data, epochs, batch_size, eta):
n = len(training_data)
for j in range(epochs):
np.random.shuffle(training_data)
batches = [training_data[k:k+batch_size]
for k in range(0, n, batch_size)]
for batch in batches:
self.update_batch(batch, eta)
def update_batch(self, batch, eta):
nabla_w = [np.zeros(w.shape) for w in self.weights]
nabla_b = [np.zeros(b.shape) for b in self.biases]
for x, y in batch:
delta_nabla_w, delta_nabla_b = self.backprop(x, y)
nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
self.weights = [w-(eta/len(batch))*nw
for w, nw in zip(self.weights, nabla_w)]
self.biases = [b-(eta/len(batch))*nb
for b, nb in zip(self.biases, nabla_b)]
实战 MNIST 手写数字识别
现在用我们实现的神经网络来识别手写数字。MNIST 数据集包含 60000 张 28×28 的手写数字图片。
- 首先加载数据:
from tensorflow.keras.datasets import mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 数据预处理
x_train = x_train.reshape(-1, 28*28).T / 255.0
x_test = x_test.reshape(-1, 28*28).T / 255.0
y_train = np.eye(10)[y_train].T
y_test = np.eye(10)[y_test].T
- 创建神经网络并训练:
# 创建网络:784 输入,30 隐藏层,10 输出
net = NeuralNetwork([784, 30, 10])
# 训练
net.SGD(list(zip(x_train.T, y_train.T)),
epochs=30, batch_size=10, eta=3.0)
- 评估准确率:
def evaluate(net, x, y):
results = [(np.argmax(net.forward(x[:,i])), np.argmax(y[:,i]))
for i in range(x.shape[1])]
return sum(int(x == y) for (x, y) in results) / len(results)
print("Test accuracy:", evaluate(net, x_test, y_test))
常见问题与解决方案
- 梯度消失:深层网络训练时梯度越来越小
-
解决方案:使用 ReLU 激活函数,Batch Normalization
-
过拟合:训练集表现好但测试集差
-
解决方案:增加数据量,L2 正则化,Dropout
-
学习率选择:太大震荡,太小收敛慢
- 解决方案:学习率衰减,Adam 等自适应优化算法
延伸学习
- 推荐书籍:《神经网络与深度学习》(Michael Nielsen)
- 进阶框架:TensorFlow/PyTorch
- 最新进展:注意力机制、Transformer
通过本文,我们从零实现了一个完整的神经网络,理解了前向传播和反向传播的原理,并在 MNIST 数据集上进行了实战。虽然我们的实现比较简单,但已经包含了神经网络最核心的思想。希望这篇文章能帮助你入门神经网络的世界!
