# 协议：先接受一个语料库，再比较成本

版本 1 — 2026 年 9 月 24 日。本说明提出一个待填写的协议；它不包含任何实测结果或数据集。配套的 notebook 使用一个小型合成 MLP 来学习如何采集内存数据。它并不执行下文的业务协议。

## 1. 在试验之前先定义有用的工作

工作示例：对一个 **1 000 篇文本**的语料库进行分类。请自行构建一个被授权、能代表你实际用途的数据集，每篇文本带唯一标识符和经过核验的参考结果。固定语料库、模型、tokenizer、代码的修订版本以及随机种子。分别保存预期 ID 列表和逐条输出，以便审计。

在任何测量之前先定义：类别、输出格式、主要指标（例如 macro-F1）、其接受阈值，以及相对于参考结果允许的最大退化。选择适合你应用的容差；这里不提供任何通用取值。训练、调参和评估数据必须保持分离。

只有当 1 000 个预期 ID 均恰好出现一次、输出中不含任何多余回答、格式有效且预先设定的质量规则得到满足时，语料库才算被接受。两个各含 1 000 行的文件本身并不能证明 ID 集合相等。请归档对集合和重复项的检查。

## 2. 只改变所声明的变体

若要研究 batch，例如准备 1、4 和 8 三种变体。保持相同的语料库、输入顺序、模型、tokenizer、精度和上下文上限。如果随后研究精度，请创建单独的实验并重新进行质量控制。描述截断情况：缩短文本会改变所完成的工作。

记录实际使用的 GPU、实际使用的 GPU 数量、device、驱动、Python、PyTorch 以及 CUDA 或 ROCm 运行时。还要在 `notes` 中记下你的代码版本、可能的生成选项以及机器上的任何并发情况。一个两台 GPU 的商用套餐并不意味着程序会同时使用这两台。

## 3. 测量可比的多轮运行

说明计时器涵盖什么：仅处理本身，还是包含读取、tokenization 和写入的完整链路。将加载、首次运行和预热后的运行区分开。内存脚本只测量它的 MLP，并不对完整的分类链路计时。

执行所声明的预热，然后按交替顺序或事先抽定的顺序，对每个变体进行五次测量。保留每个原始时长。报告中位数和最小–最大范围可以看出离散程度；五次观测不足以对 p95 做出稳健估计。不要悄悄剔除某个错误或某次慢速运行：保留其行并解释该事件。若希望在相似条件下比较首次运行，请在新进程中重新运行。

对于 PyTorch 的 GPU 测量，在初始记录之前以及操作之后同步所选的 device。记录 `allocated` 和 `reserved` 基线，重置峰值统计，然后保留该阶段的绝对峰值。`allocated` 包含在 `reserved` 之内：将两者相加会把一部分内存重复计算。两个最大值可能在不同时刻达到：它们的差并不是某一时刻缓存的度量。其他进程的分配以及 PyTorch 分配器之外的分配不在覆盖范围内。

## 4. 填写 resultats-bruts.csv

分发的 CSV 只含表头。每次运行写一行，时间用小数点和秒，内存用字节，套餐用美分 USD。空单元格表示「未记录」；零表示确实为零。注释中出现的逗号必须按通常的 CSV 规则转义。

| 字段 | 含义与填写 |
| --- | --- |
| `experiment_id`、`variant_id` | 实验与变体的稳定标识符。 |
| `corpus_revision`、`model_revision`、`tokenizer_revision`、`seed` | 不可变版本或指纹，以及公布的随机种子。 |
| `gpu_model`、`gpu_count`、`device`、`driver_version`、`python_version`、`torch_version`、`runtime_version` | 实际使用的硬件与观测到的环境；不要照抄报价中的承诺。 |
| `precision`、`batch`、`context` | 实际应用的配置。 |
| `phase`、`run_index`、`warmup_iterations` | 分离的阶段（例如 `cold` 或 `warm`）、运行序号、预热次数。不要混合计时。 |
| `expected_ids`、`observed_ids` | 预期与观测到的 ID 数量；详细列表随输出一并保留。 |
| `ids_match`、`format_valid` | 经实际校验后的 `true`/`false`，包括重复项和多余响应。 |
| `quality_metric`、`quality_threshold`、`quality_tolerance`、`quality_value` | 预先设定的名称、阈值与容差，以及实测值。在 `notes` 中说明容差方向与基准。 |
| `corpus_accepted` | 仅当所有验证条件均满足时为 `true`；否则为 `false`。 |
| `elapsed_seconds` | 所公布范围内的原始耗时，绝不是预期值。 |
| `baseline_allocated_bytes`、`baseline_reserved_bytes`、`peak_allocated_bytes`、`peak_reserved_bytes` | 仅针对被测量的 device 分别记录的读数。未测量时留空。 |
| `duration_days`、`lots`、`package_total_usd_minor` | 所选的完整套餐、计费批次数与以美分计的总价；同一笔支出不得重复累加五次。 |
| `accepted_unique_corpora` | 为经济分析而接受的有效且互不相同的语料数量；此字段不应在多次重复之间求和。 |
| `notes` | 范围、事件、质量决策、代码修订版本以及所保留材料的引用。 |

## 5. 计算，而不虚构产出

用于比较的价格是 3、7 或 30 天的完整套餐乘以批次数。对于 B200，一个批次包含两块 GPU，而该价格已覆盖这一批次。`calcul_forfaits.py` 将这一规则应用于所提供的价格。

若所选的有效工作是一个完整且被接受的语料，则 `--accepted-results` 应接收该时间段内实际验证通过的互不相同语料数量。同一语料的五次重复用于衡量波动性：它们并不会产生五份有效交付物。在比较之前先确定计量单位，并在所有变体中保持一致。若没有经过测量且被接受的数量，请将该参数留空：此时只会计算套餐成本。不要自动将某个速率外推到 3、7 或 30 天。

请将填写完毕的协议、各次输出、质量检查、原始 CSV 与经济计算一并保存。更快但未被接受的配置并不能达成同样的目标。超出内存的配置仍然是一次失败观测，而不是一个可以用零替代的耗时。
