01 · IMAGE & DATA
图像与数据:先定义模型能看见什么
模型从来没有直接“看见物体”。它接收的是数组;颜色空间、压缩、裁剪、分辨率、标注规则和数据采集方式共同限定了数组能代表什么。先建立输入和数据契约,才能讨论模型结构。
11.1 输入契约:把“图片”写成可验证的接口
学习视觉模型时最容易跳过的一步,是把文件直接丢进预训练模型,然后把输出当成客观结果。更稳妥的做法是先写输入契约:系统接受什么格式、怎样解释颜色、怎样处理方向、允许多大尺寸、出现损坏或缺失时返回什么状态。契约不是文档装饰,而是模型输入空间的边界;边界没有写清,训练、测试和部署会使用三套不同的图片。
一张图片至少有文件层、解码层、数组层和语义层四种身份。文件层关心扩展名、MIME、大小和哈希;解码层确认确实能被解码器打开;数组层确认形状、数据类型、取值范围和通道顺序;语义层说明图片是否符合任务,例如是否包含完整主体、是否允许截图、是否含有文字或敏感信息。只检查后缀只能证明名字像图片,不能证明内容可用。
契约应把空间坐标也写进去。常见数组以高度 H、宽度 W、通道 C 表示,而深度学习张量常以批次 N、通道 C、高度 H、宽度 W 表示。框坐标可能是左上右下,也可能是中心点加宽高;像素索引可能从 0 开始,显示组件却按 1 开始。训练标注、模型输出和前端覆盖层必须共用一个明确的坐标约定,并在转换处记录原图尺寸。
颜色处理不能用一句“转成 RGB”带过。RGB、BGR、灰度、RGBA、YCbCr 和线性光空间的数值含义不同;同一数组若通道顺序颠倒,模型仍会给出一个看起来像答案的结果。归一化也有契约:是把 0 到 255 除以 255,还是减去均值再除以标准差;均值和标准差来自哪个预训练配置;推理服务是否和训练脚本使用相同的插值与舍入。
尺寸策略必须和任务对象的最小尺度联系起来。直接拉伸会改变几何比例,中心裁剪会丢掉边缘主体,补边会引入人工颜色或边界。分类可以接受某些裁剪,文字识别、检测和分割则要保存缩放比例、裁剪窗口和补边偏移,才能把结果映射回原图。所有随机操作都应在 manifest 中保存种子或变换参数,方便复盘某个失败样例。
输入契约最后要声明不适用场景。比如只训练白天室内照片,就不能暗示夜间户外同样可靠;只支持单张图片,就不能默默把多页 PDF 当作一张长图;只允许公开素材,就不能让用户上传未获授权的病历。对不适用输入返回清楚的状态,比勉强给出一个高置信度类别更专业,也更容易让后续人工流程接住。
11.2 像素、通道与预处理:数值变化怎样改变视觉证据
像素值是采样和编码的产物,不等于现实世界中的物理量。手机自动曝光、白平衡、锐化、降噪和压缩都会改变分布;扫描仪会带来边缘阴影,屏幕截图会带来摩尔纹,社交平台再压缩一次后细小文字可能完全消失。模型学习的是这些处理后的统计规律,所以数据卡要记录采集链路,而不是只写“来自网络图片”。
位深和数据类型会影响可表达范围。八位整数适合普通照片,但医学、深度或遥感数据可能使用更高位深;把高位深直接截断为八位,可能抹掉对任务重要的微小差异。浮点数组还要注意 NaN、无穷大、负值和量化误差。预处理函数应显式检查这些情况,并用可读错误说明告诉调用方哪个字段不符合契约。
通道的缺失和伪造需要分开讨论。灰度图复制三次可以接入只接受 RGB 的骨干,但三通道复制并没有创造新的颜色信息;透明通道被丢弃后,前景可能与背景混合;深度图不能当作蓝色通道使用。若任务本来依赖红外、深度或多光谱信息,应修改模型输入层或设计融合模块,而不是用占位数字掩盖模态差异。
缩放插值会改变边缘与细节。最近邻适合离散标签和像素掩码,双线性较平滑,双三次更慢但可能保留细节;对掩码使用双线性会产生不存在的类别编号,对图片使用最近邻又会制造锯齿。训练与推理必须使用与任务相容的插值,检测框、关键点和掩码要同步变换,不能只改图片而忘记标签。
归一化参数必须跟着模型版本走。一个骨干使用 ImageNet 均值,另一个模型使用 [-1, 1] 范围;如果只把数组除以 255,却加载了要求标准化的权重,输出偏移可能很大。建议把 transform pipeline 当作代码资产,给每个变换命名并保存参数;任何参数改变都提高数据版本或模型 manifest 版本,不能在笔记本里临时改完而不留记录。
预处理还会决定隐私暴露面。人脸打码、屏幕裁剪和元数据清理可能是必要的安全措施,但它们也会改变任务证据。要记录脱敏发生在原图之前还是模型输入之前、是否保留可恢复版本、遮罩覆盖率如何验证;如果脱敏让模型无法判断,就应返回“证据被遮蔽”而不是把低质量结果当作正常预测。
11.3 数据卡与标签协议:把“正确答案”变成可复现规则
数据卡的核心不是罗列几个来源链接,而是让一个没有参与采集的人能够判断数据适合什么任务。至少记录数据用途、采集时间、地区或设备范围、主体类型、授权与限制、删除联系人、已知缺口和不应推断的属性。对于公开下载数据,也要记录下载日期、版本或快照哈希,因为网页内容和许可说明可能变化。
标签定义必须从观察条件出发。分类要说明“画面中出现”与“主体足够清晰”是否相同;多标签要说明标签可以共存还是互斥;检测框要说明遮挡、截断和阴影边缘画到哪里;分割要说明孔洞、透明区域、重叠实例和模糊边界。没有定义的情况不能靠标注员临场猜测,否则模型会学习到标注员的个人习惯。
可以设置三态或四态标签,而不是强迫所有图片二选一。例如 present、absent、uncertain、not_applicable 分别表示出现、未出现、不确定和任务不适用。训练时可以只使用确定样本,评估时单独报告不确定样本;这样既保留信息,也不会把“看不清”混进负类造成系统性偏差。状态字段应和最终模型输出状态保持可映射。
标注质量要用抽检和分歧记录管理。随机抽取样本由第二位标注者复核,统计类别一致率、框的 IoU 分布或边界偏差;发现分歧集中在某类场景时,先更新指南再继续标注。不要把复核者简单当作“更权威”的人,应该保存原标签、修改理由和最终裁决,让后续错误分析能区分数据错误与模型错误。
切分键应在建数据集前确定。视频任务通常按视频或拍摄会话切分,人物或病例数据按主体 ID 切分,商品或建筑按实体 ID 切分,近重复素材按感知哈希簇切分。随机按图片切分会把连续帧、同一背景和同一水印同时放进训练与测试,导致高分只反映记忆能力。切分清单要锁定并版本化。
数据卡还应列出“不能从数据得到的结论”。如果图片没有可靠年龄、身份或健康证据,就不能把分类结果解释成这些属性;如果只采集了少数设备,就不能宣称对所有摄像头都公平。把不该推断的内容写出来,能提醒产品和评估人员不要把模型输出扩展到训练目标之外。
11.4 增强、泄漏与偏差:每个随机操作都要有理由
增强的判断问题不是“这个操作常不常见”,而是“真实使用中发生这种变化时,标签是否应该保持不变”。水平翻转对多数自然物体可能合理,但对带方向的仪表、左右标识、文字和医学影像可能改变含义;大角度旋转对俯拍物体也许合理,对道路标志或地平线任务却可能制造不现实样本。每一种增强都要写假设、适用范围和验证指标。
颜色增强同样需要任务语义。亮度和对比度变化可以模拟曝光差异,但强烈色相变化会破坏以颜色区分的类别;随机灰度可能帮助形状识别,也可能抹去热成像或染色信息。建议为每项增强建立“不变性矩阵”:列出应保持不变的属性、可能被破坏的属性、允许的参数范围和必须单独评估的切片,而不是把增强列表当成固定配方。
合成增强不能掩盖真实覆盖缺口。把清晰图加噪声,不等于拥有真实夜间、雨天、镜头污渍、低端设备和复杂遮挡的数据;生成图也可能带来风格偏差和不自然纹理。合成样本要标记来源、生成参数和许可,训练、验证、测试中的比例要可追踪。测试集应优先保留真实分布,不能用合成高分替代真实证据。
泄漏不仅来自图片重复,也来自预处理和元数据。例如先对全量数据计算均值再切分,会把测试分布信息带进训练;用文件名、拍摄日期或水印暗含标签,会让模型学到捷径;把同一视频的不同帧分别增强后再切分,仍然没有消除主体泄漏。数据管道要在切分之后拟合统计量,并对文件名、EXIF 和水印做特征审查。
偏差分析应同时看总体、切片和置信度。总体准确率提高而某个设备的召回率下降,说明平均数掩盖了风险;某类图片数量少,切片分数的置信区间很宽,应报告样本量和未知,而不是给出确定结论。切片变量应与任务风险有关,避免把敏感属性当成无需授权的标签收集;必要时使用受控、去标识化的审计数据。
当发现偏差时,修复动作不止是“再训练”。可以补采代表性数据、修改标签规则、删除捷径特征、改变输入范围、增加低置信度拒答、把该切片转人工,或干脆不在该场景部署。每项修复都要在同一固定测试集和关键切片上复评,并记录是否牺牲了其他任务或带来新的隐私风险。
11.5 实操审计:从一张图片追到一个可解释结果
第一次做视觉实验时,建议建立一条最小可追溯链:原始文件哈希、解码信息、预处理参数、输入张量摘要、模型版本、输出、后处理和人工判断。不要一开始就保存所有原图副本;先保存必要的审计字段和受控链接,降低敏感数据扩散。发生争议时,凭哈希和 manifest 可以确认“当时模型究竟看到了什么”。
审计脚本应主动制造坏输入:改扩展名、截断文件、空文件、超大尺寸、单通道、带透明度、包含 NaN 的数组和方向元数据。每种输入都要得到稳定的错误类别,而不是随机抛出底层库异常。错误信息对用户可以简洁,对日志应包含规则名、文件哈希和处理阶段,方便定位到底是上传、解码还是模型前出了问题。
抽样检查不能只看图片缩略图。对同一原图保存预处理前后并排预览,查看裁剪是否切掉目标、补边颜色是否误导模型、文字是否变得不可读、掩码是否出现新类别。对于随机增强,固定随机种子生成一组审查样本;如果审查人员无法说明增强后的图片仍然属于同一个标签,就不要把它默认为安全增强。
数据与代码要一起版本化。数据快照、标签词表、切分清单和 transform 版本任何一个改变,都可能改变评估结果。报告中写清“模型权重相同但输入契约改变”的实验,避免把差异误归因于网络结构。若线上服务升级解码器或图像库,也要把它视作需要回归测试的依赖变更。
最后把适用范围转成用户可见提示。提示应说明支持的格式和尺寸、是否会保存或上传、模糊图可能返回不确定、结果不能用于哪些高风险判断。透明提示不是降低产品吸引力,而是帮助用户提供更有用的输入,也让模型的拒答和人工复核成为正常流程,而不是异常页面。
完成本节后,学习者应能回答五个问题:模型输入的每个维度代表什么;哪些变换保持或改变标签;训练和测试为何不会泄漏;数据缺口在哪里;当输入不合格时系统怎样安全退出。若只能说出模型名称和准确率,说明输入与数据基础还没有建立。
| 字段 | 示例 | 验证动作 | 失败状态 |
|---|---|---|---|
| format | JPEG/PNG,禁止伪扩展名 | 读取 MIME 与魔数并实际解码 | unsupported_format |
| shape | 短边不小于 256,最长边不超过 4096 | 检查 H、W 与宽高比 | invalid_dimensions |
| color | RGB,通道顺序明确 | 检查通道数、dtype、范围 | invalid_color |
| transform | resize + letterbox,保存比例与偏移 | 回放同一 manifest | transform_mismatch |
| quality | 模糊、过暗、损坏按规则拒绝 | 运行质量阈值与人工抽检 | low_quality |
| privacy | 处理人脸、屏幕、EXIF 的策略 | 核对脱敏记录和权限 | privacy_blocked |
| provenance | 来源、许可、快照哈希 | 检查数据卡和授权字段 | unknown_source |
| 增强 | 可能保留的属性 | 可能破坏的证据 | 最小验证 |
|---|---|---|---|
| 小幅平移 | 主体类别、粗略形状 | 边缘小目标被裁掉 | 裁剪后召回率 |
| 水平翻转 | 无方向性的轮廓 | 文字、左右方向、标识 | 方向对照集 |
| 亮度变化 | 大致形状与类别 | 颜色阈值、暗部细节 | 设备/光照切片 |
| 旋转 | 旋转不敏感的物体 | 地平线、仪器读数 | 角度分桶评估 |
| JPEG 压缩 | 低频轮廓 | 细字、细线、二维码 | 质量等级曲线 |
| 随机遮挡 | 部分可见主体 | 关键部位或小目标 | 遮挡比例与拒答率 |
图中每一步都应产生可记录的字段;只有最后的张量和模型输出没有办法解释输入时,流程才算完成。
from dataclasses import dataclass
from pathlib import Path
import hashlib
from PIL import Image
@dataclass
class ImageContract:
max_side: int = 4096
min_side: int = 64
channels: int = 3
max_bytes: int = 12 * 1024 * 1024
def sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def inspect_image(path: str, contract: ImageContract) -> dict:
file_path = Path(path)
if file_path.stat().st_size > contract.max_bytes:
return {"ok": False, "state": "too_large"}
try:
with Image.open(file_path) as image:
image.load()
width, height = image.size
mode = image.mode
if min(width, height) < contract.min_side:
return {"ok": False, "state": "too_small"}
if max(width, height) > contract.max_side:
return {"ok": False, "state": "too_large"}
if mode not in {"RGB", "RGBA", "L"}:
return {"ok": False, "state": "unsupported_color"}
return {
"ok": True,
"state": "accepted",
"sha256": sha256(file_path),
"width": width,
"height": height,
"mode": mode,
}
except (OSError, ValueError) as error:
return {"ok": False, "state": "decode_error", "detail": str(error)}
print(inspect_image("sample.jpg", ImageContract()))11.1.10 从输入审查到数据集发布
数据集发布前做一次“反向审计”:让没有参与采集的人只看数据卡、标签指南和切分清单,判断每个样本是否能进入训练、验证或测试。如果他需要询问作者才能理解类别、坐标或来源,说明契约还不够明确。审计记录保存问题、修订版本和受影响样本。
输入检查要区分硬限制和软提示。文件格式、像素总量、权限和恶意内容是硬限制,必须在模型之前阻断;模糊、遮挡和主体大小可以是软指标,先返回 uncertain 或 review_required。把所有问题都变成“继续运行”会让模型承担它不应承担的判断。
验证预处理时,把同一图片以原图、可视化变换、张量摘要和最终覆盖层四种形式保存。原图与变换图确认裁剪和方向,摘要确认 dtype 与范围,覆盖层确认坐标;四者缺一时,某些错误会在训练很久之后才暴露。
切分完成后检查每个集合的分布,但不要为了让比例好看而重新随机。主体、会话和实体必须保持隔离;少数类不足时记录缺口,采用补采、重采样或限制范围,并在报告中说明其对不确定性的影响。
数据卡应把版本和删除流程写成可执行步骤:下载或采集快照、生成哈希、标注、审查、切分、发布、撤回、删除派生物。每一步产生日志和负责人,未来更换模型或设备时可以重建同一数据状态,而不是依赖个人记忆。
本小节的专业标准是“输入可验证、标签可复现、切分无已知泄漏、增强有不变性理由、偏差有切片证据、失败有安全状态”。达到这六点,才适合进入卷积或 Transformer 的模型比较。
| 闸门 | 证据 | 不通过时 |
|---|---|---|
| 格式与解码 | 坏文件/伪扩展名测试 | 阻断并返回状态 |
| 标签一致 | 指南、抽检、分歧记录 | 暂停标注并修指南 |
| 切分隔离 | 主体/会话/近重复审查 | 重建清单 |
| 增强合理 | 不变性矩阵与对照集 | 移除或限参 |
| 来源治理 | 许可、快照、删除回放 | 限制使用/撤回 |
给自己的数据集填写表 11.1E,每项附一个真实文件或日志证据;找一位同伴只依据这些材料复现一次输入检查和切分。
11.1.11 最后一轮自检:输入先于模型
拿到一张陌生图片时,先问它能否被安全解码、是否在尺寸和颜色契约内、是否具备任务所需的主体和清晰度。只有这些条件成立,模型分数才有解释空间。
拿到一份陌生数据集时,先找来源、许可、主体/会话分组、标签指南和删除路径。没有这些字段,任何高分都应视为暂时的探索结果。
拿到一次增强实验时,先说明不变性假设,再比较真实切片和反事实样例。增强带来的训练损失下降不能自动证明现实鲁棒性。
拿到一个失败样例时,沿着哈希、预处理、张量、模型、后处理和展示逐层回放;每一步都要有版本和状态,才能把“看不见”与“没找到”分开。
输入基础的最终产物是一套可审查的契约、数据卡和回放,而不是一个孤立的图片文件夹。它们会在后续卷积、ViT、VLM 和多模态章节反复使用。
- 契约字段可执行验证。
- 标签与切分可以由同伴复现。
- 增强、泄漏和偏差有对照证据。
- 失败输入有明确状态和人工动作。
from collections import defaultdict
from hashlib import sha1
from pathlib import Path
import json
def group_key(row):
# 同一视频、主体或实体只能进入一个集合。
return row["session_id"] or row["subject_id"] or row["asset_id"]
def stable_bucket(key, seed="vision-v1"):
digest = sha1(f"{seed}:{key}".encode("utf-8")).hexdigest()
return int(digest[:8], 16) % 100
def split_rows(rows, train_end=80, valid_end=90):
groups = defaultdict(list)
for row in rows:
groups[group_key(row)].append(row)
result = {"train": [], "valid": [], "test": []}
for key, members in sorted(groups.items()):
bucket = stable_bucket(key)
name = "train" if bucket < train_end else "valid" if bucket < valid_end else "test"
result[name].extend(members)
return result
rows = json.loads(Path("labels.json").read_text(encoding="utf-8"))
splits = split_rows(rows)
print({name: len(items) for name, items in splits.items()})选一个公开、低风险的图像任务,写出格式、尺寸、颜色、坐标、质量、隐私、来源和失败状态八项字段;再列出三张输入示例,说明它们为何被接受、拒绝或转人工。
从一组包含连拍、相同主体或重复下载图片的数据中建立哈希/分组审查,比较随机切分和按会话切分的分数差异,并在报告中解释差异来自哪里。
提交输入契约、数据卡、标签指南、切分清单、增强不变性表和坏输入测试记录;用一句话写出模型明确不适用的场景。
11.1.1 像素、通道与图像契约
一张 RGB 图像通常是形状为 [H, W, 3] 的数组,三个通道保存红、绿、蓝的采样值。灰度、RGBA、深度图、热成像和医学影像的通道含义不同,不能因为数组形状相似就混用。模型输入前的色彩空间、位深、归一化常数、方向、裁剪和插值方式,都应写进契约。
像素是传感器和编码流程的结果,不是客观世界本身。同一物体在逆光、阴影、不同白平衡、不同手机镜头或 JPEG 压缩率下会形成显著不同的分布。若训练集只含正面、明亮、近距离照片,模型在远景、夜间或侧面失败不是“偶然”,而是输入范围之外的正常结果。
输入契约至少写:允许的格式和尺寸、颜色和坐标系、预处理、最大文件大小、模糊或损坏图像的处理方式、敏感内容处理、输出任务和不适用场景。服务端需要验证真实文件类型和解码结果,而不是只相信扩展名或浏览器声明。
任何一个环节丢失的信息,后续网络通常无法可靠补回。
11.1.2 数据卡、标签与切分
视觉数据卡记录来源、拍摄或生成方式、时间和地点范围、授权、主体同意、类别定义、标注人和工具、已知缺口、保留与删除政策。它不只是合规文件,也是排查分布偏移的索引:当模型在某个设备或地区失效时,可以回到采集条件检查。
标签是任务协议,不是自然事实。分类标签要定义“画面中出现”还是“主体明确可见”;检测框要定义遮挡和截断如何画;分割要定义边缘、孔洞和重叠实例如何处理。模糊标注可以保留为不确定或交由复核,不能强迫标注者猜一个确定答案。
训练、验证、测试必须按泄漏风险切分。连拍图片、同一病人的多次检查、同一建筑的不同角度、同一视频帧或带有相同水印的图片不能分到不同集合。随机按图片切分得到的高分,常常只是模型记住了人物、背景或拍摄设备。
| 泄漏来源 | 表面现象 | 更安全的切分键 |
|---|---|---|
| 视频帧 | 测试集近乎满分 | 视频或拍摄会话 ID |
| 同一主体 | 模型记住背景/人脸 | 主体或病例 ID |
| 近重复图片 | 验证集过于容易 | 去重簇或原始素材 ID |
| 后期水印 | 学到来源而非目标 | 来源/机构/设备 ID |
11.1.3 增强、泄漏与偏差
数据增强是把训练时允许的不变性写进输入。例如轻微平移、翻转、亮度改变可能适合普通物体识别;但左右方向有诊断意义、文本必须可读、颜色是判别依据时,随意翻转、旋转或强颜色抖动会改变标签。每一种增强都要回答:现实使用中这个变化是否应该保持同一个输出?
增强不能替代缺失数据。没有雨天、儿童、罕见型号或低清截图,靠随机噪声很难补出真实分布;合成图也要单独标记,不能悄悄混入测试集。先报告覆盖缺口,再决定补采、限制使用范围还是加入人工复核。
偏差应按可解释切片检查,例如设备、光照、场景、主体特征、语言文字、遮挡和图像质量。切片不是为了给人贴标签,而是为了发现模型是否把非任务因素当捷径。若某切片证据不足,应报告未知,不能把总体平均分外推成对每个人都可靠。
为一个“识别实验器材”的小任务写明输入格式、分辨率、类别定义、来源许可、切分键、三种不适用图片和两项禁止的增强。
输入契约复核标准
复核时先拿三张正常图片、三张边界图片和一张损坏文件走完整管道,逐项确认格式、色彩、方向、尺寸、质量与隐私字段都有明确结果。任何自动修复都要留下原值、修复方式和失败状态,不能让预处理悄悄改变实验结论。
数据卡还应说明哪些样本代表性不足、哪些标签只能由专家确认,以及测试集为什么可以代表上线风险。若无法证明某个切片的样本量或来源,就把结论写成未知,并安排补采或人工复核。
02 · CONVOLUTIONAL NETWORKS
卷积网络:局部模式如何逐层组合
卷积网络用共享的小滤波器扫描图像,在局部区域寻找重复出现的模式。它的价值不在于“识别边缘”这个故事,而在于把平移附近的结构和参数共享写成了模型的归纳偏置。
11.2 卷积的计算观:局部窗口、权重共享与通道混合
把卷积理解成“一个小窗口在图像上滑动”只是入口,还要明确每个输出数字怎样计算。输入有 C_in 个通道,卷积核通常同时覆盖这些通道;一个输出通道由一组形状为 C_in×K×K 的权重和偏置产生。窗口在空间上移动时复用同一组权重,这种共享让网络能在不同位置寻找相似局部模式,也让参数量不随图像宽高线性增长。
输出尺寸由输入尺寸、核大小 K、步幅 S、填充 P 和膨胀 D 决定。常用公式是 floor((H + 2P − D×(K−1) − 1)/S + 1),宽度同理。公式的价值不只是算形状,而是帮助你发现“为什么目标在边缘消失”“为什么特征图比预期小”。任何改变 stride、padding 或 dilation 的实验,都应先在纸上计算形状,再看代码输出。
特征图中的一个通道并不等于一个人类概念。早期层可能响应边缘、颜色变化或纹理,中间层组合成角点和部件,深层可能与类别相关,但它们是分布式表示。看到某个通道激活不能直接说“这是猫耳朵”;需要遮挡、反事实、跨样本统计和任务指标共同支持解释。
感受野描述一个输出位置理论上能受到输入多大区域影响。连续的 3×3 卷积会逐步扩大感受野,步幅和池化扩大得更快,膨胀卷积可以在不增加参数太多的情况下跨越间隔采样。但理论感受野与有效感受野不同:边缘权重、数据分布和优化会让网络实际依赖的区域小于公式范围。
卷积的优势来自归纳偏置而非魔法。局部连接、权重共享和对小平移的等变性在数据有限时很有帮助;它们也意味着模型可能不善于处理长距离关系、旋转或尺度变化。不要把“卷积天然鲁棒”当成部署保证;对旋转、缩放和遮挡仍要用数据和评估验证。
深度、宽度和下采样共同决定容量。增加通道可以表达更多特征,增加层数可以组合更复杂模式,但显存、延迟和过拟合风险也增加。设计骨干时先固定输入尺寸、目标延迟和样本量,再选择一个能跑通的基线;没有必要一开始就堆叠更大的网络。
11.3 下采样、归一化与残差:为什么网络能训练得更深
步幅卷积和池化的共同作用是降低空间分辨率、扩大单个特征看到的区域并减少后续计算。最大池化保留局部最强响应,平均池化保留整体统计;两者都会丢失精确位置。分类只需回答“有没有”,可以承受一部分位置损失;检测、分割和关键点需要“在哪里”,必须通过跳跃连接、多尺度特征或高分辨率分支补回空间证据。
填充策略决定边界如何参与计算。零填充会在图像边缘引入人工黑框,反射或复制填充更平滑,但也可能创造不真实的纹理。若训练集总是把主体放在中心,网络可能把边界模式当作类别信号。做边界切片和不同填充的对照实验,才能知道性能来自目标还是来自人为的边框。
批归一化、层归一化和组归一化都在稳定数值,但适用情境不同。批归一化依赖批次统计,小批量或分布变化时可能不稳定;层归一化对每个样本处理,常见于 Transformer;组归一化把通道分组,适合检测和分割的小批量训练。归一化层的训练/评估模式、统计量保存和冻结策略都要写进实验记录。
残差连接让模块学习“在输入基础上需要修正多少”,缓解深层网络的优化困难。它不是保证更高准确率的开关:如果数据、标签或输入契约错误,增加残差块只会更快地拟合错误。检查残差分支的空间尺寸与通道数是否一致,必要时用 1×1 卷积投影;用单批次过拟合测试确认梯度和标签管道正常。
下采样的时机影响小目标。过早把 32×32 的目标压到几个像素,后面再复杂的层也难以恢复;延迟下采样可以保留细节,但显存和延迟更高。评估时按目标面积、距离和遮挡分桶,不要只报告整图平均分。设计者应能说明最小可识别目标对应多少特征图像素。
可视化中间特征是排查线索,不是最终证据。对同一张图改变背景、遮挡目标、平移目标并比较特征和输出;若模型对背景比目标更敏感,优先修数据和增强,不要通过调色板让热图“看起来更合理”。
11.4 迁移学习:冻结、解冻和域差异的实际决策
迁移学习把预训练骨干当作特征起点,而不是当作不需要验证的黑盒。预训练数据的图像风格、类别、分辨率和颜色统计与目标域越相近,冻结骨干越可能有效;如果目标是工业红外、显微镜、文档扫描或极端视角,早期滤波器和归一化统计都可能需要适配。
一个稳健的微调流程通常分三步:先用冻结骨干训练新的任务头,确认标签、损失和评估脚本;再以更小学习率解冻最后几层,观察验证集和关键切片;最后才考虑全量解冻。每一步都保留 checkpoint、随机种子、数据版本和学习率,不要反复试验后只留下最好的一次。
冻结并不意味着所有参数都不会影响输出。批归一化的运行统计可能继续更新,数据增强和输入归一化也会改变特征;训练模式下 dropout 会引入随机性。需要可复现评估时,显式设置 eval/train 模式,冻结或重置统计量,并把参数 requires_grad 状态记录在 manifest 中。
学习率应和参数组职责对应。新分类头从随机初始化开始,通常需要比预训练层更大的学习率;预训练层若步子太大,会发生灾难性遗忘。权重衰减、类别不均衡损失和早停也要基于验证协议选择。不要把“训练轮数更多”当成迁移学习质量的唯一指标。
域差异可以用简单诊断量化:比较训练与目标图片的颜色直方图、亮度、分辨率、宽高比、背景和主体尺寸;用预训练特征做近邻检查,看目标域是否形成独立簇。如果差异很大,应考虑补采目标数据、重新设计预处理或限制使用范围,而不是只更换更大的骨干。
预训练权重还带有许可和数据治理责任。检查权重来源、许可证、训练数据说明和再分发限制;目标图片若包含私人或受限内容,确认是否允许发送给外部推理服务。模型可以作为起点,但数据授权与发布责任不会随着“使用公开权重”自动消失。
11.5 训练调试:先证明管道正确,再讨论模型优劣
训练视觉模型时,最有价值的第一个实验不是跑很久,而是让一个极小数据集过拟合。选 8 到 32 张样本,关闭复杂增强,训练到损失明显下降并能复现;如果做不到,优先检查标签编码、类别顺序、颜色通道、损失输入范围、梯度是否更新和评估脚本是否读对输出。小数据过拟合是管道自检,不是最终性能目标。
然后建立朴素基线:随机猜测或多数类、冻结骨干的线性头、简单卷积网络和迁移学习版本。对每个基线记录训练时间、参数量、显存、验证指标和关键切片。只有有基线,才知道复杂结构是否真的带来收益;如果基线都不稳定,不应继续增加模型容量。
训练日志至少包含 epoch、学习率、训练/验证损失、每类指标、样本量、随机种子、数据版本和 checkpoint 路径。把训练曲线和错误样例关联起来:验证损失上升可能是过拟合,某类召回下降可能是标签不平衡或增强破坏,整体分数不变但延迟增加可能不值得。
常见的数据管道错误包括:标签从文件名解析时大小写不一致,最后一个类别没有被编码,图片排序让训练和标签错位,shuffle 后的可视化没有显示真实 ID,训练集做了归一化而验证集没有做,或者检测框没有随裁剪同步移动。每个错误都应有一个最小反例和回归测试。
模型检查点不仅保存权重,还应保存类别词表、输入尺寸、归一化、骨干名称、优化器状态和代码版本。加载检查点时验证这些字段,不匹配就停止而不是静默转换。部署前用一组固定图片做 golden test,确认升级库或硬件后输出在允许误差内。
真正的学习成果是能解释一次失败:它发生在哪个阶段,证据是什么,先改哪一个变量,如何避免回归。把“模型不行”拆成数据、形状、数值、优化、评估和部署六类问题,调试会比盲目换网络快得多。
| 旋钮 | 改变了什么 | 可能收益 | 必须观察 |
|---|---|---|---|
| kernel / dilation | 局部采样范围 | 纹理或上下文更充分 | 边界伪影、有效感受野 |
| stride / pooling | 分辨率与计算 | 更快、更大上下文 | 小目标召回、定位误差 |
| channels | 特征容量 | 表达更丰富 | 过拟合、显存、延迟 |
| normalization | 数值与统计 | 训练更稳定 | 小批量、eval 模式 |
| residual | 梯度与信息路径 | 更易优化深层网络 | 分支形状、梯度 |
| freeze / unfreeze | 可训练参数范围 | 迁移更稳或更适配 | 域差异、灾难性遗忘 |
| 观察 | 先做什么 | 不应直接做什么 | 证据 |
|---|---|---|---|
| 目标域相近、样本少 | 冻结骨干训练头 | 立刻全量解冻 | 线性头基线 |
| 目标域颜色/尺度差异大 | 检查预处理与目标数据 | 只换更大模型 | 直方图和近邻 |
| 训练集高、验证集低 | 收紧增强/正则与切分 | 继续堆参数 | 曲线和错误切片 |
| 小目标召回低 | 保留高分辨率特征 | 只调分类阈值 | 面积分桶 |
| 小批量不稳定 | 评估归一化选择 | 照搬批归一化 | 批量敏感性 |
| 部署超时 | 测量每阶段耗时 | 只看参数量 | p50/p95 与 profiler |
下采样提高语义范围也会损失位置;任务头必须使用与输出需求匹配的尺度和证据。
from dataclasses import dataclass
@dataclass
class ConvSpec:
kernel: int
stride: int = 1
padding: int = 0
dilation: int = 1
def output_size(size: int, spec: ConvSpec) -> int:
numerator = size + 2 * spec.padding - spec.dilation * (spec.kernel - 1) - 1
return numerator // spec.stride + 1
def receptive_field(layers):
jump = 1
field = 1
for spec in layers:
field += (spec.kernel - 1) * spec.dilation * jump
jump *= spec.stride
return field, jump
layers = [
ConvSpec(kernel=3, padding=1),
ConvSpec(kernel=3, stride=2, padding=1),
ConvSpec(kernel=3, padding=1),
]
print("shape:", output_size(224, layers[0]))
print("field, jump:", receptive_field(layers))
def freeze_backbone(model):
for parameter in model.backbone.parameters():
parameter.requires_grad = False
for parameter in model.head.parameters():
parameter.requires_grad = True
return model11.2.8 计算量与参数量的区别
卷积核的参数量由输入通道、输出通道和核大小决定,特征图的计算量还要乘上输出高度与宽度。一个 3×3、64 到 128 通道的卷积参数并不随图片从 224 放大到 448 而增加,但每个位置都要重新做乘加,分辨率翻倍时空间计算约增为四倍。
深度可分离卷积、分组卷积和瓶颈结构减少了连接数,却可能改变通道之间的信息交流。把参数减少直接等同于质量提高是不对的;要在目标设备上测吞吐、显存和关键切片,确认节省的资源没有换来小目标漏检或边界变差。
参数量大的模型可能因算子优化、缓存和批处理而更快,参数量小的模型也可能因内存访问和不支持的算子而更慢。因此模型选择表至少同时记录参数、FLOPs、峰值显存、p50/p95 和单张成本。
11.2.9 归一化、标签和梯度的联动
批归一化会保存训练期间的运行均值和方差;小批量、跨设备或域迁移时,这些统计量可能不稳定。层归一化和组归一化对批次依赖较小,但并非无条件更好。冻结骨干时还要决定归一化统计是否冻结,否则“冻结参数”并不等于特征完全不变。
分类标签的整数顺序必须与输出头一致;多标签的 sigmoid 不应误用 softmax;检测和分割损失要分别处理框、类别和像素。最小反例是只保留两张图片,让模型过拟合并打印标签、logits、梯度范数和预测类别,先证明数据管道正确。
训练/验证模式切换、随机增强和评估阈值都影响数字。把确定性预处理、随机增强和后处理分开,配置文件显式记录;验证时固定随机种子并使用同一版本的类别词表,避免每次运行都在改变测试条件。
11.2.10 多尺度与边界证据
分类可以通过全局池化丢失部分位置,但检测、分割和关键点必须保留空间对应。FPN 或 U-Net 式跳连把高分辨率细节与深层语义融合,融合前要检查插值、通道和偏移。任何“恢复分辨率”的模块都不能凭空找回已经被输入裁剪掉的像素。
边界样本要单独评估:目标贴近图像边缘、被裁剪、被遮挡或与背景颜色相近。对同一物体平移到不同位置,比较预测框与掩码;如果只有居中样本正确,说明模型或数据学习了位置捷径。
移动端部署可能使用量化、剪枝或动态分辨率。量化后重新校准阈值和拒答,检查 INT8/FP16 对小目标和低光切片的影响;不要只在平均准确率变化很小的情况下就发布。
11.2.11 迁移学习的记录模板
冻结骨干训练任务头是建立基线的快速方式,逐层解冻可以适配目标域,但每一步都可能发生灾难性遗忘。记录可训练参数比例、参数组学习率、归一化模式、验证切片和 checkpoint,才能解释为什么某次微调改善或退化。
预训练权重带有模型卡、许可和数据偏差。目标数据包含个人、医疗、未公开产品或受限地点时,先确认上传和再分发规则;模型可以从公开权重开始,数据治理却不能因此省略。
上线前用固定 golden set 回放,比较旧版与新版的类别、坐标、拒答和资源;允许的差异写成数值容差。若差异无法解释,先阻断升级,不要把新结果直接覆盖旧报告。
| 项目 | 必须记录 | 解释作用 |
|---|---|---|
| 形状 | 每层 H/W/C、stride、padding | 定位尺寸与边界错误 |
| 参数 | 参数量、可训练比例 | 解释容量和冻结策略 |
| 数值 | dtype、归一化、梯度范数 | 发现溢出和管道错配 |
| 数据 | 分组键、类别分布、切片 | 识别泄漏与不均衡 |
| 部署 | 设备、p50/p95、显存 | 判断是否满足预算 |
| 回放 | 版本、golden 输出、容差 | 防止依赖升级回退 |
def trainable_summary(model):
total = 0
trainable = 0
for parameter in model.parameters():
count = parameter.numel()
total += count
if parameter.requires_grad:
trainable += count
return {"total": total, "trainable": trainable}
def gradient_summary(model):
values = []
for parameter in model.parameters():
if parameter.grad is not None:
values.append(float(parameter.grad.detach().abs().mean()))
return {
"tensors_with_grad": len(values),
"mean_abs_grad": sum(values) / len(values) if values else 0.0,
}11.2.12 卷积基线的深度验收
对卷积网络做验收时,先确认每层的 H、W、C 和参数量,再确认输入契约、标签顺序、归一化、损失和评估脚本。形状正确只是必要条件;一个通道颠倒、标签偏移或评估阈值错误的模型,也可能在错误管道上稳定收敛。
手算输出尺寸时把 stride、padding、dilation 写在同一张图上,标出边缘像素是否被补齐。对检测和分割记录每次裁剪/下采样后的坐标;对分类记录主体最小尺寸和最后特征图的有效空间。这样能解释为什么某些小目标在进入任务头前已经不可见。
训练调试遵循从小到大的顺序:单 batch 过拟合、固定小数据集、朴素基线、冻结骨干、逐层解冻、全量训练、目标硬件 profiling。每一步只改变一个主变量,保存配置与结果;若某一步失败,先修复而不是跳到更大网络。
卷积对小平移有共享权重优势,但旋转、尺度、光照和遮挡仍需数据或结构支持。做背景替换、目标平移和角度切片,比较输出与错误根因;把反事实结果写入错误地图,避免把热图或直觉当成鲁棒性证明。
迁移学习验收还要查看权重许可证、归一化统计和冻结状态。预训练骨干和目标域差异大时,限制范围、补采或增加拒答都可以是正确答案;没有必要为了追求更高总分而忽略关键切片。
最后检查部署:模型输出、后处理、阈值、覆盖层和日志中的 image_id 是否一致;量化或依赖升级后 golden set 是否仍在容差内;p95 和峰值显存是否满足预算。只有结构、数据、评估和运行证据都齐全,卷积基线才是可交付的基线。
| 阶段 | 检查问题 | 证据 |
|---|---|---|
| 形状 | 每层尺寸与通道对吗? | 手算表/打印日志 |
| 数据 | 标签、颜色和切分对吗? | 样例可视化/数据卡 |
| 优化 | 小批次能过拟合吗? | 损失与梯度记录 |
| 能力 | 关键切片改善吗? | 每类指标/错误地图 |
| 部署 | 资源与回放达标吗? | profiler/golden set |
故意制造一次通道顺序或坐标缩放错误,按“现象—最小复现—根因—修复—回归测试”五栏写报告,并说明为什么整体准确率不能定位该错误。
11.2.13 最后一轮自检:从公式到部署
手算卷积形状时,能够指出 stride、padding、dilation 和 pooling 各自改变了什么;看特征图时,能够说明它是线索而不是人类概念的直接标签。
训练基线时,能够用 tiny-batch 过拟合排除标签、损失和梯度错误,再用固定切分比较冻结、解冻和全量微调。
分析小目标、边缘、旋转和低光失败时,能够区分数据缺口、归纳偏置、下采样损失、阈值和坐标错误,不把所有问题都归因于“模型太小”。
部署量化或换硬件时,能够重新检查归一化、阈值、golden set、p95、显存和关键切片;若资源不足,设计区域、限流或人工降级。
卷积章节的交付物是可复现基线报告:结构、形状、权重来源、训练证据、错误地图和运行边界齐全,其他人可以据此继续实验。
- 参数量与实际计算量分开记录。
- 归一化与训练/评估模式明确。
- 输出坐标能回到原图。
- 升级与回滚有固定样例。
11.2.14 复现记录
最终记录参数、形状、预处理、切片、资源和回滚版本;若结果无法由这些字段重放,就不能作为稳定基线。
对 tiny-batch、边界平移、小目标、低光和量化前后五组样例,填写输入形状、预测、梯度/资源、错误根因和下一步动作。
import torch
def train_one_batch(model, batch, optimizer, loss_fn, steps=80):
model.train()
images, labels = batch
history = []
for _ in range(steps):
optimizer.zero_grad(set_to_none=True)
logits = model(images)
loss = loss_fn(logits, labels)
loss.backward()
optimizer.step()
history.append(float(loss.detach()))
return history
def assert_learning(history):
if len(history) < 2 or history[-1] >= history[0]:
raise AssertionError("tiny batch did not learn; inspect labels, loss, and gradients")
return {"initial": history[0], "final": history[-1]}给定输入 128、卷积核 3、padding 1、stride 2,再接一个 kernel 3、stride 1 的层,计算每层输出尺寸和理论感受野;说明为什么第二层不能找回第一次下采样丢失的像素级位置。
在同一分组切分上比较冻结骨干、只解冻最后一层和全量微调;保持输入、随机种子和评估集不变,报告每类指标、p95 延迟和关键错误样例。
提交模型结构图、形状计算、tiny-batch 过拟合记录、基线对照、迁移权重许可和部署资源估算;写下一个卷积归纳偏置可能不适合的场景。
11.2.1 卷积、感受野与特征图
二维卷积用一个小核在输入上滑动,对局部窗口做加权求和。一个卷积核在每个位置复用同一组参数,因此比全连接层更适合网格图像。输出的每个位置都对应输入中的一个局部区域;多组核形成多张特征图,学习不同的纹理、边界或组合模式。
感受野是某个输出单元受输入中多大区域影响。浅层通常可利用小范围细节,堆叠卷积、步幅或池化后,深层可利用更大上下文。感受野大不等于一定会正确使用远处信息:训练数据、优化和架构都决定有效感受野。
卷积对小幅平移有天然的参数共享优势,但不是对旋转、尺度、视角、光照和遮挡自动不变。模型看到的是训练分布中学到的统计规律;对不存在的变化,需要数据、增强、结构设计或明确的拒答边界。
11.2.2 步幅、池化与归纳偏置
步幅大于 1 会下采样,降低空间分辨率和计算量;池化以固定规则汇总邻域,也会丢失精确位置。分类常可容忍部分位置丢失,而检测、分割和关键点任务要保留空间细节,通常使用多尺度特征、跳连或解码器恢复分辨率。
卷积的局部性、平移等变性和参数共享是归纳偏置:在样本有限时,它告诉模型应优先寻找什么样的规律。偏置不是缺点;合适的偏置会降低数据需求,不合适的偏置会让模型忽略全局关系或特定几何约束。
观察中间特征图可以帮助调试,但不能把单张热图当成因果解释。可视化可能受归一化、层选择和方法参数影响。更可靠的证据是遮挡试验、反事实样本、不同切片上的一致性,以及对输出变化的定量记录。
11.2.3 迁移学习与微调
预训练视觉骨干把大量数据中学到的边缘、形状和语义模式作为起点。小数据任务可先冻结骨干、只训练任务头;当目标域与预训练域有明显差异时,再用小学习率逐层解冻。微调应固定验证协议,避免不断试验后只汇报最好的那一次。
迁移学习不是授权的捷径。检查预训练权重、训练数据说明、使用条款和已知偏差;如果目标图像包含人脸、病历、未公开产品或受限地点,还要检查数据是否允许上传到外部服务。模型能跑不表示数据可以这样处理。
先建立一个简单基线:固定输入、固定切分、一个公开骨干和可复现训练脚本。再一次只改变冻结层数、学习率、增强或分类头。没有基线就无法知道收益来自预训练、数据清理还是偶然的验证集波动。
from PIL import Image
import numpy as np
image = Image.open("sample.jpg").convert("RGB")
array = np.asarray(image)
print({
"shape": array.shape,
"dtype": str(array.dtype),
"min": int(array.min()),
"max": int(array.max()),
})
# 训练前把这个检查写进数据管道,
# 而不是假定所有图片都是正确的 RGB 8-bit 图像。选择“仪器正反面分类”或“路牌文字识别”之一,列出三种候选增强;分别说明为什么应保留、禁止或需要实测。
卷积实验复核标准
卷积基线的复核顺序是:先打印每层张量形状,再用极小批次检查模型能否过拟合,随后固定切分比较冻结、部分微调和全量微调。这样可以把形状错误、标签错位、学习率不合适和域差异分开,而不是把所有问题归结为“模型不够大”。
报告中同时保留参数量、显存、吞吐、p95 延迟和关键失败样例。若模型在整体指标上提升,却在小目标或低光切片下降,应明确说明取舍并限制适用范围。
03 · VISION TRANSFORMER
Vision Transformer:把图像变成 Token
ViT 将图像切成固定大小的 Patch,把每个 Patch 投影为向量,再用 Transformer 在 Token 之间建立关系。它不是“比卷积更会看图”,而是把视觉输入接入了一种更通用的序列建模接口。
11.3 Patch 化:图像为什么能够进入序列模型
Vision Transformer 的关键接口是把二维网格变成一串 Token。设输入为 H×W×C,Patch 边长 P,若 H、W 能被 P 整除,则 Patch 数为 (H/P)×(W/P);每个 Patch 展平后通过线性层投影到 D 维。这个步骤不是简单切图,而是决定了最小可表达空间尺度:一个 Patch 内的细字、细线和小目标会先被混合,再交给后面的注意力。
当图片尺寸不能整除 Patch 时,系统必须选择补边、裁剪或使用可变大小 Patch。补边要记录填充值和偏移,裁剪要说明丢失区域,不能默默把最后几列像素舍弃。对于检测和分割,Patch 坐标还要能映射回原图;对于长宽比差异大的图片,直接拉伸可能比补边更改任务几何。
Patch 嵌入通常包含线性投影、位置编码和可选的分类 Token。线性投影负责把局部像素变成隐藏向量,位置编码补回二维位置信息,分类 Token 或池化负责汇聚全局结果。若任务需要每个实例或每个像素的输出,仅保留一个全局向量是不够的,需要从 Token 恢复网格或增加解码器。
位置编码有绝对、相对和二维结构等不同形式。绝对位置编码容易理解,但换分辨率时需要插值;相对位置偏向于表达 Token 之间的距离,窗口或多尺度结构则用更局部的关系控制成本。换输入分辨率后,不能只改一个常量就认为模型适配成功,要检查位置参数、预处理和指标是否一起回归。
Patch 大小影响数据需求和资源。Patch 越小,模型能看到的细节越多,但 Token 数、注意力配对和内存会快速增加;Patch 越大,速度快却容易把小物体平均掉。选择时先统计任务中目标的最小边长,再估计它覆盖多少 Patch;如果只有一个 Patch 的一小部分像素包含目标,分类分数高也可能无法定位。
Patch 化还会带来边界问题。目标刚好跨越两个 Patch 时,局部证据被分割,模型需要通过层间注意力重新组合;强裁剪可能让目标只剩半个 Patch。通过平移同一目标几像素、比较输出和定位稳定性,可以发现模型是否对 Patch 网格过于敏感。
11.4 自注意力:全局关系与二次成本
自注意力先把每个 Token 映射为查询 Q、键 K、值 V,再用 QK 的相似度决定从哪些 Token 聚合信息。它允许一个 Token 直接访问远处区域,因此适合表达“左边的文字对应右边的按钮”这类长距离关系。注意力权重却不是事实解释;模型可能把背景或数据集水印当作捷径,权重图不能单独证明因果。
标准全局注意力的配对矩阵大小与 Token 数平方相关。输入边长扩大两倍、Patch 不变时,Token 约增加四倍,配对数量约增加十六倍;即使实现采用优化内核,显存访问和延迟仍会上升。做预算时同时记录 Token 数、隐藏维度、层数、头数、批量和精度,不能只看图片分辨率。
多头注意力把表示分成多个子空间,让不同头学习不同关系,但头数越多不代表理解越全面。头的输出还要经过前馈网络、残差和归一化,最终的任务性能来自整个堆叠。调试时查看梯度、激活范围和注意力熵,发现某些头塌缩或全局平均,不要直接把可视化称为“模型学到了语义”。
Transformer 的前馈层往往占据大量参数和计算;隐藏维度、扩展比例和层数共同决定容量。较大的模型可能需要更多预训练数据和正则化,否则在小数据任务上过拟合。比较 CNN 与 ViT 时要匹配参数量、预训练数据、训练步数和输入分辨率,避免把规模差异误记为架构差异。
全局关系不等于没有局部归纳偏置。窗口注意力、层级结构、卷积 Patch 嵌入和相对位置偏置都能加入局部约束;混合模型在边缘设备或小数据时可能更实用。架构选择的依据应是任务需要的空间范围、数据规模和部署预算,而不是论文排行榜。
训练稳定性还受学习率预热、权重衰减、梯度裁剪和混合精度影响。高分辨率训练可能需要梯度累积或检查点重计算;这些工程策略会改变吞吐和有效批量,必须写入实验记录。若只记录最终准确率,别人无法判断收益来自模型还是来自不同的训练预算。
11.5 规模化预训练与下游适配:看清迁移的条件
ViT 的能力通常来自大规模预训练和合适的数据增强,而不只是 Transformer 这一层结构。预训练目标可以是监督分类、图像自监督、掩码 Patch 重建或图文对齐;目标不同,得到的特征适用任务不同。下游微调前要读取模型卡,确认输入尺寸、归一化、位置编码、词表或标签映射,不要只复制一个 checkpoint 文件。
改变分辨率时,位置编码插值可能保持整体形状,却损失细小纹理;改变 Patch 大小时,原有的投影权重未必能直接使用。需要时先做少量回归图片,比较特征范数、分类 logits、空间响应和延迟,再在固定切分上训练。模型“能加载”只说明张量形状对得上,不说明语义仍然可靠。
冻结策略与卷积迁移学习类似,但 ViT 早期 Patch 嵌入和位置模块对域差异可能很敏感。小数据先冻结大部分层,训练任务头;若目标域统计差异大,逐步解冻并降低学习率。每次解冻都记录可训练参数比例、训练曲线、关键切片和资源消耗,防止只凭一次随机结果下结论。
数据规模不足时,正则化、标签平滑、随机深度和更强增强有助于防止过拟合,但会增加调参空间。先建立简洁基线,再一次改变一个因素。验证集反复调参会被“用熟”,最终需要保留一个开发者没有反复查看的测试集,作为发布前的最后证据。
预训练表示可能携带不希望的偏差,例如把拍摄背景、地域风格和设备标记与类别绑定。用反事实样本替换背景、改变水印和设备,检查输出是否稳定;若模型对非任务因素极其敏感,优先补数据、限制场景或加拒答,而不是仅靠更长的训练消除。
视觉 Transformer 的输出也要有可观测性。记录输入 Token 数、位置策略、模型版本、显存峰值、p50/p95 延迟、异常率和人工纠错;把这些字段和模型结果绑定,才能解释为什么某类超长图像常常超时或拒答。
11.6 分辨率、窗口与多尺度:把算力花在有证据的位置
高分辨率常被当成视觉模型的默认升级,但它只有在任务目标确实需要细节时才有价值。先统计小目标占原图比例、文字高度、边缘宽度和可接受误差,再决定输入尺寸。若目标平均只占几百像素,盲目把整张图放大可能只是增加背景 Token;先粗筛候选区域再高分辨率复核往往更节省。
滑窗和重叠裁剪能保留局部细节,但会产生重复检测、边界截断和窗口间坐标合并问题。合并时保存窗口 ID、缩放比例和原图偏移,使用明确的 NMS 或实例融合规则;对窗口边界上的小目标单独评估。不要把切片结果直接拼成一张“看似完整”的热图而不标明重叠和空白区域。
窗口注意力把全局问题分成局部块,计算近似线性;跨窗口关系可以通过移位、池化或少量全局 Token 交流。窗口大小越小越省资源,却可能错过远距离关系;窗口越大越接近全局注意力,成本又上升。用长距离对照集和局部对照集分别验证,不能只看平均分类分数。
多尺度结构为不同大小的目标提供不同分辨率特征。高层语义适合粗粒度类别,低层特征保留边缘和位置;融合时要对齐空间尺寸和通道,避免插值造成偏移。检测和分割的评估应按目标尺度报告,验证模型是否真的从多尺度获得收益。
资源预算要以服务指标表达:单张图最大 Token 数、并发量、显存上限、p95 延迟、失败重试次数和每千张成本。把低分辨率、区域二阶段、窗口模型和直接高分辨率放在同一表中比较,必要时设置超时后的安全降级状态,而不是无限等待。
高分辨率还增加隐私与存储风险。原图、裁剪图、缓存和中间 Token 可能包含比最终结果更多的敏感信息;设计保留期、加密和访问审计。若只需输出候选区域,处理后应尽快清理无关裁剪,避免为了提高可视化便利而保存完整的中间副本。
11.7 读懂一篇 ViT 实验:从数字回到可复现条件
阅读论文或模型卡时,先列实验条件:数据集版本、训练/验证切分、输入分辨率、Patch 大小、增强、预训练权重、微调轮数、优化器、随机种子、硬件和评估脚本。准确率差一个百分点可能来自切分、预训练数据或测试时增强,而不一定来自模型结构。把条件表写出来比背模型名称更有用。
比较结果要看不确定性。小测试集的单次分数可能受随机种子影响,最好报告多次运行的均值和范围;关键切片样本很少时给出样本量和置信区间。若论文只报告最好的一次,应在自己的复现实验中保持诚实,不能把它当成稳定上限。
参数量、FLOPs 和实际延迟不是同一个指标。内存访问、算子实现、输入尺寸、批量和设备都会改变 p95;一张图能跑通并不等于高并发服务可用。用 profiler 测量解码、预处理、模型、后处理和网络传输,找出真正的瓶颈。
注意力可视化、Grad-CAM 或遮挡图能帮助提出假设,但不同层和方法可能得到相反图形。把可视化结果与反事实实验、错误样例和指标变化结合;如果移除所谓“关键区域”后输出不变,就不要把热图写成确定解释。
最后问“如果模型不工作怎么办”。设计低质量、未知类别、超出分辨率、权限不足、工具超时和高风险请求的状态;给每个状态安排拒答、补图、区域重试或人工复核。模型能力之外的流程,是从论文原型走向产品的关键。
读完本节应能用纸笔完成 Patch 数和注意力成本估算,解释位置编码与分辨率的关系,选择 CNN、ViT 或混合模型的理由,并写出一个包含切片与资源指标的可复现实验计划。
| 输入/ Patch | Patch Token 数 | 全局配对量(相对) | 适合观察 |
|---|---|---|---|
| 224 / 16 | 196 | 1× | 常规分类与基线 |
| 384 / 16 | 576 | 约 8.6× | 细节收益与延迟 |
| 448 / 16 | 784 | 16× | 小目标、文字、显存 |
| 224 / 8 | 784 | 16× | 细粒度但成本高 |
| 长图滑窗 | 窗口数×Token | 取决于重叠 | 区域召回与合并 |
| 策略 | 保留的证据 | 主要损失 | 发布前必须测 |
|---|---|---|---|
| 整图低分辨率 | 全局布局、低成本 | 细字和小目标 | 小目标漏检 |
| 整图高分辨率 | 更多细节 | Token/延迟/成本 | p95 与显存 |
| 粗筛+区域复核 | 重点区域细节 | 粗筛漏召回 | 级联召回 |
| 滑窗重叠 | 边界细节 | 重复与坐标合并 | 边缘目标 |
| 窗口注意力 | 局部关系、近线性成本 | 远距离关系 | 长距离对照集 |
同一骨干可以服务不同任务,但只有保留空间对应关系,才能输出可核验的区域证据。
from dataclasses import dataclass
from math import ceil
@dataclass
class VisionBudget:
height: int
width: int
patch: int
hidden: int = 768
heads: int = 12
layers: int = 12
def estimate(budget: VisionBudget) -> dict:
rows = ceil(budget.height / budget.patch)
cols = ceil(budget.width / budget.patch)
tokens = rows * cols
pair_count = tokens * tokens
qkv_values = tokens * budget.hidden * 3
return {
"rows": rows,
"cols": cols,
"tokens": tokens,
"attention_pairs": pair_count,
"qkv_values": qkv_values,
"layers": budget.layers,
}
for spec in (VisionBudget(224, 224, 16), VisionBudget(448, 448, 16)):
print(estimate(spec))11.3.8 注意力矩阵与空间证据
注意力矩阵的每一行对应一个查询 Token 对所有键 Token 的权重分配;它不是天然对称,也不等于因果解释。展示矩阵时要标明层、头、Patch 网格、特殊 Token 和归一化方式,同一张图换层或换头可能得到完全不同的图。
真正验证空间依赖要做干预。遮挡高权重区域、替换低权重区域、平移目标或改变背景,比较 logits、定位和拒答;如果去掉所谓关键区域后答案不变,热图只说明相关性,不能写成“模型看到了这里”。
CLS Token、平均池化和区域池化保留的信息不同。分类可以用全局向量,细粒度任务可能需要多个区域 Token 或解码网格。比较池化时固定骨干和预算,报告小目标、边缘和背景切片,避免只用一张可视化图决定方案。
11.3.9 位置插值与可变尺寸
绝对位置编码通常按训练时的二维 Patch 网格保存,换分辨率需要插值。插值只改变位置参数,不能恢复原图被裁掉的像素;边缘位置、非方形长图和极端宽高比要单独回归。模型加载成功不等于位置语义适配成功。
相对位置偏置或窗口注意力能降低可变尺寸的压力,但窗口切分仍会影响跨区域关系。对长文字、表格和跨窗目标,测试窗口边界与跨窗层;如果关键信息被拆开,应改滑窗、增加全局 Token 或使用专用 OCR。
多尺度或层级 ViT 通过逐步下采样保留不同分辨率特征,设计时要记录每层 Token 数、特征尺寸和融合方式。层级结构会让资源估算更复杂,但能更好地服务检测和分割;用目标尺寸分桶验证它是否真的保留了细节。
11.3.10 训练与迁移的细节
ViT 往往更依赖预训练规模、正则化和增强。小数据上先冻结大部分层训练线性头,再逐步解冻;学习率、权重衰减、随机深度和标签平滑的改变都应单独记录,不能把多项改动的收益归因于模型名称。
输入尺寸变化会改变有效 batch、梯度累积和位置编码。显存不足时使用梯度累积,训练步的统计含义与真正大 batch 不同;报告有效 batch 和学习率缩放规则,保持实验可比。
预训练表示可能学习到水印、设备和背景捷径。做背景替换、去文字和跨设备测试,观察分类、检索和注意力变化;如果非任务因素影响很大,补数据或限制范围通常比延长训练更稳。
11.3.11 预算与降级的工程决策
用 Token 数而不是图片文件大小控制预算。多图请求、长图滑窗、裁剪图和特殊 Token 都计入总量;超过上限时让用户选择区域或分批处理,并保留 image_id、窗口偏移和合并规则。
高分辨率服务需要最坏情况设计。记录解码、Patch 化、注意力、后处理和传输的 p95 与显存峰值;设置超时、排队和降级状态,不要让一个超大请求无限占用 GPU。
区域二阶段的关键指标是级联召回。粗筛漏掉的目标无法由第二阶段恢复,候选太多又会超预算;报告每一级的召回、候选数和延迟,决定在何处转人工。
| 字段 | 示例 | 变更影响 |
|---|---|---|
| patch_grid | 14×14 / 28×28 | Token 数与位置插值 |
| pooling | CLS / mean / region | 全局或空间证据 |
| position | absolute_2d / relative | 可变尺寸与窗口 |
| effective_batch | 64(累积 4×16) | 学习率与统计 |
| attention_budget | tokens²×heads×layers | 显存与 p95 |
| pretrain_revision | 公开权重哈希 | 迁移和许可 |
| golden_output | logits/box/状态 | 升级回归 |
def grid(height, width, patch):
if patch <= 0:
raise ValueError("patch must be positive")
rows = (height + patch - 1) // patch
cols = (width + patch - 1) // patch
return rows, cols, rows * cols
def compare_resolution(specs):
baseline = None
rows = []
for height, width, patch in specs:
item = {"size": (height, width), "grid": grid(height, width, patch)}
if baseline is None:
baseline = item["grid"][2]
item["relative_tokens"] = item["grid"][2] / baseline
rows.append(item)
return rows
print(compare_resolution([(224, 224, 16), (384, 384, 16), (448, 448, 16)]))11.3.12 ViT 方案的深度验收
验收一个 ViT 方案先从 Patch 网格开始:输入 H×W、Patch 边长、是否补边、Token 数、特殊 Token 和位置策略必须互相一致。若 H 或 W 不能整除 P,记录最后一行/列如何处理;对检测与分割保存从 Patch 到原图的映射。
再核对注意力预算。全局注意力的配对量近似为 Token 数平方乘头数和层数;高分辨率、多图和滑窗要计算总预算。显存峰值、p95、吞吐和成本与参数量分开记录,超限时采用区域选择、窗口或人工状态。
位置编码迁移用固定图片回归:比较原分辨率和目标分辨率的 logits、特征范数、边缘与小目标错误。加载成功不等于语义适配,插值后的边界和非方形长图必须单独看。
比较 ViT 与 CNN 需要公平条件:同一分组切分、同一输入契约、相当训练预算、相同评估集和目标设备。若预训练数据、参数量或搜索次数不同,结论应写成“方案差异”,不能归因于单一架构。
注意力可视化只能提出假设。用遮挡、背景替换、Patch 平移和跨窗口对照验证模型是否依赖目标证据;如果输出对证据消失不敏感,应增加拒答、数据或专用检测,而不是美化热图。
最终文档应回答为何选择当前 Patch、分辨率、位置编码和降级路径,哪类输入不支持,更新时哪些字段会触发重训或回归,以及在预算不足时用户得到什么状态。能回答这些,才算真正理解 ViT 的工程边界。
| 检查 | 最小证据 | 未通过动作 |
|---|---|---|
| Patch 映射 | 网格、补边、坐标回放 | 修预处理/解码器 |
| 注意力预算 | Token、显存、p95 | 降级或限流 |
| 位置迁移 | 分辨率回归集 | 固定尺寸/重训 |
| 公平比较 | 数据与预算对照 | 重做实验 |
| 空间证据 | 反事实与切片 | 加工具/人工 |
为单图、长图和多图请求分别设定 Token 上限、超限状态、区域重试和 p95 目标;用一个反事实样例验证降级没有悄悄把“未看到”写成“没有”。
11.3.13 最后一轮自检:Token 预算先行
面对新的输入分辨率,先计算 Patch 网格、特殊 Token、注意力配对量和显存,再决定是否直接提高分辨率。高分辨率不是免费的清晰度。
面对位置编码迁移,先做固定图片和边缘/小目标回归;若插值后空间证据变差,选择固定尺寸、区域处理或重新训练,而不是只接受加载成功。
面对 CNN 与 ViT 的比较,先对齐数据、预训练、训练预算、输入契约、设备和评估脚本,确认比较对象是完整方案而不是单个名字。
面对注意力热图,先做遮挡、背景替换、Patch 平移和跨窗对照;没有干预证据时,不把热图写成因果解释。
ViT 章节的交付物是 Token 预算与复现实验表:架构、位置、分辨率、切片、延迟、显存、降级和边界明确。
- Token 上限和超限状态已定义。
- 长图、多图和滑窗有坐标合并规则。
- 小目标与长距离关系有专项评估。
- 模型升级可回放并可回滚。
选择一个可定位的公开图像,生成目标遮挡、背景替换、Patch 平移和长宽比变化四个版本;比较输出、区域证据和资源,不要只截图注意力图。
def patch_box(row, col, patch, image_width, image_height):
left = col * patch
top = row * patch
right = min(left + patch, image_width)
bottom = min(top + patch, image_height)
if left >= right or top >= bottom:
raise ValueError("patch is outside the image")
return {"left": left, "top": top, "right": right, "bottom": bottom}
print(patch_box(2, 5, 16, 224, 224))分别计算 224×224/16、384×384/16 和 448×448/16 的 Token 数与相对配对量;再用任务中的最小目标尺寸判断哪个方案有必要。
把同一目标在图片中平移 4、8、12 像素,保持内容不变,比较分类、定位和 Token 特征;记录模型是否对 Patch 网格过于敏感。
提交 Patch/分辨率预算、位置编码策略、预训练条件、基线对照、p95 与显存记录,并解释为何最终选择当前输入方案。
11.3.1 Patch、位置与序列
对大小为 H × W 的图像,使用边长为 P 的 Patch,会得到 (H/P) × (W/P) 个 Token。每个 Patch 展平并线性投影到隐藏维度;位置编码告诉模型 Token 原本在哪里,否则注意力本身不知道左上角与右下角的差异。
Patch 是信息压缩的第一道门。Patch 太大,细小文字、边缘和小目标可能在一个 Token 内被混合;Patch 太小,Token 数平方级地增加注意力成本。输入分辨率、Patch 大小和任务对象最小尺寸应一起设计,不能只套用某个论文配置。
很多实现使用分类 Token 汇集全局信息,也可以用池化、区域 Token 或多尺度结构。无论具体形式,输出头必须与任务相符:图像分类只需一个全局预测,分割和检测还需要保留或恢复空间坐标。
11.3.2 注意力、规模与预训练
自注意力让每个 Token 根据内容与其他 Token 交互,因而能直接建立远距离关系。它不保证“理解关系”:注意力权重不是解释,模型仍可能利用背景、频率或数据捷径得到高分。解释模型时要回到反事实和任务指标。
相较卷积,ViT 往往更依赖规模足够的预训练、正则化和合适增强;预训练后在下游任务微调是常见路径。比较架构时固定数据、训练预算和分辨率,避免把更大的预训练数据或更多计算误记为结构本身的优势。
视觉骨干的选择不是二选一。卷积、ViT、混合架构和多尺度模型各有资源与数据条件;对于小数据、低延迟、边缘设备或精细定位任务,简单卷积基线仍可能更合适。先写清任务合同和硬约束,再做可复现实验。
11.3.3 分辨率与计算预算
若边长翻倍、Patch 不变,Token 数约变为四倍,标准全局注意力的配对计算会增长得更快。高分辨率不只是显存问题,也会影响延迟、成本和吞吐。把“能跑一张图”与“能在目标设备、并发和预算下运行”区分开。
常见策略包括先低分辨率粗筛、再对候选区域高分辨率检查;使用滑窗或图像金字塔;采用窗口或稀疏注意力;在任务允许时裁剪无关背景。每种策略都会影响漏检、边界和延迟,应放入同一评估报告。
记录每次推理的原图尺寸、有效输入尺寸、裁剪区域、Token 数、模型版本、设备、耗时和输出状态。只有这样,出现“某类大图常超时”时才能定位是解码、预处理、模型还是后处理造成。
| 选择 | 收益 | 代价 | 应验证什么 |
|---|---|---|---|
| 更小 Patch | 保留细节 | Token/显存增加 | 小目标召回与 p95 |
| 更大输入 | 细节更多 | 吞吐下降 | 真实图像收益 |
| 区域二阶段 | 集中预算 | 粗筛可能漏目标 | 级联召回 |
| 窗口注意力 | 降低全局成本 | 跨区域关系受限 | 长距离案例 |
计算 224×224、Patch 16 与 448×448、Patch 16 的 Token 数,说明后者为什么不能只把“图更清楚”当作免费收益。
ViT 实验复核标准
复核 ViT 时把 Patch 大小、输入分辨率、位置编码、预训练权重和微调预算作为一组可追溯配置。先用公式估算 Token 数与注意力配对量,再在目标设备上测真实显存和 p95;纸面复杂度不能代替部署数据。
至少安排一次 Patch 网格平移、裁剪边界和小目标对照,检查模型是否依赖固定切块或背景。只有当精度收益、空间定位、成本和数据规模都满足任务合同,才把更大的模型写成合理选择。
04 · REPRESENTATION LEARNING
视觉表示:自监督与图文对齐
把图像编码成向量后,可以检索、聚类、做近邻分析或与文字对齐。向量空间很有用,但它表达的是训练目标塑造的相似性,不是事实、因果或授权结论。
11.4 表征学习:向量空间由训练目标塑形
视觉表征是把图片映射为可比较的向量或特征图。它的“相似”不是自然界自带的量,而是训练目标、样本配对和增强策略共同塑造的结果。监督分类会把同类图片拉到便于分类的位置;自监督方法从同一图片的不同视图构造正样本;图文对齐则要求图像与描述在共同空间中互相检索。换一个目标,向量的邻域就可能改变。
表示学习的第一步是决定不变性:哪些变化应该保持相似,哪些变化必须被区分。同一商品换背景可能仍是同一商品,两个外观相似但型号不同的商品却不能混为一类;同一地点的不同时间可能需要聚在一起,也可能需要区分季节。把正负样本定义错,模型会忠实地学到错误的业务含义。
数据增强会隐式定义正样本。裁剪、颜色抖动、遮挡和旋转把两张图当作同一对象的不同视图,只有在任务允许时才成立。训练前写出增强不变性清单,并对每一项做人工抽检;如果增强让人无法判断原标签,不能因为损失下降就认为它有效。
向量维度、范数和池化方式也属于表示契约。使用平均池化、CLS Token 或局部最大池化,会保留不同的空间信息;是否 L2 归一化会改变点积和余弦的关系。索引、阈值和下游分类器必须知道这些约定,不能把不同模型或不同预处理的向量直接混在同一个集合里。
近邻审查是学习表示最直观的实验:随机选查询图,查看 Top-k 的图片、标签、来源和距离。重点不在于展示几个漂亮的近邻,而在于记录错误类型:背景相似、主体相似但标签不同、同一原图重复、敏感信息泄露或模型版本混用。审查结果要回写数据卡和错误地图。
表示质量需要任务指标来证明。聚类图可以帮助发现结构,却不等于分类准确;近邻看起来相关,却不代表召回了任务所需的证据。用固定查询集报告 Recall@k、类别纯度、重复率、切片差异和人工复核一致性,才能把“向量更好”变成可验证的结论。
11.5 对比学习:正负样本、温度与批次构成
对比学习常把同一对象的两个视图设为正对,把批次中其他样本当作负对。图像编码器输出 z,经过归一化后计算相似度,再用温度参数缩放 logits。温度越小,模型越强调分数最高的候选;它不是无意义的调参项,而是决定梯度集中程度和相似度分布的关键参数。
批次内负样本有一个隐含假设:其他样本大多不是同一个语义对象。如果批次里包含同一主体、同一视频的相邻帧或同一商品的不同视角,把它们当负样本会产生冲突梯度。可以使用分组采样、去重、软标签或显式排除同实体负例,并在报告里写明负样本策略。
难负例对检索很重要。随机负例很容易区分,模型学到粗粒度颜色或背景;外观相似但标签不同的难负例能逼迫模型关注任务真正需要的差异。难负例也可能是标签错误或本应为正例,构造前要人工审查并保存来源,避免把噪声当作挑战。
对比损失的数值并不能直接解释为概率或距离阈值。训练损失下降可能来自温度变化、批次增大或数据泄漏;验证时应固定归一化和相似度公式,报告正负对分布、margin、Recall@k 和不同切片。若要上线阈值,必须在独立验证集上校准,并保存版本。
自监督预训练通常需要大量未标注数据,但未标注不等于无治理责任。图片来源、删除请求、个人信息、重复素材和数据许可仍然要记录。预训练学到的背景和设备偏差可能在下游放大,应该用反事实图和跨设备测试检查,而不是只看预训练损失。
如果只有少量数据,简单的监督基线可能比复杂对比学习更稳。先用冻结骨干或线性分类器建立基线,再尝试增强、投影头、温度和难负例;一次改变一个因素。对比学习的价值是改善下游任务和检索,而不是让损失曲线更好看。
11.6 CLIP 与零样本分类:提示词也是模型输入
图文对齐模型把图片向量和文本向量放入同一空间,零样本分类时把类别写成文字提示,计算图片与多个提示的相似度并选择最高者。这个流程不需要为每个新类别重新训练分类头,但结果会受提示模板、语言、类别粒度和训练语料影响,因此不能称为“完全不需要数据”。
类别词表首先要定义业务概念。一个类别是“有红色标签的仪器”还是“型号 X 的仪器”,反例是什么,多个类别能否同时成立,应该写进标签指南。提示模板可以包含场景、主体和视角,例如“实验室里的一张{类别}照片”;比较模板时固定模型和图片,报告每个类别和切片的变化。
文本提示的语言选择会引入差异。中文、英文、缩写、专业术语和口语描述可能对应不同的向量;不能只选择分数最高的语言再宣称模型对多语言都同样可靠。对关键类别维护版本化的同义词、反例和模板集合,必要时使用多个模板的平均或校准。
零样本分数不是置信度。最高分只表示在给定提示集合中最相似;如果真实类别不在集合里,模型仍会被迫选择一个。加入 unknown 选项、分数阈值或能量校准,并在未知类别集上评估拒答率。新类别上线前保留人工复核,不要把提示词列表当作无限扩展的标签体系。
CLIP 类方法容易受背景和文字捷径影响。图片中有“猫”字样,模型可能因为文字而非猫的形状得分很高;商品照片的品牌水印也会成为强特征。通过擦除文字、替换背景、裁剪主体和反向提示做对照,检查模型依据的证据是否符合任务目标。
零样本结果要和监督微调、线性探针及检索基线比较。记录每种方法的标注量、训练成本、提示版本、阈值、延迟和错误切片;如果零样本在长尾类别上方便但在关键类别上不稳定,可以把它当候选生成器而不是最终裁决器。
11.7 向量检索与数据治理:相似不等于同一
图像向量索引可以支持以图搜图、素材去重、相似案例浏览和跨模态检索。每条索引记录原图或缩略图的 ID、模型版本、预处理、向量维度、归一化、距离函数、来源、权限、数据版本和删除状态。缺少这些字段时,出现相似度变化无法判断是模型变了、图片变了还是索引坏了。
索引的近邻关系只是排序信号。两个外观相似的产品可能属于不同型号,两个同一地点的照片可能来自不同时间;检索系统要显示来源、拍摄时间和标签定义,不要把“视觉相似”自动写成“同一个对象”或“同一事实”。高风险身份、健康和执法判断不能由近邻排名直接替代。
租户和权限必须在服务端过滤。先按访问控制筛选候选,再做向量距离或重排;不能先返回全库 Top-k 再在前端隐藏。跨租户相似检索可能泄露库存、地点或个人信息,查询日志也可能包含敏感图片的指纹。最小化存储并为删除请求定义向量、缓存、缩略图和备份的传播时限。
不同向量空间不能混比。模型升级、颜色预处理改变、维度变化或 pooling 变化都可能使旧索引的分数失去意义。新旧索引并行构建,在固定查询集上比较召回和延迟,确认权限、删除和版本字段后再切换 alias。任何索引回滚都要能恢复对应的模型与预处理。
近邻审查应包含反例和敏感样本。检查是否把同一水印、背景、压缩伪影或文件命名排在前面;检查删除后的样本是否仍出现在缓存;检查无权访问的租户是否能通过查询间接推断数据存在。把发现的样例 ID 和修复动作写入错误地图,不要只保留一张展示截图。
向量“不可读”不等于匿名化。攻击者可能通过相似查询、成员推断或元数据关联推断原图属性;权限、加密、日志和保留期仍需设计。若任务只需要计数或类别,考虑保存更小的特征或聚合结果,减少长期保存可逆信息的必要。
11.8 表征实验的阅读和复现方法
复现一篇表示学习论文时,先冻结数据和评估协议,再复现模型。记录数据来源、去重、增强、批次构成、温度、投影头、优化器、学习率、训练轮数、随机种子、硬件和混合精度。论文中的“线性探针准确率”依赖冻结的表示、分类器训练协议和数据切分,不能直接与自己的端到端微调分数比较。
对照实验一次只改变一个主变量。先比较监督基线与自监督表示,再比较不同增强或负样本;最后加入提示词和阈值校准。每项实验都保存 checkpoint、配置、日志和固定查询结果,避免把实验室里临时改过的参数混成一个不可复现的“最佳模型”。
查看向量空间时,同时使用定量和定性证据。定量报告 Recall@k、mAP、聚类指标、校准和切片;定性抽样展示成功、近失误、重复和敏感泄露。可视化降维会改变距离结构,只用于探索,不用于替代原始向量上的评估。
部署前设计输入与索引的契约测试:空图片、极端长宽比、不同颜色模式、未知类别、删除后的 ID、无权限查询、模型维度不匹配和距离函数配置错误。测试应得到可预测的状态码,不能把底层数据库异常直接暴露给用户。
表示服务还要测资源和新鲜度。记录批量编码吞吐、单张延迟、索引构建时间、更新延迟、内存和成本;监控近邻标签分布与输入设备的变化。数据源更新或删除请求发生时,确认索引、缓存和评估集在预期时间内同步。
本节的最终判断不是“我能调用一个 embedding API”,而是能解释向量由什么目标产生、相似度如何计算、何时需要校准和拒答、如何防止权限泄露,以及模型或数据变化后怎样重建索引和复评。
| 方法 | 训练信号 | 优点 | 主要风险 |
|---|---|---|---|
| 监督分类 | 人工类别标签 | 目标明确、易评估 | 标签成本、类别边界固定 |
| 同图对比 | 增强视图为正对 | 利用未标注数据 | 增强/负样本冲突 |
| 掩码重建 | 预测被遮住 Patch | 学习局部与结构 | 重建好不等于任务好 |
| 图文对齐 | 图片-文字正对 | 零样本与跨模态检索 | 提示和语言敏感 |
| 线性探针 | 冻结表示训练线性头 | 衡量可分性 | 不代表端到端效果 |
| 近邻检索 | 距离排序 | 直观、可审查 | 相似不等于事实 |
| 环节 | 固定什么 | 报告什么 | 常见误读 |
|---|---|---|---|
| 类别定义 | 标签、反例、粒度 | 词表版本 | 最高分就是正确 |
| 提示模板 | 语言、句式、场景 | 模板对照结果 | 换模板不算改模型 |
| 相似度 | 归一化、温度、距离 | 分数分布 | 分数就是概率 |
| 未知类别 | unknown 样本与阈值 | 拒答/误接收 | 不在词表也必须选 |
| 切片评估 | 设备、光照、文字 | 每类 Recall/校准 | 总体均值代表所有场景 |
图文空间提供候选关系,阈值、来源和权限决定这些候选能否进入用户可见结果。
import numpy as np
def l2_normalize(matrix):
norm = np.linalg.norm(matrix, axis=1, keepdims=True)
return matrix / np.maximum(norm, 1e-12)
def logits(image_vectors, text_vectors, temperature=0.07):
images = l2_normalize(np.asarray(image_vectors, dtype=float))
texts = l2_normalize(np.asarray(text_vectors, dtype=float))
return images @ texts.T / temperature
def zero_shot(image_vectors, text_vectors, labels, threshold=0.0):
score_matrix = logits(image_vectors, text_vectors)
answers = []
for row in score_matrix:
order = np.argsort(-row)
best = int(order[0])
answers.append({
"label": labels[best] if row[best] >= threshold else "unknown",
"score": float(row[best]),
"ranked": [labels[int(i)] for i in order],
})
return answers
images = [[1, 0], [0, 1]]
texts = [[1, 0], [0, 1]]
print(zero_shot(images, texts, ["red tool", "blue tool"]))11.4.8 表示目标与不变性的检查
在选择表示模型前,先列出任务希望保持不变和必须区分的变化。背景、光照或轻微视角可能应保持相似;型号、文字、缺口或左右方向可能必须区分。正样本、增强和评估切片都围绕这张表设计,避免训练目标与产品判断冲突。
同一主体的多张图片适合测试实体一致性,但不能把相似外观的不同实体误当正例。随机采样正负对并人工抽查,记录主体 ID、拍摄会话和标签版本;若无法说明关系,放入 uncertain 集,而不是强行训练。
表示模型的输出有空间语义但没有自动事实含义。近邻只说明训练目标下相似,不能证明同一人、同一物或同一事件;检索界面显示来源、时间和权限,结论交给任务规则或人工。
11.4.9 对比学习的数值与批次
对比损失中的温度会改变 logits 的尺度和梯度集中。小温度让最高分更突出,过小可能造成训练不稳定;比较温度时固定批次、增强和学习率,报告正负相似度分布、Recall@k 和校准,而不是只看 loss。
批次内负样本假设其他样本不是同一语义对象。连续视频帧、同一商品多角度和同主体图片违反这个假设,应分组采样或显式屏蔽;否则模型会同时被要求拉近和推远同一实体。
难负例应来自真实错误:外观相似但标签不同、背景相同但对象不同、文字相似但型号不同。收集过程保存来源和人工复核,避免把标签错误当作挑战样本。
11.4.10 CLIP 提示与未知类别
零样本分类把类别词表作为输入的一部分。模板、语言、同义词和场景描述变化都会改变文本向量;将模板版本化,比较多模板平均、单模板和业务术语的差异,并在固定数据上选择,而不是为每张图片手工挑提示。
未知类别必须进入评估。没有 unknown 提示时,模型会在已知类别中强行选择;可以用分数阈值、能量或嵌入距离构造拒答,但阈值要在独立验证集校准,并报告误接收和误拒绝。
图片里的文字和水印可能成为捷径。擦除文字、替换背景、翻转或裁剪主体,观察分数变化;如果去掉目标后分数仍高,说明零样本结果需要人工或专用工具确认。
11.4.11 向量索引的生命周期
向量索引经历 building、candidate、shadow、active、retired 等状态。新模型或预处理建立新索引,在固定查询集和权限/删除测试通过后再切换 alias;保留旧版以便回滚,不能直接覆盖。
删除请求要穿过原图、缩略图、向量、缓存、标签、日志和备份。记录每一层的完成时间和验证查询;如果训练权重无法逐样本删除,明确披露并重新评估风险。
多租户检索先做服务端权限过滤,再做相似度排序。前端隐藏不能防止侧信道;查询日志和错误消息也不要泄露私有样本是否存在。
| 用例 | 预期状态 | 要检查的证据 |
|---|---|---|
| 同实体不同视角 | 相似但有来源 | 主体/会话 ID、Recall |
| 外观相似不同型号 | 可区分或人工 | 难负例标签、margin |
| 未知类别 | unknown/拒答 | 阈值、误接收率 |
| 同图加水印 | 结果不应只随水印变 | 反事实分数 |
| 无权限近邻 | 不可返回 | 租户过滤与日志 |
| 删除后查询 | 不可见 | 索引/缓存/备份回放 |
def choose_threshold(scores, labels, target_precision=0.9):
candidates = sorted(set(scores), reverse=True)
best = None
for threshold in candidates:
predicted = [score >= threshold for score in scores]
tp = sum(p and y for p, y in zip(predicted, labels))
fp = sum(p and not y for p, y in zip(predicted, labels))
precision = tp / (tp + fp) if tp + fp else 0.0
if precision >= target_precision:
recall = tp / max(1, sum(labels))
item = {"threshold": threshold, "precision": precision, "recall": recall}
if best is None or item["recall"] > best["recall"]:
best = item
return best
print(choose_threshold([0.91, 0.82, 0.73, 0.61], [True, True, False, False]))11.4.12 表征服务的最终验收
先固定表示契约:模型版本、输入预处理、向量维度、dtype、归一化、pooling、距离函数和最大输入长度。任何一项改变都可能改变邻域与阈值,应该生成新索引或新评估报告,而不是在旧索引里混写。
正负样本、难例和未知集分开保存,记录来源、主体/会话 ID、标签版本和人工分歧。批次构成会影响对比学习的梯度,连续帧或同实体不能默认为负例;如果样本关系未知,进入审查集。
零样本提示和阈值像模型输入一样版本化。报告模板、语言、类别定义、温度、归一化和校准集;测试 unknown 与反事实背景/水印,确认分数不会被非任务因素主导。
近邻结果带来源、时间、权限和删除状态。服务端先过滤访问权,再做排序;删除回放确认原图、缩略图、向量和缓存都不可见。向量不可读不等于匿名化,日志也必须最小化。
评价表示质量时同时看 Recall@k、类别纯度、重复率、切片差异、人工一致性和资源。可视化降维只做探索;正式结论来自固定查询集和可复现脚本。
| 闸门 | 证据 | 失败动作 |
|---|---|---|
| 契约 | manifest 与维度/距离检查 | 重编码/重建索引 |
| 样本 | 正负/难例/未知审查 | 修采样或标签 |
| 校准 | 独立阈值与切片 | 人工/拒答 |
| 权限 | 跨租户、删除回放 | 阻断查询 |
| 质量 | Recall@k、重复率、人工 | 限制范围 |
模拟模型或预处理升级,建立新旧索引并行对照;报告固定查询、Recall@k、阈值、权限、删除、成本和回滚 alias 的结果。
11.4.13 最后一轮自检:相似度需要任务定义
向量靠近只说明训练目标下相似,不能直接证明同一对象、同一事实或同一权限。检索结果必须带来源、时间、标签和访问控制。
正负样本和增强先写不变性矩阵,再检查同主体、连续帧、难负例和未知类别;批次构成错误会给对比学习造成互相冲突的梯度。
零样本提示、语言、模板、温度和阈值都版本化;分数不是概率,未知类别要有拒答或人工路径。
模型或预处理升级时建立新索引,比较固定查询、Recall@k、重复率、切片、删除和权限,不把旧向量混写。
表示章节的交付物是向量治理报告:训练目标、样本关系、距离公式、校准、索引生命周期和隐私边界可追溯。
- 向量契约字段齐全。
- 近邻错误有抽样证据。
- 跨租户查询先过滤权限。
- 删除请求覆盖派生物。
11.4.14 复现记录
最终记录正负样本规则、提示模板、距离公式、阈值、索引版本和权限回放;相似度结果只有在这些条件固定时才可比较。
11.4.15 复核标准
复核者还要确认向量近邻没有把背景、水印、重复图或无权限样本当成主要证据;发现时保留样例和修复假设,不能只删除异常结果。
列出背景、光照、旋转、文字、型号、主体和时间七个因素,分别写“应相似/应区分/不确定”;为每格指定一个对照样本或人工检查。
from collections import Counter
def audit_neighbors(query_id, neighbors, allowed_sources):
problems = []
seen = set()
for item in neighbors:
if item["source"] not in allowed_sources:
problems.append({"id": item["id"], "state": "permission"})
if item["id"] in seen:
problems.append({"id": item["id"], "state": "duplicate"})
seen.add(item["id"])
if item.get("deleted"):
problems.append({"id": item["id"], "state": "deleted_visible"})
labels = Counter(item.get("label", "unknown") for item in neighbors)
return {"query": query_id, "label_counts": dict(labels), "problems": problems}
print(audit_neighbors("q-01", [
{"id": "a", "source": "public", "label": "tool"},
{"id": "b", "source": "private", "label": "tool"},
], {"public"}))为一个低风险图像任务写出五对正样本和五对难负例,说明每一对的业务理由;检查是否把同一实体误当负例,或把不同型号误当正例。
为四个类别设计三种提示模板,固定图片与模型,报告分数、未知类别拒答和设备切片;选择阈值时说明误报和漏报代价。
提交模型/预处理契约、正负样本说明、近邻审查、权限过滤、删除回放和 Recall@k/拒答率结果;写明向量服务明确不能证明的事情。
11.4.1 表征学习与对比目标
自监督学习从数据本身构造训练信号,例如让同一张图的两个增强视图在向量空间靠近,让不同图片保持区分;也可以预测被遮住的 Patch。这样能利用大量未标注图像学习通用表示,再用少量标注完成下游任务。
正负样本的定义决定向量空间。若把“同一商品不同角度”当正样本,模型可能学到视角不变;若把外观相似但不同型号的商品误当正样本,模型会丢失任务需要的区分。训练目标必须与后续判定粒度一致。
用近邻浏览审查表示质量:随机抽取查询图,查看最相似图片及其来源、标签和分数。它能发现重复图、背景捷径、隐私泄漏和错误聚类,但不能替代固定测试集;挑几个好看的近邻也不能证明系统可靠。
11.4.2 CLIP 与零样本分类
图文对比学习把图像和对应文字拉近,让一张图与多个文本提示比较相似度。零样本分类把类别写成提示模板,选择最相近文本;它适合快速探索或长尾概念,但提示措辞、语言、类别粒度和训练语料都会明显影响结果。
类别提示应形成版本化的标签词表:每个类别有什么定义、同义词、反例、语言版本和模板。对比“a photo of …”与业务术语时,固定其他条件,报告整体及切片差异。不能只挑对自己任务最有利的提示再声称模型原生具备能力。
相似度分数不是概率,也不是置信度。若需要阈值或拒答,必须在独立验证集上校准并按类别、设备、质量等切片检查。新类别、新语言或新相机进入系统时,应回到人工复核或重新校准。
11.4.3 向量检索与数据治理
图像向量可用于以图搜图、去重和素材检索。与第 10 章的文本 RAG 一样,索引记录模型版本、预处理、向量维度、距离函数、数据版本、权限和删除事件。不同模型或预处理得到的向量通常不可直接混比。
图像近邻可能暴露地点、人脸、商品库存、病历或受版权保护的素材。索引前要检查谁可查询、能否返回缩略图、是否允许跨租户近邻、日志保留多久、原图删除后向量和缓存多久消失。向量不是“匿名化原图”的自动保证。
检索结果应显示来源和适用范围,不要把“视觉上相似”写成“同一个对象”或“同一事实”。高风险的实体识别、身份、健康和执法判断需要更严格的限制、验证和人工程序,不能由近邻排名直接替代。
随机选 20 张查询图,逐张检查前 5 个近邻:是否出现近重复、背景捷径、错误来源或隐私信息?按错误类型记录,而不是只汇报最成功的案例。
表征实验复核标准
向量实验不能只展示相似图片。复核时要给出正样本、难负例、查询来源、标签、权限状态和距离度量,并抽查近邻是否因重复图片、背景或设备而聚类。把删除请求、权限过滤和模型升级后的索引重建也纳入测试,避免向量库成为绕过原始权限的旁路。
零样本结果应报告提示模板、归一化、温度、阈值和未知类别行为;相似度不是概率,近邻也不是事实证明。结论必须说明向量适合支持哪一种检索或分组,以及明确不能支持哪一种身份、因果或敏感推断。
05 · VISION TASKS
视觉任务:分类、检测、分割与度量
“识别图片”不是一个单一任务。分类、检测、分割、关键点、OCR 和视觉问答需要不同标签、输出协议、指标和失败处理;用错指标会让模型看似高分却不适用。
11.5 任务先于模型:分类、检测、分割和关键点的输出契约
“识别一张图片”不是一个任务名称。单标签分类回答整张图最可能属于哪个互斥类别;多标签分类回答多个属性是否同时存在;检测给出类别与矩形区域;实例分割区分同类对象的像素;语义分割只关心每个像素属于哪类;关键点提供结构化坐标;OCR 还要输出文字及其顺序。任务不同,标签、损失、后处理和验收都不同。
先写输出契约再选网络。一个候选结果至少包含模型版本、类别或属性、分数、坐标系、原图尺寸、质量状态、是否需要复核和适用限制。没有目标时返回 no_detection,不确定时返回 uncertain,图片损坏返回 invalid_input;这些状态不能都被压成“预测为空”,否则产品无法区分模型没看到、没找到和不该回答。
分类的类别必须互斥或明确允许重叠。若“红色”“金属”“实验器材”是属性,就不应强行放进一个 softmax 类别列表;可以使用多标签 sigmoid,并为每个标签校准阈值。类别不均衡时,准确率被大类主导,应报告每类 precision、recall、F1、PR-AUC、样本量和拒答率。
检测框的几何定义要统一。左、上、右、下通常映射到原图像素,中心宽高适合某些模型内部格式;训练时常用归一化坐标,显示时需要乘回原图尺寸。裁剪、缩放、补边和旋转都要同步变换框与关键点,并用可视化覆盖层确认没有半个像素或宽高顺序错误。
分割标签比分类更容易出现边界分歧。细线、透明物、孔洞、遮挡和重叠实例要在指南中给出规则;训练掩码的类别编号不能被图片插值改变。评估时分别报告整体 IoU、每类 IoU、边界误差、小目标和低质量切片,不能用一个平均 Dice 掩盖某一类完全不可用。
任务定义还要写非目标。一个器材检测器可能不负责判断是否合格、不负责读取序列号、不负责识别人;一个 OCR 模型可能只保证可见字符,不保证语义正确。把非目标写进接口和界面,能防止下游把候选框或文字转成未经验证的业务结论。
11.6 匹配与指标:IoU、Precision、Recall、mAP 怎样连起来
IoU 是预测区域与真实区域交集面积除以并集面积,范围从 0 到 1。检测匹配通常要求类别相同、IoU 超过阈值且一个真值只能与一个预测匹配;阈值越高,对定位精度要求越严。分割也可以使用 IoU,但像素级类别、实例级匹配和边界质量要区分报告。
Precision 回答“预测为正的有多少是真的”,Recall 回答“真实目标有多少被找到了”。漏检代价高时偏向提高召回,误报会压垮人工队列时要控制精度;阈值不是通用的 0.5。应在独立验证集上绘制 PR 曲线,按类别、目标大小、遮挡、设备和图像质量选择阈值。
mAP 是对不同召回水平的精度进行汇总,并依赖类别、IoU 规则、插值方式和评估脚本。报告 mAP 时写清是单一 IoU、多个 IoU 平均还是其他变体;同时给出每类 AP 和样本量。一个类别 AP 很高不能说明长尾类别、边界案例或小目标同样可靠。
阈值与后处理会改变指标。NMS 的 IoU 阈值过低可能删除相邻实例,过高可能保留重复框;top-k 限制会让密集场景漏检;分割的连通域和面积过滤也会影响小目标。将模型原始输出、后处理配置和最终结果分开保存,才能定位错误来自网络还是规则。
类别不平衡和空图需要单独处理。大量无目标图片会让准确率看起来很高,却无法说明找到目标的能力;只报告有目标图片又可能忽略误报。评估集应包含有目标、无目标、多个目标、遮挡、截断和未知类别,并分别统计 false positive image rate 和每张图的候选数量。
人工复核也要量化。抽样评审预测区域是否覆盖真正目标、标签是否正确、拒答是否合理,记录评审者一致性和争议类别。若模型分数高但人类一致性低,可能是标签指南本身含糊;先修协议再调阈值。
11.7 错误切片:从一个总分找到真正的失败模式
错误切片是把结果按与任务相关的条件分组,例如目标面积、光照、设备、背景、遮挡比例、文字方向、距离和拍摄会话。切片变量应在数据卡中预先定义,或在探索时标注为假设;不能只在看到某一组分数不好后临时挑选,让报告变成“只寻找支持结论的数据”。
对每个切片至少记录样本数、正例数、关键指标、置信区间和与总体的差异。样本太少时报告不确定,必要时合并相近条件或补采数据。平均分高、某个关键切片低,仍然可能不满足发布门槛;风险权重和业务代价要写清楚。
浏览错误样例时先分类根因:输入损坏、目标不存在、标签错误、裁剪丢失、颜色通道、背景捷径、定位偏移、阈值、NMS、未知类别、工具失败或界面误读。每个样例保存原图 ID、叠加结果、模型和预处理版本、严重度、根因假设、修复计划和回归测试。
错误地图不只是待办列表。它应把现象连接到证据与动作:例如“夜间小目标漏检”对应低亮度切片、目标面积分桶、输入增强对照和高分辨率候选;修复可以是补采夜间数据、调整输入策略、增加拒答或限制夜间使用。修复后回到同一错误集验证,不要只看总体分数。
未知类别是视觉系统的常见边界。开放世界中,模型通常会把新物体分到最近的已知类;可以用能量、嵌入距离、阈值或专门的 unknown 数据设计拒答,但没有一种规则能自动解决所有未知。把未知样本纳入评估,记录误接收和正确拒答,才能决定人工队列规模。
任务负责人要能从错误地图作出产品决策:哪些错误必须阻断上线,哪些可通过提示和人工复核缓解,哪些场景明确不支持。技术修复、数据修复、流程修复和范围缩小都算有效成果,不要把“继续训练”当作唯一答案。
11.8 工程实现:让空间证据在服务链路中不丢失
输入阶段保存原图宽高和唯一 ID;预处理阶段保存缩放、裁剪、补边和旋转参数;模型阶段返回内部坐标与类别;后处理阶段映射回原图并做范围验证;展示阶段画出覆盖层并标明状态。任何一步丢掉尺寸或偏移,最终框就可能看起来合理却指向错误位置。
服务端要验证模型返回的所有字段:类别是否在允许集合,分数是否为有限数,坐标是否在原图范围,左边是否小于右边,掩码尺寸是否匹配,状态是否与候选数量一致。验证失败时记录原始响应并返回 model_output_invalid,不要把异常候选发送给用户或下游自动动作。
批量推理的顺序也要可追溯。每张图使用稳定 image_id,结果按 ID 关联而不是按数组位置猜测;超时、重试和部分失败应有独立状态。随机增强和多尺度推理要保存每个视图的参数,并在合并前去重,避免一次图片被当作多个独立样本统计。
可视化覆盖层是很有效的调试工具。显示原图尺寸、坐标轴、类别、分数、阈值和模型版本;对检测框、关键点和掩码使用不同颜色,并在缩略图与原图上都检查。不要把颜色或框的存在当作模型解释,覆盖层只用于核对空间契约。
代码测试应覆盖极端几何:一像素宽框、全图框、边界外框、旋转后的点、空掩码、多个重叠实例和超大分辨率。用固定 JSON 样例测试序列化和反序列化,确保升级依赖后字段名称、数值类型和坐标不会悄悄改变。
最后区分离线指标和在线动作。离线 mAP 达标后,在线仍可能因上传失败、权限、延迟、成本、人工队列或界面误读而失败。上线检查应把模型输出、服务状态和用户动作一起演练,确认没有候选时不会误触发业务流程。
| 任务 | 核心输出 | 常用指标 | 必须补充 |
|---|---|---|---|
| 单标签分类 | 一个类别/拒答 | 每类 P/R/F1、校准 | 未知类别、切片 |
| 多标签分类 | 多个属性分数 | 每类 AP、PR-AUC | 阈值与共存规则 |
| 目标检测 | 类别 + 盒 | AP/mAP、Recall | 小目标、NMS、空图 |
| 实例分割 | 实例掩码 | mask AP、IoU | 边界、重叠、孔洞 |
| 语义分割 | 像素类别 | mIoU、Dice | 边界和稀有类 |
| 关键点 | 坐标/可见性 | PCK、像素误差 | 遮挡、坐标映射 |
| OCR | 文字 + 区域 | 字符/词错误率 | 方向、低清、语言 |
| 字段 | 示例 | 为什么保留 |
|---|---|---|
| sample_id | img-0042 | 回到原图与标注 |
| slice | night / small | 定位分布缺口 |
| prediction | label, score, box | 复核模型输出 |
| ground_truth | label, box | 计算指标与差异 |
| root_cause | crop_offset | 连接修复假设 |
| severity | blocker / review | 决定发布动作 |
| regression | test-small-night-01 | 防止修复回退 |
模型只产生候选;任务契约、坐标验证和评估切片决定候选能否被信任或交给人工。
from math import isfinite
def validate_box(box, width, height):
if len(box) != 4:
return False, "box_length"
left, top, right, bottom = box
if not all(isfinite(float(value)) for value in box):
return False, "box_not_finite"
if not (0 <= left < right <= width and 0 <= top < bottom <= height):
return False, "box_out_of_range"
return True, "ok"
def validate_result(result, width, height, labels):
if result.get("status") not in {"ok", "uncertain", "no_detection"}:
return {"ok": False, "state": "invalid_status"}
errors = []
for item in result.get("detections", []):
if item.get("label") not in labels:
errors.append("unknown_label")
continue
good, reason = validate_box(item.get("box", []), width, height)
if not good:
errors.append(reason)
score = item.get("score")
if score is None or not 0 <= float(score) <= 1:
errors.append("invalid_score")
return {"ok": not errors, "state": "ok" if not errors else "model_output_invalid", "errors": errors}
print(validate_result({"status": "ok", "detections": [
{"label": "beaker", "box": [2, 3, 50, 70], "score": 0.91}
]}, 100, 100, {"beaker", "flask"}))11.5.4 输出协议的字段设计
分类结果至少带 label、score、threshold、model_revision、input_id 和 status;检测结果还要带原图 width/height、box_format、box、区域质量和是否需要复核。字段命名一旦对外发布,就要保持兼容或给出版本,不要在页面脚本里临时猜测数组下标。
空结果与无效输入分开。模型没有找到目标是 no_detection,图片无法解码是 invalid_input,证据不足是 uncertain,权限或高风险请求是 blocked。状态越明确,前端越能给出正确动作,统计也不会把服务故障算成模型漏检。
输出中的分数只表达模型排序或校准后的信号。若阈值由业务风险选择,把阈值版本和验证集写进结果;如果不同类别阈值不同,返回 threshold_by_label,不能让调用方默认 0.5。
11.5.5 检测与分割的边界案例
一个框可能跨越图像边缘、被裁剪或只露出一部分。标注指南要说明是否保留截断对象、框到边界还是只标可见部分;训练和评估必须使用同一规则,否则 IoU 低并不一定是模型错误。
实例重叠时,NMS 可能删除真实相邻目标;分割掩码的孔洞、细线和透明部分需要明确类别。对密集小目标、重叠、边界和低对比度样本单独评估,查看候选数、匹配错误和边界误差。
关键点和 OCR 的坐标常带可见性或方向字段。不可见点不能默认为 (0,0),旋转文本要先标方向;把“没有读到”与“读到空字符串”区分,否则下游会把失败当成正常空值。
11.5.6 阈值、校准与人工队列
阈值选择要看人工处理能力。如果人工每天只能检查一千个候选,误报上升会使队列积压;如果漏检代价更大,则应降低阈值并提高复核比例。用 PR 曲线、每张图候选数、人工分钟/样本和关键切片一起决策。
校准不是把所有分数变成真正概率的魔法。温度缩放、等距回归或分层阈值都要在独立验证集上拟合,并检查设备、光照和类别切片。模型版本或输入预处理变化后重新校准。
人工队列需要优先级、证据和回写字段。把低质量、未知、关键类别低分和工具冲突排在前面;复核结果写回错误地图和再训练清单,但不要未经审核把人工修正直接混入测试集。
11.5.7 指标读法与错误地图
看 mAP 或 mIoU 时先问评估脚本的匹配规则、IoU 阈值、忽略区域和空图处理。不同实现的数字不能直接横比;报告脚本版本和 gold 标注哈希。
把指标下降拆成数量和质量:漏检是没有候选、分数过低还是 NMS 删除;误报是背景、未知类别还是坐标错位;分割边界差是标签分歧还是输出分辨率不足。每一种根因需要不同修复。
维护一个小型回归集,包含每种已知错误和一个修复后的反例。更新模型或后处理时先跑回归,再看总体指标;若修复一个切片伤害另一切片,报告取舍并决定是否限制范围。
| 状态 | 模型/系统含义 | 应展示 | 不要做 |
|---|---|---|---|
| no_detection | 在有效输入上没有候选 | 未发现 + 范围限制 | 写成确定不存在 |
| uncertain | 证据不足或冲突 | 缺口、候选、补图动作 | 自动确认 |
| review_required | 达到人工规则 | 区域、分数、优先级 | 绕过人工 |
| invalid_input | 格式/尺寸/质量不合格 | 修复输入提示 | 重试无限循环 |
| blocked | 权限或高风险边界 | 原因与安全替代 | 给猜测答案 |
| model_output_invalid | schema/坐标异常 | 错误码/追踪 ID | 渲染非法框 |
def policy(label, score, thresholds, quality):
if quality == "low":
return {"status": "uncertain", "reason": "low_quality"}
threshold = thresholds.get(label, 1.0)
if score >= threshold:
return {"status": "review_required", "label": label,
"score": score, "threshold": threshold}
return {"status": "no_detection", "label": label,
"score": score, "threshold": threshold}
print(policy("beaker", 0.76, {"beaker": 0.70}, "good"))
print(policy("beaker", 0.76, {"beaker": 0.70}, "low"))11.5.8 任务协议的发布级验收
验收前让另一个人只看标签指南和输出 Schema,判断一组样例属于哪个任务、坐标如何解释、什么状态需要人工。若同一结果可以被解释成两种不同含义,先修协议,不要直接调模型阈值。
指标报告要保留原始预测和后处理配置。检测的 mAP、IoU、NMS、top-k、忽略区域与空图规则必须可复现;分割保留掩码尺寸和边界规则;OCR 保留字符切分和方向;多标签保留每类阈值。
评估集按目标大小、遮挡、光照、设备、背景、无目标和未知类别切片。错误地图把漏检、误报、坐标偏移、标签分歧和工具失败分开,给每种根因配一个回归样例和修复动作。
在线服务返回结果时,状态、image_id、原图尺寸、坐标、模型 revision、threshold 和 review_required 一起传递。前端覆盖层只渲染通过校验的候选;无效框、NaN 分数或未知标签直接进入错误状态。
人工复核结果不能未经审查混入测试集。将复核标签写回训练候选或困难集,保留原预测、复核理由和版本;下一次评估用锁定的测试集验证修复是否真实改善。
任务标准的核心是“输出可执行、指标可解释、空间可回放、错误可切片、拒答有动作”。达到标准后,模型换成 VLM 或接入生成系统,仍能沿用同一契约。
| 检查项 | 证据 | 不通过动作 |
|---|---|---|
| 任务定义 | 标签指南与非目标 | 修协议 |
| 坐标映射 | 原图覆盖层/回放 | 修变换 |
| 指标复现 | 脚本、版本、gold | 重算 |
| 切片错误 | 样本量、根因、回归 | 补数据/调策略 |
| 状态动作 | 空、未知、低质、阻断 | 转人工/拒答 |
为正常、无目标、低质量、未知、非法坐标和人工复核各写一条 JSON,经过校验器后确认前端只渲染允许状态;记录一条从原图到覆盖层的坐标证据。
11.5.9 最后一轮自检:空间结果要可回放
先确认任务是分类、多标签、检测、分割、关键点还是 OCR,再选择标签、损失、输出和指标;不要用一个 accuracy 代替全部任务。
坐标契约写清原图、缩放图、补边、旋转、像素起点和格式;覆盖层与原图对不上时,先修映射再讨论模型能力。
阈值、NMS、top-k 和忽略区域改变最终结果,原始输出和后处理分开保存;每类、每个目标尺度和空图都要有指标。
人工队列要有优先级和回写规则,低质量、未知、关键漏检和工具冲突不能被压成一个空结果。
任务章节的交付物是输出 Schema、坐标测试、固定评估集、切片错误地图和用户动作说明,所有状态都能追到版本和证据。
- 非法框和 NaN 不会渲染。
- 无目标、不确定和不适用分开。
- 人工修正不污染最终测试集。
- 指标能支持发布或阻断。
11.5.10 复现记录
最终记录标签、坐标、阈值、后处理、切片和人工状态;空间结果必须能够从 JSON 回到原图证据。
用 30 个候选结果模拟不同类别阈值、图像质量、目标大小和工具冲突,定义优先级、状态和复核字段;统计队列规模与关键漏检。
from collections import defaultdict
def summarize(rows):
groups = defaultdict(list)
for row in rows:
groups[row["slice"]].append(row)
report = {}
for name, items in sorted(groups.items()):
tp = sum(item["tp"] for item in items)
fp = sum(item["fp"] for item in items)
fn = sum(item["fn"] for item in items)
precision = tp / (tp + fp) if tp + fp else 0.0
recall = tp / (tp + fn) if tp + fn else 0.0
report[name] = {
"n": len(items),
"precision": round(precision, 4),
"recall": round(recall, 4),
}
return report
rows = [
{"slice": "day", "tp": 8, "fp": 1, "fn": 2},
{"slice": "night_small", "tp": 3, "fp": 2, "fn": 5},
]
print(summarize(rows))分别为单标签、多标签、检测和分割任务写出输出字段、主指标、至少两个切片和一个拒答条件;说明为什么不能用同一个 accuracy 覆盖四种任务。
对一张 1200×800 图片做等比缩放到 640×640 并补边,手算一个原图框映射到模型坐标再映射回来;用代码验证误差小于一个像素。
提交标签协议、输出 JSON Schema、指标脚本、固定评估集、切片错误地图、坐标覆盖层和人工复核规则。
11.5.1 分类与多标签任务
单标签分类在互斥类别中选一个答案;多标签分类允许同一图片同时含多个概念。输出协议要明确返回类别、分数、阈值、模型版本、是否拒答和可见限制。若类别不互斥却强行使用 softmax,系统会把“同时存在”变成不必要的竞争。
类别不均衡时,准确率会被大类掩盖。报告每类 precision、recall、F1、PR 曲线和混淆矩阵;也要检查阈值对漏检与误报的不同代价。业务中的阈值由风险和人工处理能力决定,不是 0.5 的自然规律。
分类分数只能回答模型在当前训练目标下的偏好,不能自动说明原因或定位位置。需要空间证据时,用检测或分割任务,或在输出中明确“这是整图判断,不能给出精确位置”。
11.5.2 检测、关键点与分割
目标检测输出类别和边界框,关键点输出关节或标志点坐标,语义分割给每个像素分配类别,实例分割还区分同类的不同个体。标签成本、误差形态和后处理各不相同:框能粗略定位,掩码适合边缘与面积,但对标注一致性要求更高。
坐标契约必须统一:原图还是缩放图、左上右下还是中心宽高、像素坐标是否从 0 开始、旋转后怎样映射、是否包含边界。把坐标写错一个缩放比例,模型可能正确但产品显示完全错误。
小目标、遮挡、密集实例、细长物体、反光和运动模糊是应单列的错误切片。部署中可采用“检测到但低质量”“候选区域待复核”等状态,而不是把所有结果硬判为存在或不存在。
11.5.3 IoU、mAP 与错误切片
IoU 衡量预测区域与标注区域的重叠:交集面积除以并集面积。检测通常要求类别正确且 IoU 超过阈值才算匹配;mAP 汇总不同阈值与类别下的精确率—召回表现。指标定义、阈值、匹配规则和忽略区域必须随报告一起保存。
高 mAP 不保证关键类别或小目标可用;高 IoU 也不保证边界足以支持实际测量。按类别、尺寸、遮挡、设备、场景、输入质量和时间切片,结合原图与预测覆盖层复核,才能找到模型为何失败。
错误标签至少分为漏检、误检、分类错、定位偏移、重复框、阈值错误、数据/标注错和不适用输入。把每条错误绑定样例 ID、版本、证据图、严重度和下一次实验,错误分析才能进入回归集。
def iou(a, b):
# box: (left, top, right, bottom)
left, top = max(a[0], b[0]), max(a[1], b[1])
right, bottom = min(a[2], b[2]), min(a[3], b[3])
inter = max(0, right - left) * max(0, bottom - top)
area_a = max(0, a[2] - a[0]) * max(0, a[3] - a[1])
area_b = max(0, b[2] - b[0]) * max(0, b[3] - b[1])
union = area_a + area_b - inter
return inter / union if union else 0.0
print(round(iou((10, 10, 50, 50), (30, 30, 70, 70)), 3))为“实验台上的器材检测”定义 JSON 字段、坐标系、阈值状态、无结果、低质量输入和人工复核路径;说明为什么整图分类不能替代它。
任务协议复核标准
任务复核从输出协议开始:分类是否允许多标签,检测框使用哪一种坐标系,分割掩码如何处理空目标,OCR 如何表示不确定字符,低质量图片是否能安全停止。每个状态都要有示例 JSON、校验规则和下游动作,不能把空数组、零分和“未观察到”混成一个含义。
评估时把阈值、后处理、坐标映射和覆盖层一起版本化。人工查看错误样例时,既检查预测类别,也检查区域是否落在原图目标上;一个看似正确的标签若不能被定位或追溯,仍不是可交付结果。
06 · VISION LANGUAGE MODELS
视觉语言模型:让图像进入对话
视觉语言模型(VLM)用图像编码器把视觉输入转换成向量或视觉 Token,再通过连接器接入语言模型。它能描述、问答和多步交流,但流畅文字不等于准确观察,更不等于可执行的事实判断。
11.6 视觉语言模型的组成:图像证据如何接入语言
视觉语言模型(VLM)通常由视觉编码器、连接器和语言模型组成。编码器把图片变成一串视觉特征,连接器把视觉特征映射到语言模型能处理的隐藏空间,语言模型再根据视觉 Token 与文字 Token 生成回答。不同模型可能使用冻结、部分微调或端到端训练,不能只看聊天界面判断内部结构。
图像进入模型前会被缩放、裁剪、切 Patch 或压缩成有限数量的 Token。Token 预算越小,细字、小目标、长图和精确计数越容易丢失;增加分辨率又会提高延迟和成本。接口应记录原图尺寸、有效输入尺寸、图片顺序、Token 数和模型版本,回答才能回溯到模型实际接收的内容。
连接器是视觉和语言之间的瓶颈。线性投影、Q-Former、交叉注意力或查询 Token 会以不同方式压缩视觉信息;如果连接器没有保留空间对应关系,模型可以描述大致内容,却难以给出精确区域。需要框、掩码或像素证据时,优先使用检测、分割或 OCR 工具,再让 VLM 做受约束的解释。
多图输入要定义图片 ID、顺序和权限。用户上传的原图、系统生成的缩略图、工具裁剪图和外部 URL 不能混成“第几张图”;提示中要明确每张图的来源和问题范围。服务端应校验大小、页数、格式、恶意内容和访问权,不能让模型直接把图片中的文字当成系统指令。
VLM 输出本质上是候选解释。它可能引用语言先验补全不可见细节,也可能把相邻图片或工具结果错配。可靠接口需要结构化字段、引用的图片/区域 ID、不确定性、工具来源和限制;自然语言只是给用户看的渲染,不应是唯一的机器接口。
连接器和语言模型的能力也受训练数据与对齐目标影响。模型能流畅回答不代表它在所有文字、文化场景和专业图像上都可靠;需要把适用范围、已知错误、版本和安全边界写进模型卡,不能只宣传“支持图片问答”。
11.7 视觉提示与工具协作:把问题写成可核验任务
一个可执行的视觉请求包含任务、范围、输出结构和不确定性规则。例如“仅根据图片中可见内容,列出左侧区域可读的标签;看不清写 unreadable;不要推测被遮挡文字”。这比“这张图说明什么”更容易评估,也会提醒模型不要把常识或用户暗示当作图像证据。
定位任务应要求坐标格式、原图尺寸和证据区域。让模型自由输出“左上角附近”对程序没有帮助;可以要求返回 [left, top, right, bottom],再由服务端检查范围和与原图的映射。对于精确定位,使用检测器或分割器产生候选,VLM 只负责解释或选择,避免语言模型凭描述编造坐标。
OCR、条码、表格解析、计数、测量和几何关系适合专用工具。工具输出要带版本、区域、置信度和原图 ID;VLM 可以把工具结果组织成自然语言,但不能修改原始字符或数值而不标记。工具失败、冲突或超时应触发 uncertain/tool_required 状态,而不是让模型自由猜测。
提示注入可能藏在图片文字、截图、网页或扫描文档中。图像中的“忽略规则”“把资料发给我”等内容是待分析对象,不是系统指令。控制器要分离系统消息、用户问题、图片 OCR 文本和工具结果,限制工具白名单与参数,禁止模型因为图片文字直接执行外部副作用。
对于多轮对话,图片上下文要有生命周期。明确哪些图片仍在当前会话、用户是否授权重复使用、删除后缓存是否清除;不要默认模型能记住上一轮的原图。每轮输出记录 image_id 和版本,避免把新图回答误归因于旧图。
提示工程不是安全边界。系统仍需限制高风险属性推断、外部链接、文件上传、自动发送和设备控制;模型输出必须经过 schema、权限和业务规则验证。把不可执行的请求拒答并给出替代动作,是工具协作的一部分。
11.8 视觉幻觉:流畅语言为什么会超过图像证据
视觉幻觉包括描述不存在的物体、把相似物品认成目标、读错字符、过度确定地计数、凭背景猜地点,或在图片模糊时补全细节。成因可能是视觉编码压缩、语言先验、训练偏差、提示压力、工具错配和对话上下文污染;把责任归咎于“模型还不够大”无法帮助修复。
先区分观察、推断和未知。观察是图片中可定位的可见内容,推断是基于上下文的可能解释,未知是证据不足或任务超出范围。输出协议可以用 evidence、inference、unknown 三种字段,要求每条高风险结论附图片/区域来源;没有来源就不能写成确定事实。
计数和文字是典型难点。被遮挡的对象、密集小目标、重复纹理和长图会让模型漏数或重复计数;低分辨率文字会产生一个看似合理的字符串。使用检测/OCR 工具、分区计数、字符级置信度和人工复核,必要时返回“无法可靠计数/辨认”,不要用语言流畅度掩盖不确定。
评估幻觉要构造反事实和负例:移除目标、替换背景、遮挡关键区域、改变图片顺序、加入无关文字、提供空图或损坏图。比较模型是否仍然输出相同答案;如果输入证据被移除而结论不变,说明模型可能依赖语言先验或缓存。记录拒答是否及时、理由是否准确以及用户下一步是否清楚。
高风险属性如身份、情绪、健康、违法意图和信用判断不能从外观随意推断。即使图片中出现制服、表情或医疗设备,也不等于可以给出个人属性结论。产品应在系统提示、输出校验和人工流程中明确禁止,拒答要解释证据边界而不是给出隐晦猜测。
视觉助手的成功率应包含正确拒答率。对不可读、越权、无权限、工具冲突和不适用输入,安全地停下并提供补拍、选择区域、调用 OCR 或转人工的动作。拒答不是模型失败,而是系统识别证据不足的能力;要像回答一样纳入指标和回归集。
11.9 VLM 工程验收:从自由文本到结构化、可审计响应
建议把 VLM 结果分成原始响应、解析结果、校验结果和用户渲染四层。原始响应用于调试但受权限保护;解析层把模型输出转成 JSON;校验层检查字段、坐标、引用和状态;渲染层根据状态展示答案、证据和下一步。任何一层失败都应有明确状态,不能继续沿用上一次成功结果。
结构化协议应限制枚举和值域。例如 status 只能是 answer、uncertain、tool_required、blocked;每个 claim 必须有 source_image_id 或 evidence_region;坐标必须在图像范围;分数是 0 到 1 的有限数;tool_calls 只能调用白名单工具。Schema 验证不证明内容正确,但能阻止格式错误和越权字段进入业务。
工具调用要记录请求、参数、版本、耗时和返回摘要。执行前检查用户权限、图片权限和成本预算;执行后检查工具结果是否对应同一 image_id、区域和模型版本。VLM 不能自行修改工具证据,若需要解释或纠错,应保留原始值并标注推断。
线上日志尽量保存最小必要信息。可以保存图片哈希、区域坐标、输入尺寸、状态、模型版本、工具调用和人工纠错,而不是无限期保存全部原图与完整对话。删除请求应传播到缓存、缩略图、向量、日志引用和备份计划;隐私治理是 VLM 交付的一部分。
回归集要覆盖成功与失败:清晰图、低清图、长图、密集目标、空图、无权限图、图片内注入、工具超时、未知类别、敏感请求和多图顺序。每次模型、连接器、提示模板、图像预处理或工具版本变化,都重跑回归集并比较答案、证据、拒答和资源。
学习者完成本节后,应能画出视觉编码器—连接器—语言模型—工具—校验器的边界;解释为何 VLM 不能替代精确 OCR/检测;写一个含状态、证据、区域和限制的 JSON 协议;并设计一次能发现幻觉而不是只展示成功回答的评估。
| 组件 | 输入/输出 | 适合负责 | 不应独自负责 |
|---|---|---|---|
| 图像编码器 | 图片 → 视觉 Token | 通用视觉表示 | 精确事实与权限 |
| 连接器 | 视觉 Token → 语言空间 | 跨模态对齐 | 恢复已丢失像素 |
| 语言模型 | Token → 文本/结构 | 解释、组织、澄清 | 凭空补全证据 |
| OCR/检测工具 | 区域 → 字符/框 | 精确读取与定位 | 决定高风险结论 |
| 控制器/校验器 | 候选 → 合法状态 | 权限、schema、成本 | 替模型判断语义 |
| 人工复核 | 证据 + 候选 → 决策 | 高风险与争议 | 替代所有自动化 |
| 状态 | 触发条件 | 必须返回 | 下一步 |
|---|---|---|---|
| answer | 证据足够且格式通过 | 答案、区域/来源、限制 | 展示或进入低风险流程 |
| uncertain | 模糊、遮挡、冲突 | 缺口、候选、原因 | 补图/选区/人工 |
| tool_required | 需 OCR/检测/测量 | 工具名、权限、参数 | 授权调用并回填证据 |
| blocked | 越权、敏感属性、无权限 | 边界说明、无敏感推断 | 拒答/转人工 |
| invalid_output | schema/坐标/引用错误 | 错误码、原始响应 ID | 修复或重试,禁止渲染 |
语言层可以组织答案,但证据、权限与副作用由工具和控制器负责;不确定时闭环应停在补图或人工节点。
from math import isfinite
ALLOWED_STATUS = {"answer", "uncertain", "tool_required", "blocked"}
ALLOWED_TOOLS = {"ocr", "detector", "segmenter"}
def validate_region(region, width, height):
if not isinstance(region, list) or len(region) != 4:
return False
left, top, right, bottom = region
return (
all(isfinite(float(v)) for v in region)
and 0 <= left < right <= width
and 0 <= top < bottom <= height
)
def guard(response, image_id, width, height):
if response.get("status") not in ALLOWED_STATUS:
return {"status": "invalid_output", "reason": "status"}
claims = response.get("claims", [])
for claim in claims:
if not claim.get("text"):
return {"status": "invalid_output", "reason": "empty_claim"}
if claim.get("image_id") != image_id:
return {"status": "invalid_output", "reason": "image_mismatch"}
region = claim.get("region")
if region is not None and not validate_region(region, width, height):
return {"status": "invalid_output", "reason": "bad_region"}
for call in response.get("tool_calls", []):
if call.get("name") not in ALLOWED_TOOLS:
return {"status": "blocked", "reason": "tool_not_allowed"}
return response
sample = {
"status": "uncertain",
"claims": [{"text": "标签部分不可读", "image_id": "img-1",
"region": [10, 20, 180, 90]}],
}
print(guard(sample, "img-1", 200, 120))11.6.4 图像 Token 与语言 Token 的接口
视觉编码器产生的 Token 数量和维度必须与连接器契约一致。若编码器换成不同 Patch 或分辨率,连接器可能需要重新训练;仅修改配置让形状匹配,不代表语义对齐。记录视觉 Token 数、隐藏维度、特殊 Token 和连接器版本。
图像缩放会改变文字和小目标证据,语言模型只能使用它收到的 Token。对长图、表格和密集对象设置区域选择或 OCR 路径,并在回答中引用具体区域;不能把“模型没提到”解释成“图中不存在”。
多图输入用 image_id 和顺序标识,工具裁剪图保留 parent_id 与坐标。权限过滤在编码前和检索前都要做,防止模型通过跨图上下文看到无权内容。
11.6.5 提示模板与结构化回答
提示模板写清任务、范围、输出字段、证据和不确定状态。将用户问题、系统规则、图片中的文字和工具结果分成不同消息/字段,避免一段 OCR 文本覆盖系统要求。模板需要版本化,回归集覆盖每次改动。
结构化回答可以包含 claims、evidence、confidence、status、tool_calls 和 limitations。每条 claim 绑定 image_id 和区域或工具结果;没有证据的自然语言只能作为候选,不能进入自动动作。
多轮对话中,明确图片是否仍可用、是否允许重新处理和何时删除。不要假设语言模型记得旧图;每次调用传入必要的 ID、权限和摘要,并在日志中区分新旧输入。
11.6.6 工具边界与提示注入
图片内文字是待分析内容,不是系统指令。OCR 结果也不应直接变成工具参数;控制器先做清洗、权限与 schema 验证,再决定是否调用。高风险工具默认关闭,允许列表和预算由服务端维护。
工具输出和模型解释分开保存。OCR 字符、检测框和测量值保留原始版本;VLM 可以生成摘要,但不能修改原始值而不记录修订。冲突时返回 tool_conflict 或 uncertain,转人工或要求用户选区。
外部 URL、压缩包、超大 PDF 和恶意图像都可能成为资源攻击。限制文件类型、页数、像素总量、下载域名和超时;失败状态向用户说明如何重新上传,不要无限重试。
11.6.7 幻觉与高风险属性
评估视觉幻觉要用反事实样本:删掉目标、替换背景、交换图片顺序、遮挡文字、加入无关提示和空图。比较声明、区域、工具调用和状态;证据消失后仍保持同一结论是重要线索。
身份、情绪、健康、违法意图等高风险属性不能从外观随意推断。系统提示、规则和人工流程同时禁止;拒答要说明图像证据不足或任务超出范围,并提供低风险替代。
正确拒答率、证据引用率和用户可行动性与答案准确率同样重要。记录人工纠错、补图成功率和错误严重度,决定是改模型、加工具、改提示还是缩小服务边界。
| 字段 | 示例 | 校验 |
|---|---|---|
| image_id | img-042 | 权限与存在性 |
| scope | 仅读取左上标签 | 范围非空、可解释 |
| output_schema | claims + evidence + status | 枚举/必填字段 |
| evidence_region | [120,80,420,190] | 坐标在原图内 |
| tool_policy | 允许 OCR,不允许外发 | 服务端白名单 |
| uncertainty | 看不清返回 uncertain | 禁止强行猜测 |
| retention | 处理后 24 小时删除 | 缓存/日志同步 |
ALLOWED = {"answer", "uncertain", "tool_required", "blocked"}
def validate_claims(payload, image_id, width, height):
status = payload.get("status")
if status not in ALLOWED:
return False, "bad_status"
for claim in payload.get("claims", []):
if claim.get("image_id") != image_id:
return False, "wrong_image"
region = claim.get("region")
if region is not None:
left, top, right, bottom = region
if not (0 <= left < right <= width and 0 <= top < bottom <= height):
return False, "bad_region"
if status == "answer" and not claim.get("evidence"):
return False, "missing_evidence"
return True, "ok"
print(validate_claims({
"status": "answer",
"claims": [{"image_id": "img-1", "region": [1, 2, 30, 40],
"evidence": "visible label"}],
}, "img-1", 40, 50))11.6.8 VLM 上线前的证据验收
验证 VLM 时先冻结图像编码、连接器、语言模型、提示模板、工具和状态 Schema 的版本。视觉 Token 数、图片顺序、裁剪区域和权限必须出现在请求或 manifest 中;换预处理或连接器后,不能直接沿用旧阈值和幻觉报告。
回答评估区分“内容正确”和“证据充分”。一个句子即使碰巧正确,没有 image_id、区域或工具引用,也不应进入自动业务流程。对计数、OCR、测量和表格,优先要求工具证据;模型只负责解释、整理和指出不确定。
图片内文字、OCR 结果和用户提示都可能包含注入。系统消息、用户问题、图片文本、工具结果分栏传递,控制器校验工具白名单、参数、权限和预算;VLM 不得因为图片中的指令直接上传、发送或修改外部数据。
幻觉回归集覆盖删除目标、替换背景、遮挡文字、交换多图顺序、空图、低清图、未知类别和工具冲突。记录声明、区域、状态、拒答理由和人工纠错;正确拒答率与回答准确率一起进入发布门槛。
高风险属性推断在提示、规则、模型输出和人工队列四层阻断。拒答解释图像证据和任务边界,给出补拍、选区、OCR 或人工动作,不用含糊的猜测替代答案。
最终检查 JSON 可再次读取,schema、坐标、来源和状态一致,日志使用最小必要字段,删除能传播到缓存与工具结果。能做到这些,VLM 才是可审查的视觉接口,而不是一段流畅的描述器。
| 样例 | 预期状态 | 重点证据 |
|---|---|---|
| 清晰单图 | answer | 声明与区域一致 |
| 低清/遮挡 | uncertain | 缺口与补图动作 |
| 精确文字/计数 | tool_required | OCR/检测版本 |
| 图片内指令 | blocked | 不执行副作用 |
| 多图错序 | invalid/uncertain | image_id 与顺序 |
| 敏感属性 | blocked | 边界说明与转人工 |
选 10 个视觉问题,给每条回答标注“可见事实/推断/未知”、区域或工具来源、状态和用户下一步;找出一条流畅但没有证据的回答并改写。
11.6.9 最后一轮自检:语言不能替代证据
视觉编码器、连接器、语言模型和工具分别承担不同职责;语言模型可以组织候选,却不能恢复已经被压缩或裁剪掉的像素。
每条关键声明带 image_id、区域或工具来源;看不清、冲突、无权限和高风险请求进入 uncertain、tool_required 或 blocked。
图片中的文字是待分析内容,不是系统指令;控制器负责权限、白名单、参数、成本和副作用,不能只依赖 Prompt。
评估同时看答案、证据、区域、拒答、幻觉和人工纠错;反事实样例比单张成功截图更能发现语言先验。
VLM 章节的交付物是结构化响应协议、校验器、工具边界、幻觉回归和最小日志字段,能安全地接入后续多模态系统。
- Token 和图片顺序已记录。
- OCR/检测原始结果不可被覆盖。
- 敏感属性推断有硬阻断。
- 删除和多轮图片生命周期明确。
构造 VLM、OCR 和检测器对同一图像给出不同结果的样例,定义状态、证据优先级、人工动作和日志字段;再模拟图片内注入文字。
def compare_pair(original, counterfactual, runner):
base = runner(original)
changed = runner(counterfactual)
return {
"base": base,
"counterfactual": changed,
"same_claim": base.get("claims") == changed.get("claims"),
"same_status": base.get("status") == changed.get("status"),
}
def refusal_rate(rows):
if not rows:
return 0.0
refused = sum(row["status"] in {"uncertain", "blocked", "tool_required"} for row in rows)
return refused / len(rows)
print(refusal_rate([
{"status": "answer"},
{"status": "uncertain"},
{"status": "tool_required"},
]))把“这张图说明什么?”改写成包含目标、区域、字段、证据、不可见时状态和工具边界的请求;再给出一个用户可执行的补图动作。
准备原图、遮挡目标图、替换背景图、加入无关文字图和空图,比较声明、区域引用、拒答率和工具调用;写出一个你认为最能区分语言先验的样例。
提交组件边界图、JSON Schema/校验器、工具白名单、证据引用、敏感请求拒答集和幻觉回归报告。
11.6.1 图像编码器与连接器
典型 VLM 有三部分:图像编码器提取视觉特征,投影层或查询模块把特征对齐到语言模型隐藏空间,语言模型根据图像 Token 和文本 Token 生成回答。图像被缩放、切分或压缩成有限 Token,因此细字、小目标、精确计数和长图往往是瓶颈。
多图输入不等于模型会自动比对。系统应明确图片顺序、每张图的来源与权限、是否允许跨图推断;当需要精确测量、OCR、条码或几何关系时,优先调用专用检测/OCR/测量工具,并把工具结果与原图区域一起返回。
接口协议应区分用户提供的图片、系统生成的缩略图、工具裁剪图和外部 URL;前端提示文件状态,服务端校验大小、页数、格式、恶意内容和权限。不要让模型直接读取未经验证的 URL 或把图片中的指令当作系统规则。
11.6.2 提示、定位与工具边界
好的视觉问题给出任务、范围、输出格式和不确定性要求,例如“仅根据图中可见内容,列出左侧三个标签;看不清则写无法辨认”。它不会创造图中没有的证据,也不能替代更高分辨率、补拍或专业检查。
需要定位时,要求模型返回候选区域并由程序验证坐标格式、范围和可见性;更可靠的做法是先由检测器给区域,再让 VLM 解释区域内容。模型输出是候选,控制器负责引用图片 ID、工具调用、阈值、权限和副作用。
不要把 VLM 用作身份、情绪、疾病、违法行为或其他高风险个人属性的裁判。即使模型给出貌似合理的描述,也可能基于刻板印象或不可见信息猜测。输出协议要禁止不当推断,并在请求超出范围时说明不能从图像可靠判断。
11.6.3 视觉幻觉与拒答
视觉幻觉包括描述不存在的物体、读错文字、过度确定地计数、把背景关联当作事实,或在图像模糊时编造细节。它可能由视觉编码丢失、训练偏好、提示压力、语言先验或工具结果错配造成,不应只归咎于“模型不够大”。
为高风险字段设置验证路径:OCR 文本要有字符级置信度或人工确认,计数要返回可见区域与遮挡说明,关键数值要由专用工具或规则计算,事实性描述要区分“可见”“推测”“无法判断”。模型不应自行提升不确定性为结论。
拒答是成功状态。图片过暗、区域被遮挡、任务定义不足、模型/工具冲突、权限不足或超出适用范围时,返回结构化原因和下一步:补拍、上传原图、选择区域、使用专用工具或转人工。
| 状态 | 含义 | 用户可见动作 |
|---|---|---|
| answer | 可见证据足够,已附区域/来源 | 展示答案与限制 |
| uncertain | 候选存在,但分辨率或遮挡不足 | 请求补图或复核 |
| tool_required | 需 OCR、检测或测量工具 | 经授权调用工具 |
| blocked | 权限、隐私或高风险推断 | 说明边界并转人工 |
把“这张图说明什么?”改写成一个可验证请求,写明可见范围、输出字段、看不清时的状态和是否需要 OCR/检测工具。
视觉语言复核标准
视觉语言模型的复核重点是证据链:回答中的每个关键断言都应能回到图像区域、OCR/检测工具或用户提供的上下文。对空图、遮挡、低分辨率和图片内指令分别测试,确认模型会说明不可见,而不是用语言先验补全细节。
自由文本只作为草稿,最终结果经过 JSON Schema、权限检查和工具白名单。记录图片 ID、裁剪区域、提示、模型版本、工具调用与状态,才能在幻觉回归时复现问题,也才能向用户解释为什么转人工或要求补图。
07 · VISUAL GENERATION
视觉生成:从噪声到受控输出
视觉生成模型学习训练数据中的图像分布,并按文字、图像、结构或编辑指令采样新结果。它擅长创作与原型,却不是事实来源、身份验证器或精确测量工具。
11.7 扩散模型:从逐步加噪到逐步去噪
扩散模型可以用一个直觉理解:训练时把真实图像逐步加入噪声,模型学习在给定噪声等级和条件下预测如何恢复;生成时从随机噪声开始,反复执行去噪步骤,最终得到一张样本。这个过程不是一次前向分类,而是一条随机采样轨迹,采样步数、调度器、随机种子和模型权重都会影响结果。
前向加噪通常用一组噪声日程决定每个时间步保留多少原始信号。噪声日程太激进会让早期步骤失去结构,太保守又会增加采样负担;不同实现对预测噪声、原图或速度参数的定义也不一样。阅读代码时先确认变量代表什么,不要把“t”当作真实时间或把每个 scheduler 的参数直接互换。
反向去噪由 U-Net、Transformer 或潜空间网络完成。网络输入包括带噪图、时间嵌入和可选条件,输出经过采样器更新到下一个时间步。文本到图像系统往往在潜空间工作,先由编码器压缩图像,再在低维空间去噪,最后由解码器还原;压缩会提高效率,也可能丢失细小文字和精确边缘。
采样的随机性既是创作空间,也是复现难题。固定 seed、模型版本、VAE、scheduler、步数、分辨率、提示和负面条件,才能在相同软件环境下尽量重现;GPU 算子、版本和精度仍可能带来微小差异。高价值任务保存 manifest 和输入参考,不要只保存最终 PNG。
扩散模型学习的是训练数据的分布,不是现实世界的物理模拟器。它可能生成看似合理但不存在的文字、手指、商标或结构;生成图不能作为新闻、身份证明、测量或科学证据。把用途写成草图、视觉探索或候选构图,使用真实性要求时回到原始来源和独立验证。
训练和使用都要考虑资源。采样步数增加可能提高细节但拉长延迟,分辨率增加会显著提高显存,批量生成需要限制并发和成本。先测小分辨率与少步数基线,再按任务需要增加控制;记录质量收益是否超过时间和成本,而不是只看最漂亮的一张图。
11.8 条件控制:提示、参考图、掩码和结构约束
文字提示提供语义方向,却不是严格的程序规格。主体数量、左右位置、文字拼写、比例和禁止项都可能被部分满足;长提示中的条件还会相互冲突。把需求拆成主体、场景、构图、材质、风格、禁止项、尺寸和可接受变化,并在生成后逐条检查,而不是不断堆形容词。
图生图通过参考图和噪声强度控制结构与变化范围。噪声强度低,结果更接近输入但创意空间小;噪声强度高,变化更多却可能破坏姿态、文字和身份。局部重绘用掩码限定区域,但边界融合、未遮罩区域漂移和颜色延续仍需人工审阅。每次编辑保存原图、掩码和参数。
姿态、边缘、深度和分割等结构条件可以把硬约束变成可输入的控制信号。控制强度过低时布局不稳,过高时图像僵硬或出现伪影;结构检测错误也会被模型放大。先验证控制图的质量,再讨论生成质量;控制图来自敏感图片时还要检查是否泄露原图信息。
一致性是跨图生成的难点。角色、商品和场景在不同种子、视角、光照和裁剪下可能漂移;参考图适配器、LoRA 或固定 latent 可以改善,但不保证每个细节一致。需要连续帧、商品目录或品牌资产时,用后处理、检测器和人工选片组合验证,不要承诺“同一个人/物体完全不变”。
多候选策略比追求一次命中更可靠。固定一组种子生成若干候选,先用规则和检测器过滤明显不合格的数量、文字、位置与安全问题,再由人挑选。候选数量和采样成本要受预算限制;失败候选可以保留哈希和原因用于改进,但敏感图像不应无限期保存。
生成后的编辑不能改变事实语义。去除背景、修改脸部、替换服装或补全缺失区域都应明确标示为编辑;如果输入是新闻、证据、医疗图像或法律材料,应禁止用生成模型“修复”成看似真实的结果。合成内容和原始记录要在存储、界面和引用中分开。
11.9 生成质量:从好看走向可检查
质量检查应按用途定义。艺术草图可由构图、色彩和风格一致性主导;课程插图需要文字可读、数量正确、结构清晰;产品素材需要品牌、尺寸、商标和版权审核;训练数据合成还要检查标签、分布和重复。没有用途就没有客观的“最好图片”,只能比较个人偏好。
自动指标如 CLIP 相似度、图像质量分数或重复率可以做批量筛选,不能替代人工和任务专用验证。CLIP 高分可能来自背景或提示词捷径,质量分数可能惩罚本来就故意模糊的艺术风格。报告自动指标的版本、阈值和失败案例,不把一个分数写成事实。
文字、数量、几何和品牌元素需要专用检查。OCR 检查字符,检测器检查对象数量和位置,边缘或模板匹配检查布局,安全分类器检查敏感内容;每个工具都有误差,最终发布仍需人工决定。工具结果要保存区域和版本,避免只留下“通过/失败”两个无证据状态。
去重和多样性同样重要。随机种子不同不代表内容独立,模型可能生成近重复构图、同一背景和相同手部伪影。用感知哈希和视觉向量聚类检查候选集合,设置最大相似度或每个构图的数量上限;训练合成数据还要与真实数据比较分布,防止模型循环产生自身风格。
发布前做安全与来源审查:输入素材是否有同意和许可,输出是否包含可识别真人、商标或受限制地点,是否有误导性合成风险,是否应附 AI 生成标示。模型许可证、LoRA、字体、参考图和后处理库的条款可能不同,数据卡要记录每一层责任。
生成记录应让同伴可以重放或解释差异。manifest 至少包含模型与权重版本、VAE、scheduler、seed、提示、负面提示、参考图哈希、掩码哈希、尺寸、步数、控制强度、生成时间、审阅人和公开状态。只存一张最终图片,无法回答“为什么这次不同”和“能不能公开”。
11.10 许可、标记与运营边界:生成模型也需要数据治理
输入和输出的权利不是同一件事。用户上传的照片、第三方参考、字体、商标、训练权重、LoRA 和后处理素材各自可能有授权条件;“模型可以生成”不等于“结果可以任意商用”。项目开始就列出输入来源、人物同意、用途、地区、署名和删除方式,不确定时限制公开范围并寻求专业意见。
合成标记应贯穿文件、界面和导出流程。内部 manifest 保存完整参数,对外图片可以加可见说明或元数据标记;裁剪、再编码和平台上传可能移除元数据,所以不能把隐藏标记当作唯一保障。新闻、广告、教育和公共沟通要根据场景选择更清楚的说明。
生成接口要防止资源滥用。限制分辨率、步数、并发、单用户预算和重试;对超大批量、敏感提示和外部 URL 做权限检查。失败时返回可理解状态,不要因为服务超时自动无限重试,造成成本失控或重复生成大量文件。
敏感内容治理不仅是关键词拦截。提示、参考图、局部掩码和输出都可能绕过简单的文本过滤;需要图像安全分类、人物同意、未成年人保护、人工审核和审计日志。拒绝时说明边界和可行替代,例如使用虚构角色、抽象示意或不包含个人特征的构图。
生成内容与检索内容要分开。生成图可以作为草图或视觉候选,不能冒充“从资料库找到的原图”,也不能作为事实引用。需要证明来源时展示原始链接、文件哈希和拍摄/发布信息;生成结果只保留它自己的 manifest 和审阅状态。
运营中监控提示类别、失败率、生成耗时、成本、人工拒绝、用户投诉和近重复率。模型或策略更新后回放固定提示集与敏感集,确认不会出现安全回退。下架、删除和回滚流程要能定位到模型、提示和输出文件,避免只删除页面而留下缓存与导出副本。
11.11 读懂扩散模型实验:把视觉质量拆成变量
实验矩阵应把随机变量和控制变量分开。固定模型、输入和提示,只改变 seed 观察随机性;固定 seed,只改变 scheduler 或步数观察采样;固定采样,只改变参考图或控制强度观察条件;固定全部生成参数,再比较后处理。一次改变多个因素,无法解释质量变化。
采样步数与质量通常不是线性关系。少数步数可能产生粗糙边缘,增加到某个区间后收益变小,再增加只增加成本;不同 scheduler 的最佳步数不同。用代表性提示和失败提示测 p50/p95 时间、显存、文字可读率、结构满足率和人工评分,选择预算内的点。
分辨率和潜空间尺寸要一起看。直接放大可能让细节变糊,分阶段放大或区域重绘会增加流程复杂度;高分辨率生成的显存峰值可能超过服务上限。设置超时、降级和人工选择,不能让单个请求拖垮所有用户。
生成数据用于训练时,还要防止标签污染和模式坍缩。合成图片的类别、框、掩码和来源必须有记录;混入真实数据前比较颜色、构图、重复率和难例覆盖;测试集保持真实且独立。模型生成的错误伪影可能被下一个模型学会,形成闭环污染。
评审者应看到必要上下文但避免被模型名称影响。随机化候选顺序,提供明确评分量表:主体是否符合、布局是否满足、文字是否可读、安全与来源是否合规;保存分歧和修订理由。自动指标与人工评分不一致时,分析原因而不是挑一个方便的指标。
完成本节后,你应能解释噪声和去噪的基本链路,设计可复现 manifest,使用参考图/掩码/结构条件控制变化,安排 OCR/检测/人工质量检查,并写出生成内容的许可、标示、成本和回滚边界。
| 旋钮 | 控制什么 | 常见收益 | 代价/风险 |
|---|---|---|---|
| seed | 随机轨迹 | 复现或批量多样候选 | 不同硬件仍可能微差 |
| steps | 去噪迭代次数 | 细节与结构可能改善 | 延迟/成本增加 |
| scheduler | 时间步更新规则 | 速度或风格差异 | 参数不能直接互换 |
| guidance | 条件跟随强度 | 更贴合提示 | 过高会过饱和/失真 |
| resolution | 空间细节 | 文字和纹理更清楚 | 显存、超时 |
| denoise strength | 参考图保留量 | 控制编辑幅度 | 身份/结构漂移 |
| mask/control | 区域或结构约束 | 布局更可控 | 边界伪影、控制图错误 |
| 检查对象 | 工具/方法 | 通过证据 | 失败动作 |
|---|---|---|---|
| 文字 | OCR + 人工 | 字符可读、内容正确 | 重绘/转人工 |
| 数量 | 检测器/人工计数 | 候选数与需求一致 | 换提示或编辑 |
| 布局 | 模板/坐标检查 | 主体在允许区域 | 结构条件/拒绝 |
| 安全 | 图像分类 + 人工 | 无禁止内容/同意明确 | 阻断与审计 |
| 来源 | manifest/许可 | 输入与模型条款清楚 | 限制公开范围 |
| 重复 | 哈希/向量聚类 | 候选有足够多样性 | 去重或减少批量 |
生成过程的最后一步不是保存 PNG,而是把质量、来源、标记和用途边界一起交付。
from dataclasses import asdict, dataclass
from datetime import datetime, timezone
import json
@dataclass
class GenerationManifest:
model_id: str
model_revision: str
scheduler: str
seed: int
prompt: str
negative_prompt: str
width: int
height: int
steps: int
guidance: float
input_hash: str | None
license_note: str
review_status: str = "pending"
def to_json(self):
payload = asdict(self)
payload["created_at"] = datetime.now(timezone.utc).isoformat()
return json.dumps(payload, ensure_ascii=False, indent=2)
manifest = GenerationManifest(
model_id="vision-generator",
model_revision="2026-08-01",
scheduler="ddim",
seed=17,
prompt="课程封面,抽象的视觉模型流程图",
negative_prompt="真实人物、品牌标志、不可读文字",
width=1024,
height=768,
steps=28,
guidance=6.5,
input_hash=None,
license_note="仅用于课程草图,发布前人工审查",
)
print(manifest.to_json())11.7.4 参数之间的因果顺序
生成实验要先固定输入和模型,再改变 seed、steps、scheduler、guidance、denoise strength 或 resolution。一次改变多个参数只能得到“结果不同”,不能说明哪一个旋钮负责差异。每次运行写入 manifest,并保存失败候选的原因。
随机 seed 控制采样轨迹,不能保证跨硬件逐像素一致;scheduler 和步数共同决定去噪路径,参数不能直接互换。比较时记录软件、精度和设备,允许微小差异但要求语义约束与安全状态一致。
高 guidance 可能让提示更突出,也会造成过饱和、重复纹理或结构失真;低 guidance 可能更自然但不满足条件。用结构满足率、文字可读率和人工评分共同选择,而不是以“更像提示”单一判断。
11.7.5 控制图与编辑边界
参考图、掩码、姿态、边缘和深度控制把构图约束显式化,但控制图本身可能错误或含敏感信息。先验证控制图的坐标、尺寸和许可,再运行生成;编辑后检查未遮罩区域是否漂移。
图生图噪声强度越高,变化越大,身份、文字和物体数量越容易改变。将允许变化写成检查项,不能用“看起来差不多”替代;跨图一致性需要检测器、模板或人工比较。
多候选生成要设置最大数量、预算和保留期。失败候选可保存哈希和状态用于改进,但含人物或私密内容的原图、掩码和输出应按最小必要原则处理。
11.7.6 质量审查的证据链
自动质量分数适合批量筛选,不等于人类审美或任务正确。文字用 OCR,数量用检测器,布局用模板/坐标,安全用分类器与人工;每项记录工具版本和阈值。
近重复检查使用感知哈希或向量聚类,防止候选看似多样、实际只是同一构图。生成训练数据时比较真实/合成分布和标签质量,避免模型把自己的伪影学回去。
评审者按固定量表盲审候选,分别打主体、布局、文字、来源、安全和可用性分数,保存分歧与修订理由。自动指标与人工不一致时分析原因,不挑高分指标。
11.7.7 许可和对外标示
输入照片、第三方参考、字体、商标、模型权重和 LoRA 的许可互相独立。manifest 写明来源、同意、用途、地区、署名和删除流程;不确定时限制公开和商业用途。
对外文件和界面标示 AI 生成/编辑,内部保留完整参数和审阅状态。元数据可能被平台移除,因此必要时使用可见说明或随文件附带来源记录。
生成图不能作为事实或检索引用。需要真实性时回到原始来源、拍摄信息和独立验证;生成结果只承载创作候选和自身 manifest。
| 类别 | 字段 | 示例 |
|---|---|---|
| 模型 | model/revision/VAE | generator-v2 / r17 |
| 随机 | seed/scheduler/steps | 17 / ddim / 28 |
| 条件 | prompt/negative/control | 模板版本 + 掩码哈希 |
| 资源 | resolution/p95/VRAM/cost | 1024×768 / 4.2s / 8GB |
| 质量 | OCR/layout/count/safety | 通过/需复核 |
| 治理 | license/label/reviewer | 草图许可 / 已标示 |
def constraint_report(candidate, required):
checks = {}
for name, expected in required.items():
checks[name] = candidate.get(name) == expected
passed = [name for name, ok in checks.items() if ok]
failed = [name for name, ok in checks.items() if not ok]
return {"passed": passed, "failed": failed,
"status": "pass" if not failed else "review"}
print(constraint_report(
{"subject_count": 3, "text_readable": True, "safe": True},
{"subject_count": 3, "text_readable": True, "safe": True},
))11.7.8 生成工作流的发布级验收
先冻结生成 manifest,再评价图片。模型、revision、VAE、scheduler、seed、提示、负面提示、参考图/掩码哈希、尺寸、步数、guidance、控制强度和审阅状态缺一不可;只保存最终文件无法解释差异或完成撤回。
把质量拆成任务约束而非单一美观分:主体是否正确、数量是否满足、布局是否在区域内、文字是否可读、未遮罩区域是否保持、颜色与风格是否符合、是否有安全/版权问题。每项指定 OCR、检测器、模板、向量或人工证据。
随机候选按固定顺序生成和审查,保留成功与失败。候选过多会增加成本与近重复,设置最大数量、超时和预算;低清、文字错、数量错或安全不合格的结果返回 needs_review/blocked,不自动发布。
输入素材、模型权重、字体、商标和后处理库分别记录许可。外部展示附 AI 生成/编辑说明,生成图与检索原图分开存储和引用;删除请求要覆盖缓存、导出文件和审计记录。
生成服务监控请求量、失败率、p95、显存、成本、提示类别、人工拒绝和重复率。模型或策略升级回放固定提示、敏感集、文字集和控制图,确认安全、质量、成本都没有回退。
专业验收的结论可以是“当前范围内可用”“需人工”“不支持”,而不是强行说“生成成功”。把边界写进界面和 README,用户才不会把合成结果误当成真实证据。
| 闸门 | 证据 | 动作 |
|---|---|---|
| 可重放 | 完整 manifest 与输入哈希 | 缺失则不交付 |
| 约束 | OCR/检测/布局检查 | 重绘或人工 |
| 来源 | 权重、字体、参考许可 | 限制公开 |
| 标示 | 文件/界面 AI 编辑说明 | 补标记 |
| 资源 | p95、显存、成本 | 限流/降级 |
| 安全 | 敏感提示与输出回放 | 阻断 |
从三组候选中挑出可交付、需修改、不可发布各一组,附 manifest、OCR/检测/人工证据、许可和对外标示;再模拟删除一组输出。
11.7.9 最后一轮自检:生成结果必须可标示
扩散采样的 seed、scheduler、步数、guidance、参考图和掩码共同决定结果;manifest 缺字段时,图片不能算可复现交付物。
提示词提供方向而非严格规格,数量、文字、布局和身份需要 OCR、检测、模板或人工审查;失败候选应保留原因而不是被删除。
输入素材、权重、字体、商标和后处理各有许可;生成内容与检索原图分开存储、引用和标记。
服务设置分辨率、步数、并发、成本、超时和重试上限,监控失败、重复、人工拒绝和敏感提示;更新后回放固定集。
生成章节的交付物是采样实验矩阵、质量/安全门槛、manifest、对外标示和下架回滚步骤,不能用“画面好看”代替治理。
- 质量约束有工具或人工证据。
- 合成内容不会冒充事实。
- 超预算请求会降级或阻断。
- 删除能覆盖缓存与导出。
选一个自制参考图,固定模型与提示,生成三组候选;记录 manifest、质量检查、许可和对外标示,说明哪个结果不能发布以及原因。
def decide(candidate, required_labels, max_cost):
checks = {
"text_readable": candidate.get("text_readable", False),
"layout_ok": candidate.get("layout_ok", False),
"safe": candidate.get("safe", False),
"licensed": candidate.get("licensed", False),
"cost_ok": candidate.get("estimated_cost", max_cost + 1) <= max_cost,
}
missing = [name for name, ok in checks.items() if not ok]
return {
"status": "approved" if not missing else "needs_review",
"checks": checks,
"missing": missing,
"labels": required_labels,
}
print(decide({
"text_readable": True,
"layout_ok": True,
"safe": True,
"licensed": True,
"estimated_cost": 0.08,
}, ["diagram"], 0.10))固定提示和模型,比较三种步数、两种 scheduler、三个 seed;记录文字可读率、结构满足率、显存、p95 延迟和人工评分。
使用一张自制图和一个局部掩码完成重绘,检查未遮罩区域、文字、数量、边界和来源标记是否改变;保存原图、掩码和 manifest。
提交采样实验矩阵、manifest、质量检查表、输入许可说明、合成标记、成本门槛和下架/回滚步骤。
11.7.1 扩散模型的基本直觉
扩散模型在训练时学习如何从逐步加噪的图像中预测或去除噪声;生成时从随机噪声开始,按条件逐步得到图像。采样步数、随机种子、调度器、条件强度和模型版本都会改变结果,因此生成记录需要保存这些参数。
文字条件提供方向,不是可执行规格。提示词中“蓝色”“左侧”“三个”“无文字”等约束可能被部分满足、误解或互相冲突。对构图、姿态、边缘或布局有硬要求时,用参考图、区域掩码、结构条件或后续验证,而非只堆叠形容词。
随机性是产品属性:它能产生多样候选,也会让同一请求难以重现。高价值工作流应保存 seed、模型、提示、负面条件、输入参考、生成时间和后处理版本;敏感内容还要保存最小必要的审计信息并遵守保留期。
11.7.2 条件、编辑与一致性
图生图、局部重绘、姿态/边缘/深度条件和参考一致性模块能提高控制力,但并不保证身份、文字、数量或空间关系精确。局部编辑可能改变未遮罩区域,跨图角色一致性也可能在服装、手部、饰品和背景细节上漂移。
把创作需求拆成可检查的约束:主体、场景、构图、禁止项、可接受变化和交付尺寸。生成后用人工审阅或专用检测器检查文字、标志、数量、边界、敏感内容和版权风险;检测器同样可能错,所以高风险发布仍需人工决定。
不要用生成图伪造证据、身份、真实事件或专业检查结果。系统应清楚标示它是合成内容;涉及真人、未成年人、医疗、金融、政治或新闻语境时,采用更严格的同意、限制与审核规则。
11.7.3 许可、标记与使用边界
视觉生成涉及训练权重、输入素材、输出图像、字体、商标和第三方参考的不同权利与政策。项目数据卡说明使用的模型许可、输入来源、是否包含人物、输出用途、署名和删除流程;不确定时不要承诺“可任意商用”。
内容来源和合成标记应可追溯:保留面向内部审计的生成 manifest,对外展示适当的“AI 生成/编辑”说明。标记不是万能防伪,但能减少把合成素材误当纪实照片的风险,并支持后续修正或下架。
将生成与检索分开:生成模型可以提供草图和候选,不能作为“查到的图片”或支持事实的引用。需要真实性时,回到原始来源、元数据和独立验证,而不是分析生成图中看似合理的细节。
为一张课程封面草图设计 manifest:模型/版本、提示、seed、输入素材许可、生成用途、审阅状态、修改记录和对外标示。
生成实验复核标准
每次生成实验至少保留模型与版本、提示和负面提示、随机种子、调度器、步数、输入参考、掩码、后处理和生成时间。评估不能只挑最好看的一张,应把结构满足率、文字可读性、未编辑区域保持、失败比例、成本和延迟放在同一张实验表里。
交付前区分草图、编辑结果和事实素材,检查人物同意、字体/商标、数据许可与对外标记。生成图不能替代新闻、医疗、身份或实验事实;出现不确定来源时,回到原始资料和人工审核。
08 · EVALUATION & SAFETY
评估与安全:别把演示当可靠
视觉模型的上线证据需要同时回答:任务指标是否达标、错误集中在哪里、对输入变化是否稳健、隐私和权限是否受控、在延迟与成本预算下能否运行,以及失效时怎样停止和恢复。
11.8 评估先于演示:把视觉系统拆成可回答的问题
评估从任务合同开始,而不是从某个排行榜指标开始。分类要知道哪些错分更危险;检测要知道漏掉小目标和多一个误报的代价;OCR 要知道字符错一个是否会改变意义;VLM 要知道声明是否有图像证据;生成要知道文字、布局、来源和安全是否达标。没有任务合同,平均分只能制造一种虚假的精确感。
固定评估集应包含常规、边界、低质量、长尾、未知、无目标、恶意和不适用输入。开发集可以用来调参,测试集要尽量少被反复查看,发布前最好保留一份锁定集。每次数据、预处理、模型、提示、阈值、后处理或工具变化,都重新运行同一套集并保存差异。
人工复核需要指南、盲审和分歧记录。评审者应看到任务定义和必要证据,尽量不知道候选模型名称;对“看不清”“无法定位”“需要工具”设置明确标签。统计一致率、裁决理由和时间成本,才能知道人工队列是否可承载。对高风险结果,人工复核是链路的一部分,不是展示结束后的装饰。
指标应同时报告总体与切片。分类的每类 precision、recall、F1、校准和拒答;检测的 mAP、每类 AP、IoU、召回和小目标;分割的 mIoU、边界误差和稀有类;OCR 的字符/词错误率;VLM 的证据支持率、区域准确率、幻觉和正确拒答;生成的约束满足率、重复率、人工评分与安全阻断。
指标还要带样本数、版本和不确定性。切片样本太少时,分数波动可能大于模型改进;给出置信区间或 bootstrap 范围,避免把一个小数点后的差异当作真实提升。若测试集被调参使用,应说明它不再是无偏测试,并建立新的保留集。
评估的输出应能支持行动:继续训练、修标签、调整阈值、增加人工、限制场景、降级或阻断。报告不要只写“模型准确率 92%”,而要写在什么数据、什么输入契约、什么风险假设下,92% 对用户意味着什么。
11.9 鲁棒性与分布偏移:现实输入不会保持干净
鲁棒性测试应覆盖真实而非想象的变化:压缩、模糊、低光、过曝、裁剪、旋转、遮挡、背景替换、不同设备、不同文字方向、长宽比和并发压力。每项变换保存参数和原图 ID,比较输出、指标、拒答和资源;一张被破坏的图片只能说明存在一个失败样例,不能说明失败概率。
把分布偏移拆成输入、标签和关系三类。输入偏移是相机、光照或分辨率变了;标签偏移是类别比例或定义变了;关系偏移是同样的外观与业务标签关系变了。不同偏移的修复不同:补采、重标、校准、限制范围或重新训练,不能只用一个阈值解决。
监控中记录低质量比例、未知率、类别分布、置信度、人工纠错、工具失败、p50/p95 延迟和成本变化。避免为了监控而长期保存完整敏感原图,可以使用哈希、统计摘要和受控抽样;抽样需遵守权限和保留期。漂移告警只是触发调查,不是自动证明模型变差。
对抗输入包括畸形文件、超大尺寸、恶意图片文字、提示注入、近邻探测和让模型反复重试的资源攻击。控制器负责文件解码限制、像素/Token 上限、并发/成本配额、权限过滤、工具白名单、输出 schema 和审计;提示词不能替代这些硬边界。
隐私测试要覆盖人脸、车牌、住址、屏幕、病历、未公开产品和删除请求。验证脱敏是否覆盖完整,索引和缓存是否仍可查询,日志是否包含可逆链接,备份是否有清理时间。向量和中间特征也可能泄露信息,不应因为无法直接阅读就放松保护。
当鲁棒性或隐私不达标时,可采用拒答、限流、低分辨率、区域选择、人工转接和场景缩小等降级。降级状态要对用户可见并可观测,不能悄悄返回旧结果或把失败当作“未发现”。
11.10 发布门槛:质量、性能、安全和恢复一起过关
发布门槛由硬条件和软指标组成。硬条件包括数据来源与许可清楚、关键切片达到最低召回、权限和删除测试通过、敏感请求能阻断、p95 延迟和单次成本在预算内、回滚步骤演练成功;软指标可用于排序优化,但不能抵消越权或关键漏检。
把门槛写成可测量的表格:指标、数据集版本、阈值、实际值、责任人、未通过动作和复测日期。比如“夜间小目标 recall 不低于某值”“未知图误接收率低于某值”“删除后索引不可检索”“工具超时必须转 uncertain”。避免“质量良好”“响应很快”这类无法验收的句子。
性能测试分阶段测量:上传与解码、预处理、模型、后处理、工具、网络和渲染。记录 p50、p95、峰值显存、吞吐、并发、重试和成本;平均延迟掩盖尾部超时,单张测试掩盖不了高并发。若达不到预算,优先改变输入策略、缓存、批处理、模型大小或功能范围,而不是无限扩容。
回滚需要可切换的旧模型、旧预处理、阈值、标签词表、提示模板、索引和工具版本。runbook 写清触发条件、执行人、命令、用户通知、数据保留和回放集;回滚后重放正常、低质量、越权、删除和敏感样例,确认恢复没有重新打开安全缺口。
监控和审计要区分技术错误与模型错误。服务 500、解码失败、模型输出无效、工具冲突、人工拒绝和用户纠错分别统计;错误地图能连接到版本和样例。重大版本发布采用 shadow 或小流量观察,比较新旧输出、状态、延迟、成本和切片差异。
发布不是终点。每次数据、权重、预处理、提示、工具、依赖和硬件更新,都触发影响评估;如果输入分布或业务风险改变,重新定义门槛。对学习者来说,能写出“何时暂停、谁来决定、怎样恢复”,比一次演示成功更接近真实工程。
11.11 评审实验:用反例、回放和人工证据压住自我欺骗
准备评估集时把成功、近失误和明显失败都保留。成功样例验证基本能力,近失误帮助调阈值和边界,失败样例揭示数据或结构缺口;删除失败图片只会让报告变漂亮,不能让系统变可靠。每张样例用稳定 ID 关联原图、标签、预测、版本、切片和修复状态。
反事实评估一次改变一个主要因素。把目标移到别处、替换背景、降低亮度、遮挡局部、改变文字方向、交换图片顺序或移除图片内指令,比较输出是否随证据合理变化。若结论不随目标消失而改变,记录为潜在捷径或语言先验,安排进一步实验而不是直接下因果结论。
人工评分表要短而明确。评估者分别判断任务正确性、证据充分性、位置/文字精度、拒答合理性、风险与可行动性;每项使用定义好的等级并写一个理由。抽查评审一致性,分歧高的项目通常需要修订任务合同或指南,而不是简单平均。
回放测试用于保证更新没有破坏旧能力。保留不同版本的固定输入和期望状态,比较结构化字段、引用区域、分数容差、拒答和耗时;对生成模型比较约束满足和安全状态,不要求像素逐点相同。版本变化导致合理差异时,在 manifest 中说明原因。
把指标与用户影响连接起来。漏检一个边缘小目标可能使人工多花几分钟,也可能造成重大风险;误报过多会让人工队列瘫痪;错误 OCR 可能让用户复制错误编号。报告应同时写技术指标、人工时间、成本和不可接受的失败,而不是只追求一个最高分。
完成本节后,学习者应能独立设计评估集、指标表、鲁棒性变换、隐私与对抗测试、发布门槛、监控字段和回滚演练,并能在评审中诚实回答“模型在哪些输入上不应被信任”。
| 维度 | 最小问题 | 证据 | 未通过动作 |
|---|---|---|---|
| 任务质量 | 目标/区域/文字对吗? | 固定集 + 每类指标 | 修数据/阈值/模型 |
| 拒答 | 证据不足会停吗? | 未知/低质/越权集 | 扩展边界与人工 |
| 鲁棒性 | 输入变化会怎样? | 变换参数 + 切片 | 补采/限制/降级 |
| 隐私 | 删除和权限有效吗? | 访问/删除回放 | 阻断发布 |
| 性能 | 预算内可运行吗? | p50/p95/吞吐/成本 | 优化/限流 |
| 运营 | 错误可发现和恢复吗? | 监控/runbook/回滚 | 先演练再上线 |
| 门槛 | 阈值/条件 | 实际证据 | 动作 |
|---|---|---|---|
| 关键切片召回 | 不低于项目最低线 | night_small recall + n | 补采或阻断 |
| 未知误接收 | 低于风险上限 | unknown 集混淆矩阵 | 收紧阈值/人工 |
| 隐私删除 | 删除后全链路不可查 | 缓存/索引/备份回放 | 暂停并修复 |
| 工具边界 | 越权和超时可阻断 | 权限/注入/timeout 测试 | 禁用工具 |
| p95 延迟 | 目标并发下不超预算 | 分阶段 profiler | 降级/限流 |
| 恢复 | 旧版可切回并回放 | runbook 演练日志 | 不发布 |
任何一个硬门槛未通过,都应触发修复、限制或阻断;总体平均分不能替代安全和恢复证据。
def gate(report):
hard_checks = {
"data_card": report.get("data_card", False),
"slice_recall": report.get("key_slice_recall", 0) >= 0.85,
"unknown_control": report.get("unknown_false_accept", 1) <= 0.10,
"delete_replay": report.get("delete_replay", False),
"p95_budget": report.get("p95_ms", 10**9) <= report.get("p95_budget_ms", 0),
"rollback": report.get("rollback_rehearsed", False),
"safety": report.get("safety_tests", False),
}
failed = [name for name, passed in hard_checks.items() if not passed]
return {
"status": "release" if not failed else "blocked",
"failed": failed,
"checks": hard_checks,
}
sample = {
"data_card": True,
"key_slice_recall": 0.88,
"unknown_false_accept": 0.06,
"delete_replay": True,
"p95_ms": 740,
"p95_budget_ms": 1000,
"rollback_rehearsed": True,
"safety_tests": True,
}
print(gate(sample))11.8.4 指标的定义与复现
同一个指标若匹配规则不同,数字就没有可比性。检测报告写 IoU 阈值、类别匹配、一对一规则、忽略区域和空图处理;分割写像素标签、边界和 ignore;OCR 写字符/词切分与大小写;VLM 写证据和拒答标注指南。
固定评估集之外保留开发集和最终保留集。开发集可调阈值,最终集尽量少看;如果测试集被反复用来选择模型,应重新建立保留集并说明历史结果不再是无偏证据。
报告样本量和不确定性。小切片的指标可能波动很大,使用 bootstrap 或区间,并列出每类/每切片的样本数;不确定时写“证据不足”,不要用小数点后的差异做强结论。
11.8.5 人工评审与证据一致性
评审指南把任务正确、证据充分、区域准确、拒答合理和风险可接受分开评分。评审者先看任务与图片,再看候选结果;尽量盲化模型名称,保存分歧和裁决理由。
对于 VLM,要求每条声明绑定图片 ID、区域或工具结果;对于检测/分割,核对覆盖层与原图;对于生成,检查文字、数量、布局、来源和安全。人工不是替代指标,而是检查指标没有覆盖的事实性与可用性。
抽样应覆盖成功、近失误、失败、低质量、未知和敏感输入。记录人工时间和一致性,用于决定人工队列预算;高风险场景不能用极少量抽样假装安全。
11.8.6 鲁棒性、隐私和对抗测试
真实分布变化包括相机、压缩、光照、遮挡、裁剪、语言、长宽比和并发。一次只改变一个主要因素,保存变换参数、模型输出、状态和资源;比较指标下降与拒答是否合理。
隐私回放覆盖原图、缩略图、向量、缓存、日志和备份。删除一张图片后逐层查询,确认权限和保留期;脱敏前后比较任务证据,避免以为遮挡等于安全。
对抗测试包括畸形文件、超大图、图片内指令、近邻探测、工具参数注入和无限重试。控制器用硬限制阻断;提示词只负责说明行为,不能承担资源和权限边界。
11.8.7 发布、监控和回滚细节
门槛表写清阈值、数据版本、责任人和动作。关键切片、未知误接收、删除回放、敏感拒答、p95、成本和回滚演练是硬门槛;总体平均分只能作为补充。
监控记录状态、版本、耗时、工具调用、低质量率、未知率、人工纠错和成本摘要。告警触发调查,不能自动判定根因;异常时保留足够的追踪 ID 以回放,不无限保存敏感原图。
回滚同时恢复模型、预处理、阈值、标签、索引和工具版本。执行后回放正常、低质、越权、删除和工具超时,确认恢复没有绕过校验;runbook 中写明通知、责任人和后续修复。
| 字段 | 示例 | 缺失的后果 |
|---|---|---|
| dataset_revision | eval-2026-08-20 | 无法知道测试内容 |
| split_key | subject_id/session_id | 可能发生泄漏 |
| metric_definition | IoU@0.5 + one-to-one | 不同实现不可比 |
| slice_n | night_small n=84 | 小样本被误读 |
| uncertainty | bootstrap 95% CI | 过度解读小差异 |
| model/preprocess | v3 + letterbox2 | 无法复现输入 |
| action | release/blocked/review | 指标不能支持决策 |
import random
def bootstrap_mean(values, rounds=200, seed=7):
rng = random.Random(seed)
if not values:
return 0.0, 0.0, 0.0
samples = []
for _ in range(rounds):
sample = [rng.choice(values) for _ in values]
samples.append(sum(sample) / len(sample))
samples.sort()
low = samples[int(rounds * 0.025)]
high = samples[int(rounds * 0.975)]
return sum(values) / len(values), low, high
print(bootstrap_mean([1, 1, 0, 1, 0, 1]))11.8.8 评估结论的写法
一份合格报告先说明任务、输入契约、数据集版本和测试切分,再给出指标。不要把多个模型或多个提示的最好分数混在一起;每个数字都关联模型 revision、预处理、阈值、评估脚本和样本量。
总体指标之后列出关键切片和不确定性,解释差异是否足以改变产品决策。样本太少时,报告“当前证据不足”,提出补采或延长观察,而不是用平均数覆盖缺口。
成功样例、失败样例和人工复核互相补充。成功样例证明链路通,失败样例暴露边界,人工复核判断证据与可用性;三者缺一,报告容易被演示偏差带偏。
鲁棒性结果用变换参数和状态解释。若低光下指标下降但拒答率提高且没有误接收,可能是安全降级;若模型继续自信回答,则是更严重的问题。把“拒答”也作为可度量的输出,而不是从准确率中删除。
发布门槛要明确谁来决定、什么时候暂停、如何通知和怎样回滚。监控告警只提供线索,根因需要回放和人工调查;保留最小必要追踪字段,避免为了可观测性无限保存敏感图片。
评估是一项持续工作。数据、模型、预处理、提示、工具、硬件和业务风险任一变化,都可能使旧结论失效;版本化和回归集让团队知道哪些结论仍然有效。
| 顺序 | 应回答 | 常见缺口 |
|---|---|---|
| 任务 | 输出和风险是什么? | 只写模型名称 |
| 数据 | 来源、切分、样本量? | 随机泄漏/无版本 |
| 方法 | 预处理、阈值、脚本? | 无法复现 |
| 结果 | 总体、切片、区间? | 只报平均数 |
| 失败 | 错在哪里、严重度? | 只展示成功 |
| 动作 | 发布、限制或阻断? | 指标没有决策 |
选择一个已有视觉模型演示,补写任务/数据/方法/总体指标/切片/失败/安全/资源/动作九栏;删除无法提供证据的宣传句。
11.8.9 最后一轮自检:评估结论要能行动
报告开头写清任务、输入契约、数据版本、切分和指标定义;没有这些上下文,任何小数都不可比较。模型、预处理、阈值和脚本应与结果绑定。
总体指标之后必须列出关键切片、样本量、不确定性、成功与失败样例。少量切片的波动要诚实报告,不能把置信区间隐藏起来。
人工复核、拒答和证据引用要进入评估,不只统计“回答对不对”。对高风险输出,人工流程、权限和删除是硬门槛,不是上线后的附加项。
鲁棒性与对抗测试一次改变一个因素;监控告警记录非敏感摘要,回滚同时恢复模型、预处理、阈值、索引和工具。回放验证恢复没有绕过安全状态。
评估章节的交付物是可审查的发布报告:每个数字都有数据和版本,每个失败都有动作,每个门槛都有责任人和暂停条件。
- 质量、拒答、隐私、资源一起评估。
- 切片下降不会被平均分掩盖。
- 上线与阻断的动作写明。
- 回滚演练有实际日志。
| 发现 | 不应写成 | 应采取 |
|---|---|---|
| 关键切片不足 | 总体还不错 | 补采/限制/阻断 |
| 未知误接收 | 模型很自信 | 校准/拒答/人工 |
| p95 超预算 | 平均很快 | 降级/限流/优化 |
| 删除未完成 | 日志不重要 | 暂停并清理全链路 |
11.8.10 复现记录
最终记录任务合同、数据快照、指标定义、切片、区间、人工指南、资源和发布动作。一次评估如果不能说明样本来自哪里、数字怎么算、失败怎么办,就还只是演示,不是证据。
把报告交给没有参与实验的同伴复核:他应能按 README 重跑固定集,理解每个门槛和状态,找到一个成功与一个失败样例,并解释为什么当前版本可以发布、需要限制、转人工或阻断。复核意见和修订版本也属于评估资产。
11.8.11 复核标准
复核者要检查总体和切片是否使用同一数据版本,指标脚本是否可运行,人工评分是否有指南,发布结论是否对应硬门槛。不能把“通过”写成没有条件的承诺;结论应限定在已评估的输入范围、版本和资源预算内。
若复核发现证据不足,明确列出下一步:补采哪些图片、锁定哪个测试集、重新跑哪项指标、增加哪个安全用例、谁负责以及何时复查。把不确定性转成行动,是评估章节最后的工程能力。
11.8.12 证据保留
保留原始预测、人工裁决、版本和回归日志,才能在指标争议、用户投诉或安全事件后重建事实;删掉失败记录只会让下一次评估失去参照。
11.8.13 从分数回到判断
评估表中的每一列都要能回答一个实际问题:这个错误会影响谁,人工能否发现,系统是否会误触发动作,发生后能否暂停和恢复。数字只有连接到风险、责任人和动作,才真正帮助团队作出发布决定。
11.8.14 结论边界
结论必须限定在已评估的输入范围、版本和预算内。
11.8.15 最小证据包
最小证据包包含数据快照、评估脚本、固定结果和复核日志,缺一项就不能声称可复现。
建立清晰、低光、遮挡、未知、无目标、权限、删除和工具超时样例;输出指标、状态、人工评分、资源和回滚动作。
def summarize_variants(rows):
groups = {}
for row in rows:
key = row["variant"]
groups.setdefault(key, {"n": 0, "correct": 0, "refused": 0})
groups[key]["n"] += 1
groups[key]["correct"] += int(row["correct"])
groups[key]["refused"] += int(row["status"] in {"uncertain", "blocked"})
for item in groups.values():
item["accuracy"] = item["correct"] / item["n"] if item["n"] else 0.0
item["refusal_rate"] = item["refused"] / item["n"] if item["n"] else 0.0
return groups
print(summarize_variants([
{"variant": "clean", "correct": True, "status": "answer"},
{"variant": "low_light", "correct": False, "status": "uncertain"},
{"variant": "low_light", "correct": True, "status": "answer"},
]))为器材检测助手写出质量、未知、隐私、工具、延迟、成本、人工和回滚八项门槛;每项给阈值、证据和未通过动作。
对同一组图片做压缩、低光、遮挡、背景替换和未知类别测试;删除其中一张后检查原图、缩略图、向量、缓存和日志引用是否仍可见。
提交固定评估集说明、指标/切片报告、人工指南、鲁棒性与隐私测试、发布门槛、监控字段和回滚 runbook。
11.8.1 任务指标与人工复核
指标从任务合同推导。分类可报告每类 precision、recall、校准和拒答率;检测/分割可报告 mAP、IoU、漏检率和空间误差;OCR 应报告字符或词错误率;VLM 还需要基于证据的正确性、区域定位和拒答质量。平均分之外必须提供关键切片与失败样例。
建立固定评估集并版本化,包含常规、边界、低质量、长尾、资料不足和恶意输入。评估集不能反复被人工看过再当作无偏测试;开发集用于调参,最终保留集用于发布判断。任何数据、预处理、模型或阈值变动后重跑。
人工评审要有标注指南和盲审策略。评审者确认任务和证据,不必知道候选模型名称;保存分歧样例和裁决理由。对高风险结果,人工复核不是抽样锦上添花,而是输出链路的一部分。
11.8.2 鲁棒性、隐私与对抗风险
鲁棒性测试应覆盖真实变化:模糊、压缩、光照、裁剪、遮挡、旋转、背景替换、不同设备、不同语言文字和输入上限。每项测试保留原始图、变换参数、模型输出和任务指标,避免只展示一张“模型被难倒”的图片。
图片中可能含有人脸、住址、屏幕内容、健康信息、车牌或未公开资料。最小化收集和保存,分离原图、特征、日志和评估集权限;上传前提示用户,删除请求应传播到缓存、缩略图、索引和备份计划。脱敏模型本身也要验证,不可假定一定遮住了所有敏感信息。
攻击者可能上传畸形文件耗尽资源、用图片/文字注入指令、通过相似检索探测私有资料,或诱导模型对人作敏感推断。控制器负责文件验证、尺寸/并发/成本限制、权限过滤、工具白名单、输出验证和审计;不要把这些职责交给模型提示词。
11.8.3 发布门槛、监控与回滚
发布门槛应包含硬条件:关键切片不低于最低指标、权限测试通过、拒答/转人工路径可用、p95 延迟和单次成本在预算内、数据许可明确、回滚演练成功。整体高分不能抵消越权、隐私或关键漏检风险。
运行中记录输入类型(避免保存不必要原图)、模型和规则版本、耗时、输出状态、工具调用、人工复核和用户纠错。监控输入分布、低质量比例、拒答率、错误反馈、性能和成本;突变可能说明相机更新、数据漂移、攻击或服务异常。
回滚要保留旧模型、旧预处理、阈值、标签词表、索引、评估报告和切换步骤。触发条件、责任人和用户通知写进 runbook;切回后重放正常、低质量、越权、删除和高风险样例,确认安全路径没有被恢复操作破坏。
| 维度 | 最低证据 | 未通过动作 |
|---|---|---|
| 数据 | 来源、许可、切分、覆盖报告 | 限制范围或补采 |
| 质量 | 固定集、关键切片、错误地图 | 修复后重评 |
| 安全 | 权限、隐私、注入、文件测试 | 阻断发布 |
| 性能 | p50/p95、吞吐、成本 | 降级或限流 |
| 恢复 | 版本、runbook、回滚回放 | 先完成演练 |
为“器材检测助手”写出质量、安全、延迟、成本和人工复核的硬门槛;包含一个能立即触发暂停的条件。
评估报告复核标准
一份可发布的视觉评估报告至少包含任务合同、数据版本、预处理、基线、主指标、关键切片、置信区间、失败样例、人工协议和安全门槛。每个数字都应能回答“在哪组数据、用哪个版本、经过什么后处理得到”,不能只给一个漂亮的总体平均分。
把质量门槛与越权、隐私、成本和恢复门槛分开;任何硬性安全失败都应阻断发布。上线后继续记录漂移、拒答、人工纠错和 p95,触发条件、责任人、通知与回滚步骤都写入 runbook 并实际演练。
09 · CAPSTONE
综合项目:交付可验证的视觉助手
最后把数据、视觉模型、专用工具、视觉语言解释、评估与安全连接成一个小而完整的项目。目标不是做“什么都能看”的演示,而是对一个明确定义的视觉任务给出可追溯结果,并知道何时不应回答。
11.9 项目选题:把宏大愿望缩成一个可验收的视觉任务
综合项目不追求“什么图片都能理解”,而追求一个边界清楚、数据可获得、结果可评估、失败可接住的任务。可以选择公开器材照片的候选检测、课程插图的质量审查或公开素材的相似检索;不要从身份识别、医疗诊断、执法判断或自动控制开始,因为这些任务的风险和证据要求远高于本章练习。
项目说明先写用户和决策:谁上传图片,系统给谁看,结果会影响什么动作,人工在何处介入。再写输入范围、允许来源、类别定义、空间坐标、最大尺寸、质量阈值、非目标和保留期。若一句话无法说明“不负责什么”,项目就还没有收敛。
输出协议把模型候选和产品结论分开。候选包含类别、分数、区域、模型与预处理版本;产品状态包含 answer、uncertain、no_detection、invalid_input、blocked、review_required。服务端验证候选,规则决定状态,人工或用户看到证据与下一步。不要让模型自由生成一段文本充当最终 API。
项目的成功条件要可量化并与用户动作关联。例如关键类别召回不低于设定门槛,低质量图片进入人工,未知类别误接收率受控,p95 延迟和单次成本在预算内;高风险请求必须阻断。条件不应使用“效果好”“反应快”等模糊词。
先画系统边界图:输入验证、解码与预处理、视觉模型、专用工具、后处理、结构校验、人工队列、日志、评估和回滚。每个模块写输入、输出、失败状态和责任人;如果一个模块同时负责太多事情,优先拆开,而不是把逻辑塞进一个循环或一个 Prompt。
项目从小数据和假模型开始。先用固定 JSON 预测验证协议、坐标和前端渲染,再接入真实模型;这样可以先发现字段、权限和状态设计错误,不会把模型噪声误认为工程问题。
11.10 数据与实验:让每一次改动都有证据
项目数据包至少包括数据卡、授权或可复现下载方式、标签指南、原图/标签 ID、分组切分、近重复审查、预处理 manifest 和删除记录。敏感数据使用受控路径,不把原图直接提交到公开仓库;示例可以使用自制或明确允许的素材。
切分在实验开始前锁定。按主体、会话、实体或近重复簇分组,保存 train/valid/test 清单和哈希;如果后续发现泄漏,保留旧结果并标记无效,重新建立切分,不要覆盖历史报告。评估集应与调参集隔离,保留一小组最终验收图片。
实验矩阵一次只改一个主变量:输入尺寸、增强、冻结策略、模型、阈值、后处理或工具。配置文件记录默认值、随机种子、依赖版本、硬件和预算;结果文件保存指标、样例、日志和 manifest。这样才能回答“改动带来了什么收益,又付出了什么代价”。
除了总体分数,报告关键切片:目标大小、遮挡、光照、设备、背景、文字方向、无目标、未知类别和低质量。每个切片给样本数、指标、置信区间、失败样例和修复假设。样本太少时写未知,不要把几个样本的偶然结果当作稳定结论。
错误地图按阶段组织:数据、标签、切分、解码、颜色、几何、模型、阈值、NMS、OCR/VLM 工具、权限、界面和监控。每项记录 sample_id、版本、现象、严重度、根因假设、负责人、修复和回归测试。错误地图应随着项目更新,而不是在最后一天一次性补写。
使用假模型测试协议中的边界:错误坐标、未知类别、低分、空结果、工具超时、删除后的图片、无权访问和恶意文件。假模型不需要视觉能力,却能证明系统不会把非法候选当成真实结果;完成后再用真实模型复测。
11.11 交付工程:README、测试、监控与回滚不能缺席
README 从干净目录开始写:环境、依赖、数据获得方式、数据卡、训练或推理命令、输入示例、预期 JSON、覆盖层、失败状态、隐私处理和故障排查。不要只放一个 Notebook;别人要能在没有作者口头解释的情况下运行最小样例。
代码按职责拆分:读取与验证图片、执行预处理、调用模型、映射坐标、校验结果、保存 manifest、生成报告和处理人工队列。函数输入输出写清类型和错误状态,避免把所有逻辑放在一个循环里。每个职责至少有一个正常、一个边界和一个错误测试。
模型 manifest 与代码版本一起交付。记录权重来源、许可证、模型 revision、输入尺寸、颜色归一化、标签词表、阈值、后处理、工具版本、随机种子和硬件。模型能加载却与预处理不匹配时,应在启动阶段失败;不要等线上出现大量错误才发现字段不一致。
监控字段尽量使用非敏感摘要:输入尺寸、文件哈希、状态、版本、耗时、工具调用、人工纠错和成本。需要抽样原图时严格控制权限和保留期。告警关注低质量比例、未知率、拒答率、p95、错误码和切片反馈的变化,异常时能回到某个版本和样例。
回滚 runbook 具体到执行顺序:停止新流量、切换旧模型/预处理/索引/阈值、验证健康检查、回放固定样例、通知相关人员、记录原因和后续修复。回滚之后检查删除、权限、越权和人工队列,不要只确认服务返回 200。
演示也要诚实。展示清晰成功、低质量拒答、未知类别、坐标错误被拦截、工具超时和人工复核;标明模型版本、证据区域和限制。一个漂亮的成功样例只能说明链路通了,不能说明系统在所有场景可靠。
11.12 评分与反思:评价职责是否清楚,而不是代码有多长
项目评分应看职责是否清楚、证据是否完整和边界是否诚实。读取图片、统计候选、保存 JSON、评估切片和生成报告应有清晰函数或模块;代码短但职责清楚、测试充分,比堆很多网络层更有价值。每个函数都说明输入、输出、异常和副作用。
数据分数不能脱离标注指南。检查近重复、主体泄漏、未知类别、标签分歧和切片样本量;如果标签本身不一致,先修订数据协议再比较模型。报告数据缺口和不能推断的属性,防止项目在展示时扩大结论。
模型结果要经过结构校验和人工抽查。检查 JSON 可再次读取,坐标能映射回原图,类别在允许集合,分数有限,状态与候选一致;抽样审查覆盖层和原图,记录错配、漏检、误报和拒答理由。工具输出和 VLM 描述不能覆盖原始证据。
安全评分包括输入限制、权限、隐私、图片内提示注入、工具白名单、敏感属性拒答、删除传播和成本限额。若任何一项只靠 Prompt 约束而没有服务端校验,项目应标记为未完成,而不是用演示效果抵消。
反思部分写三个问题:哪一个失败最可能在真实数据中扩大;哪一个指标没有被当前评估集覆盖;下一步是补数据、改协议、换模型、加工具、加人工还是缩小范围。把不确定性写出来,是从教程练习走向工程判断的重要一步。
进入下一章前,应能把本章方法迁移到多模态系统:每种模态都有输入契约、表示、任务输出、证据、权限、评估和回滚;模态越多,接口越需要明确,而不是把所有问题交给一个更大的模型。
11.13 项目提交前的逐项验收
数据验收:数据卡有来源、许可、采集范围、缺口、删除和不应推断项;标签指南能让两位标注者独立复现;切分按分组键完成;近重复、视频帧和同主体泄漏有审查记录;合成素材和外部模型权重有单独标记。
输入验收:服务检查扩展名之外的真实格式、大小、尺寸、颜色、方向、质量和权限;坏文件、超大图、空图、单通道、透明图和恶意文件返回明确状态;预处理记录缩放、裁剪、补边、归一化和版本。
模型验收:至少有一个朴素基线和一个目标模型;tiny-batch 或固定样例测试通过;模型、标签、阈值、后处理和工具版本能在 manifest 中还原;输出候选不直接等于业务结论;未知和不确定有拒答或人工路径。
评估验收:固定集、关键切片、鲁棒性、未知、低质量、权限、隐私、注入、工具超时和删除回放都执行;报告整体、每类、切片、样本量和不确定性;失败样例带根因假设和回归测试;高风险门槛未通过会阻断。
交付验收:README 可从干净目录运行;JSON 可以再次读取;覆盖层能回到原图;监控和成本字段可用;旧版本、旧数据协议和 runbook 可回滚;演示包含成功和失败;用户能看到限制、证据和下一步动作。
学习验收:用自己的话解释像素、卷积、Patch、对比学习、检测/分割、VLM、扩散、指标和安全边界;能指出一个模型不适用的场景;能为任何结论提供数据、代码、图表或人工复核证据。
| 模块 | 最小交付物 | 验收问题 | 失败动作 |
|---|---|---|---|
| 输入与隐私 | 契约、坏输入测试 | 能验证并安全拒绝吗? | 修验证/限制范围 |
| 数据与标签 | 数据卡、指南、切分 | 答案可复现吗? | 修标注/重切分 |
| 模型与工具 | manifest、版本、白名单 | 职责边界清楚吗? | 拆模块/禁用工具 |
| 结果协议 | JSON Schema、坐标校验 | 候选能回到证据吗? | 阻断非法输出 |
| 评估与错误 | 切片表、错误地图 | 失败集中在哪里? | 补数据/调策略 |
| 安全与运营 | 权限、监控、runbook | 越权能阻断和恢复吗? | 暂停发布 |
| 文档与演示 | README、成功/失败样例 | 别人能复现吗? | 补步骤/重演练 |
| 维度 | 优秀表现 | 基本合格 | 未完成 |
|---|---|---|---|
| 任务边界 | 目标、非目标和状态清晰 | 有目标但边界不全 | 只展示一个 Prompt |
| 数据质量 | 许可、切分、标签和缺口可追溯 | 有数据说明但缺少审查 | 随机切分无记录 |
| 代码职责 | 函数/模块职责清楚、可测试 | 能运行但耦合较多 | 所有逻辑塞在一处 |
| 空间证据 | 坐标、覆盖层和来源一致 | 部分结果可回放 | 只给一句分类文本 |
| 评估 | 指标、切片、反例和不确定性齐全 | 有总体指标和少量样例 | 只展示成功截图 |
| 安全运营 | 权限、拒答、成本、监控、回滚可演练 | 有基本限制 | 只靠提示词 |
| 反思迁移 | 能解释取舍和下一步 | 能复述概念 | 不能说明失败 |
项目不是把模型接上页面就结束,而是要让输入、证据、动作和恢复都能被另一位学习者复现。
from pathlib import Path
import json
REQUIRED_FILES = {
"README.md",
"data_card.md",
"label_guide.md",
"model_manifest.json",
"evaluation.json",
"error_map.csv",
"runbook.md",
}
def check_package(root: str):
base = Path(root)
missing = sorted(name for name in REQUIRED_FILES if not (base / name).exists())
manifest = {}
manifest_path = base / "model_manifest.json"
if manifest_path.exists():
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
required_manifest = {"model_id", "revision", "preprocess", "labels", "thresholds"}
missing_manifest = sorted(required_manifest - manifest.keys())
return {
"status": "ok" if not missing and not missing_manifest else "incomplete",
"missing_files": missing,
"missing_manifest_fields": missing_manifest,
}
print(check_package("vision_project"))11.9.14 项目范围与风险分级
项目选题先按风险分级:低风险的素材分类、器材候选检测和公开图片检索适合学习;涉及身份、健康、执法、信用或自动执行的任务需要额外合规与人工流程,不应作为本章的默认练习。风险分级决定数据、评估、拒答和发布门槛。
用一页项目章程写用户、输入、输出、非目标、场景、预算、负责人和截止条件。每个术语都给定义,例如“检测到”是候选框达到哪个 IoU/分数,还是人工确认;“可用”是达到总体指标,还是关键切片也通过。
先设计失败状态,再设计成功页面。图片损坏、低质量、未知、权限不足、工具超时和模型输出无效都要有状态、日志和下一步;这样接入真实模型时,不会因为没有错误路径而把所有问题压成一段自由文本。
11.9.15 从数据包到可复现实验
数据包结构可以包含 raw/、labels/、splits/、manifests/、cases/、reports/ 和 README。原图受控保存,labels 与 image_id 关联,splits 锁定分组,manifest 记录预处理,cases 保存正常/边界/错误输入,reports 保存指标和错误地图。
实验配置用一个文件冻结主变量:模型、revision、输入尺寸、颜色、增强、冻结比例、阈值、后处理、设备和 seed。结果目录按配置哈希命名,避免实验相互覆盖;报告自动引用配置和数据版本,减少手工复制错误。
先用假模型验证协议,再运行真实模型。假模型可以返回合法候选、非法坐标、未知类别和超时,检查服务是否正确校验;真实模型的视觉质量另行评估。两条测试链分开,工程正确性和模型能力都能独立定位。
11.9.16 模块职责与测试设计
输入模块只负责解码、大小、质量和权限;预处理模块只负责颜色、尺寸和坐标变换;模型模块只返回候选;后处理模块只做 NMS/阈值;协议模块只校验 schema;评估模块只读取固定结果计算指标。职责清楚后,替换模型不会影响删除和权限测试。
每个模块写正常、边界和失败测试。输入测试空文件、伪扩展名和超大图;坐标测试边界框、旋转和补边;协议测试缺字段、未知枚举和 NaN;评估测试空图和少样本切片;回滚测试旧版配置与数据。
代码长度不是评分重点。能解释每个函数为什么存在、输入输出是什么、异常怎样处理、是否有副作用,比写一个巨大的脚本更重要。README 用最小命令运行测试,并展示一条成功和一条拒答的 JSON。
11.9.17 发布演练与用户沟通
发布前演练从上传开始到结果、人工队列、日志和删除完成。模拟模型版本切换、工具超时、权限撤销、关键切片下降、p95 超预算和用户投诉,按 runbook 执行暂停或回滚。
用户看到的结果要包含状态、证据区域、限制和可行动作。不要只显示颜色框或一句“识别成功”;低置信度、未知和拒答是正常界面状态。对生成图标注合成/编辑,对检索结果显示来源和时间。
项目总结写清哪些结论被证据支持、哪些仍未知、下一步要收集什么数据或做什么实验。把“不能保证”写出来不会削弱教材,反而证明你理解了视觉模型的边界。
| 层级 | 测试对象 | 示例 | 通过标准 |
|---|---|---|---|
| 单元 | 函数/变换 | 坐标映射、哈希、阈值 | 输入输出稳定 |
| 协议 | JSON/状态 | 缺字段、未知枚举 | 非法候选被阻断 |
| 集成 | 模块链路 | 上传→模型→覆盖层 | ID/版本不丢 |
| 数据 | 切分/标签 | 近重复、同主体 | 无已知泄漏 |
| 模型 | 能力/切片 | 小目标、低光、未知 | 指标与拒答达标 |
| 运营 | 监控/回滚 | 超时、删除、切换 | 可观测可恢复 |
from pathlib import Path
import json
def read_json(path):
return json.loads(Path(path).read_text(encoding="utf-8"))
def validate_manifest(manifest):
required = ["model_id", "revision", "preprocess",
"labels", "thresholds"]
missing = [key for key in required if key not in manifest]
return {"ok": not missing, "missing": missing}
def verify_case(case):
required = {"id", "input", "expected_status", "model_revision"}
missing = sorted(required - case.keys())
return {"ok": not missing, "missing": missing}
print(validate_manifest({
"model_id": "vision-v1",
"revision": "r3",
"preprocess": "rgb-letterbox",
"labels": ["beaker"],
"thresholds": {"beaker": 0.7},
}))
print(verify_case({
"id": "low-01",
"input": "sample.jpg",
"expected_status": "uncertain",
"model_revision": "r3",
}))把项目脚本拆成输入、预处理、模型、后处理、协议、评估和运营七类函数;为每类写输入、输出、异常和一个测试,说明哪一类绝不能由模型 Prompt 负责。
import json
from pathlib import Path
def replay_case(path, runner):
case = json.loads(Path(path).read_text(encoding="utf-8"))
result = runner(case["input"])
assert result["status"] == case["expected_status"]
assert result["model_revision"] == case["model_revision"]
for expected in case.get("required_fields", []):
assert expected in result, expected
return {"case_id": case["id"], "status": "passed"}
print(replay_case("cases/low_quality.json", lambda value: {
"status": "uncertain",
"model_revision": "vision-v1",
"reason": "low_quality",
}))选择公开低风险数据,完成数据卡、输入验证、模型/假模型、结构化输出、覆盖层、评估集、错误地图和 README;记录至少一个拒答状态。
模拟新模型在关键切片下降、p95 超预算、工具超时和删除请求;按 runbook 暂停、回滚、回放并写出用户通知和后续修复。
提交数据卡、标签指南、输入契约、模型 manifest、代码与测试、表格/图示、评估与错误地图、安全测试、README、演练记录和反思。用一段话说明视觉模型和下一章多模态模型的共同边界。
11.9.1 项目设计与输出协议
选择低风险、范围小、可获得授权数据的任务,例如“根据公开器材照片检测是否包含指定实验用品,并标出候选区域”。冻结用户、输入范围、类别定义、允许的图片来源、输出字段、人工复核和非目标。不要从身份识别、健康诊断、执法或自动执行动作开始。
将系统分成输入验证、预处理、检测/分类、可选 OCR 或 VLM 解释、结果校验、人工队列、日志和评估模块。模型只产出候选;服务端检查坐标、类别、阈值、权限和版本,前端将候选区域、状态和限制一并展示。
输出协议可包含 status、detections、source_image_id、model_manifest、quality_flags、review_required 和 limitations。没有候选、图片损坏、低质量、冲突或超出范围都应是不同状态,不能都伪装成“未发现”。
每步都有输入、输出和失败状态;语言模型只能作为受约束的解释层。
11.9.2 数据、评估与错误地图
项目数据包包含授权原图或可复现下载方式、数据卡、标签指南、切分清单、近重复审查、预处理 manifest 和删除记录。用假模型或固定预测先测试协议:错误坐标、未知类别、低置信度、损坏图片、权限不足和工具超时应被安全处理,再接真实模型。
实验矩阵一次只改一个主要变量,例如输入尺寸、增强、冻结策略、检测阈值或是否加入 OCR。固定数据、切分、评估集、设备和成本预算;报告整体、关键类别、小目标、遮挡、低质量图片和人工复核队列的结果。失败样例比总分更能指导下一步。
错误地图按数据、标签、预处理、表示、定位、分类、阈值、工具、VLM 描述、安全和界面分层。每项记录样例 ID、版本、可视化覆盖层、严重度、根因假设、修复、回归测试和负责人。不要因为修复了指标就删除失败证据。
def validate_result(result, image_width, image_height, allowed_labels):
if result.get("status") not in {"answer", "uncertain", "no_result"}:
return {"status": "blocked", "reason": "invalid_status"}
for item in result.get("detections", []):
x1, y1, x2, y2 = item["box"]
if item["label"] not in allowed_labels:
return {"status": "blocked", "reason": "unknown_label"}
if not (0 <= x1 < x2 <= image_width and 0 <= y1 < y2 <= image_height):
return {"status": "blocked", "reason": "invalid_box"}
return result
candidate = {"status": "answer", "detections": [
{"label": "beaker", "box": [12, 8, 108, 142]}
]}
print(validate_result(candidate, 640, 480, {"beaker", "flask"}))11.9.3 交付、演练与下一步
交付包至少包含 README、数据卡、标签指南、模型与预处理 manifest、输入验证、假模型场景、评估脚本、结果可视化、错误地图、监控说明和 rollback。README 从干净目录写起:安装、数据获得方式、训练/推理命令、预期输出、限制、隐私处理和故障排查都应明确。
发布前演练正常图片、无目标、低质量、未知类别、越权、删除后的图片和服务降级。演示要展示原图、预测覆盖层、状态、模型版本和用户可行动作;不要只展示一张正确的结果图。高风险或不确定结果必须能进入人工队列而非被自动确认。
下一章会把文本、图像、音频等模态组合起来。保留本章的工作法:输入契约、数据卡、任务化输出、空间或来源证据、切片评估、权限边界、成本预算和回滚。模态变多不会消除这些责任,只会让接口和错误地图更重要。
| 交付物 | 最低内容 | 验收问题 |
|---|---|---|
| 数据卡 | 来源、许可、切分、缺口、删除 | 输入能追溯吗? |
| 任务协议 | 标签、坐标、状态、非目标 | 输出可解释吗? |
| 模型 manifest | 权重、预处理、阈值、版本 | 能重放吗? |
| 评估报告 | 切片、基线、失败样例、限制 | 结论有证据吗? |
| 安全测试 | 权限、文件、隐私、注入 | 越界会阻断吗? |
| rollback | 旧版、门槛、步骤、回放 | 坏了能恢复吗? |
官方与原始参考
建议对照阅读 ResNet、Vision Transformer、CLIP、DDPM 和 LLaVA 的原始论文;实现与实验可参考 TorchVision 文档 和 Transformers 文档。阅读时记录模型版本、数据来源、任务设置和你自己的复现实验。
课后复习与易错
易错一:把像素数组当作现实。输入格式、光照、采集和压缩决定模型的可见范围。
易错二:随机按图片切分。视频帧、同一主体和近重复图会泄漏。
易错三:只看总体准确率。类别不均衡、小目标、遮挡和设备切片都可能失败。
易错四:把 VLM 的流畅描述当作观察事实。需要区域、工具或人工证据。
易错五:把生成图当作真实来源。生成内容必须和检索、引用、事实验证分开。
易错六:只在成功图片上演示。低质量、越权、删除和服务降级同样需要测试。
提交数据卡、任务协议、输入验证、模型 manifest、预测覆盖层、固定评估集、错误地图、安全测试、README 和回滚演练;写下进入多模态章节前最想验证的一个问题。
项目交付复核标准
最终项目应让一位没有参与开发的同学从干净目录完成安装、获得允许的数据、运行假模型或真实模型、读取结构化结果并复现一条评估命令。README 要写清楚资源需求、环境变量、失败状态、数据许可、模型限制和不适用场景,不依赖口头说明。
验收演练覆盖正常、空图、低质量、未知类别、越权、删除、工具超时、成本超限和回滚。每种情况都要有日志、用户可见状态和下一步动作;如果只能展示成功截图,说明系统还没有完成可交付闭环。