本文基于 Neural Networks: Zero to Hero 系列教程整理,系统介绍神经网络从基础到实践的知识点。
神经网络基础 什么是神经网络? 神经网络(Neural Network)是一种受生物神经元启发的计算模型,由大量相互连接的节点(神经元)组成,能够通过学习和训练来识别模式、进行分类和预测。
神经网络的核心思想:
模拟人脑神经元的工作方式
通过大量简单的计算单元组合实现复杂功能
能够从数据中自动学习特征和模式
神经网络的应用:
图像识别和分类
自然语言处理
语音识别
推荐系统
游戏 AI
自动驾驶
神经元模型 生物神经元 vs 人工神经元:
生物神经元:
树突接收信号
细胞体处理信号
轴突传递信号
突触连接其他神经元
人工神经元(感知机):
输入:x₁, x₂, …, xₙ
权重:w₁, w₂, …, wₙ
偏置:b
激活函数:f
输出:y = f(Σwᵢxᵢ + b)
数学表示:
其中:
xᵢ:输入特征
wᵢ:权重
b:偏置
f:激活函数
感知机(Perceptron) 单层感知机 单层感知机是最简单的神经网络,只能解决线性可分问题。
结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import numpy as npclass Perceptron : def __init__ (self, learning_rate=0.01 , n_iterations=1000 ): self .learning_rate = learning_rate self .n_iterations = n_iterations self .weights = None self .bias = None def fit (self, X, y ): """训练感知机""" n_samples, n_features = X.shape self .weights = np.zeros(n_features) self .bias = 0 for _ in range (self .n_iterations): for idx, x_i in enumerate (X): linear_output = np.dot(x_i, self .weights) + self .bias y_predicted = self .activation(linear_output) update = self .learning_rate * (y[idx] - y_predicted) self .weights += update * x_i self .bias += update def activation (self, x ): """阶跃激活函数""" return 1 if x >= 0 else 0 def predict (self, X ): """预测""" linear_output = np.dot(X, self .weights) + self .bias y_predicted = self .activation(linear_output) return y_predicted
局限性:
只能解决线性可分问题
无法解决 XOR 问题
需要多层网络才能解决非线性问题
多层感知机(MLP) 多层感知机通过添加隐藏层来解决非线性问题。
结构:
1 输入层 → 隐藏层1 → 隐藏层2 → ... → 输出层
前向传播:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import numpy as npclass MLP : def __init__ (self, layers, activation='sigmoid' ): self .layers = layers self .activation = activation self .weights = [] self .biases = [] for i in range (len (layers) - 1 ): w = np.random.randn(layers[i], layers[i+1 ]) * 0.1 b = np.zeros((1 , layers[i+1 ])) self .weights.append(w) self .biases.append(b) def sigmoid (self, x ): """Sigmoid 激活函数""" return 1 / (1 + np.exp(-np.clip(x, -250 , 250 ))) def sigmoid_derivative (self, x ): """Sigmoid 导数""" s = self .sigmoid(x) return s * (1 - s) def forward (self, X ): """前向传播""" self .activations = [X] self .z_values = [] for i in range (len (self .weights)): z = np.dot(self .activations[-1 ], self .weights[i]) + self .biases[i] self .z_values.append(z) a = self .sigmoid(z) self .activations.append(a) return self .activations[-1 ]
反向传播算法(Backpropagation) 反向传播是训练神经网络的核心算法,通过计算梯度来更新权重。
算法原理 步骤:
前向传播 :计算网络输出
计算损失 :比较输出和真实值
反向传播 :计算梯度
更新权重 :使用梯度下降更新参数
数学推导:
对于输出层:
对于隐藏层:
1 δˡ = ((Wˡ⁺¹)ᵀ δˡ⁺¹) ⊙ f'(zˡ)
权重梯度:
偏置梯度:
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class MLP : def backward (self, X, y, output ): """反向传播""" m = X.shape[0 ] self .deltas = [] delta = (output - y) * self .sigmoid_derivative(self .z_values[-1 ]) self .deltas.insert(0 , delta) for i in range (len (self .weights) - 2 , -1 , -1 ): delta = np.dot(self .deltas[0 ], self .weights[i+1 ].T) * \ self .sigmoid_derivative(self .z_values[i]) self .deltas.insert(0 , delta) self .dW = [] self .db = [] for i in range (len (self .weights)): dW = np.dot(self .activations[i].T, self .deltas[i]) / m db = np.sum (self .deltas[i], axis=0 , keepdims=True ) / m self .dW.append(dW) self .db.append(db) def update_weights (self, learning_rate ): """更新权重""" for i in range (len (self .weights)): self .weights[i] -= learning_rate * self .dW[i] self .biases[i] -= learning_rate * self .db[i] def train (self, X, y, learning_rate=0.01 , epochs=1000 ): """训练网络""" for epoch in range (epochs): output = self .forward(X) loss = np.mean((output - y) ** 2 ) self .backward(X, y, output) self .update_weights(learning_rate) if epoch % 100 == 0 : print (f"Epoch {epoch} , Loss: {loss:.4 f} " )
激活函数 激活函数引入非线性,使神经网络能够学习复杂模式。
常用激活函数 1. Sigmoid
1 2 3 4 5 6 def sigmoid (x ): return 1 / (1 + np.exp(-np.clip(x, -250 , 250 ))) def sigmoid_derivative (x ): s = sigmoid(x) return s * (1 - s)
特点:
输出范围:(0, 1)
适合二分类输出层
缺点:梯度消失问题
2. Tanh
1 2 3 4 5 def tanh (x ): return np.tanh(x) def tanh_derivative (x ): return 1 - np.tanh(x) ** 2
特点:
输出范围:(-1, 1)
零中心化
比 Sigmoid 梯度更大
3. ReLU(Rectified Linear Unit)
1 2 3 4 5 def relu (x ): return np.maximum(0 , x) def relu_derivative (x ): return (x > 0 ).astype(float )
特点:
计算简单,梯度大
解决梯度消失问题
缺点:死亡 ReLU 问题(负值输出为 0)
4. Leaky ReLU
1 2 3 4 5 def leaky_relu (x, alpha=0.01 ): return np.where(x > 0 , x, alpha * x) def leaky_relu_derivative (x, alpha=0.01 ): return np.where(x > 0 , 1 , alpha)
特点:
5. Softmax
1 2 3 def softmax (x ): exp_x = np.exp(x - np.max (x, axis=1 , keepdims=True )) return exp_x / np.sum (exp_x, axis=1 , keepdims=True )
特点:
激活函数对比:
激活函数
优点
缺点
适用场景
Sigmoid
输出范围固定
梯度消失
输出层(二分类)
Tanh
零中心化
梯度消失
隐藏层
ReLU
计算快,梯度大
死亡 ReLU
隐藏层(最常用)
Leaky ReLU
解决死亡 ReLU
-
隐藏层
Softmax
概率分布
-
输出层(多分类)
损失函数 损失函数衡量模型预测与真实值的差距。
常用损失函数 1. 均方误差(MSE)
1 2 3 4 5 def mse_loss (y_pred, y_true ): return np.mean((y_pred - y_true) ** 2 ) def mse_derivative (y_pred, y_true ): return 2 * (y_pred - y_true) / len (y_true)
适用场景: 回归问题
2. 交叉熵损失(Cross-Entropy)
1 2 3 4 5 6 7 8 def cross_entropy_loss (y_pred, y_true ): epsilon = 1e-15 y_pred = np.clip(y_pred, epsilon, 1 - epsilon) return -np.mean(np.sum (y_true * np.log(y_pred), axis=1 )) def cross_entropy_derivative (y_pred, y_true ): return y_pred - y_true
适用场景: 分类问题(配合 Softmax)
3. 二元交叉熵(Binary Cross-Entropy)
1 2 3 4 def binary_cross_entropy_loss (y_pred, y_true ): epsilon = 1e-15 y_pred = np.clip(y_pred, epsilon, 1 - epsilon) return -np.mean(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
适用场景: 二分类问题(配合 Sigmoid)
优化器 优化器决定如何更新权重来最小化损失函数。
梯度下降 1. 批量梯度下降(BGD)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def gradient_descent (X, y, learning_rate=0.01 , epochs=1000 ): weights = np.random.randn(X.shape[1 ], 1 ) bias = 0 for epoch in range (epochs): predictions = X @ weights + bias error = predictions - y dw = (1 / len (X)) * X.T @ error db = (1 / len (X)) * np.sum (error) weights -= learning_rate * dw bias -= learning_rate * db return weights, bias
特点:
2. 随机梯度下降(SGD)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def stochastic_gradient_descent (X, y, learning_rate=0.01 , epochs=1000 ): weights = np.random.randn(X.shape[1 ], 1 ) bias = 0 for epoch in range (epochs): for i in range (len (X)): x_i = X[i:i+1 ] y_i = y[i:i+1 ] prediction = x_i @ weights + bias error = prediction - y_i dw = x_i.T @ error db = error weights -= learning_rate * dw bias -= learning_rate * db return weights, bias
特点:
3. 小批量梯度下降(Mini-batch GD)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 def mini_batch_gradient_descent (X, y, batch_size=32 , learning_rate=0.01 , epochs=1000 ): weights = np.random.randn(X.shape[1 ], 1 ) bias = 0 for epoch in range (epochs): indices = np.random.permutation(len (X)) X_shuffled = X[indices] y_shuffled = y[indices] for i in range (0 , len (X), batch_size): X_batch = X_shuffled[i:i+batch_size] y_batch = y_shuffled[i:i+batch_size] predictions = X_batch @ weights + bias error = predictions - y_batch dw = (1 / len (X_batch)) * X_batch.T @ error db = (1 / len (X_batch)) * np.sum (error) weights -= learning_rate * dw bias -= learning_rate * db return weights, bias
特点:
高级优化器 1. 动量(Momentum)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class MomentumOptimizer : def __init__ (self, learning_rate=0.01 , momentum=0.9 ): self .learning_rate = learning_rate self .momentum = momentum self .v_w = None self .v_b = None def update (self, weights, biases, dw, db ): if self .v_w is None : self .v_w = np.zeros_like(weights) self .v_b = np.zeros_like(biases) self .v_w = self .momentum * self .v_w + self .learning_rate * dw self .v_b = self .momentum * self .v_b + self .learning_rate * db weights -= self .v_w biases -= self .v_b return weights, biases
2. Adam(Adaptive Moment Estimation)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class AdamOptimizer : def __init__ (self, learning_rate=0.001 , beta1=0.9 , beta2=0.999 , epsilon=1e-8 ): self .learning_rate = learning_rate self .beta1 = beta1 self .beta2 = beta2 self .epsilon = epsilon self .m_w = None self .v_w = None self .m_b = None self .v_b = None self .t = 0 def update (self, weights, biases, dw, db ): if self .m_w is None : self .m_w = np.zeros_like(weights) self .v_w = np.zeros_like(weights) self .m_b = np.zeros_like(biases) self .v_b = np.zeros_like(biases) self .t += 1 self .m_w = self .beta1 * self .m_w + (1 - self .beta1) * dw self .m_b = self .beta1 * self .m_b + (1 - self .beta1) * db self .v_w = self .beta2 * self .v_w + (1 - self .beta2) * (dw ** 2 ) self .v_b = self .beta2 * self .v_b + (1 - self .beta2) * (db ** 2 ) m_w_corrected = self .m_w / (1 - self .beta1 ** self .t) m_b_corrected = self .m_b / (1 - self .beta1 ** self .t) v_w_corrected = self .v_w / (1 - self .beta2 ** self .t) v_b_corrected = self .v_b / (1 - self .beta2 ** self .t) weights -= self .learning_rate * m_w_corrected / (np.sqrt(v_w_corrected) + self .epsilon) biases -= self .learning_rate * m_b_corrected / (np.sqrt(v_b_corrected) + self .epsilon) return weights, biases
优化器对比:
优化器
优点
缺点
适用场景
SGD
简单
收敛慢,震荡
小数据集
Momentum
加速收敛
需要调参
一般场景
Adam
自适应学习率
内存占用大
深度学习(最常用)
完整的神经网络实现 完整的 MLP 类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 import numpy as npclass NeuralNetwork : def __init__ (self, layers, activation='sigmoid' , learning_rate=0.01 ): self .layers = layers self .activation = activation self .learning_rate = learning_rate self .weights = [] self .biases = [] for i in range (len (layers) - 1 ): w = np.random.randn(layers[i], layers[i+1 ]) * np.sqrt(2.0 / layers[i]) b = np.zeros((1 , layers[i+1 ])) self .weights.append(w) self .biases.append(b) def sigmoid (self, x ): return 1 / (1 + np.exp(-np.clip(x, -250 , 250 ))) def relu (self, x ): return np.maximum(0 , x) def sigmoid_derivative (self, x ): s = self .sigmoid(x) return s * (1 - s) def relu_derivative (self, x ): return (x > 0 ).astype(float ) def activate (self, x ): if self .activation == 'sigmoid' : return self .sigmoid(x) elif self .activation == 'relu' : return self .relu(x) def activate_derivative (self, x ): if self .activation == 'sigmoid' : return self .sigmoid_derivative(x) elif self .activation == 'relu' : return self .relu_derivative(x) def forward (self, X ): self .activations = [X] self .z_values = [] for i in range (len (self .weights)): z = np.dot(self .activations[-1 ], self .weights[i]) + self .biases[i] self .z_values.append(z) a = self .activate(z) self .activations.append(a) return self .activations[-1 ] def backward (self, X, y, output ): m = X.shape[0 ] self .deltas = [] delta = (output - y) * self .activate_derivative(self .z_values[-1 ]) self .deltas.insert(0 , delta) for i in range (len (self .weights) - 2 , -1 , -1 ): delta = np.dot(self .deltas[0 ], self .weights[i+1 ].T) * \ self .activate_derivative(self .z_values[i]) self .deltas.insert(0 , delta) self .dW = [] self .db = [] for i in range (len (self .weights)): dW = np.dot(self .activations[i].T, self .deltas[i]) / m db = np.sum (self .deltas[i], axis=0 , keepdims=True ) / m self .dW.append(dW) self .db.append(db) def update_weights (self ): for i in range (len (self .weights)): self .weights[i] -= self .learning_rate * self .dW[i] self .biases[i] -= self .learning_rate * self .db[i] def train (self, X, y, epochs=1000 , batch_size=32 , verbose=True ): for epoch in range (epochs): indices = np.random.permutation(len (X)) X_shuffled = X[indices] y_shuffled = y[indices] total_loss = 0 for i in range (0 , len (X), batch_size): X_batch = X_shuffled[i:i+batch_size] y_batch = y_shuffled[i:i+batch_size] output = self .forward(X_batch) loss = np.mean((output - y_batch) ** 2 ) total_loss += loss self .backward(X_batch, y_batch, output) self .update_weights() if verbose and epoch % 100 == 0 : avg_loss = total_loss / (len (X) // batch_size) print (f"Epoch {epoch} , Loss: {avg_loss:.4 f} " ) def predict (self, X ): return self .forward(X)
使用示例 1 2 3 4 5 6 7 8 9 10 11 12 X = np.random.randn(1000 , 10 ) y = np.random.randn(1000 , 1 ) nn = NeuralNetwork(layers=[10 , 64 , 32 , 1 ], activation='relu' , learning_rate=0.001 ) nn.train(X, y, epochs=1000 , batch_size=32 ) predictions = nn.predict(X)
正则化技术 正则化防止过拟合,提高模型泛化能力。
1. L1 和 L2 正则化 1 2 3 4 5 6 7 def l2_regularization (weights, lambda_reg ): """L2 正则化(权重衰减)""" return lambda_reg * np.sum ([np.sum (w ** 2 ) for w in weights]) def l1_regularization (weights, lambda_reg ): """L1 正则化(Lasso)""" return lambda_reg * np.sum ([np.sum (np.abs (w)) for w in weights])
在损失函数中添加:
1 2 3 4 5 6 7 def compute_loss_with_regularization (y_pred, y_true, weights, lambda_reg, reg_type='l2' ): mse = np.mean((y_pred - y_true) ** 2 ) if reg_type == 'l2' : reg = l2_regularization(weights, lambda_reg) else : reg = l1_regularization(weights, lambda_reg) return mse + reg
2. Dropout 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Dropout : def __init__ (self, dropout_rate=0.5 ): self .dropout_rate = dropout_rate self .mask = None def forward (self, x, training=True ): if training: self .mask = np.random.binomial(1 , 1 - self .dropout_rate, size=x.shape) / (1 - self .dropout_rate) return x * self .mask else : return x def backward (self, dout ): return dout * self .mask
3. 批量归一化(Batch Normalization) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class BatchNormalization : def __init__ (self, epsilon=1e-8 ): self .epsilon = epsilon self .gamma = None self .beta = None self .running_mean = None self .running_var = None def forward (self, x, training=True ): if training: mean = np.mean(x, axis=0 , keepdims=True ) var = np.var(x, axis=0 , keepdims=True ) if self .running_mean is None : self .running_mean = mean self .running_var = var else : self .running_mean = 0.9 * self .running_mean + 0.1 * mean self .running_var = 0.9 * self .running_var + 0.1 * var x_norm = (x - mean) / np.sqrt(var + self .epsilon) else : x_norm = (x - self .running_mean) / np.sqrt(self .running_var + self .epsilon) if self .gamma is None : self .gamma = np.ones((1 , x.shape[1 ])) self .beta = np.zeros((1 , x.shape[1 ])) return self .gamma * x_norm + self .beta
实践案例 案例1:手写数字识别(MNIST) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from sklearn.datasets import fetch_openmlfrom sklearn.model_selection import train_test_splitfrom sklearn.preprocessing import StandardScalermnist = fetch_openml('mnist_784' , version=1 ) X, y = mnist.data, mnist.target.astype(int ) X = (X > 127 ).astype(float ) y = (y == 0 ).astype(int ).reshape(-1 , 1 ) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2 , random_state=42 ) nn = NeuralNetwork(layers=[784 , 128 , 64 , 1 ], activation='relu' , learning_rate=0.001 ) nn.train(X_train, y_train, epochs=100 , batch_size=32 ) predictions = nn.predict(X_test) accuracy = np.mean((predictions > 0.5 ).astype(int ) == y_test) print (f"Accuracy: {accuracy:.4 f} " )
案例2:XOR 问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 X = np.array([[0 , 0 ], [0 , 1 ], [1 , 0 ], [1 , 1 ]]) y = np.array([[0 ], [1 ], [1 ], [0 ]]) nn = NeuralNetwork(layers=[2 , 4 , 1 ], activation='sigmoid' , learning_rate=0.5 ) nn.train(X, y, epochs=10000 , batch_size=4 , verbose=False ) predictions = nn.predict(X) print ("Predictions:" )print (predictions)print ("Expected:" )print (y)
总结 核心要点
神经网络基础
反向传播算法
激活函数
Sigmoid、Tanh、ReLU
选择合适的激活函数
损失函数和优化器
正则化
学习路径建议
基础阶段
进阶阶段
实践阶段
下一步学习
卷积神经网络(CNN) :图像处理
循环神经网络(RNN) :序列数据
注意力机制 :Transformer
生成对抗网络(GAN) :生成模型
强化学习 :决策问题
常见问题与解决方案 梯度消失和梯度爆炸 问题描述:
在深层网络中,梯度在反向传播过程中可能变得非常小(梯度消失)或非常大(梯度爆炸),导致训练困难。
梯度消失的原因:
使用 Sigmoid 或 Tanh 激活函数时,导数最大值小于 1
深层网络中,多个小于 1 的导数相乘,梯度指数级衰减
梯度爆炸的原因:
解决方案:
使用 ReLU 激活函数
1 2 3 def relu (x ): return np.maximum(0 , x)
梯度裁剪(Gradient Clipping)
1 2 3 4 5 6 7 def clip_gradients (gradients, max_norm=1.0 ): """裁剪梯度,防止梯度爆炸""" total_norm = np.sqrt(sum (np.sum (g**2 ) for g in gradients)) if total_norm > max_norm: scale = max_norm / total_norm gradients = [g * scale for g in gradients] return gradients
残差连接(Residual Connections)
1 2 3 4 5 class ResidualBlock : def forward (self, x ): out = self .layer(x) return out + x
批量归一化
权重初始化 好的初始化方法:
Xavier 初始化(Glorot)
1 2 3 4 def xavier_init (fan_in, fan_out ): """Xavier 初始化,适合 Sigmoid 和 Tanh""" limit = np.sqrt(6.0 / (fan_in + fan_out)) return np.random.uniform(-limit, limit, (fan_in, fan_out))
He 初始化
1 2 3 4 def he_init (fan_in, fan_out ): """He 初始化,适合 ReLU""" std = np.sqrt(2.0 / fan_in) return np.random.randn(fan_in, fan_out) * std
改进的初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def initialize_weights (layers, init_type='he' ): weights = [] for i in range (len (layers) - 1 ): fan_in = layers[i] fan_out = layers[i+1 ] if init_type == 'xavier' : limit = np.sqrt(6.0 / (fan_in + fan_out)) w = np.random.uniform(-limit, limit, (fan_in, fan_out)) elif init_type == 'he' : std = np.sqrt(2.0 / fan_in) w = np.random.randn(fan_in, fan_out) * std else : w = np.random.randn(fan_in, fan_out) * 0.1 weights.append(w) return weights
初始化方法对比:
方法
适用激活函数
公式
随机初始化
通用
w ~ N(0, 0.01)
Xavier
Sigmoid, Tanh
w ~ U(-√6/(n_in+n_out), √6/(n_in+n_out))
He
ReLU, Leaky ReLU
w ~ N(0, √2/n_in)
超参数调优 重要超参数:
学习率(Learning Rate)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class LearningRateScheduler : def __init__ (self, initial_lr=0.01 , decay_rate=0.95 , decay_step=100 ): self .initial_lr = initial_lr self .decay_rate = decay_rate self .decay_step = decay_step self .step = 0 def get_lr (self ): """指数衰减学习率""" lr = self .initial_lr * (self .decay_rate ** (self .step // self .decay_step)) self .step += 1 return lr def step_decay (self, epoch ): """阶梯衰减""" if epoch < 30 : return 0.01 elif epoch < 60 : return 0.001 else : return 0.0001
批量大小(Batch Size)
小批量(32-128):更频繁的更新,可能更稳定
大批量(256+):更快的训练,但可能陷入局部最优
网络深度和宽度
深度:更多层,学习更复杂的特征
宽度:每层更多神经元,增加容量
调优策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def hyperparameter_search (): """网格搜索超参数""" learning_rates = [0.001 , 0.01 , 0.1 ] batch_sizes = [32 , 64 , 128 ] hidden_sizes = [64 , 128 , 256 ] best_score = -np.inf best_params = None for lr in learning_rates: for bs in batch_sizes: for hs in hidden_sizes: nn = NeuralNetwork(layers=[10 , hs, 1 ], learning_rate=lr) nn.train(X_train, y_train, batch_size=bs, epochs=100 ) score = evaluate(nn, X_val, y_val) if score > best_score: best_score = score best_params = {'lr' : lr, 'batch_size' : bs, 'hidden_size' : hs} return best_params
调试技巧 1. 检查梯度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 def check_gradients (network, X, y ): """检查梯度是否正确""" def numerical_gradient (f, x, h=1e-5 ): grad = np.zeros_like(x) it = np.nditer(x, flags=['multi_index' ], op_flags=['readwrite' ]) while not it.finished: idx = it.multi_index old_value = x[idx] x[idx] = old_value + h fxh1 = f(x) x[idx] = old_value - h fxh2 = f(x) grad[idx] = (fxh1 - fxh2) / (2 * h) x[idx] = old_value it.iternext() return grad output = network.forward(X) network.backward(X, y, output) analytical_grad = network.dW[0 ]
2. 监控训练过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 def train_with_monitoring (network, X_train, y_train, X_val, y_val, epochs=1000 ): """训练并监控过拟合""" train_losses = [] val_losses = [] for epoch in range (epochs): output_train = network.forward(X_train) train_loss = np.mean((output_train - y_train) ** 2 ) network.backward(X_train, y_train, output_train) network.update_weights() output_val = network.forward(X_val) val_loss = np.mean((output_val - y_val) ** 2 ) train_losses.append(train_loss) val_losses.append(val_loss) if epoch > 100 and val_loss > min (val_losses[-100 :]): print (f"Early stopping at epoch {epoch} " ) break return train_losses, val_losses
3. 可视化
1 2 3 4 5 6 7 8 9 10 11 12 import matplotlib.pyplot as pltdef plot_training_curves (train_losses, val_losses ): """绘制训练曲线""" plt.figure(figsize=(10 , 6 )) plt.plot(train_losses, label='Train Loss' ) plt.plot(val_losses, label='Validation Loss' ) plt.xlabel('Epoch' ) plt.ylabel('Loss' ) plt.legend() plt.title('Training and Validation Loss' ) plt.show()
高级主题 自编码器(Autoencoder) 自编码器是一种无监督学习模型,用于学习数据的压缩表示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Autoencoder : def __init__ (self, input_dim, encoding_dim ): self .encoder = NeuralNetwork( layers=[input_dim, 128 , 64 , encoding_dim], activation='relu' ) self .decoder = NeuralNetwork( layers=[encoding_dim, 64 , 128 , input_dim], activation='sigmoid' ) def encode (self, X ): """编码:输入 -> 潜在表示""" return self .encoder.forward(X) def decode (self, encoded ): """解码:潜在表示 -> 重构""" return self .decoder.forward(encoded) def forward (self, X ): """前向传播:编码 -> 解码""" encoded = self .encode(X) decoded = self .decode(encoded) return decoded def train (self, X, epochs=1000 ): """训练自编码器""" for epoch in range (epochs): reconstructed = self .forward(X) loss = np.mean((X - reconstructed) ** 2 ) if epoch % 100 == 0 : print (f"Epoch {epoch} , Loss: {loss:.4 f} " )
变分自编码器(VAE) VAE 在自编码器基础上,学习数据的概率分布。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class VAE : def __init__ (self, input_dim, latent_dim ): self .latent_dim = latent_dim self .encoder_mean = NeuralNetwork([input_dim, 128 , latent_dim]) self .encoder_logvar = NeuralNetwork([input_dim, 128 , latent_dim]) self .decoder = NeuralNetwork([latent_dim, 128 , input_dim]) def encode (self, X ): """编码:输出潜在空间的均值和方差""" mean = self .encoder_mean.forward(X) logvar = self .encoder_logvar.forward(X) return mean, logvar def reparameterize (self, mean, logvar ): """重参数化技巧""" std = np.exp(0.5 * logvar) epsilon = np.random.randn(*std.shape) return mean + std * epsilon def decode (self, z ): """解码""" return self .decoder.forward(z) def forward (self, X ): """前向传播""" mean, logvar = self .encode(X) z = self .reparameterize(mean, logvar) reconstructed = self .decode(z) return reconstructed, mean, logvar def loss (self, X, reconstructed, mean, logvar ): """VAE 损失:重构损失 + KL 散度""" recon_loss = np.mean((X - reconstructed) ** 2 ) kl_loss = -0.5 * np.sum (1 + logvar - mean**2 - np.exp(logvar)) return recon_loss + kl_loss
注意力机制基础 注意力机制允许模型关注输入的不同部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Attention : def __init__ (self, hidden_dim ): self .hidden_dim = hidden_dim self .W_q = np.random.randn(hidden_dim, hidden_dim) * 0.1 self .W_k = np.random.randn(hidden_dim, hidden_dim) * 0.1 self .W_v = np.random.randn(hidden_dim, hidden_dim) * 0.1 def forward (self, query, key, value ): """计算注意力""" Q = query @ self .W_q K = key @ self .W_k V = value @ self .W_v scores = Q @ K.T / np.sqrt(self .hidden_dim) attention_weights = softmax(scores, axis=1 ) output = attention_weights @ V return output, attention_weights
性能优化 计算优化 1. 向量化操作
1 2 3 4 5 6 7 8 9 10 11 def slow_forward (X, weights, bias ): output = np.zeros((X.shape[0 ], weights.shape[1 ])) for i in range (X.shape[0 ]): for j in range (weights.shape[1 ]): output[i, j] = np.sum (X[i] * weights[:, j]) + bias[j] return output def fast_forward (X, weights, bias ): return X @ weights + bias
2. 使用 NumPy 优化
1 2 3 4 def einsum_example (A, B, C ): return np.einsum('ij,jk,ik->i' , A, B, C)
内存优化 1. 梯度检查点
1 2 3 4 5 6 7 8 9 10 class CheckpointedNetwork : def forward (self, X, checkpoint=False ): if checkpoint: pass else : pass
2. 混合精度训练
1 2 3 X_float16 = X.astype(np.float16)
实践建议 开发流程
从简单开始
使用小数据集测试
逐步调试
监控训练
常见错误
维度不匹配
1 2 3 4 5 6 output = X @ weights assert X.shape[1 ] == weights.shape[0 ], "维度不匹配" output = X @ weights
忘记转置
1 2 3 4 5 gradient = X @ delta gradient = X.T @ delta
激活函数应用错误
1 2 3 4 5 6 7 8 output = sigmoid(linear_output) if task == 'classification' : output = sigmoid(linear_output) elif task == 'regression' : output = linear_output
总结 核心要点回顾
神经网络基础
神经元模型和感知机
多层感知机(MLP)
前向传播
反向传播算法
激活函数
Sigmoid、Tanh、ReLU
选择合适的激活函数
损失函数和优化器
正则化技术
常见问题
学习路径
基础阶段 :理解神经元、感知机、前向传播
进阶阶段 :掌握反向传播、实现完整 MLP
高级阶段 :学习正则化、优化技巧、解决实际问题
下一步学习方向
卷积神经网络(CNN) :图像识别和处理
循环神经网络(RNN/LSTM) :序列数据和自然语言处理
Transformer :注意力机制和现代 NLP
生成模型 :GAN、VAE、扩散模型
强化学习 :决策和游戏 AI
参考资料: