神经网络概述
浅层神经网络(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_split
class ShallowNeuralNetwork:
def __init__(self, input_size, hidden_size, activation='relu', learning_rate=0.01, epochs=1000):
self.input_size = input_size
self.hidden_size = hidden_size
self.lr = learning_rate
self.epochs = epochs
self.activation_type = activation
# 初始化参数
self.W1 = np.random.randn(hidden_size, input_size) * 0.01
self.b1 = np.zeros((hidden_size, 1))
self.W2 = np.random.randn(1, hidden_size) * 0.01
self.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_derivative
elif self.activation_type == 'leaky_relu':
return leaky_relu, leaky_relu_derivative
else: # 默认使用ReLU
return relu, relu_derivative
def _sigmoid(self, z):
"""输出层激活函数"""
return 1 / (1 + np.exp(-z))
def _forward_propagation(self, X):
"""前向传播"""
# 隐藏层计算
self.Z1 = np.dot(self.W1, X) + self.b1
self.A1 = self.activation(self.Z1)
# 输出层计算
self.Z2 = np.dot(self.W2, self.A1) + self.b2
self.A2 = self._sigmoid(self.Z2)
return self.A2
def _backward_propagation(self, X, Y):
"""反向传播"""
m = X.shape[1] # 样本数
# 输出层梯度
dZ2 = self.A2 - Y
dW2 = (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, db2
def _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 loss
def fit(self, X, Y):
"""训练模型"""
# 转置数据以匹配网络维度
X = X.T
Y = 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 * dW1
self.b1 -= self.lr * db1
self.W2 -= self.lr * dW2
self.b2 -= self.lr * db2
# 每100次迭代打印损失
if epoch % 100 == 0:
print(f"Epoch {epoch}, Loss: {loss:.4f}")
return losses
def predict(self, X, threshold=0.5):
"""预测类别"""
X = X.T
A2 = self._forward_propagation(X)
predictions = (A2 > threshold).astype(int)
return predictions.ravel()
def predict_prob(self, X):
"""预测概率"""
X = X.T
return self._forward_propagation(X).ravel()
# 激活函数实现
def tanh(z):
return np.tanh(z)
def tanh_derivative(z):
return 1 - np.tanh(z)**2
def 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() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, 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.01
self.b1 = np.zeros((hidden_size, 1))
# ... 其他参数
- 参数初始化:权重使用小随机数,偏置初始化为零
- 激活函数选择:根据参数选择tanh、ReLU或Leaky ReLU
2. 前向传播
def _forward_propagation(self, X):
# 隐藏层计算
self.Z1 = np.dot(self.W1, X) + self.b1
self.A1 = self.activation(self.Z1)
# 输出层计算
self.Z2 = np.dot(self.W2, self.A1) + self.b2
self.A2 = self._sigmoid(self.Z2)
- 隐藏层使用选择的激活函数
- 输出层使用sigmoid函数进行二元分类
3. 反向传播
def _backward_propagation(self, X, Y):
# 输出层梯度
dZ2 = self.A2 - Y
dW2 = (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 * dW1
self.b1 -= self.lr * db1
# ... 其他参数更新
- 迭代训练过程
- 每次迭代包含前向传播、损失计算、反向传播和参数更新
关键概念总结
网络架构:
- 输入层 → 隐藏层 → 输出层
- 隐藏层引入非线性能力
激活函数选择:
函数 优点 缺点 适用场景 Tanh 中心化输出,梯度更强 梯度消失问题 隐藏层 ReLU 计算高效,缓解梯度消失 神经元"死亡"问题 最常用隐藏层 Leaky ReLU 解决神经元死亡问题 额外超参数 需要更稳定训练时 梯度计算:
- 反向传播算法高效计算梯度
- 链式法则分解复杂导数
- 向量化实现提高计算效率
训练技巧:
- 小随机数初始化打破对称性
- 学习率控制更新步长
- 批量梯度下降稳定训练
应用与扩展
浅层神经网络适用于:
- 中小规模数据集
- 中等复杂度的非线性问题
- 二元分类任务
可扩展为:
- 多分类(使用softmax输出)
- 深度神经网络(添加更多隐藏层)
- 不同任务(回归、多标签分类等)
本文展示了神经网络的核心原理,通过调整超参数(隐藏层大小、学习率、激活函数)可以优化模型性能。理解这些基础知识是掌握更复杂深度学习模型的关键。