AI Infra
Day 2436 min read

Day 24 · W4 复习:一条命令起环境的完整清单、五道验收题、错题本

把 W4 五天的工程活压成一张能打勾的清单:开机前、开机后、收尾三段,每项对应哪个脚本、哪条计费事实。然后做路线图 W4 的五道验收题,把这周三篇文章里口径不一致的地方统一掉,最后整理错题本。W4 结束时的标准只有一句:一条命令起环境,跑完自己消失,钱花在哪一眼可查。

这一周解决了什么

W4 一行 GPU 代码没写。五天干的全是工程杂务:租卡、存储、开机脚本、自动销毁、记账。但这周决定了后面十一个月会不会因为一次忘关机把三个月预算烧光,以及每次实验的数字能不能在同一个环境下复现。

W1 到 W3 的产出是数字,W4 的产出是一条流水线。它的验收标准路线图写得很死:一条命令起环境,跑完自动销毁。拆成五天就是:

做了什么交出的东西
Day 19第一次租 GPU,搞清两家平台的结构,选卡,读 nvidia-smi选卡三步法(显存 → 带宽 → 每美元带宽)、第一次开机的 12 条清单
Day 20实例销毁后什么会丢,三种存储的命运和费率,「存着」还是「重下」的账三类资产各自的去处,一棵决策树,一张写死的方案表
Day 21bootstrap 脚本,5 分钟起环境,幂等,每步计时bootstrap.sh + requirements.txt + run.sh 骨架
Day 22三层自动销毁:trap、看门程序、余额上限run.sh 完整版、idle-watch.sh、控制台三个开关、失效方式表
Day 23成本看板,一次开机一行,脚本自动记账,$/1M token 换算gpu-ledger.csv 格式、开机/销毁两段记账代码、summarize.py

要诚实地说一件事:这五篇写的时候还没有真正开过机。所有脚本在本机干跑过、所有计费事实从文档核对过、所有价格是 2026 年 9 月初从官网和公开接口查的,但「从零到能跑代码几分钟」「这周花了多少钱」这两道验收题的答案现在是预期值,不是实测值。这篇复习把该留空的地方留空,等 W4 真上机那天填。

一页笔记

以下是 W4 五篇里以后会反复查的事实,全部压在这里。价格以 2026 年 9 月为准,会变;规则不会变。

两家平台

RunPodVast.ai
结构平台统一定价,Secure / Community 两档机器市场,房东各自定价
计费按秒计量,每 5 分钟结算扣款,不收流量费按秒,存储和上传下载流量都另收,房东自定
便宜档2026-09 文档里已无 Spot,便宜靠 Community Cloud 和 Savings planInterruptible,出价制,被更高出价顶掉时暂停不销毁
余额归零Pod 停机;无 network volume 的直接销毁实例停机;没绑卡则排期删除实例和数据
CLIrunpodctl,新版 pod 操作收在 runpodctl podvastai,pip 装,所有子命令在 vast.py 一个文件里
实例自己的 ID环境变量 RUNPOD_POD_ID文档无明确页面,上机 env | sort 看,常见 CONTAINER_ID
什么时候用第一次,流程要稳流程稳了之后省钱,搜索时必加过滤

Vast 搜索的完整过滤条件,五个一个都不能省:

vastai search offers 'gpu_name=RTX_4090 num_gpus=1 verified=true reliability>0.98 inet_down>200 inet_down_cost<0.01 storage_cost<0.3' -o 'dph'

选卡

顺序是显存装得下 → 带宽决定 decode 快慢 → 小时价决定每美元买到多少带宽。算力那列 M5 之前排最后。

显存带宽 GB/s7B fp16 decode 上限 tok/s7B @2048 序列 KV cache 最多装用途
T4(Colab)16 GB320装不下装不下W1–W3 已用完价值
RTX 3090 / 409024 GB936 / 100869 / 75≈ 18,000 token,batch 8W5–W7 主力,便宜卡调试
L424 GB30022同上同显存带宽差 3 倍,不选
A100 80GB SXM80 GB2039150≈ 130,000 token,batch 64贵卡出数,M3 两卡 TP
H100 80GB SXM80 GB3352248同上M9 之前用不上

一个 W4 才看清的结论:7B 在 24 GB 卡上 KV cache 只装得下 batch 8,离 ridge point 164 差二十倍,永远是 memory-bound。要看 Day 16 那种「曲线离开斜线」,在 24 GB 卡上得用 TinyLlama(每 token 22.5 KB,batch 128 × 2048 才 6 GB)。显存决定你能不能爬到屋顶,和算力无关。

存储:三种盘,三种死法

Container Disk 容器盘Volume Disk 卷盘Network Volume 网络卷
挂在哪/,~ 也在这/workspace/workspace,替代卷盘
stop 时清空保留保留
delete 时清空清空保留
运行费率0.10 美元/GB/月0.100.07
停机费率不收0.20,翻倍0.07
~/.cache/huggingface 在这,stop 就没50 GB 停一个月 10 美元锁数据中心,创建 Pod 时必须挂上

Vast 只有一块容器盘,停机照收且可能比运行时贵,--disk 创建后不能改,7B 模型 30 GB 起步。Vast 的 Volume 绑物理机器,几乎用不上。

