1. 为什么我还在用 Colab 跑深度学习实验
第一次接触 Colab 是在一个本地显卡烧掉的下午。当时手头一个图像分类的小项目刚跑到一半,风扇突然狂转然后黑屏,拆开一看显卡供电模块糊了。那段时间显卡价格又离谱,重新买一张的钱够我吃好几个月外卖。一个做算法的朋友随口说了句"你试试 Colab 啊,免费给 GPU",我就这么入了坑,一用就是好几年。
Colab 本质上是 Google 提供的一个云端 Jupyter Notebook 环境,你打开浏览器就能写 Python、跑训练、存数据,背后挂着一块真实的 GPU 或者 TPU。免费档位最常见的就是 Tesla K80,偶尔能分到 T4,运气好还能碰到 P100。K80 这块卡放到今天确实老了——Kepler 架构,24GB 显存但被拆成两块 12GB,算力也就那样,FP32 大概 8.7 TFLOPS。但关键在于"免费"两个字,对于学生党、刚入门的新手、或者只是想快速验证一个想法的人来说,这个门槛低到几乎没有。
我写这个系列的第二篇,是因为第一篇发出去之后后台收到一堆问题:怎么保持连接不掉、数据集怎么传上去、为什么我的 GPU 用着用着就没了、断点续训到底怎么写。这些问题我在实际使用中全都踩过,而且每一个都让我浪费过至少半天时间。所以这篇不打算讲"怎么打开 Colab"这种基础操作,而是聚焦在真正影响你实验效率的那些细节上——环境配置、数据流转、训练稳定性、资源调度,以及那些官方文档不会告诉你的坑。
适合读这篇的人:手上有 Colab 账号、跑过一两次 notebook、但总觉得用得不顺手、经常被断开或者速度慢到怀疑人生的朋友。如果你完全没接触过,建议先去看第一篇把基础跑通,再回来抠这些细节。
2. Colab 的运行机制与资源分配逻辑
2.1 免费 GPU 到底是怎么分给你的
很多人以为 Colab 是"打开就有 K80",其实不是。你拿到的硬件是动态分配的,取决于当前时段、你的账号历史使用情况、以及后台的调度策略。我做过一个粗略统计:工作日下午打开,大概率是 K80;凌晨或者周末,碰到 T4 的概率明显上升。T4 是 Turing 架构,16GB 显存,FP32 算力 8.1 TFLOPS,但支持 FP16 和 INT8 加速,实际跑推理和混合精度训练比 K80 快不少。
分配逻辑官方从来没公开过,但根据社区里大量用户的反馈和我自己的观察,大致有这么几条规律:新账号或者长期不活跃的账号,前几次使用往往能拿到较好的卡;连续高强度使用(比如一天跑好几个小时)之后,分配到的资源会变差,甚至直接给你 CPU 实例;同一个账号同时开多个 notebook,只有第一个能拿到 GPU,后面的全是 CPU。这个机制其实很好理解——资源池就那么大,平台要保证尽可能多的人能用上,所以会做限流。
提示:如果你打开 notebook 发现
torch.cuda.is_available()返回 False,先别急着骂,大概率是当前时段 GPU 池满了。关掉等十几分钟再开,或者换个时间段,通常就能恢复。
2.2 会话生命周期与断连的本质
Colab 的会话(session)不是永久的。免费用户最长连续运行 12 小时,但这只是理论上限,实际中经常更短。触发断连的原因主要有三类:一是空闲超时,浏览器标签页不活跃大概 90 分钟就会被回收;二是资源超限,比如你显存爆了、内存吃太多、或者磁盘写满;三是平台主动调度,这个没法预测。
这里有个很多人搞混的点:浏览器关掉不等于会话结束。只要 notebook 还在后台执行代码,会话就还活着。但如果你把标签页关了又不去管它,过一段时间照样会被回收。反过来,就算你一直开着页面,如果代码跑完了停在那里不动,空闲计时器一样会走。
理解这个机制之后,策略就清晰了:要么让代码一直有活干,要么用脚本定期制造"活动"。我自己的做法是在训练循环里加一个轻量的心跳输出,比如每个 epoch 打印一次时间戳,这样既能看到进度,又能让系统认为会话是活跃的。但注意,这个只能延缓空闲回收,不能突破 12 小时的硬上限。
2.3 存储结构:哪些东西会丢,哪些不会
Colab 的存储分两块,搞不清楚这块会吃大亏。/content目录是临时的,会话一结束全部清空,你下载的数据集、训练好的权重、写的中间文件,统统没了。而挂载到/content/drive的 Google Drive 是持久的,除非你手动删,否则一直在。
我刚用的时候不知道这个区别,辛辛苦苦跑了一晚上的模型,第二天打开发现啥都没了,那种心情你们体会一下。后来学乖了,所有重要产出第一时间往 Drive 里写。但 Drive 也有坑:它的读写速度比本地磁盘慢很多,尤其是大量小文件的时候,IO 会成为瓶颈。所以我的习惯是——数据集解压到/content本地跑,训练完的权重和日志再同步回 Drive。
| 存储位置 | 持久性 | 读写速度 | 适合放什么 |
|---|---|---|---|
/content | 会话结束即清空 | 快 | 解压后的数据集、临时文件、checkpoint |
/content/drive | 持久保存 | 慢 | 最终权重、训练日志、代码备份 |
/tmp | 会话结束即清空 | 最快 | 高频读写的缓存文件 |
这个表格是我踩了无数次坑之后总结的,你可以直接照着用。核心原则就一句话:跑的时候用本地,存的时候用 Drive。
3. 环境配置的实操细节与避坑
3.1 挂载 Drive 与目录规划
挂载 Drive 的代码很简单,但里面有个授权流程容易卡住:
from google.colab import drive drive.mount('/content/drive')运行之后会弹出一个授权链接,点进去选账号、复制验证码、粘贴回来。这一步在无痕模式下经常失败,建议用正常窗口。挂载成功后,你的 Drive 根目录就出现在/content/drive/MyDrive下面。
我强烈建议在 Drive 里建一个固定的项目目录结构,比如:
MyDrive/ colab_projects/ project_a/ data/ checkpoints/ logs/ notebooks/这样每次开新会话,挂载完直接cd进去就行,不用每次重新找路径。而且多个项目之间不会互相干扰,清理的时候也方便。我见过有人把所有东西堆在 Drive 根目录,几百个文件混在一起,找都找不到。
3.2 依赖安装的正确姿势
Colab 预装了一堆常用库——PyTorch、TensorFlow、NumPy、Pandas 基本都有。但版本不一定是你想要的,而且有些冷门库需要自己装。这里有个关键技巧:pip 安装默认装到系统环境,重启会话就没了。所以每次开新会话,依赖都要重装。
我的做法是写一个setup.sh或者一个初始化 cell,把所有安装命令集中起来,开新会话第一件事就是跑它。比如:
pip install -q transformers==4.30.0 pip install -q datasets pip install -q wandb-q是 quiet 模式,减少输出刷屏。装完之后建议验证一下版本:
import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))这三行是我每次开新会话必跑的,确认环境没问题再往下走。曾经有一次我没检查,直接开训,跑了半小时才发现装的是 CPU 版本的 torch,白费功夫。
注意:Colab 的预装环境偶尔会更新,导致你之前能跑的代码突然报错。遇到这种情况,先
pip list看看关键库的版本,大概率是某个依赖被升级了。锁定版本号是最稳妥的办法。
3.3 GPU 型号检测与适配
不同 GPU 的显存和算力差异很大,代码里最好做一下适配。比如 batch size 的设置,K80 上可能只能开到 16,T4 上能开到 64。我通常会在开头加一段检测逻辑:
import torch gpu_name = torch.cuda.get_device_name(0) if 'K80' in gpu_name: BATCH_SIZE = 16 elif 'T4' in gpu_name: BATCH_SIZE = 64 elif 'P100' in gpu_name: BATCH_SIZE = 48 else: BATCH_SIZE = 32 print(f"Using {gpu_name}, batch size = {BATCH_SIZE}")这样不管分到什么卡,代码都能自动调整,不用手动改来改去。虽然简单,但省心。
4. 数据流转:从本地到 Colab 的高效方案
4.1 小数据集的直接上传
如果你数据量不大(几百 MB 以内),最简单的方式就是直接拖拽上传到/content。Colab 左侧有个文件面板,点上传按钮选文件就行。但这种方式有两个限制:一是单个文件不能太大,超过一定大小会失败;二是上传速度取决于你的网络,而且上传过程中页面不能关。
我一般只在小规模测试的时候用这招,比如传个几百张图片验证代码能不能跑通。正式训练的数据集,还是走 Drive 或者命令行下载。
4.2 大数据集走 Drive 挂载
数据量大的话,先把数据集传到 Drive,然后在 Colab 里从 Drive 读取。但前面说过,Drive 的 IO 慢,直接在上面训练会很卡。所以标准流程是:
- 数据集压缩包放 Drive
- Colab 里
cp到/content本地 - 在本地解压
- 从本地路径读取训练
cp /content/drive/MyDrive/colab_projects/project_a/data/dataset.zip /content/ cd /content unzip -q dataset.zip -d ./data解压到本地之后,训练速度会快很多。我实测过,同样一个 5GB 的图像数据集,从 Drive 直接读每个 epoch 要 8 分钟,拷到本地之后降到 2 分钟出头。这个差距在跑几十个 epoch 的时候非常明显。
4.3 从公开源直接下载
很多常用数据集可以直接在 Colab 里用命令下载,省去上传的麻烦。比如:
wget -q https://example.com/dataset.tar.gz tar -xzf dataset.tar.gz或者用 Python 的下载库:
import urllib.request urllib.request.urlretrieve('https://example.com/data.zip', 'data.zip')这种方式的好处是不占用你的上传带宽,Colab 的下载速度通常很快。但要注意,下载链接必须是公开可访问的,而且下载过程中如果会话断了,得重新来。所以大文件建议配合断点续传工具,或者先下到 Drive 再拷本地。
4.4 数据同步的自动化脚本
训练过程中,checkpoint 和日志需要定期同步回 Drive,防止会话突然断掉导致丢失。我通常写一个简单的同步函数,在每个 epoch 结束时调用:
import shutil import os def sync_to_drive(local_path, drive_path): if not os.path.exists(drive_path): os.makedirs(drive_path) shutil.copy(local_path, drive_path) print(f"Synced {local_path} to {drive_path}")然后在训练循环里:
for epoch in range(EPOCHS): train_one_epoch() save_checkpoint(f'/content/checkpoint_epoch_{epoch}.pt') sync_to_drive( f'/content/checkpoint_epoch_{epoch}.pt', f'/content/drive/MyDrive/colab_projects/project_a/checkpoints/checkpoint_epoch_{epoch}.pt' )这样即使会话在下一个 epoch 中途断了,你至少还有上一个 epoch 的权重。我吃过一次亏,跑了 6 个小时没同步,结果断连之后全部重来,从那以后就养成了每个 epoch 同步的习惯。
5. 训练稳定性:断点续训与资源监控
5.1 断点续训的完整实现
断点续训是 Colab 上跑长任务的必备技能。核心思路很简单:定期保存模型状态、优化器状态、当前 epoch 数,下次启动时先检查有没有 checkpoint,有就加载继续。
import os import torch def save_checkpoint(model, optimizer, epoch, loss, path): torch.save({ 'epoch': epoch, 'model_state_dict': model.state_dict(), 'optimizer_state_dict': optimizer.state_dict(), 'loss': loss, }, path) def load_checkpoint(model, optimizer, path): if os.path.exists(path): checkpoint = torch.load(path) model.load_state_dict(checkpoint['model_state_dict']) optimizer.load_state_dict(checkpoint['optimizer_state_dict']) start_epoch = checkpoint['epoch'] + 1 print(f"Resumed from epoch {start_epoch}") return start_epoch return 0然后在主训练脚本里:
start_epoch = load_checkpoint(model, optimizer, CHECKPOINT_PATH) for epoch in range(start_epoch, EPOCHS): train_loss = train_one_epoch(model, optimizer, train_loader) save_checkpoint(model, optimizer, epoch, train_loss, CHECKPOINT_PATH) sync_to_drive(CHECKPOINT_PATH, DRIVE_CHECKPOINT_PATH)这里有个细节:优化器状态也要存。很多人只存模型权重,恢复之后发现学习率调度、动量这些全丢了,训练效果会打折扣。完整的 checkpoint 应该包含模型、优化器、epoch、loss,有时候还要存学习率调度器的状态。
5.2 显存与内存监控
Colab 免费档的显存和内存都是有限的,K80 是 12GB 可用显存(另外 12GB 被系统占用),内存大概 12GB 左右。跑大模型或者大 batch 的时候很容易爆。监控方法有两种:
一是用nvidia-smi命令:
!nvidia-smi输出会显示当前显存占用、GPU 利用率、温度等信息。我习惯在每个 epoch 结束后跑一次,看看有没有异常增长。
二是用 Python 的 psutil 监控内存:
import psutil print(f"RAM used: {psutil.virtual_memory().percent}%")如果发现显存持续增长不释放,大概率是某个地方张量没 detach 或者梯度没清零。这种问题在训练循环里很常见,尤其是自定义 loss 的时候。
提示:显存爆了不一定报错,有时候会静默地变慢,因为系统开始用内存做交换。所以定期监控比等报错更靠谱。
5.3 防止空闲断连的实用技巧
前面说过,空闲 90 分钟会被回收。但"空闲"的定义是浏览器不活跃,不是代码不执行。所以如果你在跑一个很长的训练,浏览器标签页一直开着,通常不会被回收。但如果你关了浏览器去睡觉,那就危险了。
我的做法是:训练脚本里加一个心跳打印,每个 epoch 输出一次时间戳和当前 loss。这样即使我关了浏览器,只要代码在跑,会话就还活着。另外,Colab 的浏览器端有个自动重连机制,偶尔断一下它会自己恢复,但前提是会话本身还在。
还有一个技巧是用while True循环配合time.sleep制造持续活动,但这个不推荐,因为会浪费资源,而且平台可能会检测到异常行为。正常训练的心跳输出就够了。
6. 常见问题排查与实战经验
6.1 典型问题速查表
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
CUDA out of memory | batch 太大或显存泄漏 | 减小 batch size,检查梯度清零 |
| 会话突然断开 | 超时或资源超限 | 检查心跳输出,减少内存占用 |
| GPU 不可用 | 当前时段资源紧张 | 换时间段重试,或等十几分钟 |
| Drive 挂载失败 | 授权过期或网络问题 | 重新运行挂载代码,换浏览器 |
| 训练速度突然变慢 | 显存交换或 GPU 降频 | 用 nvidia-smi 检查状态 |
| pip 安装后 import 失败 | 装到了错误的环境 | 重启会话后重装,检查路径 |
这张表是我这几年遇到问题之后一条条记下来的,基本覆盖了 90% 的情况。遇到问题先对照查一遍,能省不少时间。
6.2 几个我踩过的深坑
第一个坑是在 Drive 上直接训练。刚开始图省事,数据集放 Drive 不解压,直接读。结果每个 epoch 要等十几分钟,还以为是模型太复杂。后来拷到本地才发现是 IO 瓶颈。这个教训告诉我,Colab 上的存储分层一定要用对。
第二个坑是忘记设置随机种子。Colab 每次重启环境都是新的,随机种子不固定的话,同样的代码跑出来的结果不一样,调试的时候非常痛苦。现在我所有实验开头都会加:
import random import numpy as np import torch def set_seed(seed=42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) set_seed(42)第三个坑是依赖版本冲突。Colab 预装的库版本经常变,有一次我装了个新库,把 numpy 升级了,结果 pandas 用不了。后来学乖了,装任何库之前先pip list看一眼,有冲突就锁定版本。
6.3 资源使用的经验法则
用了这么久,我总结了几条资源使用的经验法则,分享出来供参考:
- batch size 从小的开始试,逐步往上加,直到显存占用到 80% 左右。留 20% 余量给系统和其他开销。
- 数据集能小则小,训练前先做 EDA,去掉明显无用的数据,减少 IO 和内存压力。
- checkpoint 频率要合理,太频繁影响训练速度,太稀疏断连损失大。我一般每个 epoch 存一次,epoch 特别短的话每 5 个 epoch 存一次。
- 日志输出要精简,每个 batch 都打印会拖慢速度,每个 epoch 打印一次就够了。
- 会话用完主动断开,释放资源给其他人,也避免后台继续占用你的配额。
这些法则看起来简单,但都是实际跑过几十次实验之后才形成的习惯。新手最容易犯的错就是一开始就把 batch size 拉满,结果各种 OOM,然后怀疑人生。
7. 把 Colab 用成生产力工具的几点体会
Colab 免费 GPU 这个东西,说它强吧,限制一大堆;说它弱吧,关键时刻真能救急。我的态度是:把它当成一个"快速验证想法"的工具,而不是"长期跑大实验"的平台。一个想法从代码到初步结果,Colab 能在半小时内给你答案,这个价值就足够了。真要跑几天的训练,还是得想办法搞本地卡或者租云服务器。
用久了之后,我形成了一套固定的工作流:开新会话先挂 Drive、跑初始化脚本、检查 GPU、设种子;训练时本地跑、定期同步、心跳输出;遇到问题先查速查表、再搜社区、最后自己调试。这套流程让我在 Colab 上的效率比刚开始高了不止一倍。
最后分享一个小技巧:如果你经常用 Colab,建议把常用的初始化代码、工具函数、检查逻辑整理成一个colab_utils.py放在 Drive 里,每次开新会话直接sys.path.append然后 import。这样不用每次复制粘贴一大堆代码,省时省力。我现在这个工具文件已经攒了几十个函数,从数据加载到模型保存到可视化,基本覆盖了日常需求。