图解人工智能的数学基础(最优化)

简介: 本文深入解析人工智能中最优化问题的核心:通过最小化损失函数来训练模型。涵盖回归(MSE)与分类(交叉熵)任务的典型损失函数,详解梯度下降原理及BGD、SGD、Mini-batch等算法差异,并介绍Momentum、Adam等现代优化技巧,辅以PyTorch代码实现。

 人工智能中的最优化问题

   机器学习(如训练神经网络)的全部过程,就是寻找一组参数,使得模型在特定任务上的错误率

最小。这,就是最优化问题。

最优化的基本数学模型如下公式所示:

image.gif

image.gif

image.gif


损失函数(Loss Function):衡量“好坏”的标准

目标函数的选择完全取决于你希望模型完成什么任务。不同的任务需要不同的“量尺”来衡量错误

适用于回归问题 (Regression)

回归问题是预测一个连续数值(如房价、股票价格、气温)

均方误差 (Mean Squared Error, MSE)

image.gif 编辑

import torch
import torch.nn as nn
# --- 均方误差损失 (MSELoss) ---
print("--- 均方误差损失 (MSELoss) ---")
# 模拟回归任务的预测值和真实值
# 预测值 (模型的输出)
predictions_mse = torch.tensor([10.0, 12.0, 15.0], requires_grad=True)
# 真实值 (数据的标签)
targets_mse = torch.tensor([11.0, 13.0, 14.0])
# 实例化 MSELoss
mse_loss_fn = nn.MSELoss()
# 计算损失
loss_mse = mse_loss_fn(predictions_mse, targets_mse)
print(f"预测值: {predictions_mse}")
print(f"真实值: {targets_mse}")
print(f"MSE 损失: {loss_mse.item():.4f}") # .item() 获取张量中的标量值
# 演示反向传播 (梯度计算)
loss_mse.backward()
print(f"MSE 损失对预测值的梯度: {predictions_mse.grad}")
print("-" * 30)

image.gif

image.gif

适用于分类问题 (Classification)

分类问题是预测一个离散的类别(如猫/狗、垃圾邮件/非垃圾邮件)

交叉熵损失 (Cross-Entropy Loss)

这是几乎所有现代分类任务(如图像识别、自然语言处理)的首选损失函数

image.gif 编辑

import torch
import torch.nn as nn
# --- 二分类交叉熵损失 (BCELoss 和 BCEWithLogitsLoss) ---
print("--- 二分类交叉熵损失 (BCELoss & BCEWithLogitsLoss) ---")
# 模拟二分类任务的预测值和真实值
# 真实标签 (0 或 1)
targets_bce = torch.tensor([1.0, 0.0, 1.0]) 
# ----------------- 使用 nn.BCELoss -----------------
# 预测概率 (0到1之间)。注意:如果模型输出的是 logits (Logit是Sigmoid之前的原始输出值), 
# 则需要先手动通过 sigmoid 激活函数。
predictions_bce_prob = torch.tensor([0.9, 0.2, 0.8], requires_grad=True) 
bce_loss_fn = nn.BCELoss()
loss_bce_prob = bce_loss_fn(predictions_bce_prob, targets_bce)
print("\n--- 使用 nn.BCELoss (需要手动 Sigmoid) ---")
print(f"预测概率: {predictions_bce_prob}")
print(f"真实标签: {targets_bce}")
print(f"BCELoss 损失: {loss_bce_prob.item():.4f}")
loss_bce_prob.backward()
print(f"BCELoss 对预测概率的梯度: {predictions_bce_prob.grad}")
# ----------------- 使用 nn.BCEWithLogitsLoss (推荐) -----------------
# 模型的原始输出 (logits),无需手动 sigmoid
predictions_bce_logits = torch.tensor([2.2, -1.4, 1.8], requires_grad=True) # 对应 sigmoid(2.2)=0.9, sigmoid(-1.4)=0.2, sigmoid(1.8)=0.8
bce_logits_loss_fn = nn.BCEWithLogitsLoss()
loss_bce_logits = bce_logits_loss_fn(predictions_bce_logits, targets_bce)
print("\n--- 使用 nn.BCEWithLogitsLoss (内部包含 Sigmoid, 更稳定) ---")
print(f"预测 Logits: {predictions_bce_logits}")
print(f"真实标签: {targets_bce}")
print(f"BCEWithLogitsLoss 损失: {loss_bce_logits.item():.4f}")
loss_bce_logits.backward()
print(f"BCEWithLogitsLoss 对 Logits 的梯度: {predictions_bce_logits.grad}")
print("-" * 30)