存着还是重下的账:50 GB 卷盘每周开机 6 小时停机 162 小时,一个月约 10 美元,占月预算 17% 到 33%,还不保证重启有 GPU;重下 13.5 GB 权重在千兆网上 1 到 2 分钟。默认每次 delete、每次重下。 例外只有两条:连续几天每天开机不止一次可以 stop 过夜(50 GB 一晚 0.33 美元),以及 M3 之后数据超过 100 GB 再开网络卷。

三类资产各放哪

决策树第一问:丢了 5 分钟能重造吗? 这里的 5 分钟指几乎零成本的时间,有 GPU 时间参与就算不能重造。

资产放哪开机怎么来收尾怎么走
代码、配置、脚本私有 gitclonepush
密钥(HF / 云 API / R2 / webhook)本机 .env,不进 gitscp 后注入环境变量随实例销毁
pip 依赖不存bootstrap 装,版本锁死销毁
模型权重、公开数据集不存,HF_HOME=/workspace/hfhf download 后台预热销毁
小结果(< 10 MB 的 CSV / JSON / PNG)git,跟代码push
大结果(trace、自己量化出的权重)Cloudflare R2需要时 rclone 拉rclone 推
自己筛出来的固定 prompt 集gitclonepush

五个脚本各干什么

文件干什么关键设计
bootstrap.sh装系统工具、检查 torch、clone、装 Python 依赖、HF 登录、预热模型、smoke test、起看门程序、写账本前半行set -euo pipefail;step 函数每步计时写 CSV;幂等三手段;exec > >(tee -a LOG) 2>&1 留日志;看门程序挪到第一步之前
requirements.txt钉死 Python 包版本版本号本身不重要,有版本号才重要;uv pip freeze 出 lock 随结果留档
run.sh跑一个实验,推结果,通知,销毁自己trap on_exit EXIT;顺序推结果 → 通知 → 销毁;KEEP_ALIVE=1 逃生口;DRY_RUN=1 本机干跑
idle-watch.sh每分钟查 GPU 利用率、python 进程、ssh 会话,连续空闲 20 分钟销毁不开 -e;读不到利用率当 100;提前 5 分钟通知;/workspace/.keep 保命开关
common.shdestroy_selfnotify 只留一份两边 source,改 API 字段只改一处
summarize.py本机跑,汇总当月账本按实验、按卡型、列出 end 为空和没写结论的行

三层保险

防的失败机制响应最可能怎么失效
第一层 trap任务正常跑完,我不在场run.sh 退出路径调 API 销毁自己几秒最高:任务没通过 run.sh 起(手动 ssh 调试);trap 注册前崩;API key 过期
第二层看门实例活着,GPU 没人用三条件连续 20 分钟空闲 → 销毁20 分钟,第 15 分钟先通知看门程序没起来或被 OOM 杀;.keep 忘删;开着 ssh 去吃饭
第三层余额前两层全失效只充 10 到 20 美元不绑卡;低余额告警阈值 5 美元余额 ÷ 小时价某次充多了;开了 auto-pay;告警进垃圾箱
容器外每日检查interruptible 被顶掉后 stop 状态计磁盘费;看门程序静默死亡本机或 CF Worker 每天列出 stop 超 24 小时的实例,销毁并通知一天还没写,W4 上机前补

第二层是主力,第一层只是快。第三层生效一次的代价是整个余额,它把「灾难」从三个月预算改写成两周预算。

账本

gpu-ledger.csv 九列:date, experiment, provider, gpu, price_per_hour, start, end, cost_usd, note。开机时 bootstrap 写前六列,销毁时补后三列并 git push,push 在销毁 API 之前。end 为空的行是被抢占或手动删的,月底单独查;note 为空的行是没产出的开机,月底单独面对。

$/1M token 的换算只有一步,是产出物 01 那张卡片上要填的数:

$/1M token = 小时价 × 1e6 ÷ (tok/s × 3600)
A100 SXM 1.39 美元/时,7B decode batch 1 ≈ 150 tok/s  → 2.57 美元
batch 32 ≈ 4,800 tok/s                              → 0.08 美元

差 32 倍,原因就是 Day 5 那个点从算术强度 1 往 153 挪了一段。这是「continuous batching 是吞吐的命门」第一次变成美元。

一次完整生命周期,东西在哪、谁在看着

把五篇的东西拼成一条线。上面一行是步骤,中间一行是此刻盘上有什么,下面三条横杠是三层保险各自覆盖哪一段。

一次开机的生命周期(实线框 = 实例上执行,虚线框 = 本机执行) 1 开机 pod create scp .env 2 bootstrap 先起看门程序 apt · uv · 记账半行 3 拉东西 git clone hf download 4 run.sh tmux 里跑实验 结果写 results/ 5 trap 退出 push → 通知 → 销毁自己 6 收尾 git pull 控制台确认为空 此刻盘上有什么 空 /workspace .env 在可写层 torch 在可写层 timing.csv 代码、权重在卷盘 可重造 结果在卷盘 唯一副本,不可重造 副本已在 GitHub / R2 盘可以死了 盘没了 本机有一切要留的 谁在看着 第一层 trap,秒级 第二层看门,20 分钟 第三层余额上限,从充值那一刻起覆盖一切,包括我忘了做第 6 步 第 4 步是全程唯一有「不可重造」东西的时刻,所以第 5 步的顺序是推结果在前、销毁在后,永远如此。
六步里只有第 4 步结束时盘上有不可重造的东西。三层保险的覆盖范围从窄到宽:trap 只管第 5 步,看门管实例活着的全程,余额从充值那刻起兜底一切。

