深度学习之神经网络

正向传播

线性组合

z = wᵀx + b(线性组合),这是神经元的线性计算部分:

diff 复制代码
- w:权重向量,包含了神经元对每个输入特征的重要性权重
- x:输入向量,包含了所有输入特征
- wᵀ:权重向量的转置
- b:偏置项,用于调整神经元的激活阈值
- wᵀx:表示权重向量与输入向量的点积运算
// 对于有3个输入特征的情况:
z = w₁x₁ + w₂x₂ + w₃x₃ + b

z = wᵀx + b的作用

  1. 在预处理阶段添加这些特征
  2. 通过深层网络自动学习这些非线性关系
  3. 使用特殊的网络结构(如多项式网络)

z = wᵀx + b的原因

  1. 普适性和灵活性:
    • wᵀx + b 形式可以为每个输入特征分配不同的权重
    • 通过调整权重 w,可以反映不同特征的重要程度
    • 偏置项 b 提供了额外的自由度,使模型更灵活
  2. 可解释性:
    • 线性组合形式直观且容易理解
    • 每个权重 w 直接表示对应特征的贡献度
    • 便于分析和解释模型的决策过程
  3. 计算效率:
    • 线性运算计算简单,效率高
    • 求导简单,有利于反向传播
    • 易于并行化处理
  4. 非线性能力:虽然单个神经元是线性的,但通过激活函数引入非线性,多层网络叠加可以逼近任意复杂函数,不需要在输入端就引入复杂的非线性变换
  5. 梯度传播:
    • 线性组合的导数形式简单
    • 有利于梯度的稳定传播
    • 减少梯度消失/爆炸的风险

非线性激活:将线性组合的结果通过激活函数进行非线性变换

a = σ(z)(激活函数)

这是神经元的非线性变换部分:

erlang 复制代码
 - z:上一步计算得到的线性组合结果
- σ:激活函数,常见的有:
- Sigmoid: σ(z) = 1/(1+e⁻ᶻ)
- ReLU: σ(z) = max(0,z)
- tanh: σ(z) = (eᶻ-e⁻ᶻ)/(eᶻ+e⁻ᶻ)
- a:神经元的最终输出

激活函数的作用:

diff 复制代码
- 引入非线性:使网络能够学习复杂的非线性关系
- 标准化输出:某些激活函数(如sigmoid)可以将输出压缩到特定区间
- 解决梯度消失/爆炸:某些激活函数(如ReLU)可以缓解这些问题

激活函数的原因

  1. 引入非线性
    • 使网络能够学习和拟合复杂的非线性函数
    • 增强模型的表达能力
    • 能够解决更复杂的现实问题
  2. 特征转换
    • 将输入映射到不同的空间
    • 提取更有意义的特征表示
    • 增加模型的泛化能力
  3. 梯度信息
    • 提供有意义的梯度信息
    • 使得反向传播成为可能
    • 指导网络权重的更新
  4. 防止退化
    • 避免网络退化为简单的线性模型
    • 保持深层网络的学习能力
    • 维持网络的深度优势

损失函数

损失函数用于衡量模型预测值与真实值之间的差距。常见的损失函数包括:

  1. 均方误差(MSE):适用于回归问题
scss 复制代码
// y是真实值,ŷ是预测值
// n是样本数量
MSE = (1/n)∑(y - ŷ)²
  1. 交叉熵损失(Cross Entropy):适用于分类问题
arduino 复制代码
// y是真实标签(one-hot编码)
// ŷ是预测概率
CE = -∑(y * log(ŷ))

反向传播

反向传播是计算神经网络中各参数梯度的算法:

  1. 基本步骤
    • 前向传播计算预测值
    • 计算损失函数值
    • 计算损失函数对各层参数的梯度
    • 更新参数
  2. 链式法则应用
less 复制代码
// L是损失函数
// a是激活函数输出
// z是加权和
// w是权重
∂L/∂w = ∂L/∂a * ∂a/∂z * ∂z/∂w
  1. 梯度计算流程
    • 从输出层开始
    • 逐层向后计算梯度
    • 利用链式法则传递误差

最终结果

  1. 前向传播公式
scss 复制代码
// 隐藏层
z₁ = w₁x + b₁
a₁ = σ(z₁) = 1/(1 + e^(-z₁))

// 输出层
z₂ = w₂a₁ + b₂
ŷ = σ(z₂) = 1/(1 + e^(-z₂))

//损失函数(均方误差)
L = 1/2(y - ŷ)²
  1. 反向传播推导
  • 输出层参数梯度
scss 复制代码
//对w₂的梯度
∂L/∂w₂ = ∂L/∂ŷ * ∂ŷ/∂z₂ * ∂z₂/∂w₂
= -(y - ŷ) * ŷ(1-ŷ) * a₁

//对b₂的梯度
∂L/∂b₂ = ∂L/∂ŷ * ∂ŷ/∂z₂ * ∂z₂/∂b₂
= -(y - ŷ) * ŷ(1-ŷ) * 1
  • 隐藏层参数梯度
css 复制代码
// 对w₁的梯度
∂L/∂w₁ = ∂L/∂ŷ * ∂ŷ/∂z₂ * ∂z₂/∂a₁ * ∂a₁/∂z₁ * ∂z₁/∂w₁
= -(y - ŷ) * ŷ(1-ŷ) * w₂ * a₁(1-a₁) * x

