首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【AI 进阶笔记】cv 小白上手 Kaggle Bird vs Drone 【图像分类】

【AI 进阶笔记】cv 小白上手 Kaggle Bird vs Drone 【图像分类】

原创
作者头像
繁依Fanyi
修改2025-04-06 09:27:09
修改2025-04-06 09:27:09
47410
代码可运行
举报
运行总次数:0
代码可运行

今天又来啦记笔记啦!

Bird vs Drone

在这里插入图片描述
在这里插入图片描述

下载完成后,把我们的数据集拖到 Cloud Studio 工作台中,等待上传完成

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上传完成后,移动到顺眼的目录 unzip 解压一下

在这里插入图片描述
在这里插入图片描述

看一下解压后的标签,可以看到标签的风格是 YOLO 风格的,其中每个标签的第一列是类别,后面是归一化的边界框坐标。不过我想先尝试一下不用 label,不对内容进行目标检测,仅仅用图片名称的分类数据来进行分类检测

在这里插入图片描述
在这里插入图片描述

然后就可以开工啦!


ResNet 50 作为基线

Kaggle 数据集 “Bird vs Drone” 是个很不错的入门项目,适合我这种小白练习分类任务(鸟 vs 无人机),也可以延伸到目标检测或视频分析。


🐣 Step 1:先了解这个项目是干嘛的?

这个数据集的目标是 区分图像中是鸟还是无人机。常见任务有两个方向:

  1. 图像分类:输入一张图像,输出是 “鸟” 还是 “无人机”。
  2. (进阶)目标检测/追踪:不仅识别鸟/无人机,还要在图像中框出来。(这个前面学的 Faster R-CNN 是相关的)

🧰 Step 2:搞定基本环境

你需要:

  • 一个 Kaggle 账号:https://www.kaggle.com
  • 会用 Kaggle Notebook 或本地 Jupyter Notebook(推荐先用 Kaggle 的 Notebook)
  • 基本的 Python + PyTorch 或 TensorFlow 知识(我用 PyTorch)

📦 Step 3:数据集结构

从 Kaggle 页面描述看,这个数据集大概包含:

  • 一些图像(大概率是 .jpg/.png 格式)
  • 对应的标签(可能是通过文件名区分,如 bird_001.jpg / drone_001.jpg,或者有一个 CSV 文件)

🛠️ Step 4:训练图像分类模型(从头到尾流程)

照例先来个简单流程:

步骤 1:数据加载

首先,我们需要创建一个数据集类,用来加载图像和对应的标签。这里我们会使用 torchvisionPIL 来处理图像,以及 torch.utils.data.Dataset 来定义我们自己的数据集。

代码语言:python
代码运行次数:0
运行
复制
class BirdVsDroneSimpleDataset(Dataset):
    def __init__(self, img_dir, transform=None):
        self.img_dir = img_dir
        self.transform = transform
        self.img_paths = [os.path.join(img_dir, fname) for fname in os.listdir(img_dir) if fname.endswith('.jpg')]

    def __len__(self):
        return len(self.img_paths)

    def __getitem__(self, idx):
        img_path = self.img_paths[idx]
        img = Image.open(img_path).convert('RGB')

        # 用文件名判断标签:B 开头是鸟,D 开头是无人机
        fname = os.path.basename(img_path)
        if fname.startswith('B'):
            label = 0  # 鸟
        elif fname.startswith('D'):
            label = 1  # 无人机
        else:
            raise ValueError(f"Unknown file name format: {fname}")

        if self.transform:
            img = self.transform(img)

        return img, label

transform = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor()
])

train_dataset = BirdVsDroneSimpleDataset("train/images", transform=transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)
步骤 2:解析标签格式

每个标签文件包含了物体的类和归一化的边界框坐标。一开始,我们的目标是简单分类,不需要直接用到边界框坐标。但如果以后需要物体检测,我们可以利用这些坐标来训练模型。

步骤 3:构建模型

接下来我们使用一个预训练模型(比如 ResNet50)来进行图像分类。我们将替换模型的最后一层以适应我们的二分类任务。

