浅层神经网络:原理与Python实现
神经网络概述
浅层神经网络(Single Hidden Layer Neural Network)是最基础的深度学习模型,包含输入层、一个隐藏层和输出层。这种网络能够学习非线性关系,解决逻辑回归无法处理的复杂问题。
网络架构示例
我们构建一个具有以下结构的浅层神经网络:
- 输入层:3个神经元(特征)
- 隐藏层:4个神经元(使用非线性激活函数)
- 输出层:1个神经元(二元分类)
数学表示
-
前向传播:
Z [ 1 ] = W [ 1 ] X + b [ 1 ] A [ 1 ] = g [ 1 ] ( Z [ 1 ] ) Z [ 2 ] = W [ 2 ] A [ 1 ] + b [ 2 ] Y ^ = A [ 2 ] = g [ 2 ] ( Z [ 2 ] ) \begin{aligned} Z^{[1]} &= W^{[1]} X + b^{[1]} \\ A^{[1]} &= g^{[1]}(Z^{[1]}) \\ Z^{[2]} &= W^{[2]} A^{[1]} + b^{[2]} \\ \hat{Y} &= A^{[2]} = g^{[2]}(Z^{[2]}) \end{aligned} Z[1]A[1]Z[2]Y^=W[1]X+b[1]=g[1](Z[1])=W[2]A[1]+b[2]=A[2]=g[2](Z[2]) -
参数维度:
- W [ 1 ] W^{[1]} W[1]: (4, 3) 矩阵
- b [ 1 ] b^{[1]} b[1]: (4, 1) 向量
- W [ 2 ] W^{[2]} W[2]: (1, 4) 向量
- b [ 2 ] b^{[2]} b[2]: (1, 1) 标量
激活函数详解
激活函数引入非线性,使神经网络能够学习复杂模式。以下是三种常用激活函数:
1. Tanh (双曲正切)

g ( z ) = e z − e − z e z + e − z g(z) = \frac{e^z - e^{-z}}{e^z + e^{-z}} g(z)=ez+e−zez−e−z
导数:
g ′ ( z ) = 1 − g ( z ) 2 g'(z) = 1 - g(z)^2 g′(z)=1−g(z)2
特点:
- 输出范围: (-1, 1)
- 均值接近0,有助于中心化数据
- 优于sigmoid函数
Tanh 函数存在和 sigmoid 函数一样的缺点:当 z 趋近于无穷大(或无穷小),导数的梯度就趋近于 0 ,这使得梯度算法的速度会减慢。
def tanh(z):return np.tanh(z)def tanh_derivative(z):return 1 - np.tanh(z)**2
2. ReLU (修正线性单元)

