1. 将模型预期转化为数据契约
先从你的程序所期望的对象入手,再选择校验器。对于表格输入,要命名列、类型和单位。对于图像,要明确尺寸、通道和方向处理。对于文本,要定义编码、必填字段以及空输入的处理策略。一份数据可读,并不代表它适合计算。
区分三种决策:拒绝、原样接受,或按文档化的规则转换。把字符串转成数字、替换缺失值、截断输入,都会改变被处理的内容。这些操作不应仅仅因为某个工具选择了默认类型就发生。
本指南中的示例仅用于教学,不会实际执行。它针对的是包含一个标识符和三个介于 −100 到 100 之间的数值的对象。这些边界是为了说明契约而虚构的,没有物理单位,也与任何 Kernodeck 数据集无关。它们必须替换为真实项目的规则。
左右滚动表格即可查看所有列。| 层级 | 规则 | 可识别的失败 |
|---|---|---|
| 模式 | 恰好包含 id 和 values | 字段缺失或意外出现。 |
| 类型 | id 为字符串;values 为数字列表 | 数字以文本、布尔值或缺失值形式呈现。 |
| 形状 | 每个对象三个数值 | 向量过短或过长。 |
| 取值 | [−100, 100] 内的有限数字 | NaN、无穷大或超出教学定义域的取值。 |
| 语料 | 标识符唯一 | 两个对象拥有相同的标识符。 |
2. 在转换之前验证读取
固定格式及其方言。对于 CSV,要记录分隔符、编码以及是否有表头。Python 标准 CSV 读取器通常返回字符串;它不会自行判定你的列是整数。像 0012 这样的标识符若被转换成 12,就可能失去意义。因此请让标识符保持其预期的类型。
在创建业务对象之前,请检查字段数量和列名。某一行因意外分隔符而错位时,不能因为部分值仍可转换就让它通过。对于二进制文件或图片,也应进行实际读取:扩展名正确并不能保证内容可解码。
已解码的 JSON 还不等于通过校验的契约。Python 模块默认接受某些非有限值以及对象中重复的名称。如果你的格式禁止这些情况,请在解码时配置拒绝,然后应用你的模式规则。在将整个文件加载到内存之前,也要设置合适的体积上限。
3. 按规则类型隔离错误
构造一个小型集合,让其中每个无效条目只违反一条重要规则。这样你就能知道该检查能发现什么。如果唯一的错误示例同时存在错误标识符、错误维度和无穷大数,那么它被拒绝并不能证明这三条规则都有效。
表中各记号表示的是已经读入的教学对象。无穷大是一个非有限数值,不是应采用的 JSON 语法。判定结果是通过推理得出的预期,并非某个已执行程序的输出。第二个带 a 的对象放在有效的 a 对象之后测试,以校验唯一性。
当契约演进时,请保留这些用例。如果你决定接受数字字符串,请建立一个显式的转换步骤,并记录这一决定。不要为了消除语料库里的第一个拒绝而悄悄修改检查逻辑。
左右滚动表格即可查看所有列。| 标识符与值 | 预期判定 | 所检验的规则 |
|---|---|---|
| a · [1, 2, 3] | 接受 | 有效参考。 |
| b · ["4", 5, 6] | 拒绝:类型 | 在该契约中,字符串不是数字。 |
| c · [7, 8] | 拒绝:形状 | 只有两个值,而非三个。 |
| d · [0, 无穷大, 1] | 拒绝:取值 | 非有限值不能参与计算。 |
| a · [4, 5, 6],位于第一个 a 之后 | 拒绝:重复 | 在语料库范围内保证唯一性。 |
4. 保留显式校验器和可用的错误消息
下面的片段展示了对一个已解码对象的检查。它在第一条失败的规则处停止,既不处理整个文件,也不处理其所有可能的格式。容器 seen 属于语料库遍历流程的一部分:如果每行都重新创建它,重复检查就会变得毫无意义。
有用的消息应包含规则、逻辑文件和对象位置。避免把对象的全部内容都抄进去。如果需要收集多个错误,请限制保留的细节,同时维持完整的计数器。一份高达数 GB 的报告同样无助于定位首要原因。
对于 NumPy 数组,逐元素检查有限性可以作为类型和形状检查的补充。它不能取代业务边界检查:一个有限数仍可能是负长度,或者是以错误单位表示的取值。
import math
def valider_objet(item, seen):
if type(item) is not dict or set(item) != {"id", "values"}:
raise ValueError("SCHEMA")
identifiant = item["id"]
if type(identifiant) is not str or not identifiant.strip():
raise ValueError("IDENTIFIANT")
if identifiant in seen:
raise ValueError("DOUBLON")
values = item["values"]
if type(values) is not list or len(values) != 3:
raise ValueError("FORME")
for value in values:
if type(value) not in (int, float):
raise ValueError("TYPE")
if not (-100 <= value <= 100) or not math.isfinite(value):
raise ValueError("VALEUR")
seen.add(identifiant)
return item5. 从样本迈向完整语料库
短样本可以让你快速修正读取器和契约。请同时选择普通用例和边界用例:空输入、最大体积、不常见字符、第一个和最后一个分区。只挑选开头几行可能会漏掉位于较靠后文件或稀有类别中的异常。
完整校验会遍历所有相关条目并应用全局规则。对于大数据量,请逐步处理文件并记录其身份。把所有标识符都放进内存的集合适合小型示例,但可能变得过于昂贵;此时请选择与数据量相适配的唯一性策略,而不要放弃检查。
报告必须说明其覆盖范围:调试用样本、某个分区的全部,还是所定义语料的全部。保留读取、接受和拒绝的数量,以及所应用的规则。如果之后文件发生变化,旧报告不会自动验证新的输入。
6. 决定如何处理被拒绝的数据
当错误使计算结果失去意义时,应停止工作:关键列缺失、单位不兼容或标识符对应关系丢失。如果你的任务允许排除个别条目,请在启动前定义该策略,保留被拒绝的记录,并仅在真正被接受的范围内计算结果。
剔除并不等于修正。如果你替换缺失值或对输入进行归一化,请生成一个可识别的新版本并重新验证。将转换操作及其参数与实验一起保留。否则,两个同名实验可能使用不同的数据。
在送入 GPU 之前,还要检查实际构建出的批次:维度顺序、数值类型、可能的掩码,以及与目标的对应关系。文件校验先于各种转换;它并不能证明后续流水线仍保持这些属性。用一个具有代表性的样本可以检验这最后一道边界。
7. 生成一份易于理解的启动许可
预期的输出是一份简短报告,回答四个问题:输入是什么、规则是什么、覆盖范围是什么、决定是什么。有效状态必须指向一个明确的语料标识。部分状态必须指出还有哪些内容需要检查。拒绝状态必须能让人找回相关对象,而无需不必要地传播其内容。
还要对校验器本身进行检验:正确的用例能通过,每个错误用例都以正确的理由被拒绝,且各项计数能够对上。然后在应用中验证一小段流程。这种双重检查可以避免将数据合规性同模型质量或 GPU 可用性混为一谈。
合规的输入仍可能存在偏差、标注错误或与研究问题不匹配。本指南涵盖结构合规性和显式规则;它既不认证代表性,也不认证使用权利。在长时间处理之前,这些决定应补充进档案。