代码语言:python
代码运行次数:0
运行
复制
import torch.nn as nn
import torchvision.models as models

# 使用 ResNet50 预训练模型
model = models.resnet50(pretrained=True)

# 修改最后一层全连接层,以适应2分类问题
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 2)  # 2类(鸟 vs 无人机)

# 发送到 GPU(如果可用)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
步骤 4:定义损失函数和优化器

我们使用交叉熵损失(CrossEntropyLoss)来训练分类模型,优化器选用 AdamW

代码语言:python
代码运行次数:0
运行
复制
import torch.optim as optim

criterion = nn.CrossEntropyLoss()
optimizer = optim.AdamW(model.parameters(), lr=1e-4)
步骤 5:训练模型

定义训练循环,并记录损失和准确率。

代码语言:python
代码运行次数:0
运行
复制
def train_model(model, train_loader, val_loader, criterion, optimizer, num_epochs=10):
    train_losses, val_losses = [], []
    train_accuracies, val_accuracies = [], []

    for epoch in range(num_epochs):
        # ---------- 训练 ----------
        model.train()
        running_loss = 0.0
        correct, total = 0, 0
        for inputs, labels in train_loader:
            inputs, labels = inputs.to(device), labels.to(device)
            optimizer.zero_grad()
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()

            running_loss += loss.item() * inputs.size(0)
            preds = torch.argmax(outputs, dim=1)
            correct += (preds == labels).sum().item()
            total += labels.size(0)

        epoch_loss = running_loss / total
        epoch_acc = correct / total
        train_losses.append(epoch_loss)
        train_accuracies.append(epoch_acc)

        # ---------- 验证 ----------
        model.eval()
        val_loss = 0.0
        val_correct, val_total = 0, 0
        with torch.no_grad():
            for inputs, labels in val_loader:
                inputs, labels = inputs.to(device), labels.to(device)
                outputs = model(inputs)
                loss = criterion(outputs, labels)
                val_loss += loss.item() * inputs.size(0)

                preds = torch.argmax(outputs, dim=1)
                val_correct += (preds == labels).sum().item()
                val_total += labels.size(0)

        val_epoch_loss = val_loss / val_total
        val_epoch_acc = val_correct / val_total
        val_losses.append(val_epoch_loss)
        val_accuracies.append(val_epoch_acc)

        # ---------- 日志打印 ----------
        print(f"[{epoch+1}/{num_epochs}] Train Loss: {epoch_loss:.4f}, Acc: {epoch_acc:.4f} | Val Loss: {val_epoch_loss:.4f}, Acc: {val_epoch_acc:.4f}")

    return train_losses, train_accuracies, val_losses, val_accuracies
步骤 6:验证模型

验证集部分的代码与训练相似,区别在于需要设置为 model.eval() 来关闭 dropout 等。在上面训练的时候已经验证了,这里就不写了


步骤7:绘制 loss / accuracy 曲线
代码语言:python
代码运行次数:0
运行
复制
import matplotlib.pyplot as plt

def plot_metrics(train_losses, train_accuracies, val_losses, val_accuracies):
    epochs = range(1, len(train_losses) + 1)
    
    plt.figure(figsize=(12, 5))

    # Loss
    plt.subplot(1, 2, 1)
    plt.plot(epochs, train_losses, 'b', label='Train Loss')
    plt.plot(epochs, val_losses, 'r', label='Val Loss')
    plt.title('Loss over Epochs')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.legend()

    # Accuracy
    plt.subplot(1, 2, 2)
    plt.plot(epochs, train_accuracies, 'b', label='Train Acc')
    plt.plot(epochs, val_accuracies, 'r', label='Val Acc')
    plt.title('Accuracy over Epochs')
    plt.xlabel('Epoch')
    plt.ylabel('Accuracy')
    plt.legend()

    plt.tight_layout()
    plt.show()

训练结果讲解

下面是我训练10轮得到的结果:

Epoch

Train Loss

Train Acc

Val Loss

Val Acc

1

0.0019

0.9994

0.4266

0.7920

2

0.0011

0.9997

0.3262

0.8172

3

0.0021

