十类图片深度学习提升准确率(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()
相关推荐
嵌入式-老费11 小时前
自己动手写深度学习框架(感知机)
人工智能·深度学习
化作星辰12 小时前
使用 PyTorch来构建线性回归的实现
人工智能·pytorch·深度学习
mm-q291522272912 小时前
【天野学院5期】 第5期易语言半内存辅助培训班,主讲游戏——手游:仙剑奇侠传4,端游:神魔大陆2
人工智能·算法·游戏
谢景行^顾12 小时前
深度学习-损失函数
人工智能·深度学习
xier_ran12 小时前
关键词解释: LoRA(Low-Rank Adaptation)详解
人工智能
黄焖鸡能干四碗12 小时前
信息安全管理制度(Word)
大数据·数据库·人工智能·智慧城市·规格说明书
paopao_wu12 小时前
DeepSeek-OCR实战(01):基础运行环境搭建-Ubuntu
linux·人工智能·ubuntu·ai·ocr
Altair澳汰尔12 小时前
新闻速递丨Altair RapidMiner 数据分析和 AI 平台助力企业加速智能升级:扩展智能体 AI 及分析生态系统
人工智能·ai·数据分析·仿真·cae·rapidminer·数据自动化
oil欧哟12 小时前
GitHub星标3万,OpenAI 官方支持——深度解读 AI Agent 连接协议的行业标准 MCP
人工智能·github
极客BIM工作室12 小时前
单层前馈神经网络的万能逼近定理
人工智能·深度学习·神经网络