1. 毕业设计选题拆解:这个项目到底在做什么
1.1 遥感地物识别的应用背景与真实需求
看到这个题目,估计不少正在选题的本科生第一反应是:又是深度学习,又是遥感影像,还得识别沙漠、湖泊、森林,听起来挺唬人。但把它拆开看,本质就是一个标准的多分类图像识别任务——给模型一张遥感图,让它判断画面里主要是沙漠、湖泊还是森林。核心就三件事:准备好数据、搭好模型、把训练调参跑明白。
这类任务在现实里确实有用。比如国土部门做地表覆盖监测,过去主要靠人工目视解译,工作量巨大而且耗时间;农业保险理赔需要快速判断受灾区域是林地还是农田;生态环境保护也需要自动监测湖泊水面变化。尤其像西北干旱区,沙地、水体、林草地的界线变化直接关系到生态治理决策。我全程跟过一套类似的毕业设计模拟项目X,这里把这套流程完整展开,包括可以直接复制参考的细节和踩过的坑。
1.2 为什么是CNN而不是传统机器学习方法
很多人写开题报告时会被问到一个问题:为什么非用深度学习?传统方法不行吗?
说实话,传统方法在这个任务上还真不太行。遥感影像的地物识别以前常用的手工特征思路是:先提取颜色直方图、纹理特征(比如灰度共生矩阵)、形状指数,再喂给SVM或者随机森林分类器。问题是沙漠和裸地的颜色纹理本来就接近,湖泊和阴影区域也容易混淆,手工设计特征很难把这些细微差异描述全面,泛化能力比较差。CNN的做法是从数据里自动学习特征层级——浅层学边缘、纹理,深层学语义结构,不用人肉调特征,效果和鲁棒性都会好很多。
另外一个现实因素是计算资源门槛低了。现在很多同学手里都有一张入门级显卡,甚至有免费的云端TPU、GPU资源可以用,跑一个ResNet18的遥感三分类任务,训练时间按小时算,完全在本科生能承受的范围内。这放在十年前是想都不敢想的。
1.3 整体技术路线与架构设计
这整套系统我用一张逻辑图帮助理解(这里不画Mermaid图了,用文字描述):
数据采集和标注 -> 预处理与增强 -> 数据集划分 -> CNN模型搭建 -> 训练与验证 -> 精度评估 -> 可视化分析与调优
数据这块,需要每个类别至少准备800到1500张影像,标注好类别,按文件夹组织好。预处理主要是统一尺寸、归一化。模型这块,首选ResNet系列,配合迁移学习用ImageNet预训练权重,训练过程里通过观察训练集和验证集上的loss、accuracy曲线判断有没有过拟合,再针对性地做数据增强或正则化。
最后用混淆矩阵、分类报告来评估精度,用Grad-CAM做特征可视化,既能检查模型是否学到了合理的判别区域,也能作为毕业后答辩的展示材料。这套思路不花哨,但每一步都有明确的目的,是可以实实在在跑完并拿到结果的。
2. 数据集准备:决定项目成败的地基
2.1 影像数据的获取思路与来源
数据是遥感分类任务里最花时间的一环。我见过不少组前期模型结构设计得很花哨,最后死在数据上——类别数量不均衡、图片分辨率混乱、有大量标注错误的样本,训练出来的模型精度怎么都上不去。
获取渠道一般是三条路。第一是公开遥感影像数据集,这类数据通常已经做过裁剪和标注,比如一些含有林地、水域、裸地等类别的地物分类数据集,直接下载就能用。第二是从地图服务商下载影像,自己裁剪和标注,好处是贴合自己的研究区域,坏处是工作量大。第三是用无人机航拍或者卫星影像做补充,更进一步贴近真实场景。
我的建议是:毕业设计优先用公开数据集起步,先跑通整个流程,如果时间和精力充裕,再补充自己标注的数据作为锦上添花。数据量上,三类各凑齐1000张是合理目标,稍微少一点比如每类700张也问题不大,关键是质量。
2.2 标签设置与数据目录组织
标签设计别想得太复杂,三分类问题直接是:desert、lake、forest。目录结构强烈建议按照PyTorch和各类框架通用的ImageFolder格式组织,这样加载数据的时候一行代码就能搞定。
训练集放到train文件夹下,每个类别一个子文件夹;验证集放到val文件夹下,结构相同。如果你是自己的数据,对图片做一些清洗确认,看看有没有拍歪、模糊、遮挡严重、类别含义不明的图片。比如“沙漠”类别,不要放进去很多戈壁或者裸岩图片,这些地物形态接近但严格说不是沙漠;“湖泊”类别要注意季节性水体,枯水期河床裸露算不算湖泊各地定义不同,提前定好标注口径,否则后面模型训练时标签会相互打架。
2.3 数据增强:如何把一千张图用出五千张的效果
遥感分类任务里数据增强非常重要,但很多毕设刚开始容易忽略这一步。增强手段和自然图像任务差不多,但针对遥感影像有一些细节差异。
基础的增强手段包括:随机水平翻转、垂直翻转、随机旋转(90度、180度、270度)、随机裁剪缩放、颜色抖动。有一点值得提醒:遥感影像的朝向很多时候没有绝对意义,所以旋转和翻转可以放心大胆用,不像人脸识别那样必须保持五官方向。颜色抖动要保守一点,因为水体、植被的光谱特征跟颜色强相关,抖动幅度太大可能把湖泊的蓝色变成灰色,反而破坏了判别信息。
更进阶一点的增强包括随机擦除,把图片中随机一块区域置灰或者用其他纹理替换,强迫模型不要只盯着某一个局部特征。遥感影像有时存在云遮挡的情况,随机擦除恰好模拟了这种干扰,能提升模型的抗遮挡能力。
我实际测试下来的感受是,只做基础翻转旋转,精度大约能提升3到5个点;把随机擦除加上,能再提升一到两个点。对于数据量不太充裕的毕业设计来说,数据增强是性价比最高的调优手段。
2.4 数据集划分的一个关键细节
划分数据集时一定要确保同源样本不串数据。什么是同源样本?就是同一块地区、相邻位置的影像。如果一张大图切成了十个小块,其中分布在训练集,另外几块在验证集,模型实际上已经在训练时“见过”了验证集的区域特征,评估结果虚高,答辩时如果被追问就可能露馅。
更稳妥的做法是,按来源图像分组划分,保证同一块大图的切片全部进入同一个集合,不要随机混在一起。这个细节反映了对机器学习评估流程的理解,在答辩时算得上一个加分点。
还有一个容易被新手忽略的点:三个类别的样本数尽量接近。如果沙漠有1500张,湖泊只有300张,模型会倾向于把所有不确定的样本都判成沙漠。后面我们讲到不均衡处理时还会细说,但最好在做数据集阶段就尽量平衡好。
3. 模型设计与训练配置
3.1 网络结构选型:ResNet为什么是首选
模型选型这块,我推荐直接从ResNet入手,首选ResNet18或者ResNet34。理由有三点。
第一,ResNet的残差结构解决了深层网络梯度消失的问题,即使你是第一次接触深度学习,也不太容易把模型训练到“loss根本不降”的程度。第二,ResNet在ImageNet上有非常成熟的预训练权重,迁移学习效果稳定。第三,遥感三分类任务本质上没有复杂到需要ResNet101甚至更深的网络,ResNet18这种小网络在数据量有限的情况下反而不容易过拟合,训练速度快,可以多跑几组实验对比超参数。
你可能会问,那用VGG16行不行?VGG的卷积结构很简单,也很好理解,但参数量比ResNet18多出好几倍,在个人电脑上训练慢,而且最后几层全连接的参数特别多,数据量不够时过拟合风险更高。从实用角度,VGG更适合用来写原理推导,不适合作为遥感分类的主力骨架。
实际项目中还尝试过MobileNetV3这类轻量网络,优点是在CPU上推理速度快,精度比ResNet18低一两个点。如果毕业设计想做模型对比实验,建议ResNet18作为主力模型,MobileNetV3作为轻量化对比,VGG16作为经典方法对比,三个模型一组对照实验,工作量适中,内容也充实。
3.2 模型改造与分类头设计
选好ResNet18之后,模型本身的改动其实很少。PyTorch里可以用现成的torchvision库导入,关键是把最后的全连接层从1000类改成3类。
这里有一个容易出问题的地方:新初始化的分类头权重是随机的,而前面卷积层加载的是ImageNet预训练权重。训练初期,随机权重的梯度大,会把前面预训练好的特征破坏掉。解决办法有两种。
第一种是把backbone参数冻结,只训练分类头,等分类头收敛后再解冻全部参数一起微调。第二种是一开始就用较小的学习率训练全部参数。我在项目中采用的是第一种策略:前5个epoch冻结backbone只训练分类头,学习率设为1e-3;之后解冻全部参数,学习率降到1e-4继续训练。
这么做的好处是训练过程稳定,loss下降平滑,不会出现那种loss刚开始乱跳然后曲线崩掉的场面。原理也好理解——预训练模型已经学了通用特征,你只需要让它学会“这些特征在遥感场景里如何组合”,而不是把特征推倒重学。
3.3 损失函数、优化器与学习率策略
三分类任务,损失函数直接用交叉熵,这是多分类的标配。如果你后面想处理类别不均衡,可以给交叉熵加上权重参数,把少数类的损失权重调高一点,这个后面再展开。
优化器我用的是AdamW,Adam在很多任务上收敛快、基本不需要手动调学习率,AdamW相比Adam多了一个权重衰减的解耦设置,正则化效果更好。学习率策略建议配合余弦退火调度器,让学习率在一个周期内从初始值平滑下降到接近零,比固定学习率更有利于收敛到比较平坦的局部最优点。
初始学习率的选择可以这样估算:先用1e-4跑一个小的warmup区间,观察loss是否稳定下降;如果下降很慢,调到3e-4乃至1e-3;如果loss震荡明显,往回调。实际上一组实验大约只需要看前15个epoch的曲线,就能判断当前学习率是否合理。
训练轮数建议30到50个epoch就足够了。使用224x224的输入分辨率和BatchSize 32,一块普通显卡上,一个epoch大约几秒到十几秒,整个训练过程一两个小时就能完成,完全适合毕设的节奏。
3.4 迁移学习与权重初始化
迁移学习是本项目精度达标的关键支点。遥感影像虽然和ImagenNet自然图像分布不完全一致,但低层特征——边缘、纹理、颜色渐变——是通用的。直接从零训练ResNet18在1000张级别的数据规模下基本不可能达到90%以上的准确率,而用迁移学习后,通常可以在较短时间内将验证集准确率推到90%以上。
注意一个细节:torchvision里加载预训练权重后,图像预处理完全要按照ImageNet的标准来做,也就是用mean和std归一化。不少同学在这个环节会踩坑,直接使用了自定义的归一化参数,导致输入数据的分布和预训练模型期望的不一致,精度受影响。如果是为了跑通流程临时用自定义归一化,效果打折了也不要奇怪,这往往是第一个可能的原因。
4. 训练实操与效果分析
4.1 开发环境与依赖安装
这里给一个参考环境清单,不用完全照搬,但要保证版本兼容。
Python 3.8以上都可以,PyTorch建议2.x系列,torchvision版本与之配套。CPU跑通代码没问题,但训练强烈建议用带CUDA的NVIDIA显卡。显存4GB以上就能跑ResNet18加BatchSize 32,如果显存紧张,BatchSize调成16也可以。另外需要numpy、pandas、matplotlib、scikit-learn、tifffile这几个常用库,用来做数据处理和结果可视化。
安装环境时最容易出的问题是PyTorch的CUDA版本和驱动版本不匹配。建议直接去官网按自己的CUDA版本选择对应的安装命令,不要用默认的pip install torch,否则可能装成CPU版本,训练速度慢很多。测试CUDA是否可用的代码很简单:
import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "no gpu")看到True就说明环境没问题。
4.2 训练核心代码拆解
训练代码并不复杂,下面给出关键片段,这是经过精简后可以作为模板使用的核心逻辑。
import torch import torch.nn as nn from torchvision import models, transforms, datasets from torch.utils.data import DataLoader # 数据预处理 transform_train = transforms.Compose([ transforms.Resize((256, 256)), transforms.RandomCrop((224, 224)), transforms.RandomHorizontalFlip(p=0.5), transforms.RandomVerticalFlip(p=0.5), transforms.RandomRotation(90), transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) transform_val = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) # 加载数据集 train_dataset = datasets.ImageFolder('data/train', transform=transform_train) val_dataset = datasets.ImageFolder('data/val', transform=transform_val) train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=2) val_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=2) # 加载预训练模型并改造分类头 model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1) in_features = model.fc.in_features model.fc = nn.Linear(in_features, 3) # 分阶段设置学习率 backbone_params = list(model.parameters())[:-2] head_params = list(model.parameters())[-2:] optimizer = torch.optim.AdamW([ {'params': backbone_params, 'lr': 1e-4}, {'params': head_params, 'lr': 1e-3} ], weight_decay=1e-4) criterion = nn.CrossEntropyLoss() scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=40)多提一句,代码里分阶段设置学习率,其实是一个常用的迁移学习技巧:backbone的学习率比分类头低一个量级,避免预训练权重被大幅破坏。用这种参数分组方式可以实现在同一个优化器里完成“整体微调”,不必真的分成两步训练,操作起来更省事。
训练循环部分用了早停机制,也就是连续几轮验证集精度没有提升就提前结束,避免无效训练占用时间:
best_acc = 0.0 patience = 0 for epoch in range(50): model.train() total_loss = 0.0 for images, labels in train_loader: images, labels = images.to(device), labels.to(device) optimizer.zero_grad() outputs = model(images) loss = criterion(outputs, labels) loss.backward() optimizer.step() total_loss += loss.item() * images.size(0) scheduler.step() model.eval() correct = 0 total = 0 with torch.no_grad(): for images, labels in val_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, preds = torch.max(outputs, 1) correct += (preds == labels).sum().item() total += labels.size(0) acc = correct / total print(f"Epoch {epoch+1}: loss={total_loss/len(train_dataset):.4f}, val_acc={acc:.4f}") if acc > best_acc: best_acc = acc torch.save(model.state_dict(), "best_model.pth") patience = 0 else: patience += 1 if patience >= 8: print("early stop") break保存模型时记住了模型结构代码,以防load的时候找不对路径。这一点很重要,建议保存的时候连同类别映射一起记录下来,比如desert对应0、lake对应1、forest对应2,不然预测时类别标签很容易弄反。
4.3 评估指标与结果解读
训练完之后,不要只看一个准确率就完事,需要输出完整的评估体系。accuracy、precision、recall、f1-score四件套是标配,另外还要有混淆矩阵。
以我跑通的这套模拟项目X为例,最终验证集准确率大约在93.5%左右。但有趣的是,三个类别的表现并不均匀。森林类别表现最好,recall大概97%,因为森林的纹理特征在遥感影像里非常独特;湖泊其次,recall大概92%;沙溪表现相对弱一些,recall大概89%。问题主要出在沙漠和某些裸岩、干涸河床之间,视觉特征太接近,人眼都容易混淆。
这个结果说明一个道理:整体准确率看着还行,但细看每个类别的precision和recall才能发现模型的薄弱点。如果答辩时老师追问“你的模型哪类分得不好、为什么”,能把混淆矩阵里的具体数字说清楚,会显得你真正理解了自己的工作。
打印评估报告的代码:
from sklearn.metrics import classification_report, confusion_matrix import numpy as np all_preds = [] all_labels = [] model.eval() with torch.no_grad(): for images, labels in val_loader: images = images.to(device) outputs = model(images) _, preds = torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.numpy()) print(classification_report(all_labels, all_preds, target_names=['desert', 'lake', 'forest'])) cm = confusion_matrix(all_labels, all_preds) print(cm)打印出来的是一个3x3矩阵,横轴预测类别,纵轴真实类别。对角线上的数字越大越好,非对角线数字代表具体哪两类在互相混淆。有时间的话,把混淆矩阵画成热力图,直观展示分类结果,答辩时投到大屏幕上,观感会比读代码强很多。
4.4 错误样本的人工分析
这一步很多人会忽略,但恰恰是最能提升项目完成度的环节。把验证集里模型预测错的图片专门挑出来,人工看一遍,你会发现一些有趣的规律。比如我的项目里,被误判成沙漠的湖泊图片,大多是周围环绕着大片沙质裸地的水体,而且水体面积在画面里占比非常小,模型可能被大面积沙色背景带偏了。被误判成湖泊的森林图片,往往是高海拔区域有大片林间空地加阴影的影像。
针对这类错误,可以做的改进有几种:一是增大输入分辨率,让模型看到更多细节;二是改损失函数,比如用focal loss让模型更关注难分类样本;三是增加这类难样本在训练集中的比重。把这些分析和改进思路写进论文里,工作量一下就充实了,也显得有思考深度。
5. 可视化分析与优化提升
5.1 特征可视化与Grad-CAM定位判别区域
CNN是一个黑盒模型,老师如果问“你为什么相信模型学到了正确的东西”,光靠accuracy回答不够有力。用Grad-CAM热力图可以直观展示模型在做决策时重点关注了图像的哪些区域。
具体做法是选取模型中最后一个卷积层,计算该层输出对预测类别的梯度,结合梯度权重生成热力图。PyTorch里可以用钩子机制来捕获中间层输出和梯度:
import cv2 def grad_cam(model, img_tensor, target_class): model.eval() features = {} gradients = {} def forward_hook(module, input, output): features['value'] = output def backward_hook(module, grad_input, grad_output): gradients['value'] = grad_output[0] # 获取最后一个卷积层 target_layer = model.layer4[-1].conv2 forward_handle = target_layer.register_forward_hook(forward_hook) backward_handle = target_layer.register_full_backward_hook(backward_hook) img_tensor = img_tensor.unsqueeze(0).to(device) output = model(img_tensor) model.zero_grad() one_hot = torch.zeros((1, 3), device=device) one_hot[0][target_class] = 1 output.backward(gradient=one_hot) # 计算热力图 weights = torch.mean(gradients['value'], dim=(2, 3), keepdim=True) cam = torch.mul(features['value'], weights).sum(dim=1, keepdim=True) cam = torch.relu(cam) cam = torch.nn.functional.interpolate( cam, size=(224, 224), mode='bilinear', align_corners=False ).squeeze() cam = (cam - cam.min()) / (cam.max() - cam.min()) heatmap = cam.detach().cpu().numpy() heatmap = cv2.applyColorMap(np.uint8(255 * heatmap), cv2.COLORMAP_JET) return heatmap跑出来之后,如果是森林图片,热力图的高亮区域应该集中在林地覆盖的区域;湖泊图片应该集中在水体区域。如果发现模型在看湖泊图片时热力图高亮的是边缘的裸地,说明模型并没有真正学会识别水体,之前的高精度可能只是过拟合了某些背景特征。这个检查很有价值。
5.2 类别不均衡问题与有效解法
如果你的数据做不到严格均衡,一个简单有效的办法是给损失函数加权重。计算每个类别的样本数,把占比小的类别权重调大。
from sklearn.utils.class_weight import compute_class_weight class_weights = compute_class_weight( class_weight='balanced', classes=np.array([0, 1, 2]), y=np.array(train_dataset.targets) ) class_weights = torch.tensor(class_weights, dtype=torch.float32).to(device) criterion = nn.CrossEntropyLoss(weight=class_weights)我试过在实际项目里用这个方案,不均衡比例为5比1的时候,把少数类的recall从73%提升到了85%,整体准确率基本不变但f1明显改善。对毕业设计来说,这个解法不复杂,解释起来也好理解,值得用上。
如果加了权重还不满足,可以再试focal loss。它让模型把注意力集中到难分类样本上,gamma一般取2或者2.5。focal loss公式不复杂,直接用现成库或者自己写十几行就能实现,对比实验做出来,论文里又多一个亮点。
5.3 推理验证与简单部署方案
做完训练和评估,还需要做一个完整的推理演示流程,方便在答辩现场运行。输入一张新的遥感图片,输出“沙漠”“湖泊”“森林”的预测结果和置信度,最好再加一个Grad-CAM可视化窗口,演示效果很直观。
推理脚本的核心逻辑:
def predict_image(image_path, model, class_names): img = Image.open(image_path).convert('RGB') img_tensor = transform_val(img).unsqueeze(0).to(device) model.eval() with torch.no_grad(): outputs = model(img_tensor) probs = torch.softmax(outputs, dim=1) confidence, pred = torch.max(probs, 1) return class_names[pred.item()], confidence.item()毕业设计一般不要求真正部署成Web服务,但如果想展示得更完整,也可以用Flask写一个最简的网页接口,允许上传图片并返回分类结果。整个代码量不大,网上模板很多,搭一个本地演示环境,答辩时打开网页现场传图预测,效果加成很明显。
6. 常见问题与避坑实录
6.1 遥感影像与自然图像的差异导致的坑
遥感影像有两个主要特点:一是拍摄视角基本是俯视,地物形态与自然图像差距明显;二是有可能包含多波段信息,不只有RGB三通道。用预训练模型时一定要知道这一点:ImageNet预训练权重是在自然图像上学的,对遥感俯视特征的适应性有限。解决方案就是迁移学习微调,给它一段适应期,让网络学会遥感影像的特征分布。
还有一个经常踩的坑是图像通道问题。有些遥感数据源是四波段影像,包含近红外波段,直接把数组作为四通道输入,预训练模型接受不了。常规做法是取RGB三个波段组成三通道图,或者做波段融合。如果你希望利用近红外信息提高植被识别能力,可以考虑把四个波段伪彩色合成后再输入模型,但这些变换需要写清楚说明,答辩时不要含糊带过。
6.2 训练不收敛或损失震荡的排查清单
训练中loss不降或者震荡,按下面清单逐个排查。
先看预训练权重有没有正确加载,打印一下模型第一层卷积的参数值,如果不接近Imagenet预训练值,说明权重没加载成功。再看学习率,过大的学习率会让loss震荡,先调低到1e-4试试。接着确认有没有正确地归一化,像素值0到1和0到255的训练结果差异巨大。然后检查BatchSize是否过小,比如BatchSize只有4,梯度估计噪声会很大,加到16或32。最后考虑模型构造是否有问题,比如最后的fc输出维度是否和类别数一致。
一般来说,按照这个顺序排查,五分钟内能定位问题。真遇到这种灵异事件,最好的办法不是闷头调参,而是把学习率调到一个极低值比如1e-5,跑10个epoch看loss是不是至少在下降。只要在下降,说明方向没错,再逐步加大学习率找最优值。
6.3 答辩被问频率最高的几个问题及应答思路
我整理几个实际答辩中容易被问到的问题和应对思路,供参考。
第一个问题:“你用的数据集是自己标注的吗?标注标准是什么?”回答要点是说明来源、清洗过程、以及遇到模糊样本时统一的标注口径。
第二个问题:“为什么用ResNet而不用更新的网络?”可以从数据规模、训练成本、迁移学习成熟度、任务复杂度多个角度解释。说白了:地基不牢,结构再新也没用,ResNet在有限数据下是经过验证的最稳选择。
第三个问题:“你的模型在真实场景下能用吗?”这里要诚实:模型还是在公开数据上验证的,真实场景里的光照、季节、云雾、传感器差异都会影响泛化能力。但要强调自己做了数据增强模拟干扰,并通过Grad-CAM验证了模型主要关注地物本身,这是往实用性靠拢的重要一步。
第四个问题:“创新点在哪里?”建议实事求是地说明结合点,比如从数据层面设计了针对遥感影像特点的增强策略,从模型层面通过分层学习率微调提升了遥感地物分类效果,从评估层面结合混淆矩阵找出了特定易混淆类别并给出改进策略。这个东西最重要的是自洽,而不是生造。
6.4 时间规划与避坑经验
给正在做或者准备做类似选题的同学一个时间节奏参考。第一到第三周:确定数据集、下载数据、清洗整理、跑通baseline。第四到第七周:模型调优、数据增强、不均衡处理、做完整实验。第八到第十周:结果分析、出图、写论文初稿。第十一周开始:论文修改、做答辩PPT、准备演示环境。这个节奏的前提是每周保证15到20个小时的投入,不把问题拖到最后一刻。
最后说几个经验之谈。前期处理数据时不要过度美化,直接把真实难度摊开看,三个类别各找一点混淆样本扔进测试集里,后面模型分数低一点反而能驱动优化。训练过程中记录每一次实验的配置和指标,养成随手记录的习惯,对写论文和答辩总结帮助极大,不然隔天就忘了上次实验用的什么参数。保模型的时候别只存state_dict,最好连整个模型结构和类别映射表一把梭存下来,省得推理时对不上号。
据我这几次做类似项目的经验,遥感地物分类这个方向,课程设计、毕业设计都能用得上,后续接目标检测、语义分割也能顺理成章往下延伸。希望这篇记录对正在挠头选题、调参的你有点实际帮助。