0.9991

0.7032

0.7241

4

0.0003

0.9999

0.6701

0.7977

5

0.0003

0.9999

0.6050

0.7517

6

0.0001

1.0000

0.4924

0.7822

7

0.0029

0.9993

0.9964

0.6937

8

0.0034

0.9989

1.8049

0.5994

9

0.0001

1.0000

2.0533

0.5989

10

0.0001

1.0000

1.4974

0.6707


❗ 模型状态分析:明显过拟合
🔥 表现细节:
  • 训练集准确率几乎100%(从头到尾)
  • 验证集准确率从第2轮以后开始波动下降
  • 验证 loss 不断上升,尤其第7轮以后大幅恶化

这就是典型的:

模型在训练集学得太好了,但对没见过的验证图泛化能力变差。


🎯 改进方向

优化点

解释

建议操作

✅ 数据增强

增强模型泛化能力,防止过拟合

加入随机旋转、裁剪、颜色扰动

✅ 模型正则化

强迫模型不要过于“记住”训练集

使用 Dropout 层 或 weight_decay

✅ 更强 backbone

如果模型本身太弱,学习不稳定

尝试 EfficientNet 等等

✅ 更平滑训练

减小学习率、加入 early stopping

调低 lr,观察 loss 曲线变化

✅ 类别不平衡

检查是否鸟和无人机数量严重不均

若不平衡,考虑使用 WeightedLoss


🖼️ 测试一张图片

从测试集中找张图推理看看效果

代码语言:python
代码运行次数:0
运行
复制
from PIL import Image
import torch.nn.functional as F

def predict_image(model, image_path, transform, class_names=['bird', 'drone']):
    model.eval()
    image = Image.open(image_path).convert('RGB')
    img_tensor = transform(image).unsqueeze(0).to(device)

    with torch.no_grad():
        output = model(img_tensor)
        probs = F.softmax(output, dim=1)
        pred_class = torch.argmax(probs).item()

    print(f"Prediction: {class_names[pred_class]}, Confidence: {probs[0][pred_class]:.4f}")
    return image

调用上面的函数

代码语言:python
代码运行次数:0
运行
复制
image_path = "test/images/BT/BIRD_123.jpg"  
predict_image(model, image_path, transform)

可以看到测试集的图片能够被正确识别出,

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

但下面我在网上找的图片却被判定为 bird

在这里插入图片描述
在这里插入图片描述

数据增强

接下来从简单的增广方法开始,比如随机旋转、随机裁剪、颜色扰动等。这样能增强训练数据的多样性,减少过拟合的风险。

📦 数据增强示例

可以使用 torchvision.transforms 来实现数据增强:

代码语言:python
代码运行次数:0
运行
复制
from torchvision import transforms

# 数据增强(训练集)
train_transform = transforms.Compose([
    transforms.RandomResizedCrop(224),  # 随机裁剪并缩放到224x224
    transforms.RandomHorizontalFlip(),  # 随机水平翻转
    transforms.RandomRotation(20),  # 随机旋转 -20 到 20 度
    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),  # 随机调整亮度、对比度等
    transforms.ToTensor(),  # 转换为Tensor
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),  # 正常化
])

# 验证集一般不需要增强,只做归一化
valid_transform = transforms.Compose([
    transforms.Resize(256),  # 调整为统一大小
    transforms.CenterCrop(224),  # 中心裁剪为224x224
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
📦 修改数据加载器

修改 train_loaderval_loader 来应用这些转换:

代码语言:python
代码运行次数:0
运行
复制
# 训练集应用增强
train_dataset = BirdVsDroneSimpleDataset("train/images", transform=train_transform)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4)

# 验证集只做归一化
val_dataset = BirdVsDroneSimpleDataset("valid/images", transform=valid_transform)
val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=4)
在这里插入图片描述
在这里插入图片描述

模型正则化

继数据增强之后,正则化(Regularization)是非常重要的一步,它能进一步减少过拟合、提升模型的泛化能力。我们来一步步加上 几种主流的正则化方法


🔹 1. Dropout(丢弃法)

