当前位置: 首页 > news >正文

浅层神经网络:原理与Python实现

神经网络概述

浅层神经网络(Single Hidden Layer Neural Network)是最基础的深度学习模型,包含输入层、一个隐藏层输出层。这种网络能够学习非线性关系,解决逻辑回归无法处理的复杂问题。

网络架构示例

我们构建一个具有以下结构的浅层神经网络:

  • 输入层:3个神经元(特征)
  • 隐藏层:4个神经元(使用非线性激活函数)
  • 输出层:1个神经元(二元分类)
输出层
隐藏层
输入层
o
h1
h2
h3
h4
x1
x2
x3

数学表示

  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])

  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 (双曲正切)

Tanh函数图
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+ezezez

导数:
g ′ ( z ) = 1 − g ( z ) 2 g'(z) = 1 - g(z)^2 g(z)=1g(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 (修正线性单元)

ReLU函数图
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

Leaky ReLU 函数图
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)

梯度计算(反向传播)

反向传播通过链式法则计算损失函数对参数的梯度:

先计算输出层梯度,再计算隐藏层梯度

梯度公式

  1. 输出层梯度:
    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=m1dZ[2]

  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](1A[1])2=m1dZ[1]XT=m1dZ[1]

反向传播流程

计算输出层误差 dZ2 = A2 - Y
计算输出层梯度 dW2 = dZ2·A1ᵀ/m
计算隐藏层误差 dZ1 = W2ᵀ·dZ2 ⊙ g' [1]
计算隐藏层梯度 dW1 = dZ1·Xᵀ/m
计算偏置梯度 db2 = sum(dZ2)/m
计算偏置梯度 db1 = sum(dZ1)/m

完整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()
  • 示例输出
损失率函数图
损失率函数图
Leaky ReLU 函数图
可视化决策边界图

代码解析

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# ... 其他参数更新
  • 迭代训练过程
  • 每次迭代包含前向传播、损失计算、反向传播和参数更新

关键概念总结

  1. 网络架构

    • 输入层 → 隐藏层 → 输出层
    • 隐藏层引入非线性能力
  2. 激活函数选择

    函数优点缺点适用场景
    Tanh中心化输出,梯度更强梯度消失问题隐藏层
    ReLU计算高效,缓解梯度消失神经元"死亡"问题最常用隐藏层
    Leaky ReLU解决神经元死亡问题额外超参数需要更稳定训练时
  3. 梯度计算

    • 反向传播算法高效计算梯度
    • 链式法则分解复杂导数
    • 向量化实现提高计算效率
  4. 训练技巧

    • 小随机数初始化打破对称性
    • 学习率控制更新步长
    • 批量梯度下降稳定训练

应用与扩展

浅层神经网络适用于:

  • 中小规模数据集
  • 中等复杂度的非线性问题
  • 二元分类任务

可扩展为:

  • 多分类(使用softmax输出)
  • 深度神经网络(添加更多隐藏层)
  • 不同任务(回归、多标签分类等)

本文展示了神经网络的核心原理,通过调整超参数(隐藏层大小、学习率、激活函数)可以优化模型性能。理解这些基础知识是掌握更复杂深度学习模型的关键。

http://www.dtcms.com/a/266953.html

相关文章:

  • Golang服务端处理Unity 3D游戏地图与碰撞的详细实现
  • docker运行的一些常用命令
  • SAP入门到放弃系列-流程订单-Process Instruction Category-自定义设置
  • QNetworkAccessManager异步请求有时候操作UI控件崩溃问题
  • ASP.NET MVC架构 路由提取
  • 第2期汽车模型数字工程沙龙,世冠科技分享汽车控制系统开发国产应用
  • 飞凌OK3568核心板与FPGA之间PCIe通信测试操作手册
  • FPGA实现40G网卡NIC,基于PCIE4C+40G/50G Ethernet subsystem架构,提供工程源码和技术支持
  • Day05: Python 中的并发和并行(1)
  • 堆的应用(建堆、堆排序、TOP-K问题)
  • 网安系列【3】之深入理解内容安全策略(CSP)
  • 迁移Ubuntu启动文件到另一块硬盘
  • ubuntu 18.04配置镜像源
  • 操作Choose Boot Java Run time for the IDE 导致AS重新安装后依然无法启动(已解决)
  • 考研408《计算机组成原理》复习笔记,第三章(3)——多模块存储器
  • Web前端:全选框的使用
  • Abase和ByteKV存储方案对比
  • 【C#】入门
  • tmux 左下角会话名显示不全的解决方法
  • SpringBoot-规划多模块目录结构
  • 项目介绍:Awesome System Prompts
  • 免费PDF处理软件,支持多种操作
  • 开源项目XYZ.ESB:数据库到数据库(DB->DB)集成
  • 系统架构师
  • Class5多层感知机的从零开始实现
  • Linux awk 命令
  • 浅谈 webshell 构造之如何获取恶意函数
  • chrome插件合集
  • 4 位量化 + FP8 混合精度:ERNIE-4.5-0.3B-Paddle本地部署,重新定义端侧推理效率
  • 【LUT技术专题】CLUT代码讲解