深度学习day04

Softmax

主要理论

Softmax 函数是一种将实数向量映射为概率分布的函数,常用于多分类问题的输出层。其核心思想是通过指数运算放大差异,再归一化得到概率。对于一个输入向量 z = [z₁, z₂, ..., zₙ],Softmax 的计算公式为:

  • 性质:输出值的范围为 (0,1),且所有输出之和为 1,符合概率分布的特性。
  • 梯度:在反向传播中,Softmax 的梯度计算与交叉熵损失结合时形式简洁,利于优化。

实现代码

Python 原生实现

python 复制代码
import numpy as np

def softmax(z):
    exp_z = np.exp(z - np.max(z))  # 防溢出优化
    return exp_z / np.sum(exp_z, axis=0)

PyTorch 实现

python 复制代码
import torch
import torch.nn as nn

# 直接调用内置函数
softmax_layer = nn.Softmax(dim=1)  # dim 指定计算维度
output = softmax_layer(torch.randn(3, 5))

注意事项

  • 数值稳定性 :原始公式可能因指数爆炸导致溢出,需通过减去最大值(z - max(z))优化。

  • 维度处理 :在多维张量中需明确指定计算维度(如 dim=1axis=-1)。

  • 与交叉熵结合 :深度学习框架中常将 LogSoftmaxNLLLoss 结合使用,提升数值稳定性。

多层感知机

多层感知机(MLP)理论基础

多层感知机(Multilayer Perceptron, MLP)是一种前馈人工神经网络,由输入层、隐藏层(至少一层)和输出层组成。其核心理论基于以下关键点:

激活函数

MLP通过非线性激活函数引入非线性能力。常用激活函数包括:

反向传播算法

通过链式法则计算损失函数对权重的梯度,使用梯度下降法更新参数。损失函数如交叉熵(分类)或均方误差(回归)。

权重初始化

常用Xavier或He初始化方法,避免梯度消失/爆炸问题。


实现代码

以下是一个完整的MLP实现示例,包含训练和测试流程:

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# 定义MLP模型
class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(MLP, self).__init__()
        self.layers = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, output_dim)
        )
    
    def forward(self, x):
        return self.layers(x)

# 参数设置
input_dim = 784  # 例如MNIST图像展平后
hidden_dim = 128
output_dim = 10
lr = 0.001
epochs = 10
batch_size = 64

# 模拟数据加载(实际使用时替换为真实数据)
x_train = torch.randn(1000, input_dim)
y_train = torch.randint(0, output_dim, (1000,))
train_dataset = TensorDataset(x_train, y_train)
train_loader = DataLoader(train_dataset, batch_size=batch_size)

# 初始化模型和优化器
model = MLP(input_dim, hidden_dim, output_dim)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=lr)

# 训练循环
for epoch in range(epochs):
    for batch_x, batch_y in train_loader:
        optimizer.zero_grad()
        outputs = model(batch_x)
        loss = criterion(outputs, batch_y)
        loss.backward()
        optimizer.step()
    print(f'Epoch {epoch+1}, Loss: {loss.item():.4f}')

# 测试函数(示例)
def test(model, test_loader):
    model.eval()
    correct = 0
    with torch.no_grad():
        for x, y in test_loader:
            outputs = model(x)
            _, predicted = torch.max(outputs.data, 1)
            correct += (predicted == y).sum().item()
    accuracy = 100 * correct / len(test_loader.dataset)
    print(f'Accuracy: {accuracy:.2f}%')

关键改进技巧

正则化方法

  • Dropout层:在训练时随机失活神经元

  • L2正则化:通过优化器的weight_decay参数实现

批量归一化

在隐藏层后添加nn.BatchNorm1d层,加速收敛:

python 复制代码
nn.Sequential(
    nn.Linear(input_dim, hidden_dim),
    nn.BatchNorm1d(hidden_dim),
    nn.ReLU()
)

学习率调度

使用torch.optim.lr_scheduler动态调整学习率:

python 复制代码
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)
# 每个epoch后调用 scheduler.step()

深度学习计算

层(Layers)和块(Blocks)

在深度学习中,网络通常由多个层堆叠而成。每一层接收输入数据,进行变换(如线性变换、非线性激活),并产生输出。多个层可以组合成一个"块",块本身也可以被视为一个更大的层,这种模块化设计使得网络构建更灵活。

代码示例 (PyTorch): 定义一个简单的多层感知机 (MLP) 块

python 复制代码
import torch.nn as nn

