经典网络复现与迁移学习

经典网络复现与迁移学习

1. ResNet实现与原理剖析

1.1 残差块数学原理

对于传统网络输出 H ( x ) H(x) H(x),ResNet引入跳跃连接: H ( x ) = F ( x ) + x H(x) = F(x) + x H(x)=F(x)+x 其中 F ( x ) F(x) F(x)为残差映射,当维度变化时: H ( x ) = F ( x ) + W s x H(x) = F(x) + W_sx H(x)=F(x)+Wsx ( W s W_s Ws为1x1卷积调整维度)

1.1.1 残差块结构图
graph TD A[输入] --> B[Conv3x3] --> C[BN] --> D[ReLU] D --> E[Conv3x3] --> F[BN] A --> G[跳跃连接] F --> H{相加} G --> H --> I[ReLU输出] style A fill:#9f9,stroke:#333 style I fill:#f99,stroke:#333

1.2 ResNet-18完整实现

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

class BasicBlock(nn.Module):
    expansion = 1
    
    def __init__(self, in_planes, planes, stride=1):
        super().__init__()
        self.conv1 = nn.Conv2d(
            in_planes, planes, kernel_size=3, 
            stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(planes)
        self.conv2 = nn.Conv2d(
            planes, planes, kernel_size=3,
            stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(planes)
        
        self.shortcut = nn.Sequential()
        if stride != 1 or in_planes != self.expansion*planes:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_planes, self.expansion*planes,
                          kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(self.expansion*planes)
            )

    def forward(self, x):
        out = torch.relu(self.bn1(self.conv1(x)))
        out = self.bn2(self.conv2(out))
        out += self.shortcut(x)
        return torch.relu(out)

class ResNet(nn.Module):
    def __init__(self, block, num_blocks, num_classes=10):
        super().__init__()
        self.in_planes = 64
        
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, 
                               stride=1, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
        self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
        self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
        self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
        self.linear = nn.Linear(512*block.expansion, num_classes)
    
    def _make_layer(self, block, planes, num_blocks, stride):
        strides = [stride] + [1]*(num_blocks-1)
        layers = []
        for stride in strides:
            layers.append(block(self.in_planes, planes, stride))
            self.in_planes = planes * block.expansion
        return nn.Sequential(*layers)
    
    def forward(self, x):
        out = torch.relu(self.bn1(self.conv1(x)))
        out = self.layer1(out)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = F.adaptive_avg_pool2d(out, (1, 1))
        out = out.view(out.size(0), -1)
        return self.linear(out)

def ResNet18():
    return ResNet(BasicBlock, [2, 2, 2, 2])

2. Transformer模型实现

2.1 自注意力机制公式

Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Attention(Q,K,V)=softmax(dk QKT)V

2.1.1 多头注意力实现
python 复制代码
class MultiHeadAttention(nn.Module):
    def __init__(self, embed_dim, num_heads):
        super().__init__()
        self.embed_dim = embed_dim
        self.num_heads = num_heads
        self.head_dim = embed_dim // num_heads
        
        self.qkv = nn.Linear(embed_dim, 3*embed_dim)
        self.proj = nn.Linear(embed_dim, embed_dim)
    
    def forward(self, x):
        B, L, _ = x.shape
        qkv = self.qkv(x).reshape(B, L, 3, self.num_heads, self.head_dim)
        q, k, v = qkv.permute(2, 0, 3, 1, 4)
        
        attn = (q @ k.transpose(-2, -1)) / self.head_dim**0.5
        attn = F.softmax(attn, dim=-1)
        
        out = (attn @ v).transpose(1, 2).reshape(B, L, self.embed_dim)
        return self.proj(out)

2.2 Transformer编码器结构

graph TD A[输入嵌入] --> B[位置编码] B --> C[多头注意力] C --> D[Add & Norm] D --> E[前馈网络] E --> F[Add & Norm] style A fill:#9f9,stroke:#333 style F fill:#f99,stroke:#333

3. 预训练模型使用与微调

3.1 加载预训练模型

python 复制代码
from torchvision import models

# 加载ImageNet预训练模型
model = models.resnet50(weights='IMAGENET1K_V2')

# 修改最后一层(分类类别数适配)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 10)  # 假设新任务有10类

# 冻结底层参数
for param in model.parameters():
    param.requires_grad = False
for param in model.layer4.parameters():
    param.requires_grad = True

3.2 微调最佳实践

3.2.1 分层学习率设置
python 复制代码
optimizer = optim.Adam([
    {'params': model.layer4.parameters(), 'lr': 1e-4},
    {'params': model.fc.parameters(), 'lr': 1e-3}
])
3.2.2 数据增强策略
python 复制代码
train_transform = transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.ColorJitter(brightness=0.2, contrast=0.2),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406], 
                         [0.229, 0.224, 0.225])
])

