十类图片深度学习提升准确率(0.9317)

复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import torch.backends.cudnn as cudnn
import numpy as np
import torchvision
import torchvision.transforms as transforms
import torchvision.models as models
from torch.utils.data import DataLoader
from collections import Counter
from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR, SequentialLR

# 超参数设置
BATCH_SIZE = 128
EPOCHES = 100
LR = 0.001
WARMUP_EPOCHS = 5

# 启用cudnn加速
cudnn.benchmark = True

# 改进的数据增强
transform_train = transforms.Compose([
    transforms.RandomCrop(32, padding=4),
    transforms.RandomHorizontalFlip(p=0.5),
    transforms.RandomRotation(15),
    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
    transforms.ToTensor(),
    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261)),
])

transform_test = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))
])


# 更精确的模型修改函数
def modify_model_for_cifar10(model, model_name):
    # 修改第一层卷积以适应32x32输入
    if hasattr(model, 'conv1'):
        if isinstance(model.conv1, nn.Conv2d):
            # 对于ResNet等模型
            model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)

    # 修改分类器层
    if model_name == 'resnet34':
        model.fc = nn.Linear(model.fc.in_features, 10)
    elif model_name == 'efficientnet_b3':
        model.classifier = nn.Linear(model.classifier[1].in_features, 10)
    elif model_name == 'densenet121':
        model.classifier = nn.Linear(model.classifier.in_features, 10)
    elif model_name == 'mobilenet_v3_large':
        # MobileNetV3的特殊处理
        model.classifier = nn.Sequential(
            nn.Linear(model.classifier[0].in_features, 1280),
            nn.Hardswish(inplace=True),
            nn.Dropout(p=0.2, inplace=True),
            nn.Linear(1280, 10),
        )
    elif model_name == 'vgg19_bn':
        model.classifier = nn.Sequential(
            nn.Linear(512 * 1 * 1, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, 10),
        )

    return model


def get_models(device):
    """获取多个预训练模型"""
    model_names = [
        'resnet34',
        'efficientnet_b3',
        'densenet121',
    ]

    models_list = []
    for name in model_names:
        try:
            # 使用新的weights API
            if name == 'resnet34':
                weights = models.ResNet34_Weights.IMAGENET1K_V1
                model = models.resnet34(weights=weights)
            elif name == 'efficientnet_b3':
                weights = models.EfficientNet_B3_Weights.IMAGENET1K_V1
                model = models.efficientnet_b3(weights=weights)
            elif name == 'densenet121':
                weights = models.DenseNet121_Weights.IMAGENET1K_V1
                model = models.densenet121(weights=weights)

            model = modify_model_for_cifar10(model, name)
            model = model.to(device)
            models_list.append(model)
            print(f"成功加载模型: {name}")
        except Exception as e:
            print(f"加载模型 {name} 失败: {e}")

    return models_list


