简介:这份资源是2023年春复旦大学人工智能A实验的完整资料包,适合正在学习人工智能课程、需要参考实验设计与Python实现的学生使用。内容围绕机器学习、深度学习等核心知识点,覆盖多个实验模块,可辅助理解从数据预处理到模型训练的完整流程。压缩包共52个文件,以43个Python脚本为主,包含具体实验代码与运行逻辑;另有4个Markdown笔记、3个PDF报告和2个数据集压缩包,分别用于记录实验步骤、展示项目方案与提供训练数据,结构清晰便于按目录检索。资源包整体仅2.35MB,轻量精简,不影响快速下载与本地部署。目前已有107人学习下载,适合复旦大学相关课程的同学对照参考,也适合其他高校人工智能入门者借鉴实验思路与代码组织方式。通过这份资料,读者可以获得完整的实验代码框架、项目报告样例及数据预处理思路,有助于缩短实验环境搭建时间,提升对人工智能实验环节的整体把握。
1. 拿到人工智能A实验包先别跑:十分钟看清这份zip值不值得
拿到一份“2023年春某高校人工智能A实验_A同学.zip”这类压缩包,大多数人第一反应是解压、找train.py、直接跑。反直觉的是,直接跑往往是最慢的路:依赖版本、数据集路径、模型保存格式,任何一环不匹配,报错就会层层叠加,最后连实验要求都没看全。这份实验包真正解决的核心问题不是代码写得多惊艳,而是能不能让后来者按原样复现。对新手,跟着README和目录结构走,能省掉一半配环境的时间;对想补项目履历的工程师,它是一份完整的AI实验基准,覆盖图像分类、模型训练、结果可视化这条标准链路。所以,在解压之前先花十分钟看懂结构,才是最省时间的打开方式。
2. 目录拆解:从README到requirements,先读懂文件结构再动手
一个合格的AI实验包,绝大多数会按 code、data、docs、results 的约定来组织。你在终端里看到完整文件列表之后,第一件事不是打开某个 .py 文件,而是确认入口脚本在哪、数据脚本要不要单独生成、结果输出到哪里。这一步没做,后面跑通了也说不清每个文件的作用。
2.1 解压后的第一件事:用 find 列全文件,别只看 readme
常见做法是先解压到独立目录,然后用 find 把两层以内的文件全部列出来。README 会告诉你实验目标,但只有完整文件列表能让你看清楚“这个包实际写了什么”。
unzip ai_lab.zip -d ai_lab cd ai_lab find . -maxdepth 2 -type f | sortunzip的-d参数指定解压目录,避免把一堆文件散落在当前路径下。find . -maxdepth 2只往下看两层目录,既能覆盖大部分结构,又不会把深层缓存目录带进来;-type f只看文件不看目录;sort让输出按字典序排列,方便横向对比命名规律。
拿到列表之后,我一般会先找三类东西:以train、main、run开头的入口脚本;以.md、.txt、.pdf结尾的说明文档;以及名字像data、dataset的目录。入口脚本决定从哪启动,文档决定实验要求,数据目录决定你是否需要额外下载数据集。三样东西在同一个包内能互相呼应,这份代码的完整度就算过关。
典型完整结构通常长这样:
ai_lab/ ├── README.md ├── requirements.txt ├── run.py ├── data/ │ └── download_data.py ├── code/ │ ├── model.py │ └── dataset.py └── docs/ └── 实验说明.md如果你看到的列表里没有 README,也没有 requirements.txt,只有一堆没有目录结构的 .py 文件,那这份包大概率是从别人手里转了几手之后丢过的。这时候别急着怨文件不全,先照下面的方式自己补一个目录,再往下走。
2.2 典型目录分工:code、data、results、docs 分别放什么
AI 实验包的目录命名不是随机的。最常见的是 code(代码)、data(数据)、results(输出结果)、docs(说明文档)。数据如果太大,一般不会直接放进 zip,而是放一个download_data.py或fetch_data.sh,让使用者自己下载后放到 data 目录下。
| 目录 | 职责 | 典型文件 | 注意事项 |
|---|---|---|---|
| docs | 实验要求与报告模板 | 实验说明.md | 先读它,决定工作边界 |
| code | 模型定义、训练与评估脚本 | train.py、model.py | 所有改动都在这层做 |
| data | 原始数据与预处理脚本 | download_data.py | 尽量只读,不要原地修改 |
| results | 模型输出、曲线图、日志 | curves.png、log.txt | 可重新生成,不入原始代码 |
results通常是交给老师或验收方看的东西,重新跑就会覆盖旧文件。如果你要保留某次跑出来的结果,记得先复制一份到单独目录,不要跟代码混在一起。data目录一旦被预处理脚本原地改动,数据集就脏了,后期想恢复只能重新下载。很多人把预处理脚本放在 data 目录下,换台机器后全部相对路径失效,这类问题几乎都是目录职责不清引起的。
2.3 requirements.txt:版本锁为什么决定你能不能复现
正常 AI 实验包的依赖文件是完整的,但“完整”和“能跑”之间还差一个版本对齐。2023 年前后的实验,常见组合是 TensorFlow 2.6、numpy 1.19、scikit-learn 1.0。这三个版本之间的关系比很多人想的要敏感:numpy 升到 1.21 之后,旧版 TensorFlow 的某些接口会直接抛类型错误。
tensorflow==2.6.0 numpy==1.19.5 scikit-learn==1.0.2 matplotlib==3.4.3 pandas==1.3.5像这样把版本写死(==)的文件叫版本锁。>=的写法适合新项目,但复现旧实验时一定要改成==,否则 pip 会帮你装上当前最新的依赖,而最新版很可能和实验代码不兼容。看到requirements.txt里全是>=,第一件事就是手动锁定版本,或者创建环境时直接指定版本。有了版本锁也建议加一行pip list确认实际安装结果,pip 在解析依赖时可能因为某个包的传递依赖与锁定版本冲突,最终装上的是奇怪版本。这种问题不一定会立刻报错,而是等训练到一半才炸,提前检查比事后排错便宜得多。
3. 环境搭建:用 conda 锁住 Python 和依赖版本,旧实验就能原样跑
实验包里的 requirements.txt 只解决依赖列表,真正决定能不能跑的是 Python 解释器版本和底层数值库组合。复现旧实验的坑,几乎有一半都出在这两层。下面这套流程是我处理这类旧项目时固定的方案。
3.1 先选 Python 版本:tensorflow 和 torch 的兼容性区间
不同项目的 Python 版本选择不是玄学,而是由主流深度学习框架的发布周期决定的。TensorFlow 2.6 官方支持 Python 3.7 到 3.9;PyTorch 1.10 支持 3.6 到 3.9。这里取交集,Python 3.8 是覆盖率最高的选择,也是大多数 AI 实验包的默认环境。
conda create -n ai_lab python=3.8 -y conda activate ai_lab python --versionconda create -n的-n是环境名,python=3.8指定解释器版本,-y跳过确认。激活之后用python --version验证当前环境确实是 3.8,避免后续 pip 装错环境。
为什么不直接用一个最新 Python 3.11 从头配?因为旧项目里可能是cv2、sklearn、tensorflow三个库加起来才能形成一个可运行组合,而它们对 Python 3.11 的支持都不完整。与其在几百行报错里找一个根本不存在的兼容方案,不如一开始就把解释器版本卡在当年最常见的档位。
3.2 用 conda 创建环境并安装依赖:最小命令与参数说明
环境创建好之后,安装依赖有两条路径:一条是pip install -r requirements.txt,另一条是 conda 从 channel 安装。对一个以 TensorFlow 为主的实验包,我一般用 pip,因为 PyPI 上的轮子比 conda 默认源更新更全。
pip install -r requirements.txt pip checkpip install -r会按 requirements 文件逐个解析并安装。装完后必须执行pip check,它会列出哪些包之间存在版本冲突。比如常见报错是numpy 1.26 requires ... but you have numpy 1.19 which is incompatible,说明某个包刚才覆盖了 numpy 版本。遇到这种情况,直接重新执行pip install -r requirements.txt不一定有效,因为 pip 默认不会降级已经安装的包。
正确做法是在pip install后面加--upgrade,或者先卸载冲突包再安装。对旧实验包,我更推荐用conda install装 numpy 这类底层库,因为 conda 解决二进制依赖冲突更彻底,能自动选到匹配的 build,而 pip 可能装上另一个不兼容的小版本。
conda install numpy=1.19.5 scikit-learn=1.0.2 -y pip install tensorflow==2.6.0混用两种包管理器要记住一个原则:底层数值库尽量交给 conda,上层模型库用 pip。这样 numpy 与 TensorFlow 之间的二进制兼容性由 conda 兜底,TensorFlow 本身的安装轮子由 pip 保证。顺序是先把底层 numpy、pandas 装好,再装上层框架。
3.3 依赖装完不等于能用:用 pip check 和 conda list 做双保险
依赖装完只能说“装上了”,不代表“能用”。旧实验包最容易翻车的一步,是 import 阶段直接抛ModuleNotFoundError或AttributeError。前者是包没装上,后者是装错了版本。
python -c "import tensorflow as tf; print(tf.__version__)"这条命令返回的版本号如果和 requirements 不一致,说明在安装过程中某个依赖被间接替换了。常见的元凶是protobuf。TensorFlow 2.6 对 protobuf 有硬性版本约束,而新版 protobuf 会把tf_record等处直接打崩。解决办法是把 protobuf 也用==写死,比如protobuf==3.19.6。
提示:装完依赖后,跑一下
conda list导出当前环境的完整版本快照。这份快照是实验报告里“可复现环境”的直接证据,也是自己回滚的后悔药——哪天改坏了,对比快照就知道动了哪个包。
4. 跑通第一个实验:图像分类从数据加载到损失曲线的完整步骤
大多数 AI 实验包的第一个实验是图像分类,因为它的数据路径、标签映射、训练循环最有代表性。很多人卡在数据加载这一层,而不是模型训练本身。下面把从数据到训练再到看曲线的完整链路捋一遍。
4.1 用 ImageFolder 读取图像数据:标签从哪来、顺序怎么定
图像分类实验最常见的做法是把数据按类别放成子目录,然后用ImageFolder直接加载。标签顺序由目录名的字典序决定,而不是文件夹在磁盘里的排列顺序。这一点不看代码的人很容易忽略,等到写混淆矩阵时才发觉类别反了。
from torchvision import datasets, transforms # 常见做法:训练集和验证集分别挂在 data 下的子目录 transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) train_data = datasets.ImageFolder("data/train", transform=transform) print(train_data.classes) # 按字典序输出的类别名 print(train_data.targets[:10])ImageFolder的构造逻辑是扫描data/train下的第一层子目录作为类别,每张图片的标签就是它所在目录的索引。classes属性会按字母顺序排列类别名,targets是每张图对应的整数标签。这里的Normalize用的是预训练模型的默认统计值,因为实验模型大多是预训练模型微调,沿用默认参数效果更稳定。如果数据是单通道灰度图,mean 和 std 要改成单个值,否则形状对不上。
Resize((224, 224))会直接改变宽高比,图片内容可能被拉伸。实验数据如果不规整,训练精度会明显偏低。标准改进是先把图片通过Resize缩放到较短边,再用CenterCrop裁剪到 224,避免图片变形。
4.2 训练脚本必调的四个参数:batch_size、lr、epochs、seed
实验包的训练脚本一般用argparse接收参数,入口命令长这样:
python train.py --batch_size 32 --lr 0.001 --epochs 50 --seed 42batch_size决定每次迭代进的样本数,同时受显存约束,32 是默认值,跑不动就降到 16 或 8。lr是学习率,0.001 对 Adam 是保守起点,对 SGD 来说偏大,需要改成 0.01 附近再看。epochs不是越大越好,50 轮在小数据集上通常够用,再多就要小心过拟合。seed是随机种子,写死 42 后,模型初始化和数据打乱的顺序固定下来,两次训练结果才可比较。
| 参数 | 常见默认值 | 作用 | 调试建议 |
|---|---|---|---|
| batch_size | 32 | 每次迭代样本数 | 显存不够降到 16 或 8 |
| lr | 0.001 | 参数更新步长 | Adam 用 0.001;SGD 从 0.01 起 |
| epochs | 50 | 完整遍历数据次数 | 看验证集曲线,早停 |
| seed | 42 | 随机种子 | 固定后结果可复现 |
实际操作里最容易错的是参数名不一致。比如代码里写的是--learning-rate,命令里写成--lr,argparse 会直接报 unrecognized argument。拿到不熟悉的代码,先执行python train.py --help,看它实际定义了哪些参数,再照着传,别想当然。
4.3 看曲线判断训练状态:loss 和 accuracy 到底信哪个
训练结束后,实验包通常会在 results 目录下生成 loss 曲线和 accuracy 曲线。看曲线不是看它有没有下降,而是看训练集和验证集之间的差距。
import matplotlib.pyplot as plt # train_loss 与 val_acc 是训练过程中收集的列表 plt.figure(figsize=(8, 4)) plt.subplot(1, 2, 1) plt.plot(train_loss, label="train loss") plt.title("Loss") plt.xlabel("epoch") plt.ylabel("loss") plt.legend() plt.subplot(1, 2, 2) plt.plot(val_acc, label="val acc") plt.title("Accuracy") plt.xlabel("epoch") plt.ylabel("acc") plt.legend() plt.savefig("results/curves.png", dpi=150)这里把损失曲线和精度曲线画在同一个画布的两个子图里。subplot(1, 2, 1)表示一行两列的第一格,第二格是 accuracy;savefig的dpi=150保证图片在报告里放大不糊。实验报告里一般只看测试集 accuracy,但调参时真正要看的是 val_acc,因为测试集只能最后用一次,看多了会过拟合到测试集上。
如果 train loss 一直降而 val_acc 在某个 epoch 后不再升,基本可以断定模型过拟合了。这时优先调低 epochs 或增加数据增强,而不是继续加大模型。这类实验最常见的返工原因,就是拿验证集当测试集反复调参,最后测试集分数虚高却被详细追问时露馅。
5. 避坑记录:复现 2023 年旧实验代码的五个常见坑
这一章是复现这一类 AI 实验包时最容易遇到的五个问题。每条按现象、原因、解决三部分写,方便你对照排查。
5.1 Python 版本过高导致 tensorflow 装不上
现象:在 Python 3.10 环境里执行pip install tensorflow==2.6.0,pip 提示 No matching distribution found,或者安装完成后 import 直接报错。
原因:TensorFlow 2.6 的预编译轮子只覆盖 Python 3.7 到 3.9,Python 3.10 没有官方轮子。pip 找不到匹配安装包,也不是源码构建,直接放弃。
解决:回到 Python 3.8 或 3.9。用 conda 建一个 python=3.8 的环境,再进入环境安装。不要尝试用--ignore-installed绕过,底层的 C 扩展会在运行时崩溃。
conda create -n ai_lab python=3.8 -y conda activate ai_lab pip install tensorflow==2.6.05.2 中文路径和空格让数据加载直接崩掉
现象:实验代码在 Windows 上跑,数据集路径带中文目录,ImageFolder报路径不存在;路径里有空格,训练到一半找不到文件。
原因:旧实验代码的路径处理常用字符串拼接,遇到中文路径时编码或分隔符问题会导致相对路径解析失败;空格则会被某些文件解析函数拆分。
解决:把整个实验包和数据集放到纯英文、无空格的路径下,比如D:\ai_lab\data。如果一定要保留中文目录名,在代码里统一改用pathlib.Path处理路径,兼容性会好很多。
注意:Python 自带
open和os.path在处理中文路径时通常没问题,问题大多出在第三方库依赖的底层文件读取逻辑上。换路径比改库省事得多。
5.3 随机种子没锁导致两次训练结果对不上
现象:同一份代码,同一批数据,先后跑两次训练,测试集 accuracy 相差几个百分点,报告没法写。
原因:模型权重初始化、数据 shuffle、数据增强的随机性都没有固定。深度学习框架默认只用全局随机数,代码里没有显式设置 seed,每次运行的随机序列完全不同。
解决:在训练脚本开头统一设置 Python、numpy、torch 的随机种子。
import random import numpy as np import torch random.seed(42) np.random.seed(42) torch.manual_seed(42) if torch.cuda.is_available(): torch.cuda.manual_seed_all(42)这样设置后,两次训练的随机序列完全一致。注意torch.cuda.manual_seed_all只影响 GPU,CPU 上的结果由torch.manual_seed决定。如果代码里用了额外的数据增强库,还需要设置对应库的 seed。
5.4 无图形界面服务器上 matplotlib 报错
现象:在远程服务器上跑训练,plot 那一步直接报No display found and $DISPLAY is not set,或者后面plt.show()卡住不动。
原因:服务器没有图形环境,matplotlib 默认使用 TkAgg 这类依赖显示器的后端,自然找不到显示设备。
解决:在代码文件开头指定非交互式后端 Agg,必须在pyplot导入之前设置。
import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as pltAgg后端只做渲染,不弹窗口,非常适合服务器环境。设置后plt.savefig能正常保存,plt.show()不会执行显示动作,避免卡死。
5.5 加载旧模型时报版本错配
现象:训练完保存的模型,在另一台机器上加载时,报ValueError: Unknown layer或KeyError。
原因:模型保存时用的是带类的对象,加载时依赖库版本不一致,pickle 结构对不上。最典型的是 TensorFlow 的 SavedModel 在新版本中读取旧格式,或者 PyTorch 保存了类路径而新环境里类名变了。
解决:保存时优先用model.save("model.h5")配合load_model成对使用,而不是直接存 pickle。版本差异已经出现时,回到和保存时一致的依赖版本加载一次,再重新导出标准格式。
model.save("results/model.h5") # 另一侧环境 from tensorflow import keras model = keras.models.load_model("results/model.h5")model.h5是 HDF5 格式,只要 TensorFlow 大版本一致,跨小版本加载的兼容性比 pickle 好得多。验证实验时,同一份权重至少在两个环境里能读出来,结果才可信。
6. 三个进阶验证技巧:把别人的实验包变成能讲清楚的自己作品
跑通实验只是第一步,交报告时真正拉开差距的是验证环节。这里说三个我常用的技巧,都能在当前实验包代码上直接加。
6.1 用多组随机种子重跑训练,证明实验结论稳定
只跑一次的精度没有任何说服力。把训练脚本包在一个 for 循环里,换三组 seed,统计均值方差,报告里写“三组随机种子下测试集精度均值为 X±Y”,比单次结果可信很多。
for seed in 42 2023 7; do python train.py --seed $seed --epochs 50 done这个循环把同一模型在三个不同随机种子下各训练一次。最终报告里列出三次 accuracy,如果波动在 1% 以内,说明模型稳定;波动超过 3%,说明训练过程本身方差大,需要先调参再谈结论。
6.2 把错误样本可视化,给实验结果加一页“证据”
只看 accuracy 数字,很难判断你是真理解还是碰运气。把验证集里预测错误的图片挑出来,按 predicted label 和 true label 排成图,能一眼暴露模型的系统性错误。
from torchvision import transforms import matplotlib.pyplot as plt # mis_idx 是验证集中预测错误的样本索引列表 plt.figure(figsize=(10, 10)) for i, idx in enumerate(mis_idx[:9]): plt.subplot(3, 3, i + 1) img, true_label = val_data[idx] pred_label = preds[idx] plt.imshow(transforms.ToPILImage()(img)) plt.title(f"true: {true_label}, pred: {pred_label}") plt.axis("off") plt.savefig("results/errors.png", dpi=150)这张图用于实验报告的分析部分,比文字描述直接。你会发现错误大多集中在易混淆类别或光照极端的样本上,这本身就是可以展开讨论的内容。
6.3 用 git 记录每次改动,翻车也留后悔药
实验包的原始代码不要在原目录上直接改。解压后第一步就git init,每次调参、改预处理都提交一次,这样不管你怎么折腾,都能回到任何一个已知的可用状态。
git init git add . git commit -m "baseline: reproduce 2023 spring lab" python train.py --lr 0.001 --epochs 50 --seed 42 git add results/ git commit -m "try lr 0.001"第二个 commit 把训练结果也纳入版本管理,模型文件丢失后还能从 git 历史里找回来。AI 实验最大的痛点是很多过程不可复现,git 是成本最低的后悔药。这三个技巧既不会改动原始教学代码的语义,又能让报告结论更扎实。这些年做实验评审时,凡是按这个习惯走的项目,被追问细节时的底气都明显不一样。希望帮到你。
本文还有配套的精品资源,点击获取