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

简介: 本文深入解析人工智能中最优化问题的核心:通过最小化损失函数来训练模型。涵盖回归(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


目录
相关文章
|
4月前
|
机器学习/深度学习 数据挖掘 PyTorch
PyTorch深度学习实战 |手算​​FCN全卷积神经网络
本文介绍了FCN-8s语义分割网络的实现细节。首先解释了语义分割的概念及其与图像分类的区别,重点分析了FCN网络结构中的全卷积化、上采样和跳跃连接三个关键技术。全卷积化将传统CNN的全连接层改为卷积层,实现像素级分类;上采样通过双线性插值恢复特征图尺寸;跳跃连接则融合高低层特征以提升细节表现。文章详细推导了损失函数的计算过程,并提供了完整的PyTorch实现代码,包括双线性插值权重初始化、VGG16骨干网络和FCN-8s主体结构。最后通过测试验证了模型能正确输出与输入尺寸匹配的预测结果。
418 3
|
4月前
|
机器学习/深度学习 PyTorch 测试技术
PyTorch深度学习实战 |多头注意力机制
摘要:本文详细介绍了Transformer中的多头自注意力机制,从整体结构到实现细节,包括四部分内容:(1)多头自注意力的基本架构;(2)内部计算流程解析;(3)注意力计算公式详解;(4)代码实现。重点阐述了多头并行的计算方式、缩放点积注意力的计算步骤(QK转置、缩放、softmax和加权求和),以及残差连接和层归一化的作用。通过"Are you OK?"示例展示了输入张量如何经过8个64维注意力头处理后拼接成512维输出。文章最后提供了完整的PyTorch实现代码,并附测试用例验证模型
316 0
|
4月前
|
机器学习/深度学习 编解码 算法
PyTorch深度学习实战 |手算​​U-net
本文详细解析了U-Net网络架构及其在医学图像分割中的应用。重点对比了U-Net与FCN的核心区别:U-Net采用特征拼接(Concat)保留所有层级信息,而FCN使用特征相加(Add)进行融合。文章深入剖析了U-Net的编码器-瓶颈-解码器结构,解释了其独特的裁剪拼接机制和Overlap-tile策略,并提供了完整的PyTorch实现代码。现代U-Net通过SamePadding实现了输入输出尺寸一致,显著提升了分割精度。文章还探讨了弹性形变数据增强和带空间权重的损失函数设计,为医学图像分析提供了实用解决
347 2
|
4月前
|
机器学习/深度学习 数据可视化 PyTorch
PyTorch深度学习实战 | 基于LSTM的时间序列预测任务
本文介绍了使用LSTM模型预测印度德里市平均温度的两个项目。项目1对温度数据进行归一化处理,采用滑动窗口法构建监督学习样本,设计5层LSTM网络结构,并详细说明了模型训练过程及评估方法。项目2在数据处理上增加了标准化和周期性特征,改进了网络架构,引入了学习率调整和早停机制优化训练过程。两个项目均通过可视化对比预测值和真实值,验证了LSTM模型在时间序列预测中的有效性。文章从数据处理、模型构建到训练优化,完整呈现了温度预测的实现流程,为时序预测任务提供了实用参考。
293 0
|
4月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch深度学习实战 |层归一化层和FeedForward
本文介绍了PyTorch深度学习中Add&Norm层和FeedForward层的实现原理。Add&Norm层由残差连接(Add)和层归一化(Norm)组成,能加速模型收敛并稳定训练。层归一化会对神经网络每层的输出进行归一化处理,文中详细展示了其计算方法和PyTorch实现代码。FeedForward层是一个两层的全连接网络,通过线性变换提取更深层次特征。文章还分析了Transformer模型中使用层归一化的原因,并提供了完整的代码实现,包括参数初始化和前向传播过程。
220 0
|
4月前
|
机器学习/深度学习 人工智能 供应链
别再让 AI 给小白讲天书了:复杂概念要这样降维
本指南教你用AI将复杂技术“降维”为生活化表达:聚焦受众身份、禁用术语公式、强绑生活类比、直击“是什么/有何用/易错哪”三核心,让Transformer、Agent等概念秒变老板能懂的业务语言。
345 0
别再让 AI 给小白讲天书了:复杂概念要这样降维
|
4月前
|
机器学习/深度学习 自然语言处理 PyTorch
PyTorch深度学习实战 |手动计算 Transformer和完整的代码实现
本文介绍了基于PyTorch实现Transformer模型的完整过程。主要内容包括:1)Transformer架构的核心组件实现,如多头注意力机制、位置前馈网络、位置编码等;2)模型构建步骤,包括词嵌入层、编码器/解码器块和输出层的实现;3)完整的训练流程,包含数据处理、损失计算和参数优化;4)评估方法验证模型性能。文章通过代码示例详细展示了如何从零开始构建Transformer,并应用于机器翻译任务,同时对模型各层的输入输出维度进行了说明。该实现可作为深度学习实践者学习Transformer架构的实用指南
336 0
|
4月前
|
机器学习/深度学习 自然语言处理 算法
PyTorch深度学习实战 | Transformer模型初识
本文介绍了Transformer模型在机器翻译任务中的工作原理。主要内容包括:1)模型分为编码器(处理英文输入)和解码器(生成中文输出)两部分;2)推理时采用自回归模式,逐步生成翻译结果;3)训练时使用教师强制模式,始终以真实标签指导模型学习。文章详细阐述了编码器-解码器结构的工作流程,包括词嵌入、多头注意力机制等核心组件,以及如何通过残差连接和层标准化优化模型性能。最后解释了编码器和解码器三个关键计算步骤的张量维度变化过程。
278 0
|
4月前
|
机器学习/深度学习 编解码 算法
PyTorch深度学习实战 | 标准化和归一化
本文介绍了数据预处理中的标准化和归一化方法,包括计算过程、特性对比及实际应用。以波士顿房价数据集为例,展示了原始数据、标准化和归一化后的模型效果差异。同时讲解了深度学习中常用的层归一化(LN)和批量归一化(BN)技术,分别适用于文本和图像处理任务,并给出了PyTorch实现示例。LN通过调整词向量分布缓解梯度消失等问题,而BN则对图像各通道单独处理。两种技术都能提升模型训练效果,但适用场景不同。
271 0
|
4月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch深度学习实战 |常见层 layer结构的实现和代码实战
本文介绍了PyTorch中常见的7种神经网络层结构及其输入输出逻辑。通过代码示例演示了全连接层(nn.Linear)、卷积层(nn.Conv2d)、LSTM层、GCN图卷积层和Transformer层的使用方法,重点讲解了各层的输入输出维度变换规则。文章以一张海绵宝宝图片为例,详细展示了图像数据的预处理流程,包括使用PIL和OpenCV两种方法读取图片并转换为PyTorch张量的过程。通过"代码+实战"的方式帮助读者理解神经网络层如何对特征进行维度变换,最终实现从原始输入到目标输出的映射
285 0

热门文章

最新文章