def train_ensemble(models, train_loader, test_loader, device, epochs=100):
    """训练集成模型"""

    # 为每个模型创建优化器和学习率调度器
    optimizers = []
    schedulers = []

    for model in models:
        # 使用AdamW优化器,权重衰减防止过拟合
        optimizer = optim.AdamW(model.parameters(), lr=LR, weight_decay=1e-4)

        # 学习率调度:预热 + 余弦退火
        warmup_scheduler = LinearLR(optimizer, start_factor=0.1, total_iters=WARMUP_EPOCHS)
        cosine_scheduler = CosineAnnealingLR(optimizer, T_max=epochs - WARMUP_EPOCHS)
        scheduler = SequentialLR(optimizer,
                                 schedulers=[warmup_scheduler, cosine_scheduler],
                                 milestones=[WARMUP_EPOCHS])

        optimizers.append(optimizer)
        schedulers.append(scheduler)

    # 使用标签平滑的交叉熵损失
    criterion = nn.CrossEntropyLoss(label_smoothing=0.1)

    best_accuracy = 0.0

    for epoch in range(epochs):
        print(f"\nEpoch {epoch + 1}/{epochs}")

        # 训练阶段
        for model in models:
            model.train()

        train_loss = 0.0
        train_correct = 0
        train_total = 0

        for batch_idx, (data, target) in enumerate(train_loader):
            data, target = data.to(device), target.to(device)
            batch_size = data.size(0)
            train_total += batch_size

            # 为每个模型单独计算损失和梯度
            batch_loss = 0
            for model, optimizer in zip(models, optimizers):
                optimizer.zero_grad()
                output = model(data)
                loss = criterion(output, target)
                loss.backward()
                optimizer.step()

                batch_loss += loss.item()

                # 统计训练准确率(使用最后一个模型的预测)
                if model == models[-1]:
                    _, predicted = torch.max(output, 1)
                    train_correct += (predicted == target).sum().item()

            train_loss += batch_loss / len(models) * batch_size

            if batch_idx % 100 == 0:
                print(f'训练进度: {batch_idx}/{len(train_loader)}, 当前批次损失: {batch_loss / len(models):.4f}')

        # 更新学习率
        for scheduler in schedulers:
            scheduler.step()

        # 评估阶段
        current_accuracy = evaluate_ensemble(models, test_loader, device, epoch)

        # 保存最佳模型
        if current_accuracy > best_accuracy:
            best_accuracy = current_accuracy
            for i, model in enumerate(models):
                torch.save(model.state_dict(), f'best_model_{i}.pth')
            print(f"新的最佳准确率: {best_accuracy:.4f}")

        # 打印训练统计
        print(f"训练损失: {train_loss / train_total:.4f}, 训练准确率: {train_correct / train_total:.4f}")

    print(f"\n训练完成! 最佳准确率: {best_accuracy:.4f}")
    return best_accuracy


def evaluate_ensemble(models, test_loader, device, epoch=None):
    """评估集成模型性能"""
    models_correct = [0] * len(models)
    ensemble_correct = 0
    total = 0

    # 可以根据验证集性能调整权重(这里使用等权重)
    model_weights = [1.0] * len(models)

    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            batch_size = data.size(0)
            total += batch_size

            # 收集所有模型的预测概率
            all_probs = []

            for i, model in enumerate(models):
                model.eval()
                output = model(data)
                probs = F.softmax(output, dim=1)
                all_probs.append(probs * model_weights[i])

                # 单个模型准确率
                _, predicted = torch.max(output, 1)
                models_correct[i] += (predicted == target).sum().item()

            # 加权集成预测
            ensemble_probs = sum(all_probs)
            _, ensemble_predicted = torch.max(ensemble_probs, 1)
            ensemble_correct += (ensemble_predicted == target).sum().item()

    # 打印结果
    ensemble_accuracy = ensemble_correct / total
    if epoch is not None:
        print(f"Epoch {epoch + 1} 评估结果:")
    else:
        print("最终评估结果:")

    print(f"集成模型准确率: {ensemble_accuracy:.4f}")
    for i, correct in enumerate(models_correct):
        print(f"模型 {i + 1} 准确率: {correct / total:.4f}")
    print("-" * 50)

    return ensemble_accuracy


def main():
    # 设置设备
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print(f"使用设备: {device}")

    # 数据准备
    print('==> 准备数据..')

    # 下载数据集
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train)
    trainloader = DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2, pin_memory=True)

    testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
    testloader = DataLoader(testset, batch_size=100, shuffle=False, num_workers=2, pin_memory=True)

    classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
    print(f'类别: {classes}')

    # 模型初始化
    print('==> 构建模型..')
    mlps = get_models(device)

    if len(mlps) == 0:
        print("错误: 没有成功加载任何模型!")
        return

    print(f"成功加载 {len(mlps)} 个模型进行集成学习")

    # 显示模型参数数量
    for i, model in enumerate(mlps):
        total_params = sum(p.numel() for p in model.parameters())
        print(f"模型 {i + 1} 参数数量: {total_params:,}")

    # 训练集成模型
    best_accuracy = train_ensemble(mlps, trainloader, testloader, device, EPOCHES)

    print(f"\n训练完成! 最终最佳准确率: {best_accuracy:.4f}")


if __name__ == '__main__':
    main()
相关推荐
NAGNIP11 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab13 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab13 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP16 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年16 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼17 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS17 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区18 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈18 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang19 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx