毕业设计选题人工智能:从技术科普到可可落地的项目实践
背景痛点:选题“高大上”≠能跑通
做毕设最怕“开局一张嘴,剩下全靠编”。AI 方向尤其如此,很多同学一上来就想“复现 GPT”“干掉 AlphaGo”,结果三个月过去,连环境都没装好。我总结了三类高频踩坑:
- 选题太大:直接做“通用对话机器人”,数据、算力、知识储备都不够,最后只能拿别人的接口包装一下,答辩被问“创新点在哪”直接社死。
- 技术栈混乱:今天 PyTorch、明天 TensorFlow,后天听说 JAX 很酷,环境冲突把系统盘撑爆,Git 仓库里躺着十几个残次版本。
- 忽视部署:实验室 2080Ti 上跑通 95% 准确率,心想稳了,结果导师说“现场演示用笔记本”,风扇一响,模型直接 OOM,分数瞬间对半。
一句话:本科 AI 毕设的核心不是“发论文”,而是“能跑、能看、能讲”。先把故事讲圆,再谈创新。
技术选型对比:让框架替你背锅
先把结论说在前面:本科场景优先选“开发快、模型小、部署省”的方案,别被“最新最热”绑架。下面用一张表把三种常见路线放在同一维度对比(满分 5 星)。
| 维度 | PyTorch | TensorFlow Lite | ONNX Runtime |
|---|---|---|---|
| 开发效率 | ★★★★☆ | ★★★☆☆ | ★★☆☆☆ |
| 模型体积 | ★★☆☆☆ | ★★★★★ | ★★★★☆ |
| 部署难度 | ★★☆☆☆ | ★★★★★ | ★★★★☆ |
| 中文社区 | ★★★★★ | ★★★☆☆ | ★★☆☆☆ |
| 跨平台 | ★★☆☆☆ | ★★★★★ | ★★★★☆ |
经验之谈:
- 如果你只想在笔记本上做 Demo,PyTorch 最快;
- 如果最后要塞进安卓 APK,直接上 TFLite,量化后模型 2 MB 不是梦;
- 若实验室要求 Windows / Linux 双机演示,ONNX 一次导出两头跑,省得折腾。
核心实现细节:以“校园场景图像分类”为例
下面用“ResNet18 识别教学楼/食堂/操场”这个小而全的案例,把端到端流程拆成 5 步。每一步都给出“最少可用”的输入输出,保证你能跑通。
1. 数据准备:先别急着爬全网
- 打开相机,围绕三个场景各拍 200 张,共 600 张,分辨率 640×480 足够;
- 按 8:1:1 分成 train/val/test,文件夹层级用 ImageFolder 格式,省代码;
- 用 Albumentations 做“旋转+色彩抖动”30 行代码搞定数据增广,防止过拟合。
2. 模型微调:站在巨人肩膀
- 直接
torchvision.models.resnet18(pretrained=True),替换最后一层fc=Linear(512, 3); - 冻结前面层,只训最后一层 5 个 epoch,再解冻全局 10 个 epoch,学习率 1e-3 → 1e-4;
- 用
CosineAnnealingLR平滑下降,笔记本 1050Ti 也能 20 min 跑完。
3. 导出与转换:一次训练多端运行
- PyTorch → ONNX:
torch.onnx.export(model, dummy, "campus.onnx", opset_version=11) - ONNX → TFLite:
onnx-tf convert -i campus.onnx -o campus.pbtflite_convert --graph_def_file=campus.pb --output_file=campus.tflite
记得加--optimization=DEFAULT把模型压到 1.8 MB。
4. 本地推理:写个 50 行脚本就能演示
# infer_onnx.py import cv2, numpy as np, onnxruntime as ort mean, std = np.array([0.485, 0.456, 0.406]), np.array([0.229, 0.224, 0.225]) def preprocess(path): img = cv2.resize(cv2.imread(path), (224, 224))[:,:,::-1] / 255.0 return ((img - mean) / std).astype(np.float32).transpose(2,0,1)[None] sess = ort.InferenceSession("campus.onnx") inputs = preprocess("test.jpg") logits = sess.run(None, {sess.get_inputs()[0].name: inputs})[0] print(["teaching", "canteen", "playground"][logits.argmax()])5. 安卓 Demo:把.tflite塞进 Asset
- 用 Android Studio 新建 Empty Activity,把
campus.tflite丢进app/src/main/assets; - 依赖
implementation 'org.tensorflow:tensorflow-lite:2.14.0'; - 用
TensorImage做输入预处理,GPU delegate 一开,帧率 30 FPS 小意思。
完整训练脚本:Clean Code 版
下面给出单文件可跑通版本,带类型标注与日志,复制即可训练。建议把超参数抽到argparse,方便调参。
# train_campus.py import os, torch, torch.nn as nn from torchvision import datasets, transforms, models from torch.utils.data import DataLoader from torch.optim.lr_scheduler import CosineAnnealingLR DATA_DIR = "campus_images" BATCH_SIZE = 16 EPOCHS_FT = 5 EPOCHS_ALL = 10 LR = 1e-3 DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") def get_dls(): tfms = transforms.Compose([ transforms.RandomResizedCrop(224), transforms.ColorJitter(0.2,0.2,0.2), transforms.ToTensor(), transforms.Normalize([0.485,0.456,0.406], [0.229,0.224,0.225]) ]) train_ds = datasets.ImageFolder(os.path.join(DATA_DIR, "train"), tfms) val_ds = datasets.ImageFolder(os.path.join(DATA_DIR, "val"), tfms) return (DataLoader(train_ds, BATCH_SIZE, shuffle=True, num_workers=4), DataLoader(val_ds, BATCH_SIZE, shuffle=False, num_workers=4)) def build_model(n_classes=3): m = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) m.fc = nn.Linear(m.fc.in_features, n_classes) return m.to(DEVICE) @torch.no_grad() def accuracy(model, loader): model.eval() correct, total = 0, 0 for x,y in loader: x,y = x.to(DEVICE), y.to(DEVICE) correct += (model(x).argmax(1) == y).sum().item() total += y.size(0) return correct/total def train(): tr_loader, val_loader = get_dls() model = build_model() criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.fc.parameters(), lr=LR) sched = CosineAnnealingLR(optimizer, T_max=EPOCHS_FT) # 阶段1:只训最后一层 for epoch in range(EPOCHS_FT): model.train() for x,y in tr_loader: x,y = x.to(DEVICE), y.to(DEVICE) loss = criterion(model(x), y) optimizer.zero_grad(); loss.backward(); optimizer.step() sched.step() print(f"Stage1 Epoch{epoch} acc={accuracy(model, val_loader):.3f}") # 阶段2:全局微调 optimizer.add_param_group({"params": (p for p in model.parameters() if p.requires_grad)}) sched.T_max = EPOCHS_ALL for epoch in range(EPOCHS_ALL): model.train() for x,y in tr_loader: x,y = x.to(DEVICE), y.to(DEVICE) loss = criterion(model(x), y) optimizer.zero_grad(); loss.backward(); optimizer.step() sched.step() print(f"Stage2 Epoch{epoch} acc={accuracy(model, val_loader):.3f}") torch.save(model.state_dict(), "campus.pth") print("Training done, campus.pth saved.") if __name__ == "__main__": train()生产考量:冷启动、资源与隐私
- 冷启动:首次加载
.tflite会构建 GPU delegate,耗时 1-2 s,可在 Application 层预加载并显示占位图; - 资源限制:量化后模型 1.8 MB,推理峰值内存 60 MB,在 4 GB 手机毫无压力,但 2 GB 老设备要开
nnapi; - 隐私合规:采集同学人脸照片需脱敏,只保留场景;若上传云端,要提供“数据不出域”的说明,否则答辩容易被问 GDPR/个保法。
避坑指南:血与泪的 5 句话
- 数据泄露:别把带学生正脸的压缩包传到 GitHub Public,一旦开源,删库也跑不掉;
- 过拟合:训练 acc 99%,验证 65%,多半是增广没做或学习率爆炸;
- GPU 依赖:写代码时加
device="cuda" if torch.cuda.is_available() else "cpu",否则演示现场没显卡直接拉闸; - 路径硬编码:Windows 路径
\与 Linux/混用,用pathlib.Path一把梭; - 忽视 README:验收老师只给你 5 min 配置,不写清依赖版本,等于主动放弃印象分。
结尾:把模型跑在手机上,故事才刚刚开始
上面这套流程下来,你已经拥有“能训练、能转换、能部署”的最小闭环。下一步不妨思考:
- 把 TFLite 封装成 Flutter 插件,让 iOS 端也能一键识别;
- 用 FastAPI 把 ONNX 模型包成 HTTP 服务,微信小程序直接调用;
- 或者给模型加增量学习,新学期拍 10 张新楼照片,本地微调 1 min 即可更新。
动手复现,把 Demo 拿到同学手机上跑一圈,你会惊喜地发现:所谓“毕业设计选题人工智能”,最难的从来不是算法,而是让算法真正跑出门。祝你答辩顺利,代码常 Green!