image.gif

多分类交叉熵损失

image.gif 编辑

import torch
import torch.nn as nn
# --- 多分类交叉熵损失 (CrossEntropyLoss) ---
print("--- 多分类交叉熵损失 (CrossEntropyLoss) ---")
# 模拟三分类任务的预测值和真实值 (例如:猫, 狗, 鸟)
num_classes = 3
# 模型的原始输出 (logits)。假设 batch_size=2
# 第一个样本: 倾向于第0类 (猫)
# 第二个样本: 倾向于第1类 (狗)
predictions_ce_logits = torch.tensor([
    [2.0, 0.5, -1.0],  # 第一个样本的 logits (对应 Cat, Dog, Bird)
    [0.1, 1.5, 0.3]   # 第二个样本的 logits
], requires_grad=True)
# 真实类别索引 (不需要 One-Hot 编码)
# 第一个样本真实是第0类 (猫)
# 第二个样本真实是第1类 (狗)
targets_ce = torch.tensor([0, 1]) 
# 实例化 CrossEntropyLoss
cross_entropy_loss_fn = nn.CrossEntropyLoss()
# 计算损失
loss_ce = cross_entropy_loss_fn(predictions_ce_logits, targets_ce)
print(f"预测 Logits:\n{predictions_ce_logits}")
print(f"真实类别索引: {targets_ce}")
print(f"CrossEntropyLoss 损失: {loss_ce.item():.4f}")
# 演示反向传播
loss_ce.backward()
print(f"CrossEntropyLoss 对预测 Logits 的梯度:\n{predictions_ce_logits.grad}")
print("-" * 30)

image.gif

image.gif


优化算法的核心——梯度下降

目的:求损失函数的最小值和对应的参数

原理:梯度方向是函数值变化最快的方向

image.gif 编辑

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.animation import FuncAnimation
# --- 1. 定义目标函数和梯度 ---
# 假设目标函数是简单的二次函数 (简化版,类似上图中的盆地)
def loss_function(w, b):
    # J(w, b) = (w - w_optimal)^2 + (b - b_optimal)^2 + offset
    return (w - 0.05)**2 + (b + 0.5)**2 + 0.2
# 定义梯度(偏导数)
def gradient(w, b):
    dw = 2 * (w - 0.05) # 损失函数对 w 的偏导
    db = 2 * (b + 0.5)  # 损失函数对 b 的偏导
    return dw, db
# --- 2. 运行梯度下降并记录历史 ---
def run_gd(start_w, start_b, alpha, n_iterations):
    w, b = start_w, start_b
    history = [(w, b, loss_function(w, b))]
    for _ in range(n_iterations):
        dw, db = gradient(w, b)
        
        # 参数更新核心公式
        w = w - alpha * dw
        b = b - alpha * db
        
        current_loss = loss_function(w, b)
        history.append((w, b, current_loss))
    return np.array(history)
# 设置参数
alpha = 0.05       # 学习率
n_iterations = 50  # 迭代次数 (动画帧数)
start_w, start_b = 0.5, 0.5 # 随机起点
path_history = run_gd(start_w, start_b, alpha, n_iterations)
# --- 3. 3D 可视化设置 ---
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
# 生成曲面数据
w_range = np.linspace(path_history[:, 0].min() - 0.1, path_history[:, 0].max() + 0.1, 100)
b_range = np.linspace(path_history[:, 1].min() - 0.1, path_history[:, 1].max() + 0.1, 100)
W, B = np.meshgrid(w_range, b_range)
Z = loss_function(W, B)
# 绘制曲面
ax.plot_surface(W, B, Z, cmap=plt.cm.coolwarm, alpha=0.8, antialiased=True)
# 设置轴标签
ax.set_xlabel('w', fontsize=16)
ax.set_ylabel('b', fontsize=16)
ax.set_zlabel('costs', fontsize=16)
ax.set_title('梯度下降 3D 动态可视化', fontsize=18)
# --- 4. 动画函数 ---
# 初始化路径线和当前点
line, = ax.plot([], [], [], 'k--', alpha=0.6, label='下降路径') # 虚线路径
point, = ax.plot([], [], [], 'o', color='navy', markersize=8, label='当前参数') # 移动的点
def animate(i):
    # 更新虚线路径 (从起点到第 i 步)
    line.set_data(path_history[:i, 0], path_history[:i, 1])
    line.set_3d_properties(path_history[:i, 2])
    
    # 更新当前点的位置
    point.set_data(path_history[i:i+1, 0], path_history[i:i+1, 1])
    point.set_3d_properties(path_history[i:i+1, 2])
    
    # 更新迭代次数标签 (对应您图中的 'epochs: 140000')
    ax.legend([line, point], [f'迭代次数: {i}', '当前参数'], loc='upper left')
    return line, point,