虽然 ResNet 本身没有太多 Dropout,但可以在全连接层前加上一个:

代码语言:python
代码运行次数:0
运行
复制
import torch.nn as nn
import torchvision.models as models

class ResNetWithDropout(nn.Module):
    def __init__(self, num_classes=2):
        super().__init__()
        self.base_model = models.resnet50(pretrained=True)
        in_features = self.base_model.fc.in_features
        self.base_model.fc = nn.Sequential(
            nn.Dropout(0.5),  # 添加Dropout
            nn.Linear(in_features, num_classes)
        )

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

🔹 2. L2 正则化(权重衰减)

这个是在 optimizer 中设置的,默认不会加上。示例如下:

代码语言:python
代码运行次数:0
运行
复制
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-4)
  • weight_decay=1e-4 表示给每个参数增加一个 L2 惩罚。
  • 太大会导致欠拟合,太小不起作用,一般从 1e-4 ~ 1e-6 之间调试。

🔹 3. Early Stopping(早停)

这个不改模型,但改训练逻辑。

一句话概括:验证集 loss 连续 N 次没有下降,就提前终止训练,避免过拟合。

可以在训练代码中这样做:

代码语言:python
代码运行次数:0
运行
复制
best_val_loss = float('inf')
patience = 3
counter = 0

for epoch in range(num_epochs):
    train(...)  # 训练逻辑
    val_loss = validate(...)

    if val_loss < best_val_loss:
        best_val_loss = val_loss
        counter = 0
        # 保存模型
        torch.save(model.state_dict(), "best_model.pth")
    else:
        counter += 1
        if counter >= patience:
            print("早停触发,终止训练")
            break

🔹 4. Label Smoothing(标签平滑)

loss function 中设置:

代码语言:python
代码运行次数:0
运行
复制
criterion = nn.CrossEntropyLoss(label_smoothing=0.1)

它的作用是:不让模型对标签太自信,降低过拟合。


在这里插入图片描述
在这里插入图片描述

更换 Backbone

EfficientNet 在多个计算机视觉任务中都表现得非常强大,尤其是在高效的计算资源利用上,通过优化网络结构,能够在保持高性能的同时减少参数量和计算量。


📦 安装 EfficientNet

首先,我们需要安装 efficientnet-pytorch 库,来使用 EfficientNet:

代码语言:bash
复制
pip install efficientnet-pytorch

📦 使用 EfficientNet 替换 ResNet50

将 ResNet50 替换为 EfficientNet。EfficientNet 可以直接用来替换模型的 backbone,同时保留全连接层。以下是如何进行修改:

代码语言:python
代码运行次数:0
运行
复制
import torch
import torch.nn as nn
from efficientnet_pytorch import EfficientNet

class EfficientNetWithDropout(nn.Module):
    def __init__(self, num_classes=2):
        super().__init__()
        # 加载预训练的 EfficientNetB0(可以选择不同的版本:B0, B1, B2, B3, B4)
        self.base_model = EfficientNet.from_pretrained('efficientnet-b0')
        
        # 替换全连接层
        in_features = self.base_model._fc.in_features
        self.base_model._fc = nn.Sequential(
            nn.Dropout(0.5),  # Dropout
            nn.Linear(in_features, num_classes)  # 输出层,假设是二分类
        )

    def forward(self, x):
        return self.base_model(x)
📦 使用 EfficientNet 进行训练

在训练过程中,我们用这个新的 EfficientNetWithDropout 模型来替换原来的 ResNet50WithDropout,然后继续训练:

代码语言:python
代码运行次数:0
运行
复制
model = EfficientNetWithDropout(num_classes=2).to(device)
在这里插入图片描述
在这里插入图片描述

模型融合

模型融合(Ensemble Learning) 是高手级提升模型性能的重要策略之一,接下来一步步完成 EfficientNet + ConvNeXt 的融合


🧠 一、模型融合原理简述

常用模型融合方法:

方法

特点

Soft Voting

平均多个模型的预测概率(常用于分类)

Hard Voting

多数投票(取每个模型预测类别,选最多)

Weighted Voting

给表现更好的模型更高权重

Stacking