class MLPBlock(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super().__init__()
        self.linear1 = nn.Linear(input_dim, hidden_dim)  # 全连接层1
        self.relu = nn.ReLU()                           # 激活层
        self.linear2 = nn.Linear(hidden_dim, output_dim) # 全连接层2

    def forward(self, x):
        x = self.linear1(x)  # 线性变换
        x = self.relu(x)     # 非线性激活
        x = self.linear2(x)  # 线性变换
        return x

# 使用块
model = MLPBlock(input_dim=784, hidden_dim=256, output_dim=10)

参数管理

深度学习模型的核心是其可学习的参数(如权重 w和偏置 b)。我们需要有效地访问、初始化和修改这些参数。

  • 访问参数:

    python 复制代码
    # 获取模型中所有参数的迭代器
    for name, param in model.named_parameters():
        print(f"Parameter name: {name}, Shape: {param.shape}")
    
    # 访问特定层的权重 (例如第一个全连接层的权重)
    weight = model.linear1.weight.data
  • 初始化参数: 好的初始化对训练至关重要(例如 Xavier/Glorot 初始化)。

    python 复制代码
    # 对特定层应用初始化
    def init_weights(m):
        if type(m) == nn.Linear:
            nn.init.xavier_uniform_(m.weight)  # Xavier 初始化权重
            nn.init.zeros_(m.bias)             # 初始化偏置为0
    
    model.apply(init_weights)  # 将初始化函数应用到模型的每个子模块
  • 绑定参数: 有时需要共享参数(如词嵌入层)。

    python 复制代码
    # 假设有两个线性层,希望共享权重
    shared_layer = nn.Linear(20, 20)
    layer1 = shared_layer
    layer2 = shared_layer  # layer1 和 layer2 现在共享相同的权重和偏置

参数初始化

初始化对网络能否有效学习有重大影响。常见初始化方法:

  • Xavier/Glorot 初始化: 适用于 tanh, sigmoid 等激活函数,旨在保持各层激活值和梯度的方差稳定。假设激活函数关于0对称且导数在0处为1。

python 复制代码
PyTorch 实现:nn.init.xavier_uniform_(), nn.init.xavier_normal_()
  • He/Kaiming 初始化: 适用于 ReLU 及其变种,修正了 Xavier 假设的不足。

python 复制代码
PyTorch 实现:nn.init.kaiming_uniform_(), nn.init.kaiming_normal_()
  • 常数/固定值初始化: 如将所有偏置初始化为零 nn.init.zeros_(),或权重初始化为常数。

自定义层

当内置层不满足需求时,可以自定义层。需要继承 nn.Module 并定义 __init__ (初始化参数) 和 forward (定义前向传播逻辑) 方法。

代码示例 (PyTorch): 自定义一个带 'same' padding 的卷积层

python 复制代码
class CustomConv2d(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1):
        super().__init__()
        # 计算所需的 padding 以实现 'same' 输出尺寸
        padding = (kernel_size - 1) // 2  # 仅对奇数 kernel_size 有效
        self.conv = nn.Conv2d(
            in_channels, out_channels, kernel_size, stride=stride, padding=padding
        )

    def forward(self, x):
        return self.conv(x)

# 使用自定义层
layer = CustomConv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1)

读写文件(模型保存与加载)

训练好的模型需要保存以便后续使用或部署。需要保存模型的结构和参数。

  • 保存整个模型 (结构 + 状态字典):

    python 复制代码
    torch.save(model, 'model.pth')  # 保存整个模型
  • 仅保存状态字典 (推荐): 更轻量,兼容性更好。

    python 复制代码
    torch.save(model.state_dict(), 'model_state_dict.pth')  # 仅保存参数
  • 加载模型:

    python 复制代码
    # 加载整个模型 (需要模型类定义在作用域内)
    model = torch.load('model.pth')
    
    # 加载状态字典到现有模型实例
    model.load_state_dict(torch.load('model_state_dict.pth'))
    model.eval()  # 切换到评估模式(影响 dropout, batchnorm 等)

GPU 计算

利用 GPU 加速计算是深度学习的常态。核心是确保模型参数和输入数据都在 GPU 上。

  • 检测 GPU 可用性:

    python 复制代码
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print(f"Using device: {device}")
  • 将模型和数据移至 GPU:

    python 复制代码
    model = model.to(device)  # 将模型参数移至 GPU
    
    # 训练时,将每个 batch 的数据移至 GPU
    for X, y in train_loader:
        X, y = X.to(device), y.to(device)
        # ... 训练步骤 ...
  • 注意: 模型和输入数据必须在同一个设备上才能进行计算。to(device) 操作会记录梯度计算需求。

相关推荐
传说故事1 小时前
【论文阅读】RL Token: Bootstrapping Online RL with Vision-Language-Action Models
论文阅读·人工智能·具身智能·rl
crossoverJie1 小时前
OpenAI 收购 Python 工具链 uv 和 Ruff
开发语言·人工智能·python·uv
阳光普照世界和平1 小时前
借力大模型,重构研发效能:全流程提效实战指南
大数据·人工智能·重构
龙文浩_1 小时前
AI / 机器学习 / 深度学习,它们的关系、核心流程、算法、任务、训练逻辑
人工智能·python·深度学习·神经网络·机器学习
测试_AI_一辰1 小时前
Agent & RAG 测试工程笔记 14:RAG门控层拆解:什么时候该答?什么时候必须拒绝?
人工智能·算法·ai·自动化·ai编程
大数据AI人工智能培训专家培训讲师叶梓1 小时前
Fast-WAM:重构 WAMs 的效率与性能平衡
人工智能·重构·大模型·具身智能·人工智能讲师·大模型讲师·大模型培训
研究点啥好呢1 小时前
3月24日GitHub热门项目推荐|让AI无所不能
人工智能·python·开源·github
威联通安全存储1 小时前
深度观察:跨越“存起来”的误区,智造时代如何重构工业数据底座?
大数据·人工智能·python·重构
智算菩萨1 小时前
GPT-5.4辅助科技论文写作完全指南(国内可用)
人工智能·科技·gpt·ai·ai写作·论文写作·ai-native