GPU教育论坛:高校AI教学资源分享
【摘要】 GPU教育论坛:高校AI教学资源分享 ——从“0卡”到“千卡”:一门可复制的深度学习课程设计全栈指南 1. 课程定位与总体设计 1.1 目标学生画像先修:Python、线性代数、概率论人数:80–120人/届背景:60%工程、40%理科,深度学习0基础 1.2 课程矩阵(16周,3学分)周次主题GPU需求实验产出评价方式1–2神经网络基础0卡(CPU)MNIST 97%Autograder...
GPU教育论坛:高校AI教学资源分享
——从“0卡”到“千卡”:一门可复制的深度学习课程设计全栈指南
1. 课程定位与总体设计
1.1 目标学生画像
- 先修:Python、线性代数、概率论
- 人数:80–120人/届
- 背景:60%工程、40%理科,深度学习0基础
1.2 课程矩阵(16周,3学分)
周次 | 主题 | GPU需求 | 实验产出 | 评价方式 |
---|---|---|---|---|
1–2 | 神经网络基础 | 0卡(CPU) | MNIST 97% | Autograder |
3–4 | CNN+数据增强 | 0卡+Kaggle GPU | CIFAR-10 90% | Kaggle榜 |
5–6 | 预训练+微调 | 单卡 | 5类花卉95% | 报告+代码 |
7–8 | 混合精度 | 8卡 | ImageNet 1h | 速度/精度 |
9–10 | 多机DDP | 32卡 | BERT-base预训练 | loss曲线 |
11–12 | 大模型微调 | 云GPU券 | ChatGLM-6B LoRA | BLEU+演示 |
13–14 | 模型压缩 | 单卡 | ResNet50剪枝50% | 推理延迟 |
15–16 | 课程项目 | 自由 | 开放命题 | 路演+代码 |
1.3 技术栈选型
- 框架:PyTorch ≥2.1
- 加速:CUDA 12.1、cuDNN 8.9、Apex/TorchAMP
- 容器:Singularity(校内HPC强制)+Docker(个人笔记本)
- 调度:Slurm 22.05
- 监控:Weights & Biases + Prometheus + Grafana
2. “0卡”起步:CPU+模拟器+云GPU的三级递进实验
2.1 实验1:MNIST CPU baseline
目标:让学生在没有显卡的个人笔记本上跑出第一个“能work”的神经网络,建立信心。
2.1.1 环境准备(CPU only)
# Windows/Mac/Linux 通用
conda create -n ai_cpu python=3.10 -y
conda activate ai_cpu
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install tqdm matplotlib
2.1.2 网络定义(functional API风格,方便后续改GPU)
# mnist_cpu.py
import torch, torch.nn as nn, torch.optim as optim
from torchvision import datasets, transforms
device = torch.device("cpu") # 第一行就让学生看到“device”概念
class Net(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 32, 3, padding=1), nn.ReLU(),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(),
nn.MaxPool2d(2)
)
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(64*7*7, 128), nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(128, 10)
)
def forward(self, x): return self.classifier(self.features(x))
train_loader = torch.utils.data.DataLoader(
datasets.MNIST(root=".", train=True, download=True,
transform=transforms.ToTensor()), batch_size=64, shuffle=True)
model = Net().to(device)
opt = optim.Adam(model.parameters(), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()
for epoch in range(3):
for x, y in train_loader:
x, y = x.to(device), y.to(device)
opt.zero_grad()
loss = loss_fn(model(x), y)
loss.backward()
opt.step()
print(f"epoch {epoch} loss={loss.item():.4f}")
2.1.3 教学要点
- 强调“device”抽象:后续改cuda:0即可迁移
- 用torchinfo.summary(model, (1,28,28))可视化参数量,引出计算量概念
- 课堂小练习:把batch_size调到1024,观察内存占用,引出“显存”与“内存”差异
2.2 实验2:CIFAR-10 + Kaggle GPU 免费券
2.2.1 云GPU环境(Kaggle Kernel)
# 学生只需在Kaggle Notebook里打开GPU开关
# 免费30h/周,足够做完实验
2.2.2 数据增强+轻量CNN(向ResNet过渡)
from torchvision.models import resnet18
model = resnet18(weights=None) # 不预训练,从头训练
model.conv1 = nn.Conv2d(3, 64, 3, padding=1, bias=False) # 32x32
model.maxpool = nn.Identity()
model.fc = nn.Linear(512, 10)
训练脚本与单机DDP完全一致(见下一节),学生只需改device=“cuda”。
2.2.3 排行榜机制
- 公开榜单:学生提交.csv,实时看到排名
- 隐藏测试集:防止手工标注刷分
- 前10%额外加分,激发“卷”GPU效率
3. 单卡到8卡:PyTorch DDP与混合精度教学实战
3.1 实验3:ImageNet子集(100类,13万张图)
3.1.1 数据集制作(一次生成,复用4年)
# 从完整ImageNet-1k抽100类
python tools/subset_imagenet.py --source /dataset/imagenet --class_file data/imagenet100.txt --target /dataset/imagenet100
3.1.2 单机8卡DDP模板
import os, torch, torch.distributed as dist, torch.multiprocessing as mp
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.cuda.amp import autocast, GradScaler
from torchvision.models import resnet50
from utils import get_args, get_loader, AverageMeter
def main(rank, world_size):
os.environ["MASTER_ADDR"] = "127.0.0.1"
os.environ["MASTER_PORT"] = "12355"
dist.init_process_group("nccl", rank=rank, world_size=world_size)
torch.cuda.set_device(rank)
model = resnet50().cuda(rank)
model = DDP(model, device_ids=[rank])
opt = torch.optim.SGD(model.parameters(), lr=0.1*world_size, momentum=0.9, weight_decay=1e-4)
scaler = GradScaler()
train_loader = get_loader(train=True, batch_size=64, distributed=True)
for epoch in range(90):
train_loader.sampler.set_epoch(epoch)
losses = AverageMeter()
for x, y in train_loader:
x, y = x.cuda(rank, non_blocking=True), y.cuda(rank, non_blocking=True)
opt.zero_grad()
with autocast(): # 混合精度
loss = torch.nn.functional.cross_entropy(model(x), y)
scaler.scale(loss).backward()
scaler.step(opt)
scaler.update()
losses.update(loss.item())
if rank == 0: print(f"epoch {epoch} loss {losses.avg:.4f}")
dist.destroy_process_group()
if __name__ == "__main__":
world_size = torch.cuda.device_count()
mp.spawn(main, args=(world_size,), nprocs=world_size)
3.1.3 课堂讨论要点
- 为什么lr=0.1*world_size?——线性缩放原则
- GradScaler的作用?——防止underflow
- num_workers、pin_memory、non_blocking=True 三件套
- 通过nvidia-ml-py实时打印显存,让学生直观看到AMP节省30%
3.2 实验4:BERT-base预训练(中文Wiki 2G语料)
3.2.1 数据预处理(参考HuggingFace教程)
python -m datasets.load_dataset wikipedia --language zh --date 20230601 --beam_runner DirectRunner
python tools/create_mlm_data.py --input data/zhwiki --output data/mlm --max_seq_len 128
3.2.2 多机32卡DDP(校园超算)
见第4节。
4. 多机千卡:Slurm+Singularity打通校园超算
4.1 超算环境简介
- 节点:20台DGX-A100,每台8×A100 80GB
- 网络:InfiniBand HDR 200Gbps
- 系统:CentOS 7.9,Slurm 22.05
4.2 容器镜像制作(教师提前做,学生直接用)
# Singularity定义文件 gpu_ai.def
Bootstrap: docker
From: pytorch/pytorch:2.1.0-cuda12.1-cudnn8-devel
%post
pip install transformers datasets wandb nvidia-ml-py3
singularity build gpu_ai.sif gpu_ai.def
# 上传到全局/NFS/singularity/gpu_ai.sif
4.3 Slurm脚本模板
#!/bin/bash
#SBATCH -J bert_pretrain
#SBATCH -p gpu
#SBATCH -N 4
#SBATCH --ntasks-per-node=8
#SBATCH --cpus-per-task=8
#SBATCH --gres=gpu:8
#SBATCH -t 24:00:00
#SBATCH -o %x-%j.out
module load singularity/3.11
srun singularity exec --nv /nfs/singularity/gpu_ai.sif \
python -m torch.distributed.run \
--nproc_per_node=8 --nnodes=4 --node_rank=$SLURM_NODEID \
--master_addr=$(scontrol show hostnames $SLURM_JOB_NODELIST | head -n1) \
--master_port=6000 \
bert_mlm_pretrain.py --max_steps 100000 --warmup_steps 10000 --batch_size 64
4.3.1 课堂演示
- 实时watch -n 1 squeue查看排队
- 用slurm-spank-x11拉起TensorBoard,投影到教室大屏
- 对比单节点vs 4节点loss下降曲线,让学生直观感受“线性加速比”
5. 教学管理:账号、配额、作业、排行榜一站式脚本
5.1 账号自动化(基于LDAP+Slurm account)
# tools/create_user.py
import subprocess, string, secrets
def create_user(uid, csv_file):
pwd = ''.join(secrets.choice(string.ascii_letters) for _ in range(12))
subprocess.run(["useradd", "-m", "-s", "/bin/bash", uid])
subprocess.run(["chpasswd"], input=f"{uid}:{pwd}")
subprocess.run(["sacctmgr", "add", "account", uid, "Fairshare=100"])
with open(csv_file, "a") as f:
f.write(f"{uid},{pwd}\n")
5.2 GPU配额脚本(基于Slurm QOS)
# 每名学生每周GPU时长≤24h
sacctmgr create qos name=student_gpu weekly=24:00:00
sacctmgr modify user set qos=student_gpu where name=<uid>
5.3 作业自动评测(Autograder)
- 学生提交zip含code/与README.md
- GitHub Classroom自动触发CI(Runner带GPU)
- 评分维度:
- 精度是否过线
- 训练时间(惩罚暴力for循环)
- 显存峰值(鼓励AMP)
- 代码风格(black+flake8)
5.4 排行榜与可视化
- 前端:React + Ant Design
- 后端:FastAPI,定时拉取W&B API
- 投影:每节课前5分钟滚动播放“本周GPU利用率TOP10”
6. 学生视角:一份可复制的课程生存指南
6.1 没有GPU?三步走
- Kaggle Kernel:每周免费30h,记得关GPU再关浏览器
- Colab Pro+:教育邮箱9.9$/月,A100 40G
- 校内云:提交工单,24h内审批
6.2 如何“抢”卡?
- Slurm优先级=排队时间+公平份额,凌晨3–6点提交 Job 成功率+50%
- 多节点任务用srun --exclusive,避免被小作业插队
6.3 Debug清单
现象 | 可能原因 | 排查命令 |
---|---|---|
NCCL error | 端口未放行 | export NCCL_DEBUG=INFO |
OOM | batch_size太大 | nvidia-smi dmon -s p |
速度慢 | num_workers=0 | 设成CPU核心数 |
7. 教师视角:如何评估实验效果与持续迭代
7.1 数据驱动
- 每届保留W&B project,形成纵向数据库
- 指标:平均训练时间↓、峰值显存↓、最终精度↑、学生满意度问卷
7.2 反馈闭环
- 结课问卷必答:哪个实验最耗时?哪段代码最困惑?
- 教学团队每月例会,用GitHub Issue模板跟踪“待优化实验”
7.3 持续集成
- 每年CUDA大版本升级后,用CI自动跑通全部notebook
- 录制“教师操作录屏”,降低新助教上手门槛
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)