用一个“元模型”学习多个子模型输出

建议小白先从 Soft Voting 或 Weighted Voting 开始,比较简单实用。


⚙️ 二、实现 EfficientNet + ConvNeXt 融合
🧩 1. 构建两个模型
代码语言:python
代码运行次数:0
运行
复制
from efficientnet_pytorch import EfficientNet
from torchvision.models import convnext_base, ConvNeXt_Base_Weights

class EnsembleModel(nn.Module):
    def __init__(self, num_classes=2):
        super().__init__()
        # EfficientNet
        self.efficientnet = EfficientNet.from_pretrained('efficientnet-b0')
        in_feat_e = self.efficientnet._fc.in_features
        self.efficientnet._fc = nn.Linear(in_feat_e, num_classes)

        # ConvNeXt
        self.convnext = convnext_base(weights=ConvNeXt_Base_Weights.IMAGENET1K_V1)
        in_feat_c = self.convnext.classifier[2].in_features
        self.convnext.classifier[2] = nn.Linear(in_feat_c, num_classes)

    def forward(self, x):
        out1 = self.efficientnet(x)
        out2 = self.convnext(x)

        # Soft Voting (平均两个输出的 softmax 概率)
        prob1 = torch.softmax(out1, dim=1)
        prob2 = torch.softmax(out2, dim=1)

        final_out = (prob1 + prob2) / 2
        return final_out

🔧 2. 训练方式建议(冻结 & 微调)

可以先冻结 EfficientNet 和 ConvNeXt 的大部分参数,只训练最后一层,全连层的效果可能就很好;也可以后期解冻微调

代码语言:python
代码运行次数:0
运行
复制
# 冻结特征提取层,只训练最后的线性层
for param in model.efficientnet.parameters():
    param.requires_grad = False
for param in model.convnext.parameters():
    param.requires_grad = False

# 只解冻最后一层
for param in model.efficientnet._fc.parameters():
    param.requires_grad = True
for param in model.convnext.classifier[2].parameters():
    param.requires_grad = True

🧪 3. Loss & Metrics

用原来的交叉熵损失函数、准确率评估方式评估一下:

代码语言:python
代码运行次数:0
运行
复制
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=1e-4)

📊 4. 可选升级:Weighted Voting(可调融合比例)
代码语言:python
代码运行次数:0
运行
复制
final_out = 0.7 * prob1 + 0.3 * prob2  # 给 EfficientNet 更高权重

可以做超参数搜索,找最优组合。

在这里插入图片描述
在这里插入图片描述

参数调整

调参(Hyperparameter Tuning)是模型优化的关键步骤,像高手一样调参,可以让你在 Kaggle 或项目中脱颖而出。


🎯 一、调参的目的是什么?

调参 = 在 训练速度、模型泛化能力、最终准确率 之间找到一个最优平衡点。

目前已经有了不错的模型(EfficientNet + ConvNeXt),现在我们要做的是榨干它的潜力


🧱 二、常见可调参数(分类场景)

参数

常见范围

作用说明

learning rate

1e-4 ~ 1e-2

学习速度,太大震荡,太小太慢

batch size

16, 32, 64

影响稳定性和训练效率

optimizer

SGD / Adam / AdamW

不同优化器适应不同模型结构

weight_decay

1e-5 ~ 1e-3

L2 正则化,抑制过拟合

dropout

0.2 ~ 0.5

防止过拟合,尤其是全连接层

scheduler

CosineAnnealingLR / StepLR / ReduceLROnPlateau

控制学习率下降节奏

model weights

权重融合比例(0.5/0.5、0.7/0.3)

用于模型融合


⚙️ 三、怎么调参(方法)
1. 手动调参(新手推荐)

简单粗暴,适合现在阶段。每次改一个参数,观察变化,比如:

代码语言:python
代码运行次数:0
运行
复制
learning_rates = [1e-3, 5e-4, 1e-4]
for lr in learning_rates:
    optimizer = torch.optim.Adam(model.parameters(), lr=lr)
    train_model(model, ...)

用表格记录结果:

lr

train_acc

val_acc

notes