// 对b₁的梯度
∂L/∂b₁ = ∂L/∂ŷ * ∂ŷ/∂z₂ * ∂z₂/∂a₁ * ∂a₁/∂z₁ * ∂z₁/∂b₁
= -(y - ŷ) * ŷ(1-ŷ) * w₂ * a₁(1-a₁) * 1
  1. 最终更新公式
ini 复制代码
// 输出层参数更新
w₂_new = w₂_old - α * ∂L/∂w₂
b₂_new = b₂_old - α * ∂L/∂b₂

// 隐藏层参数更新
w₁_new = w₁_old - α * ∂L/∂w₁
b₁_new = b₁_old - α * ∂L/∂b₁

完整代码

python 复制代码
import numpy as np

class NeuralNetwork:
    def __init__(self, layers):
        """
        初始化神经网络
        layers: 列表,包含每层神经元数量,如[2,3,1]表示2个输入,3个隐藏,1个输出
        """
        self.layers = layers
        self.weights = []
        self.biases = []
        
        # 初始化权重和偏置
        for i in range(len(layers)-1):
            w = np.random.randn(layers[i], layers[i+1]) * 0.01
            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(-x))

    def sigmoid_derivative(self, x):
        """sigmoid导数"""
        return x * (1 - x)

    def forward(self, X):
        """前向传播"""
        self.activations = [X]
        
        for i in range(len(self.weights)):
            net = np.dot(self.activations[-1], self.weights[i]) + self.biases[i]
            self.activations.append(self.sigmoid(net))
        
        return self.activations[-1]

    def backward(self, X, y, learning_rate):
        """反向传播"""
        m = X.shape[0]
        delta = self.activations[-1] - y
        
        for i in range(len(self.weights) - 1, -1, -1):
            dW = np.dot(self.activations[i].T, delta) / m
            db = np.sum(delta, axis=0, keepdims=True) / m
            
            if i > 0:
                delta = np.dot(delta, self.weights[i].T) * self.sigmoid_derivative(self.activations[i])
            
            # 更新权重和偏置
            self.weights[i] -= learning_rate * dW
            self.biases[i] -= learning_rate * db

    def train(self, X, y, epochs, learning_rate):
        """训练神经网络"""
        for epoch in range(epochs):
            # 前向传播
            output = self.forward(X)
            
            # 计算损失
            loss = np.mean(np.square(output - y))
            
            # 反向传播
            self.backward(X, y, learning_rate)
            
            if epoch % 1000 == 0:
                print(f"Epoch {epoch}, Loss: {loss}")

def main():
    # 创建示例数据:XOR问题
    X = np.array([[0,0], [0,1], [1,0], [1,1]])
    y = np.array([[0], [1], [1], [0]])

    # 创建神经网络:2个输入,4个隐藏,1个输出
    nn = NeuralNetwork([2, 4, 1])

    # 训练网络
    nn.train(X, y, epochs=10000, learning_rate=0.1)

    # 测试网络
    print("\n测试结果:")
    predictions = nn.forward(X)
    for i in range(len(X)):
        print(f"输入: {X[i]}, 预测: {predictions[i][0]:.4f}, 实际: {y[i][0]}")

if __name__ == "__main__":
    main()

总结

  1. 神经网络是由一个一个神经元组成,最简单的神经网络:输入层 -> 隐藏层 -> 输出层
  2. 每一个神经元包含了线性变化z = wᵀx + b和激活函数a = σ(z)来你和输入到输出之间的各种关系
  3. 通过链式运算来拟合输入到输出的各种关系,通过方向传播和梯度下降算法使用大量的测试集来不断修正w和b从而提升输入到输出的准确性,来完成识图、预测房价等各种各样的功能
相关推荐
闲人编程几秒前
目标检测:YOLOv5实现与训练
人工智能·pytorch·计算机视觉
lee40071 分钟前
大模型简介
人工智能
用户49430538293803 分钟前
基于GIS数据的即时建筑模型编辑软件
前端·算法·gis
jndingxin10 分钟前
OpenCV图像拼接(2)特征查找与图像匹配之基于仿射变换的图像匹配的一个类cv::detail::AffineBestOf2NearestMatcher
人工智能·opencv·计算机视觉
怪我冷i14 分钟前
LogicFlow介绍
人工智能·学习·大模型
奔跑的废柴20 分钟前
LeetCode 452. 用最少数量的箭引爆气球 java题解
java·算法·leetcode·贪心算法·贪心
kkk1234425 分钟前
AI软件栈:推理框架(二)-Llama CPP1
人工智能·llama
佛州小李哥28 分钟前
在云平台上用Claude 3.7 AI代理自动化电脑图形界面点击操作做表格
人工智能·计算机视觉·ai·语言模型·aws·亚马逊云科技·ai代理
小白白搭建32 分钟前
Linkreate wordpressAI插件 24小时自动生成原创图文,新增从百度、必应搜索引擎自动获取相关下拉关键词
人工智能·搜索引擎·百度·deepseek·wordpressai插件·wordpress免费插件·wordpress自动发文
胡耀超32 分钟前
4.玩转热图(相关矩阵、缺失值、多维相关、聚类热图、时间序列)——Python数据挖掘代码实践
python·机器学习·数据挖掘·matplotlib·聚类·可视化·seaborn