# 5. 创建动画并显示/保存
ani = FuncAnimation(fig, animate, frames=len(path_history), interval=100, blit=False)
# 在 Jupyter/Colab 中,可以使用 HTML(ani.to_jshtml()) 显示
# 在本地,可以使用 ani.save('gradient_descent.gif', writer='pillow') 保存为GIF
plt.show()

image.gif

分类

更新参数                                                                                            局部最优解    

批量梯度下降(BGD)               基于所有样本                                   可能停留  

随机梯度下降(SGD)               基于一个样本                                    可跳出  

小批量梯度下降(MGD)           基于一个小批量样本                         可跳出    

 

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
import matplotlib.pyplot as plt
# --- 1. 模拟数据 (与之前相同) ---
true_weight = 2.0
true_bias = 3.0
X_train = torch.randn(100, 1) * 10 # 100个样本
y_train = true_weight * X_train + true_bias + torch.randn(100, 1) * 2
# 将数据打包成 TensorDataset
train_dataset = TensorDataset(X_train, y_train)
# --- 2. 定义模型 ---
class LinearRegression(nn.Module):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.linear = nn.Linear(1, 1)
    def forward(self, x):
        return self.linear(x)
# --- 3. 定义损失函数 ---
criterion = nn.MSELoss()
# --- 4. 训练函数 (封装训练过程,方便复用) ---
def train_model(model_instance, optimizer_instance, data_loader_instance, num_epochs, description):
    loss_history = []
    print(f"\n--- 开始训练: {description} ---")
    
    for epoch in range(num_epochs):
        current_epoch_loss = 0.0
        num_batches = 0
        for batch_X, batch_y in data_loader_instance:
            optimizer_instance.zero_grad()
            outputs = model_instance(batch_X)
            loss = criterion(outputs, batch_y)
            loss.backward()
            optimizer_instance.step()
            
            current_epoch_loss += loss.item()
            num_batches += 1
        
        # 记录每个 epoch 的平均损失
        avg_epoch_loss = current_epoch_loss / num_batches
        loss_history.append(avg_epoch_loss)
        
        if (epoch + 1) % (num_epochs // 5) == 0: # 每 1/5 打印一次
            print(f'Epoch [{epoch+1}/{num_epochs}], Avg Loss: {avg_epoch_loss:.4f}')
            
    print(f"--- 训练完成: {description} ---")
    print(f"最终模型参数: W={model_instance.linear.weight.item():.4f}, B={model_instance.linear.bias.item():.4f}")
    return loss_history
# --- 5. 实例化模型和优化器 (每次实验都重新实例化,避免参数污染) ---
# --- 实验 1: 批量梯度下降 (Batch Gradient Descent, BGD) ---
# batch_size = 总样本数,确保每个 epoch 只进行一次参数更新
model_bgd = LinearRegression()
optimizer_bgd = optim.SGD(model_bgd.parameters(), lr=0.001) # BGD通常需要较小的学习率,否则容易震荡
dataloader_bgd = DataLoader(dataset=train_dataset, batch_size=len(X_train), shuffle=False) # BGD一般不shuffle
loss_history_bgd = train_model(model_bgd, optimizer_bgd, dataloader_bgd, num_epochs=200, description="批量梯度下降 (BGD)")
# --- 实验 2: 随机梯度下降 (Stochastic Gradient Descent, SGD) ---
# batch_size = 1,每次只用一个样本
model_sgd = LinearRegression()
optimizer_sgd = optim.SGD(model_sgd.parameters(), lr=0.01) # SGD通常需要较大的学习率,因为梯度噪声大
dataloader_sgd = DataLoader(dataset=train_dataset, batch_size=1, shuffle=True) # SGD通常shuffle
loss_history_sgd = train_model(model_sgd, optimizer_sgd, dataloader_sgd, num_epochs=200, description="随机梯度下降 (SGD)")
# --- 实验 3: 小批量梯度下降 (Mini-batch Gradient Descent, MGD) ---
# batch_size = 一个合理的小批量大小 (例如 16, 32, 64)
model_mgd = LinearRegression()
optimizer_mgd = optim.SGD(model_mgd.parameters(), lr=0.01) # MGD学习率也比较灵活
dataloader_mgd = DataLoader(dataset=train_dataset, batch_size=16, shuffle=True) # MGD通常shuffle
loss_history_mgd = train_model(model_mgd, optimizer_mgd, dataloader_mgd, num_epochs=200, description="小批量梯度下降 (MGD)")

image.gif

image.gif

优化技巧

小批量梯度下降 (Mini-batch GD):每个批的反向传播后就直接对参数进行更新。

带动量的随机梯度下降 (Momentum):通过计算前几步的滑动平均来计算动量,用于当前步的更新。

Nesterov 加速的梯度下降 (Nesterov Accelerated GD):不算当前位置的梯度,而是计算这个位置大概的梯度。

自适应梯度Adagrad:对每个参数的学习率惊醒不同动态的改变,首先得到的是每个参数的梯度,在更新时候,学习率除于一个正则项。

自适应动量Adam:不仅对梯度进行自适应的调整,也对动量进行自适应的调整。

image.gif

import torch
import torch.nn as nn
import torch.optim as optim
# 假设模型和损失函数已经定义
# model = MyModel() 
# criterion = nn.CrossEntropyLoss()
# 假设 model 已经实例化
# 示例:定义模型参数
model_params = model.parameters() 
learning_rate = 0.001 
# 1. 动量法 (Momentum) 的实现
# PyTorch 的 optim.SGD 可以通过设置 momentum 参数实现动量法
# 通常 momentum=0.9
optimizer_momentum = optim.SGD(model_params, lr=learning_rate, momentum=0.9)
# 2. Nesterov 加速的梯度下降 (NAG) 的实现
# 在 optim.SGD 中设置 nesterov=True
# 注意:只有当 momentum > 0 时,nesterov 才会生效
optimizer_nesterov = optim.SGD(model_params, lr=learning_rate, momentum=0.9, nesterov=True)
# 3. 自适应梯度 (Adagrad) 的实现
# 学习率 lr 仍然需要传入
optimizer_adagrad = optim.Adagrad(model_params, lr=0.01)
# 4. 自适应动量 (Adam) 的实现
# Adam 不需要动量因子,它使用 beta1 和 beta2 参数,默认值通常很好
# lr=0.001 是 Adam 的常见起始学习率
optimizer_adam = optim.Adam(model_params, lr=0.001)

image.gif

image.gif


目录
相关文章
|
5月前
|
机器学习/深度学习 数据挖掘 PyTorch
PyTorch深度学习实战 |手算​​FCN全卷积神经网络
本文介绍了FCN-8s语义分割网络的实现细节。首先解释了语义分割的概念及其与图像分类的区别,重点分析了FCN网络结构中的全卷积化、上采样和跳跃连接三个关键技术。全卷积化将传统CNN的全连接层改为卷积层,实现像素级分类;上采样通过双线性插值恢复特征图尺寸;跳跃连接则融合高低层特征以提升细节表现。文章详细推导了损失函数的计算过程,并提供了完整的PyTorch实现代码,包括双线性插值权重初始化、VGG16骨干网络和FCN-8s主体结构。最后通过测试验证了模型能正确输出与输入尺寸匹配的预测结果。
463 3
|
5月前
|
机器学习/深度学习 人工智能 算法
图解人工智能的数学基础(高数)
本文系统讲解微积分核心概念:数列与递推、极限(含无穷小/大)、导数(含中值定理、泰勒公式)、积分(不定/定/变上限/反常)及微分方程,并延伸至多元函数、偏导数、链式法则与二重积分,结合Sigmoid函数、药物衰减等实例及SymPy代码演示,突出其在AI与工程中的应用基础。
465 5
|
5月前
|
机器学习/深度学习 PyTorch 测试技术
PyTorch深度学习实战 |多头注意力机制
摘要:本文详细介绍了Transformer中的多头自注意力机制,从整体结构到实现细节,包括四部分内容:(1)多头自注意力的基本架构;(2)内部计算流程解析;(3)注意力计算公式详解;(4)代码实现。重点阐述了多头并行的计算方式、缩放点积注意力的计算步骤(QK转置、缩放、softmax和加权求和),以及残差连接和层归一化的作用。通过"Are you OK?"示例展示了输入张量如何经过8个64维注意力头处理后拼接成512维输出。文章最后提供了完整的PyTorch实现代码,并附测试用例验证模型
357 0
|
5月前
|
机器学习/深度学习 存储 人工智能
图解人工智能的数学基础(线性代数)
本文系统讲解线性代数核心概念,涵盖向量(定义、几何/坐标表示、内积)、矩阵(含义、运算、秩、逆、相似、分解)、行列式(几何意义与变换关系)、线性方程组、特征值与特征向量、二次型、向量空间及范数等,强调其在AI与神经网络中的实际应用。
648 7
|
5月前
|
机器学习/深度学习 自然语言处理 PyTorch
PyTorch深度学习实战 |手动计算 Transformer和完整的代码实现
本文介绍了基于PyTorch实现Transformer模型的完整过程。主要内容包括:1)Transformer架构的核心组件实现,如多头注意力机制、位置前馈网络、位置编码等;2)模型构建步骤,包括词嵌入层、编码器/解码器块和输出层的实现;3)完整的训练流程,包含数据处理、损失计算和参数优化;4)评估方法验证模型性能。文章通过代码示例详细展示了如何从零开始构建Transformer,并应用于机器翻译任务,同时对模型各层的输入输出维度进行了说明。该实现可作为深度学习实践者学习Transformer架构的实用指南
414 0
|
5月前
|
机器学习/深度学习 编解码 算法
PyTorch深度学习实战 |手算​​U-net
本文详细解析了U-Net网络架构及其在医学图像分割中的应用。重点对比了U-Net与FCN的核心区别:U-Net采用特征拼接(Concat)保留所有层级信息,而FCN使用特征相加(Add)进行融合。文章深入剖析了U-Net的编码器-瓶颈-解码器结构,解释了其独特的裁剪拼接机制和Overlap-tile策略,并提供了完整的PyTorch实现代码。现代U-Net通过SamePadding实现了输入输出尺寸一致,显著提升了分割精度。文章还探讨了弹性形变数据增强和带空间权重的损失函数设计,为医学图像分析提供了实用解决
434 2
|
5月前
|
机器学习/深度学习 数据可视化 PyTorch
PyTorch深度学习实战 | 基于LSTM的时间序列预测任务
本文介绍了使用LSTM模型预测印度德里市平均温度的两个项目。项目1对温度数据进行归一化处理,采用滑动窗口法构建监督学习样本,设计5层LSTM网络结构,并详细说明了模型训练过程及评估方法。项目2在数据处理上增加了标准化和周期性特征,改进了网络架构,引入了学习率调整和早停机制优化训练过程。两个项目均通过可视化对比预测值和真实值,验证了LSTM模型在时间序列预测中的有效性。文章从数据处理、模型构建到训练优化,完整呈现了温度预测的实现流程,为时序预测任务提供了实用参考。
340 0
|
5月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch深度学习实战 |层归一化层和FeedForward
本文介绍了PyTorch深度学习中Add&Norm层和FeedForward层的实现原理。Add&Norm层由残差连接(Add)和层归一化(Norm)组成,能加速模型收敛并稳定训练。层归一化会对神经网络每层的输出进行归一化处理,文中详细展示了其计算方法和PyTorch实现代码。FeedForward层是一个两层的全连接网络,通过线性变换提取更深层次特征。文章还分析了Transformer模型中使用层归一化的原因,并提供了完整的代码实现,包括参数初始化和前向传播过程。
261 0
|
5月前
|
人工智能 知识图谱
图解人工智能的数学基础(概率论)
本内容系统讲解概率论与数理统计核心知识:从随机事件、古典/几何概型、条件概率、贝叶斯公式,到一维随机变量及其分布(离散型/连续型)、数字特征(期望、方差、协方差、相关系数),再到大数定律、中心极限定理及卡方/t/F分布,最后涵盖最大似然估计方法。理论结合水果店、掷骰子等生活实例,图文并茂,深入浅出。
477 2
|
5月前
|
机器学习/深度学习 人工智能 数据可视化
手算神经网络
本文介绍了使用2×3×1神经网络实现房价预测的全过程。首先通过手动计算演示了单个样本的前向传播和反向传播,包括权重初始化和梯度更新。随后使用PyTorch实现了完整的神经网络模型,包含数据准备、网络结构定义、损失函数计算和优化器设置。在训练过程中记录了损失值变化,并可视化展示训练效果。最后提供了一个挖空版本的代码框架,帮助读者逐步完成神经网络的关键实现步骤,包括导入包、定义网络框架、数据准备、训练循环和结果可视化等模块。通过这个完整的项目实践,读者可以掌握神经网络从理论到实现的全流程。
182 0