一条命令起环境:完整清单

W4 的验收就是这张表。每一项对应哪一天、哪个脚本、哪条事实,打完勾才算环境工程化做完。

开机前(本机,不花钱)

  • 账户余额 ≤ 20 美元,没有保存的信用卡,auto-pay 关,低余额告警开、阈值 5 美元。(Day 19、Day 22 第三层)
  • 本机 .env 齐:HF_TOKEN(只读)、RUNPOD_API_KEYVAST_API_KEY(只开 Pod 读写)、R2 的 access key(只开一个 bucket)、NOTIFY_URL。文件权限 600,在 .gitignore 里。(Day 20、Day 21)
  • 仓库里有 .git/hooks/pre-commit,拦 hf_ / rpa_ / sk- 前缀的字符串。(Day 21)
  • bash -n bootstrap.sh run.sh idle-watch.shshellcheck 过;DRY_RUN=1 干跑 run.sh 两次,一次 rc=0 一次 rc=3,通知里的 rc 对得上,dry-run 销毁在 push 和通知之后。(Day 21、Day 22)
  • 想好这次实验叫什么、跑多久、值多少钱。实验名和小时价是开机命令的必填参数,这就是「不该开」的闸门。(Day 23)
  • 选卡按显存 → 带宽 → 每美元带宽。W5–W7 是 RTX 3090 / 4090,A100 留给 M3。(Day 19)
  • 镜像选官方 PyTorch runtime,CUDA 版本 ≤ 目标机器驱动上限。Vast 上按 cuda_vers>=12.4 过滤。(Day 21)
  • Vast 搜索带全五个过滤条件;出价比 min_bid 高 10%,dph_totalmin_bid 差不到 30% 就直接 on-demand。(Day 19、Day 20)
  • 容器盘 20 GB、卷盘 30 GB(RunPod);Vast --disk 30 起,量化实验 50。不开网络卷。(Day 20)
  • 不勾 Jupyter 端口;只用密钥登录。(Day 19)

开机后(实例,按秒计费,不在这里想逻辑)

  • 本机 ~/.ssh/configgpu 项改成这次的 ip 和端口,ssh gpu 进去。(Day 19)
  • 第一件事 tmux new -s work。任何超过一分钟的任务都在 tmux 里跑。(Day 19、Day 21)
  • scp .env gpu:/root/.env,bash bootstrap.sh <实验名> <小时价>。看门程序应该在第一步就起来,tail idle-watch.log 确认每分钟一行。(Day 21、Day 22)
  • nvidia-smi 核对:卡型和租的一致,Processes 为空,驱动 CUDA Version ≥ torch.version.cuda。(Day 19、Day 21)
  • 5 秒验货:带宽在标称 75% 到 90%。低于 60% 直接销毁换机器。(Day 19、Day 13)
  • Vast 上顺手测 curl 下载速率和 dd 写入速率;env | sort 记下实例 ID 变量名进 common.sh。(Day 20、Day 22)
  • df -h /workspace 看剩多少;hf cache scan 看缓存里有什么。(Day 20)
  • 另开一个 tmux 窗格 nvidia-smi dmon -s u -d 2 挂着,sm%mem% 并排看就是终端里最便宜的 roofline 近似。(Day 19)
  • 实验通过 EXP_NAME=xxx bash run.sh <脚本> <参数> 起,不手敲 python。(Day 21、Day 22)
  • 本机另一个终端把 runpodctl pod delete <id>vastai destroy instance <id> 敲好不回车,或设闹钟。第一层第二层都是我写的代码,这是手动版兜底。(Day 19)

收尾(实例 → 本机)

  • echo "一句结论" > /tmp/ledger_note。想不出结论就照实留空,月底面对它。(Day 23)
  • run.sh 的 trap 自己跑:push 小结果、rclone 推大结果、通知、销毁。看手机上通知先到、ssh 后断。(Day 22)
  • 手动跑的情况:rclone ls r2:aiinfra-lab/... 确认远端有文件,再销毁。同步成功是销毁的硬前置条件。(Day 20)
  • 销毁用 delete / destroy,不用 stop。(Day 19、Day 22)
  • 回控制台确认实例列表为空,network volume 列表也为空。CLI 返回成功不等于真的没了。(Day 19、Day 22)
  • 本机 git pull,账本那行 endcost_usdnote 三列都填上了。(Day 23)
  • 每周跑一次 python3 summarize.py,月底和 Billing Explorer 对一次账,差 10% 以内算对。(Day 23)

一条命令的意思不是真的只敲一次回车,是开机之后我不需要想任何事:参数在命令行里,密钥在 .env 里,顺序在脚本里,销毁在 trap 和看门程序里,账在 CSV 里。我要做的只剩看结果和写一句结论。

五篇文章里口径不一致的地方,统一掉

复习的另一个用处是把五天里各自为政的地方对齐。读一遍发现三处,现在写死。

账本放哪。 Day 20 的仓库结构里写 cost/runs.csv,Day 21 的 bootstrap 用 /workspace/aiinfra-lab,Day 23 的记账代码写 $HOME/work/gpu-ledger.csv 且 bootstrap 接两个位置参数。统一为:仓库 clone 到 /workspace/aiinfra-lab(Day 21 的 REPO_DIR),账本是 $REPO_DIR/cost/gpu-ledger.csv,bootstrap 的两个位置参数改成环境变量 EXP_NAMEPRICE,和 run.sh 用的 EXP_NAME 同名。这样三个脚本共用一套变量。Day 23 那段记账代码已经按这个口径改回去了,Day 20 的 cost/runs.csv 也改成了同一个文件名,现在回头读不会再看到三个版本。

RunPod 的 spot。 Day 19 和 Day 20 按 2026 年 9 月的文档写清了 RunPod 已无 Spot 档位,但 Day 22 讨论抢占时沿用了「RunPod 的 spot pod 被抢占进入 stop 状态」的说法,Day 23 的名词表也写「RunPod 叫 Spot」。以 Day 19 为准:当前 RunPod 没有可中断实例,抢占那一整套逻辑只对 Vast 的 interruptible 成立。Day 22 那节的结论不受影响,因为 Vast 被顶掉同样是 stop 状态、磁盘照收,容器外每日检查照样要写;只是标题里的「spot」在 RunPod 上对应不到任何按钮。如果 RunPod 以后重新上 Spot,再把这条改回来。

价格是哪一档。 Day 19 的表写 RunPod on-demand 4090 约 0.74、A100 SXM 1.59、H100 3.29 美元;Day 23 写 4090 0.34、A100 SXM 1.39、H100 2.69。两组都对,前者是 Secure Cloud,后者是 Community Cloud,同一天查的。账本里 price_per_hour 填的是开机那一刻页面上那台机器的价,不用管哪一档;但估算时按 Community 算,因为 W5–W7 全在 Community 上开。

还有一条不算不一致,算补充:RunPod 计费 Day 19 写「按秒」,Day 22 写「每 5 分钟结算」。文档的原意是按秒计量、每 5 分钟从余额里扣一次,两句都对,合起来说才完整。

三层保险覆盖矩阵

Day 22 最后那张失效方式表是按层列的,这里换成按失败方式列,一眼看出哪一格是空的。

谁能拦住哪种失败 第一层trap 第二层看门 容器外每日检查 第三层余额 任务正常跑完,我不在场 ssh 手动调试,被叫走(没走 run.sh) run.sh 在 trap 注册前就崩了 开着 ssh 会话去吃饭,两小时没动 interruptible 被顶掉,stop 状态计磁盘费 看门程序自己被 OOM 杀,静默死亡 ● 能拦住 ○ 有条件:trap 那格要任务走了 run.sh;每日检查那格要 ssh 会话超过 24 小时才算 ✕ 拦不住 第二层那两个 ✕ 是设计上的盲区:有 ssh 连接就不杀。改法是 `who -u` 看会话空闲时间,超过 30 分钟不算活跃,被坑一次之后加。
第一层只拦得住第一行,所以它不是主力。第二层拦住前三行但对「开着 ssh」和「容器停了」两种情况是盲的,容器外每日检查补的就是这两格。第三层那一列全是实心,代价是生效一次烧光余额。

看这张图的方法:横着看一行,如果只有最后一列是实心,说明这种失败发生时我的损失是整个余额,要么补一道保险,要么接受。第四行「开着 ssh 去吃饭」就是这种情况,现在接受,因为改法只有几行(who -u 读会话空闲时间),留到被坑一次再加。第五行「interruptible 被顶掉」在写容器外每日检查之前也是这种情况,所以那个检查要在 W4 上机前写完,不能拖。

五道验收题

路线图给 W4 的五道题。前两道是事实题,现在就能答;后三道要真上机才有数,这里写预期值和留空的格子。

1. spot 被抢占时你会丢什么?怎么让损失最小?

先纠正题目:2026 年 9 月 RunPod 没有 Spot,能被抢占的只有 Vast 的 interruptible。被更高出价顶掉时实例暂停不销毁:GPU 被拿走,进程冻结,显存里的一切(权重、KV cache、正在算的张量)全没;磁盘保留,存储费照收;价格回落后恢复,但 Python 进程以为还在显存里的东西已经不在,大多数情况下报 CUDA 错误退出。

丢的是:显存内容(可重造),以及上次 push 之后、被顶掉之前产生的结果(不可重造)。损失最小的办法有三条:一,只把「重跑不心疼」的任务放 interruptible,W5–W7 十几分钟一次的扫描都符合;二,结果边跑边落盘、每完成一个 batch 就 push 一次,不要全部跑完再 push;三,暂停状态超过 30 分钟就销毁,不让它挂着计磁盘费,这条靠容器外每日检查(暂停后容器内的看门程序也停了)。出价比 min_bid 高 10%,少被顶几次比省那 10% 划算,因为每次恢复都要重新加载模型。

顺带一句:被顶掉其实是免费的演习。顶掉之后如果我丢的只是「重开一台 bootstrap 两分钟」,Day 20 的持久化决策就做对了;如果丢了半小时结果,说明 run.sh 里 push 的频率不够。这个习惯到 M9 训练侧会变成正式课题,叫 checkpoint。

2. network volume 关机后还计费吗?你最终选了什么方案、为什么?

计费。RunPod 网络卷不管 Pod 开不开、甚至 Pod 删了都按 0.07 美元/GB/月收,按小时计费;卷盘停机后翻倍到 0.20;Vast 容器盘停机照收且可能更贵。

最终方案是不开网络卷,每次 delete,每次重下。三个理由:一,重下 13.5 GB 权重在千兆网上 1 到 2 分钟,和 pip 装依赖并行,几乎不占实际时间,折成 4090 机时不到 3 美分;二,50 GB 卷盘停机一个月 10 美元,占月预算 17% 到 33%,买的只是省那两分钟,还附带「重启可能分到零张 GPU」;三,网络卷把我锁在一个数据中心,那里的 Community 便宜卡缺货时数据在别处用不了,而且创建 Pod 时忘了挂就等于没有。什么时候改主意:M3 之后数据集加多个模型超过 100 GB、每次重下超过十分钟,再开;W7 自己量化出的 AWQ 权重要烧 20 到 40 分钟 GPU 才能重造,那是「不可重造」,推 R2 而不是重量化。

3. 从零到能跑代码实际要几分钟?卡在哪一步最久?

现在没有实测,只有预算。按 Day 21 的时间预算,选对镜像(自带 torch)的话:apt 20 秒 + Python 依赖 40 秒 + clone 5 秒 + TinyLlama 下载 20 秒 + smoke test 10 秒,预期第一次 90 到 150 秒,第二次(幂等)15 到 30 秒,验收线 300 秒。

最可能卡最久的一步,按概率排:2a.torch-check 那行超过 100 秒说明镜像没带 torch,换镜像;5.model-prefetch 那行算出下载速率低于 50 MB/s 说明机房到 HuggingFace 慢,Vast 上换房东;1.apt 超过 60 秒说明 apt 源慢,砍掉 htop。真实答案是 timing 表那一列最大的数,不是猜的。记录表留在这里,上机填三次看方差:

步骤预期 (s)第 1 次第 2 次第 3 次备注
0.idle-watch(挪到最前)0–1
1.apt10–30
2a.torch-check0–2超 100 s = 镜像选错
3.git2–10
2b.python-deps20–60
4.hf-login1–3
5.model-prefetch5–30算 2.2 GB ÷ 秒数 = MB/s
6.smoke5–10含 CUDA 初始化,不是性能数据
total90–150验收线 300

4. 三层自动销毁分别在什么情况下生效?哪一层最可能失效?

第一层 trap 在任务通过 run.sh 起并走到退出路径时生效,正常结束、set -e 中断、exit 1、ssh 断线导致的 SIGHUP 都算,任务结束后几秒销毁。第二层看门在实例活着但 GPU 利用率低于 5%、没有 python 进程、没有 ssh 会话连续 20 分钟时生效,第 15 分钟先推通知。第三层在前两层全失效、实例跑到余额归零时由厂商计费系统停机,损失上限等于余额。

最可能失效的是第一层,因为它的前提「任务走了 run.sh」在调试阶段大部分时间不成立,我 ssh 进去手敲命令时根本没有 trap;run.shtrap 那行之前崩、API key 过期、Vast 实例 ID 变量名对不上也都会让它哑掉。所以第二层是主力,第一层的价值只是快。第二层自己的盲区是「开着 ssh 会话去吃饭」和「容器被停后看门程序随之消失」,后者由容器外每日检查补,前者暂时接受。

5. 这周花了多少钱?花在哪?

没上机,答案是预期。W4 五天真正要花钱的只有 Day 19 第一次开机和 Day 22 的两次验收,其余全在本机干跑或查文档:

时长预期花费
Day 19 第一次开机:nvidia-smi、5 秒验货、填记录表RTX 4090 Community25 分钟≈ 0.15 美元(0.34/时)
Day 21 在 CPU pod 上调 bootstrap 前五步CPU pod1 小时≈ 0.05 美元
Day 21 在 GPU 上跑完整 bootstrap 三次RTX 3090 / 409015 分钟≈ 0.08 美元
Day 22 验收一:跑五分钟任务看实例自己消失RTX 3090 / 409010 分钟≈ 0.06 美元
Day 22 验收二:空转 20 分钟看看门程序销毁RTX 3090 / 409022 分钟≈ 0.12 美元
存储(容器盘 20 GB + 卷盘 30 GB,合计约 1.5 小时)≈ 0.01 美元
合计≈ 2.2 小时≈ 0.5 美元,不到 1 美元

对照一下不做 W4 的代价:4090 忘关一晚 8 小时是 5.9 美元(Secure 档价),A100 忘关一个周末 65 小时是 100 到 160 美元。W4 全周的花费不到一次忘关一晚的十分之一。

W4 花的钱 vs W4 防的钱(美元,横条按 4 px = 1 美元,最长一条截断) W4 全周预期 ≈ 0.5 4090 忘关一晚(8 h) 5.9 A100 忘关一个周末(65 h) 100 到 160 第三行是三个月的实验预算。三层保险加起来一个下午加不到 1 美元机时,回报率不用再算。
W4 的账要这样看:不是花了多少,是防住了多少。

「花在哪」这一问真正的答案是账本。上机之后 python3 summarize.py 2026-09 打出来的三张小表就是答案,上面这张预算表只是用来和它对照的。如果实际比预期高出一倍以上,先看是不是某次验收重跑了,再看是不是在 GPU 上想逻辑了。

自测:换平台再走一遍

上面五道是路线图的题。再加几道,专门考「换到另一家平台,规则还成立吗」。合上笔记做。

1. 同一套 bootstrap 搬到 Vast 上,哪四处要改?

答案

一,WORKDIR:Vast 没有卷盘和 /workspace 的约定,开机时 WORKDIR=/root/work bash bootstrap.sh 覆盖。二,磁盘大小在创建实例时 --disk 30 设够,创建后不能改。三,实例 ID 的环境变量名以 env | sort 看到的为准,写进 common.shdestroy_self。四,脚本上机走 On-start script 字段,不是 RunPod 的 Container Start Command;密钥用 --env 传或 scp .env,注意 --env 会留在本机 shell 历史里。另外 Vast 有流量费,搜索时 inet_down_cost<0.01 不能省。

2. Vast 上 dph_total 0.37、min_bid 0.27 的一台 4090,走 on-demand 还是 interruptible?出多少?

答案

差 27%,在「差 30% 以上值得出价、10% 以内直接 on-demand」的规则边缘。任务是十几分钟的扫描、结果边跑边 push,可以走 interruptible,出 min_bid 上浮 10% 约 0.30 美元;如果是要连续跑一小时以上的量化,直接 on-demand 0.37,省下的几美分抵不过被顶一次重新加载模型的时间。

3. RunPod 上一个 Pod 处于 stop 状态过了周末,它扣了什么钱?为什么 Day 22 的看门程序管不到它?

答案

卷盘按停机费率 0.20 美元/GB/月扣,30 GB 三天约 0.06 美元,不多但一直扣;容器盘已清空不扣;如果挂了网络卷再加 0.07/GB/月。看门程序在容器里,stop 时容器被丢掉,看门程序随之消失,所以第二层对 stop 状态是盲的。管它的是容器外每日检查(列出 stop 超 24 小时的实例销毁),兜底的是第三层余额。

4. run.sh 的 trap 里如果先销毁再 push,会发生什么?如果 push 失败呢?

答案

先销毁,容器一没,后面的 push 永远不会执行,实验结果随实例消失,这是整个脚本里后果最重的一个错。顺序永远是推结果 → 通知 → 销毁。push 失败时如果只打一行日志继续往下走,脚本会照样销毁,结果丢了,这是我第一版 on_exit 的写法。正确的写法是 push 失败就置 KEEP_ALIVE=1 跳过销毁、发通知、留给我手动处理,Day 20 那句「同步成功是销毁的硬前置条件」说的就是这个。Day 22 里的 on_exit 已经改成了这个版本,多付几小时机时,换结果不丢。

5. 看门程序三个条件里,为什么读不到 GPU 利用率时要当作 100 而不是 0?

答案

nvidia-smi 偶尔超时或挂掉时,我不知道 GPU 在不在忙。当作 0 会累加空闲计数,20 分钟后杀掉一个可能正在跑的任务;当作 100 只是多等 20 分钟。错杀的代价是一次实验重跑,多等的代价是 20 分钟机时,前者贵得多。同理看门程序不开 set -e,任何一次检查失败都不能让它自己退出。

6. A100 SXM 1.39 美元/时和 RTX 4090 0.34 美元/时,跑 7B fp16 各是多少 $/1M token?哪张卡「便宜」?

答案

A100:150 tok/s × 3600 = 0.54M tok/h,1.39 ÷ 0.54 ≈ 2.57 美元。4090:13.5 GB ÷ 1008 GB/s ≈ 13.4 ms,约 75 tok/s,0.27M tok/h,0.34 ÷ 0.27 ≈ 1.26 美元。4090 每百万 token 便宜一半,但每个 token 慢一倍。$/1M token 是「每美元买到多少 token」,不是「多快」,产出物 01 两个数都要给。

错题本

W4 的错和 W1 到 W3 性质不同:前三周错在形状、单位、异步,这周错在以为。以为 stop 了不花钱,以为账单页就是看板,以为这次一定记得关。按五篇的常见误区汇总,分四类。

计费类:以为不花钱的地方在花钱

实际出处
stop 了就不花钱卷盘停机费率翻倍到 0.20 美元/GB/月;Vast 容器盘停机照收且可能更贵;RunPod 停机 Pod 重启可能分到零张 GPUDay 19、20、22
网络卷「便宜又永久」0.07 美元/GB/月不管开不开机,锁数据中心,创建时必须挂上;现在的数据量重下只要两分钟Day 20
只比 GPU 小时价Vast 房东流量费差 15 倍(0.0026 vs 0.039 美元/GB),下 174 GB 模型流量费是 GPU 费四倍的账单真实存在Day 20
200 Mbps 下行「够快」Mbps 除以 8 才是字节,25 MB/s,13.5 GB 要 9 分钟不是 1 分钟Day 20
账单页就是看板账单页没有实验名和结论,回答不了「花在哪个实验」「值不值」Day 23
记录留在实例上销毁后容器盘就没了,账本必须在销毁 API 之前 pushDay 23

纪律类:以为靠记性