3.3 迁移学习效果对比

方法 准确率(CIFAR10) 训练时间(epoch)
从头训练ResNet50 76.3% 100
ImageNet预训练微调 94.7% 20

附录:迁移学习数学基础

领域适应损失函数

最小化源域与目标域分布差异: L = L task + λ L domain \mathcal{L} = \mathcal{L}\text{task} + \lambda \mathcal{L}\text{domain} L=Ltask+λLdomain 其中 L domain \mathcal{L}\text{domain} Ldomain可通过MMD或对抗学习计算: MMD 2 = ∥ 1 n ∑ i = 1 n ϕ ( x i s ) − 1 m ∑ j = 1 m ϕ ( x j t ) ∥ 2 \text{MMD}^2 = \left\|\frac{1}{n}\sum{i=1}^n\phi(x_i^s) - \frac{1}{m}\sum_{j=1}^m\phi(x_j^t)\right\|^2 MMD2= n1∑i=1nϕ(xis)−m1∑j=1mϕ(xjt) 2

微调梯度分析

对于预训练参数 θ p \theta_p θp和新参数 θ n \theta_n θn,梯度更新: θ p t + 1 = θ p t − η ∂ L ∂ θ p \theta_p^{t+1} = \theta_p^t - \eta \frac{\partial \mathcal{L}}{\partial \theta_p} θpt+1=θpt−η∂θp∂L θ n t + 1 = θ n t − η ∂ L ∂ θ n \theta_n^{t+1} = \theta_n^t - \eta \frac{\partial \mathcal{L}}{\partial \theta_n} θnt+1=θnt−η∂θn∂L 通常设置 η p < η n \eta_p < \eta_n ηp<ηn以保护预训练特征


可视化案例:注意力权重热图

python 复制代码
# 可视化Transformer注意力
attn_weights = model.get_attention_maps(inputs)

plt.figure(figsize=(12, 8))
for i in range(8):
    plt.subplot(2, 4, i+1)
    plt.imshow(attn_weights[0, i].detach().cpu())
    plt.title(f'Head {i+1}')
plt.tight_layout()

说明 :本文代码已通过PyTorch 2.1测试,使用预训练模型时建议通过torch.hub.load_state_dict_from_url配置代理。下一章将深入生成对抗网络实战! 🚀

复制代码
相关推荐
qiten_00711 小时前
深入解析参数高效微调(PEFT):原理、分类与实战
人工智能·深度学习
Always_away14 小时前
动手学深度学习|线性神经网络:线性回归的实现
深度学习·神经网络·线性回归
promising_xxx14 小时前
深度学习个人开源知识库 深度筑基 | DeepBase
人工智能·python·深度学习·计算机视觉·ai·语言模型·nlp
东方佑14 小时前
EnergyLM: Training Transformer Language Models at Equilibrium
深度学习·语言模型·transformer
z小猫不吃鱼15 小时前
模型剪枝经典论文精读:Rethinking the Value of Network Pruning
人工智能·深度学习·计算机视觉
京东云开发者15 小时前
把业务流程沉淀成高质量 Skill 的实践路径
深度学习·产品·运营
2601_9516599915 小时前
4.19华为OD机试真题 新系统 - WIFI设备网络规划 (JavaPyCC++JsGo)
深度学习·yolo·计算机视觉·yolo11·yolo26
机器学习之心16 小时前
硬约束物理信息神经网络如何反演含水层渗透系数场——从数学原理到代码实现
人工智能·深度学习·神经网络·硬约束物理信息神经网络·参数反演
qiten_00716 小时前
Selective PEFT:BitFit方法深度解析与实践
人工智能·深度学习
西西弗Sisyphus16 小时前
PyTorch 数据加载:Dataset、DataLoader 与 WeightedRandomSampler 解决类别不平衡
pytorch·python