深度学习之神经网络

正向传播

线性组合

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从而提升输入到输出的准确性,来完成识图、预测房价等各种各样的功能
相关推荐
_一条咸鱼_2 分钟前
Python 垃圾回收机制 GC 深度解析(三)
人工智能·深度学习·面试
Tech Synapse25 分钟前
基于Surprise和Flask构建个性化电影推荐系统:从算法到全栈实现
python·算法·flask·协同过滤算法
終不似少年遊*32 分钟前
国产之光DeepSeek架构理解与应用分析04
人工智能·python·深度学习·算法·大模型·ds
天天扭码32 分钟前
一分钟解决 | 高频面试算法题——最大子数组之和
前端·算法·面试
杰杰批37 分钟前
力扣热题100——矩阵
算法·leetcode·矩阵
明月看潮生40 分钟前
青少年编程与数学 02-016 Python数据结构与算法 28课题、图像处理算法
图像处理·python·算法·青少年编程·编程与数学
_GR1 小时前
2025年蓝桥杯第十六届C&C++大学B组真题及代码
c语言·数据结构·c++·算法·贪心算法·蓝桥杯·动态规划
心想事“程”1 小时前
决策树详解+面试常见问题
算法·决策树·机器学习
訾博ZiBo1 小时前
AI日报 - 2025年4月23日
人工智能
羊小猪~~1 小时前
深度学习基础--CNN经典网络之InceptionV3详解与复现(pytorch)
网络·人工智能·pytorch·python·深度学习·机器学习·cnn