1e-3

0.99

0.78

初始尝试

5e-4

0.99

0.81

好一点

1e-4

0.98

0.83

更稳泛化更好


2. Grid Search(格子搜索)

穷举全部组合,比如:

代码语言:python
代码运行次数:0
运行
复制
from itertools import product

lrs = [1e-3, 1e-4]
bss = [32, 64]
wds = [0.0, 1e-4]

for lr, bs, wd in product(lrs, bss, wds):
    print(f"正在尝试 lr={lr}, bs={bs}, weight_decay={wd}")
    # 设置 optimizer、DataLoader 等重新训练

🔍 每轮尝试后保存结果,选出最优参数组合。


3. 高阶:使用 Optuna / Ray Tune(自动调参框架)

等熟练之后,建议用:

  • Optuna(强烈推荐):自动搜索参数空间,用贝叶斯优化找最优组合。
  • Ray Tune:支持分布式、并行搜索。

用 Optuna 示例(调 lr):

代码语言:python
代码运行次数:0
运行
复制
import optuna

def objective(trial):
    lr = trial.suggest_loguniform('lr', 1e-5, 1e-2)
    optimizer = torch.optim.Adam(model.parameters(), lr=lr)
    acc = train_and_eval(model, optimizer)
    return acc  # 越高越好

study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=20)
print("Best params:", study.best_params)

🧪 四、如何判断调参有效?
  • 验证集准确率 / loss 是否上升、收敛更平稳;
  • 混淆矩阵、分类报告(precision/recall/F1) 更细致评估;
  • 可视化 loss/acc 曲线,判断是否过拟合。

📝 五、调参建议
  • 先调学习率:最关键的参数,通常从 1e-3 或 5e-4 开始;
  • 再调 batch size 和 dropout:大 batch 会更稳,但显存消耗大;
  • 最后调权重衰减等正则化项
  • 融合时调权重比例:EfficientNet vs ConvNeXt 谁表现更好就给更高比例。

希望这篇文章对你有所帮助!下次见!🚀

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ResNet 50 作为基线
    • 🐣 Step 1:先了解这个项目是干嘛的?
    • 🧰 Step 2:搞定基本环境
    • 📦 Step 3:数据集结构
    • 🛠️ Step 4:训练图像分类模型(从头到尾流程)
      • 步骤 1:数据加载
      • 步骤 2:解析标签格式
      • 步骤 3:构建模型
      • 步骤 4:定义损失函数和优化器
      • 步骤 5:训练模型
      • 步骤 6:验证模型
      • 步骤7:绘制 loss / accuracy 曲线
  • 训练结果讲解
    • ❗ 模型状态分析:明显过拟合
      • 🔥 表现细节:
    • 🎯 改进方向
    • 🖼️ 测试一张图片
  • 数据增强
    • 📦 数据增强示例
    • 📦 修改数据加载器
  • 模型正则化
    • 🔹 1. Dropout(丢弃法)
    • 🔹 2. L2 正则化(权重衰减)
    • 🔹 3. Early Stopping(早停)
    • 🔹 4. Label Smoothing(标签平滑)
  • 更换 Backbone
    • 📦 安装 EfficientNet
    • 📦 使用 EfficientNet 替换 ResNet50
    • 📦 使用 EfficientNet 进行训练
  • 模型融合
    • 🧠 一、模型融合原理简述
    • ⚙️ 二、实现 EfficientNet + ConvNeXt 融合
      • 🧩 1. 构建两个模型
      • 🔧 2. 训练方式建议(冻结 & 微调)
      • 🧪 3. Loss & Metrics
      • 📊 4. 可选升级:Weighted Voting(可调融合比例)
  • 参数调整
    • 🎯 一、调参的目的是什么?
    • 🧱 二、常见可调参数(分类场景)
    • ⚙️ 三、怎么调参(方法)
      • 1. 手动调参(新手推荐)
      • 2. Grid Search(格子搜索)
      • 3. 高阶:使用 Optuna / Ray Tune(自动调参框架)
    • 🧪 四、如何判断调参有效?
    • 📝 五、调参建议
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档