实际出处
「这次一定记得关」忘关不是粗心,是去睡觉、被叫走、ssh 断了以为任务死了的正常状态;靠记性的方案失败是确定的,只是时间未定Day 22
绑卡开 auto-pay余额永远不归零,第三层作废,损失上界从余额变成银行卡额度Day 19、22
在按秒计费的机器上想逻辑脚本在本机 bash -n + shellcheck + DRY_RUN=1 干跑完再上机;调脚本用几美分的 CPU podDay 21、22
第一层跑通就够了第一层依赖任务走了 run.sh,调试时大部分不满足;第二层才是主力Day 22
验收在脑子里过不故意触发一次,不知道通知能不能到、API 能不能通、顺序对不对;两次验收不到 1 美元Day 22

脚本类:以为跑一次就够

实际出处
脚本不幂等中途断线重跑、stop/resume 再跑、第二天接着用,三种场景都会让不幂等的脚本报错或重装;测法是连跑两次比 timingDay 21
镜像随便选「反正脚本会装」装 torch 2 到 5 分钟、2.5 GB,一项吃光 5 分钟预算;镜像选择是整个脚本里最重要的决定,而它不在脚本里Day 21
requirements.txt 不写版本今天和下周装的不是同一个 transformers,W3 的数字就不能和 W2 比Day 21
替换官方 template 的启动命令它负责起 ssh 和 Jupyter,替换掉就进不去了;要追加Day 21
无人值守不留日志路径 C 没人看着终端,exec > >(tee -a LOG) 2>&1,进去先 tailDay 21
长任务直接在 ssh 里跑SIGHUP 连带杀掉,钱照扣;超过一分钟进 tmuxDay 19、21
看门程序开 set -e一次 nvidia-smi 超时就让它自己退出,第二层静默消失Day 22
trap 里先销毁再 push容器一没后面的命令永远不执行,结果随实例消失Day 22
只看 GPU 利用率判空闲下载模型、装包阶段利用率是 0 但任务在跑;加 python 进程和 ssh 会话两个条件Day 22

安全类:以为「先跑通再说」

实际出处
token 写进脚本先跑通跑通就忘了,然后 push 出去;token 只从环境变量读,pre-commit hook 拦 hf_ / rpa_ / sk- 兜底Day 20、21
私人 SSH 私钥拷进租来的机器机器是别人的,Vast 上是某位房东的;拉代码用 deploy key 或带 token 的 httpsDay 20
脚本里 echo $HF_TOKENset -x 跑过 source日志进 tmux 回滚缓冲、进记录,一次打印等于一次泄露Day 20
不需要 Jupyter 也开着端口公网 ip 开着 Jupyter 等于开着门;部署时取消勾选Day 19

W1 到 W3 的错是「不知道」,读一遍就补上;W4 的错是「知道但会忘」。所以 W4 的治法不是记住,是把每一条变成脚本里的一行、控制台里的一个开关、或者 pre-commit 里的一个正则。清单那一节每个勾后面括号里的出处,就是这张错题本的另一种排法。

学习方法反思

W4 和前三周最大的不同是没有「算出数字就是过」这条硬标准。工程活的验收容易变成「我觉得差不多了」。这周的做法是把路线图那句「一条命令起环境,跑完自动销毁」拆成能打勾的清单,每一项都要么对应一个能跑的脚本,要么对应一条能核对的文档原文。写清单的时候发现三处口径不一致,这是复习真正的收益:五天各写各的,不回头看不会发现账本路径有三个版本。

另一件事是诚实标注预期和实测。这周五篇全是纸上工程,所有「几分钟」「多少钱」都是算的不是测的。把它们写成预期值加留空表,比写成「我测到 120 秒」诚实,也比空着不写有用,因为上机那天就知道该填哪一格、和什么比。这条规则 W2、W3 已经在用,W4 一样。

还有一条是用自己已经会的东西做锚点。第二层看门程序是「cron 读一个指标、低于阈值 N 分钟推一条通知」,这和我给 BTC 信号做的那套 CF Worker 是同一个骨架;心跳(dead man’s switch)也是那个 Worker 加一个 KV 键。Day 0 说的「用已经懂的东西做锚点」在 W1 是 matmul 和显存,在 W4 是 cron 和 webhook。新东西没有想象中那么多。

全周名词总表