g ( z ) = max ( 0 , z ) g(z) = \max(0, z) g(z)=max(0,z)
导数:
g ′ ( z ) = { 1 if z > 0 0 otherwise g'(z) = \begin{cases} 1 & \text{if } z > 0 \\ 0 & \text{otherwise} \end{cases} g′(z)={10if z>0otherwise
特点:
- 当 z > 0 时,梯度始终为1,能提高运算速度
- 缓解梯度消失问题
- 广泛用于隐藏层
- 当 z < 0 时,梯度一直为0,但在实际应用中影响不大
def relu(z):return np.maximum(0, z)def relu_derivative(z):return (z > 0).astype(float)
3. Leaky ReLU

g ( z ) = { z if z > 0 α z otherwise g(z) = \begin{cases} z & \text{if } z > 0 \\ \alpha z & \text{otherwise} \end{cases} g(z)={zαzif z>0otherwise
导数:
g ′ ( z ) = { 1 if z > 0 α otherwise g'(z) = \begin{cases} 1 & \text{if } z > 0 \\ \alpha & \text{otherwise} \end{cases} g′(z)={1αif z>0otherwise
特点:
- 解决ReLU的"死亡神经元"问题
- α \alpha α通常设为0.01
def leaky_relu(z, alpha=0.01):return np.where(z > 0, z, alpha * z)def leaky_relu_derivative(z, alpha=0.01):return np.where(z > 0, 1, alpha)
梯度计算(反向传播)
反向传播通过链式法则计算损失函数对参数的梯度:
先计算输出层梯度,再计算隐藏层梯度
梯度公式
-
输出层梯度:
d Z [ 2 ] = A [ 2 ] − Y d W [ 2 ] = 1 m d Z [ 2 ] A [ 1 ] T d b [ 2 ] = 1 m ∑ d Z [ 2 ] \begin{aligned} dZ^{[2]} &= A^{[2]} - Y \\ dW^{[2]} &= \frac{1}{m} dZ^{[2]} A^{[1]T} \\ db^{[2]} &= \frac{1}{m} \sum dZ^{[2]} \end{aligned} dZ[2]dW[2]db[2]=A[2]−Y=m1dZ[2]A[1]T=m1∑dZ[2] -
隐藏层梯度:
d Z [ 1 ] = W [ 2 ] T d Z [ 2 ] ⊙ g [ 1 ] ′ ( Z [ 1 ] ) = W [ 2 ] T d Z [ 2 ] ⊙ ( 1 − A [ 1 ] ) 2 d W [ 1 ] = 1 m d Z [ 1 ] X T d b [ 1 ] = 1 m ∑ d Z [ 1 ] \begin{aligned} dZ^{[1]} &= W^{[2]T} dZ^{[2]} \odot g^{[1]\prime}(Z^{[1]})= W^{[2]T} dZ^{[2]} \odot (1-A^{[1]})^2 \\ dW^{[1]} &= \frac{1}{m} dZ^{[1]} X^T \\ db^{[1]} &= \frac{1}{m} \sum dZ^{[1]} \end{aligned} dZ[1]dW[1]db[1]=W[2]TdZ[2]⊙g[1]′(Z[1])=W[2]TdZ[2]⊙(1−A[1])2=m1dZ[1]XT=m1∑dZ[1]
反向传播流程
完整Python实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_splitclass ShallowNeuralNetwork:def __init__(self, input_size, hidden_size, activation='relu', learning_rate=0.01, epochs=1000):self.input_size = input_sizeself.hidden_size = hidden_sizeself.lr = learning_rateself.epochs = epochsself.activation_type = activation# 初始化参数self.W1 = np.random.randn(hidden_size, input_size) * 0.01self.b1 = np.zeros((hidden_size, 1))self.W2 = np.random.randn(1, hidden_size) * 0.01self.b2 = np.zeros((1, 1))# 设置激活函数self.activation, self.activation_derivative = self._get_activation_functions()def _get_activation_functions(self):"""选择激活函数及其导数"""if self.activation_type == 'tanh':return tanh, tanh_derivativeelif self.activation_type == 'leaky_relu':return leaky_relu, leaky_relu_derivativeelse: # 默认使用ReLUreturn relu, relu_derivativedef _sigmoid(self, z):"""输出层激活函数"""return 1 / (1 + np.exp(-z))def _forward_propagation(self, X):"""前向传播"""# 隐藏层计算self.Z1 = np.dot(self.W1, X) + self.b1self.A1 = self.activation(self.Z1)# 输出层计算self.Z2 = np.dot(self.W2, self.A1) + self.b2self.A2 = self._sigmoid(self.Z2)return self.A2def _backward_propagation(self, X, Y):"""反向传播"""m = X.shape[1] # 样本数# 输出层梯度dZ2 = self.A2 - YdW2 = (1/m) * np.dot(dZ2, self.A1.T)db2 = (1/m) * np.sum(dZ2, axis=1, keepdims=True)# 隐藏层梯度dZ1 = np.dot(self.W2.T, dZ2) * self.activation_derivative(self.Z1)dW1 = (1/m) * np.dot(dZ1, X.T)db1 = (1/m) * np.sum(dZ1, axis=1, keepdims=True)return dW1, db1, dW2, db2def _compute_loss(self, Y):"""计算交叉熵损失"""m = Y.shape[1]loss = - (1/m) * np.sum(Y * np.log(self.A2) + (1 - Y) * np.log(1 - self.A2))return lossdef fit(self, X, Y):"""训练模型"""# 转置数据以匹配网络维度X = X.TY = Y.reshape(1, -1)losses = []for epoch in range(self.epochs):# 前向传播_ = self._forward_propagation(X)# 计算损失loss = self._compute_loss(Y)losses.append(loss)# 反向传播dW1, db1, dW2, db2 = self._backward_propagation(X, Y)# 更新参数self.W1 -= self.lr * dW1self.b1 -= self.lr * db1self.W2 -= self.lr * dW2self.b2 -= self.lr * db2# 每100次迭代打印损失if epoch % 100 == 0:print(f"Epoch {epoch}, Loss: {loss:.4f}")return lossesdef predict(self, X, threshold=0.5):"""预测类别"""X = X.TA2 = self._forward_propagation(X)predictions = (A2 > threshold).astype(int)return predictions.ravel()def predict_prob(self, X):"""预测概率"""X = X.Treturn self._forward_propagation(X).ravel()# 激活函数实现
def tanh(z):return np.tanh(z)def tanh_derivative(z):return 1 - np.tanh(z)**2def relu(z):return np.maximum(0, z)def relu_derivative(z):return (z > 0).astype(float)def leaky_relu(z, alpha=0.01):return np.where(z > 0, z, alpha * z)def leaky_relu_derivative(z, alpha=0.01):return np.where(z > 0, 1, alpha)# 测试与可视化
if __name__ == "__main__":# 创建非线性可分数据集X, y = make_classification(n_samples=500, n_features=3, n_redundant=0,n_informative=3, n_clusters_per_class=1,flip_y=0.1, class_sep=1.5, random_state=42)# 划分训练测试集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 创建并训练模型model = ShallowNeuralNetwork(input_size=3, hidden_size=4, activation='relu', learning_rate=0.1, epochs=2000)losses = model.fit(X_train, y_train)# 评估模型train_preds = model.predict(X_train)test_preds = model.predict(X_test)train_acc = np.mean(train_preds == y_train)test_acc = np.mean(test_preds == y_test)print(f"\n训练准确率: {train_acc:.4f}")print(f"测试准确率: {test_acc:.4f}")# 可视化训练过程plt.figure(figsize=(10, 6))plt.plot(losses)plt.title("Training Loss over Epochs")plt.xlabel("Epochs")plt.ylabel("Loss")plt.grid(True)plt.show()# 可视化决策边界 (使用前两个特征)plt.figure(figsize=(10, 8))plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=plt.cm.Paired, edgecolors='k', s=50, label="Training Data")plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=plt.cm.Paired, marker='s', edgecolors='k', s=50, label="Test Data")# 创建网格x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1xx, yy = np.meshgrid(np.linspace(x_min, x_max, 100),np.linspace(y_min, y_max, 100))# 固定第三个特征为中值zz = np.median(X[:, 2]) * np.ones_like(xx)grid = np.c_[xx.ravel(), yy.ravel(), zz.ravel()]# 预测概率probs = model.predict_prob(grid).reshape(xx.shape)# 绘制决策边界plt.contourf(xx, yy, probs > 0.5, alpha=0.3, cmap=plt.cm.Paired)plt.contour(xx, yy, probs, levels=[0.5], colors='red', linewidths=2)plt.title("Decision Boundary Visualization")plt.xlabel("Feature 1")plt.ylabel("Feature 2")plt.legend()plt.colorbar(plt.cm.ScalarMappable(cmap=plt.cm.Paired), label="Probability")plt.show()
- 示例输出


代码解析
1. 神经网络类结构
class ShallowNeuralNetwork:def __init__(self, input_size, hidden_size, activation='relu', learning_rate=0.01, epochs=1000):# 参数初始化self.W1 = np.random.randn(hidden_size, input_size) * 0.01self.b1 = np.zeros((hidden_size, 1))# ... 其他参数
- 参数初始化:权重使用小随机数,偏置初始化为零
- 激活函数选择:根据参数选择tanh、ReLU或Leaky ReLU
2. 前向传播
def _forward_propagation(self, X):# 隐藏层计算self.Z1 = np.dot(self.W1, X) + self.b1self.A1 = self.activation(self.Z1)# 输出层计算self.Z2 = np.dot(self.W2, self.A1) + self.b2self.A2 = self._sigmoid(self.Z2)
- 隐藏层使用选择的激活函数
- 输出层使用sigmoid函数进行二元分类
3. 反向传播
def _backward_propagation(self, X, Y):# 输出层梯度dZ2 = self.A2 - YdW2 = (1/m) * np.dot(dZ2, self.A1.T)# 隐藏层梯度dZ1 = np.dot(self.W2.T, dZ2) * self.activation_derivative(self.Z1)dW1 = (1/m) * np.dot(dZ1, X.T)
- 计算输出层和隐藏层的梯度
- 使用激活函数的导数进行链式法则计算
4. 训练过程
def fit(self, X, Y):for epoch in range(self.epochs):# 前向传播_ = self._forward_propagation(X)# 计算损失loss = self._compute_loss(Y)# 反向传播dW1, db1, dW2, db2 = self._backward_propagation(X, Y)# 更新参数self.W1 -= self.lr * dW1self.b1 -= self.lr * db1# ... 其他参数更新
- 迭代训练过程
- 每次迭代包含前向传播、损失计算、反向传播和参数更新
关键概念总结
-
网络架构:
- 输入层 → 隐藏层 → 输出层
- 隐藏层引入非线性能力
-
激活函数选择:
函数 优点 缺点 适用场景 Tanh 中心化输出,梯度更强 梯度消失问题 隐藏层 ReLU 计算高效,缓解梯度消失 神经元"死亡"问题 最常用隐藏层 Leaky ReLU 解决神经元死亡问题 额外超参数 需要更稳定训练时 -
梯度计算:
- 反向传播算法高效计算梯度
- 链式法则分解复杂导数
- 向量化实现提高计算效率
-
训练技巧:
- 小随机数初始化打破对称性
- 学习率控制更新步长
- 批量梯度下降稳定训练
应用与扩展
浅层神经网络适用于:
- 中小规模数据集
- 中等复杂度的非线性问题
- 二元分类任务
可扩展为:
- 多分类(使用softmax输出)
- 深度神经网络(添加更多隐藏层)
- 不同任务(回归、多标签分类等)
本文展示了神经网络的核心原理,通过调整超参数(隐藏层大小、学习率、激活函数)可以优化模型性能。理解这些基础知识是掌握更复杂深度学习模型的关键。