名词一句话首次出现
on-demand / interruptible独占不打断 vs 出价制可暂停。RunPod 2026-09 已无 SpotDay 19
Secure / Community CloudRunPod 两档机器来源,后者便宜两三成Day 19
dph_total / min_bid / reliability / inet_downVast offer 的四个关键字段:总价、最低出价、房东在线率、下行带宽Day 19
Container Disk / Volume Disk / Network VolumeRunPod 三种盘:stop 即清空 / stop 保留费率翻倍 / 独立于 Pod 锁数据中心Day 19、20
镜像 / 可写层容器启动自的只读分层快照和叠在其上的一层;容器盘就是可写层Day 20
HF_HOME / blobs / snapshots / refsHF 缓存根目录和它的三层结构Day 20
hf download / hf_xethuggingface_hub 命令行下载和当前的加速后端;hf_transfer 已弃用Day 20
对象存储 / Cloudflare R2 / rclone按 GB 收费的文件服务;R2 出站免费 10 GB 内免费;rclone 统一操作各家Day 20
deploy key只对一个仓库有效的只读密钥,放租来的机器上Day 20
bootstrap / 幂等从零到能跑的引导脚本;跑一次和跑十次结果一样Day 21
set -euo pipefail出错即停、未定义变量即停、管道任一段失败即失败Day 21
runtime / devel 镜像只有运行时库 vs 多带 nvcc;M5 写 kernel 才要 develDay 21
驱动 ≥ runtime = wheelGPU 侧三层版本规则;nvidia-smi 右上角是驱动上限不是已装版本Day 19、21
uv / --system快的 Python 包管理器;装到系统 Python 不建虚拟环境Day 21
exec > >(tee -a LOG) 2>&1之后所有输出同时进屏幕和文件Day 21
tmux / SIGHUP / nohup会话管理器;终端断开时的信号;忽略该信号Day 19、21、22
trap CMD EXIT / $?退出时执行;退出码要在 trap 函数第一行取Day 22
RUNPOD_POD_ID / podTerminateRunPod 注入的实例 ID;GraphQL 销毁 mutationDay 22
utilization.gpu采样窗口内有 kernel 在跑的时间比例,测忙不忙不测算力Day 5、19、22
dead man’s switch定期报平安,平安消失才告警;抓看门程序静默死亡Day 22
DRY_RUN / KEEP_ALIVE本机干跑开关 / 调试时跳过销毁的逃生口Day 22
low balance alert / auto-pay / spend limit低余额邮件;自动扣卡充值(不开);默认 80 美元/时上限(用不到)Day 22
ledger / $/1M token一次开机一行的账本;小时价 × 1e6 ÷ (tok/s × 3600)Day 23
实际均价某卡总花费 ÷ 总开机小时,含 bootstrap 和下载的不产出时间Day 23
MiB vs GB / Mbps vs MB/s1024 进制 vs 1000 进制;比特 vs 字节差 8 倍Day 2、19、20

全周参考资料汇总

文档,全部 2026 年 9 月核对过可达:

视频,两段选的都是「一次看全流程」的对照:

LearnBase · Runpod vs Vast ai Which Is Better?? · 两家平台的界面和定价并排走一遍,看的时候对照本文「两家平台」那张表,注意它讲的价格是录制时的,规则才是要记的。
tutoriaLinux · Basic tmux Tutorial - Windows, Panes, and Sessions over SSH · W4 里出现最多次的工具。看会话、窗格、脱离和接回四个动作就够,Day 19 的「一个窗格跑实验、一个窗格挂 nvidia-smi dmon」就是它的用法。
  • 攒钱换房车的福叔,《Runpod 设置完整教程 – 在云端运行大型AI模型!》,B 站 BV1YGsDzCE35,28 分钟中文版,Day 19 已嵌入。
  • Day 21、22、23 嵌入过的 RunPod 官方 CPU pod 教程、Vast 官方 Quickstart、trap 教学、nvidia-smi 监控视频,不重复列。

下周预告:M1 加餐周

W1 到 W4 走完,路线图里 M1 的四周任务结束了。但离 M2 开始还有六天,而且这四周里有几个词一直在用却没有真正讲过:SM、tensor core、bf16、warp、dense 和 sparse。W2 在 T4 上撞到「不支持 bf16」时只知道绕开,W3 测算力时只知道「要走 fp16 tensor core 才对得上 65 TFLOPS」,W4 选卡时只会比带宽。这些地方现在都是黑盒,M2 开始碰 KV cache 实测、量化、continuous batching,黑盒会越来越碍事。所以 M1 最后六天补硬件和数值的地基,顺序是从硅片到规格表再到市场:

Day标题补的是哪个黑盒
25GPU 解剖:SM、tensor core、寄存器/shared/L2/HBM 到底是什么Day 5 说「权重装不进片上」、Day 13 测带宽层次时那张没展开的图
26数值格式:fp32/tf32/fp16/bf16/fp8/int8/int4 各占几位、差在哪T4 为什么不支持 bf16;量化省字节为什么直接换来 decode 速度
27CUDA 执行模型:kernel、grid、block、warp、stream 与 launch 开销Day 11 timeline 上的 gap 背后是什么;为 M5 Triton 铺路
28怎么读一张 GPU 规格表:dense 与 sparse、SXM 与 PCIe、NVLink 与 $/tokenDay 14 的 312 vs 624 陷阱;Day 19 选卡表里那些数字从哪来
292026-09 市场校准:JD 里要什么,路线图哪里要加勾学了四周,对照一下招聘方到底要什么,路线图加六个勾
30M1 总复习:一页笔记、20 道全月自测、错题本汇总与 M2 预告把 W1 的数字、W2 的计时、W3 的实测、W4 的环境、加餐周的硬件压成一页

加餐周和 W4 一样零成本,全是纸笔和文档。它不在路线图原本的 M1 里,是我自己加的,理由只有一个:M2 的每一个实验都要在一张真实的卡上跑,而我到现在还说不清那张卡里面有什么。

W4 一行 GPU 代码没写,但从下周开始,每次开机都不用再想任何事了。

评论

  1. 加载中…

只保存昵称和内容。会显示你的大致地区(国家 / 省),不保存 IP 地址。

← 365 天课程目录