简介:面向参加第六届中国研究生人工智能创新大赛华为专项赛的研究生、指导教师与算法爱好者,这份docx聚焦赛题官方说明与备赛要点,适合在选题、方案设计与提交前核对要求时查阅。文档围绕“AI助力提升未知无规则缺陷图像检测能力”和“样本稀疏场景下的数值类预测”两道赛题展开,梳理题目背景、主要挑战(小样本缺陷检测、参数量与推理效率约束;转化样本稀疏、延迟反馈与冷启动)、具体任务、评分构成、提交材料及参考数据集与文献,并给出咨询专家信息,便于读者快速理解命题意图和技术边界。资源包共1个docx文件,约576KB,体量轻便,适合本地检索与打印批注。目前已有189人学习,可作为参赛团队拆解任务、规划模型与对照验收指标的入口材料。
1. 选题这一步就走错:七道赛题里真正决定成败的是验收路径
拿到这份赛题文档,多数人第一反应是翻到评分表,挑权重最高的那道。带过几轮类似的方案评审之后我发现,最容易出问题的地方恰恰是这一步:有的题数据能立刻下载、指标能在本地跑出来;有的题关键数据在出题方手里,你连自家模型到底几分都不知道;还有的题交付物里明确要求一份可解释性文档,写不出来直接扣人工分。选题的真正依据不是难度,而是验收路径有没有闭合:你能不能在没有真值的情况下,自己造一套自己信得过的评估闭环。下面把七道人工智能赛题拆成一套可复用的方案骨架,从选题、四层结构、关键模块实现一路讲到提交前的自查清单与答辩技巧,课程设计和毕设也能照着改。
2. 赛题拆解:七道题的评分权重与交付物对照
七道题表面上是七个不相干的方向,落到工程上其实只有三类:一类比精度,一类比泛化,一类比交付质量。先把文档里的评分规则摊开看,再决定投入哪一道,远比上来就调模型划算。很多人盯着「检测精度权重最高」这句话就冲进去了,忽略了前面还有三项门槛指标在卡人。
2.1 把评分公式翻译成技术约束
先看第一道题的权重描述:模型数量、参数量、推理效率、检测精度,权重依次上升。翻译过来就是——精度是主战场,但前三项是门槛,模型数量多、参数大、单图慢的方案,精度再高也上不去。同时总分被切成竞赛得分 40% 和专家评分 60%,专家那 60% 用的是内部未公开数据,考察的是泛化性。这条规则的含义很直接:公开测试集能刷到的分数上限只有四成,剩下六成靠方案文档、可解释性和泛化设计。把八成的精力砸在公开集上刷 0.5 个 IoU,是把力气用错了地方。
其余几道题的规则也遵循同样的逻辑,我把关键约束整理成一张对照表,选题时直接对着看:
| 赛题方向 | 核心指标 | 硬约束 | 交付物 |
|---|---|---|---|
| 未知缺陷图像检测 | 分割 IoU、缺陷分类标签 | 模型数量少、参数量小、单图推理快 | 分割结果图、可解释性文档、代码 |
| 稀疏样本数值预测 | 转化率预估精度 | 正负比约 1:10000、存在延迟反馈、新广告冷启 | 模型说明、代码、数据集说明 |
| Agent 设备规划控制 | 操控准确率、运行速度、泛化性 | 插件规模 2000+、多步并行规划 | 工作流、≥1000 条评估数据集 |
| 大模型内容安全评测 | 对齐鲁棒性相关指标 | 不得对线上服务做测试 | 方案文档、过程记录 |
| 细粒度猫狗识别 | 品种识别 + 个体识别准确率 | 网络 ≤50MB、输入 224×224 | 模型文件、方案文档、代码 |
| AI 辅助开发 | 打榜判分 + 五项人工评审 | 固定底座模型、函数级完整输出 | Prompt 方案、代码、复现说明 |
| 图像质量评估 | PLCC、SROCC + 单图耗时 | 仅 CPU、禁用官方外数据 | output.txt、readme.txt |
表格里最右一列比中间两列更值得先看。交付物决定了你最后两周是通宵补文档还是从容收尾,而文档分在专家评审里往往占到一半。
2.2 三类可行性:能闭环、半闭环、只能自建评估
第一类是本地能完全闭环的:未知缺陷检测、细粒度宠物识别、图像质量评估、AI 辅助开发。这四道题都有公开训练集,指标也能在本地算出来——IoU 能算、品种准确率能算、PLCC 和 SROCC 更是几行代码的事。闭环意味着你可以做 A/B 对比,可以判断一次改动到底是涨了还是玄学波动,这是方案能迭代下去的前提。
第二类是半闭环的:稀疏样本下的转化率预估。公开数据能跑出 AUC,但线上真实分布和公开集差得远,正负比一万比一这种极端稀疏度,本地调出来的阈值到评测集上大概率要重来。这类题的策略是「结构优先」——把 ESMM 这类全空间建模、延迟反馈加权、负采样校准这些结构性设计做扎实,别指望靠调参撞大运。
第三类只能自建评估:Agent 设备规划控制。它要求你自己造一份不少于一千条、控制指令不少于二十种的评估集,这份评估集的质量基本等于方案质量。听起来吓人,其实是好事——评估集本身就是交付物,你造得越细,专家看得越明白。两人小队我一般建议选第一类,稳;有工程底子、想把评估体系当亮点的,选第三类。
2.3 选题打分表:五个维度各打一分
真到定题那一步,我会拉一张五分制的表:数据可获得性、指标可本地复现、算力门槛、交付物工作量、创新空间。任何一项低于 2 分就要慎重。经验值是总分低于 15 分的题,后面一定会在某个环节卡住你两周以上——要么是数据拿不到,要么是算力不够复现 baseline,要么是文档写不出新意。
算力这一项特别容易被低估。细粒度识别限死 50MB 网络规模,听起来是减负,实际上意味着你要在剪枝、量化、蒸馏上做完整实验才能压进预算,训练轮次反而更多。缺陷检测那边如果要跑多尺度特征融合,显存占用也不低。选题时就该把「我有什么卡、能跑几天」写在纸上,再回头看那张评分表。
3. 总体方案设计:数据—模型—评估—交付四层骨架
七道题看着分散,落到工程上是同一套骨架:数据层负责把少量真实样本撑到能训,模型层在参数量、时延、模型数量三个约束下找平衡点,评估层保证本地指标和评测口径一致,交付层让评委能一键跑起来。这四层任何一层缺位,最后都会以「分数不明原因偏低」的形式反噬。
3.1 四层结构与时间分配
数据层往下是模型层,模型层往上必须回接到评估层,评估层的结论再反推模型改动,这是个环,不是流水线。交付层看起来最轻,实际决定了专家评分的天花板——一份跑不起来的代码,方案写得再漂亮也是零分。
我一般按这个比例切时间,四周的周期大致如下:
| 阶段 | 时间占比 | 必须产出的东西 |
|---|---|---|
| 数据与评估闭环 | 25% | 划分文件、本地指标脚本、基线分数 |
| 基线跑通 | 20% | 一个能跑通的单模型 + 完整指标 |
| 主攻模块 | 35% | 精度/时延/参数量的改进对比表 |
| 交付与文档 | 20% | 一键复现脚本、可解释性文档 |
评估闭环排在最前面,是血泪经验。先有指标脚本再有模型,你才知道每次改动值不值;反过来做,很容易在两周后发现自己一直在优化一个算错的分数。
3.2 数据层:少量真实样本下的配比与泄露防护
真实样本少是七道题里五道都有约束,通行做法是三条腿走路:几何与光照增强撑多样性,缺陷贴图合成撑类别,公开数据集撑底量。合成这一步值得认真做,直接随机贴一块上去会有明显的「贴纸感」,模型学到的是边界而不是缺陷本身。用泊松融合把缺陷 patch 融进正常图,纹理过渡自然得多:
import cv2, random def paste_defect(bg, patch, mask, scale=(0.05, 0.25)): """把缺陷 patch 融合到正常图上,用于扩充训练集""" h, w = bg.shape[:2] s = random.uniform(*scale) # 缺陷面积占比,控制大小分布 pw, ph = max(8, int(w * s)), max(8, int(h * s)) patch = cv2.resize(patch, (pw, ph), interpolation=cv2.INTER_LINEAR) mask = cv2.resize(mask, (pw, ph), interpolation=cv2.INTER_NEAREST) x, y = random.randint(0, w - pw), random.randint(0, h - ph) center = (x + pw // 2, y + ph // 2) # NORMAL_CLONE 保留背景梯度,避免出现硬边 return cv2.seamlessClone(patch, bg, mask, center, cv2.NORMAL_CLONE)scale的取值区间决定了合成缺陷的尺寸分布,最好照着真实样本里缺陷面积的直方图来定,别拍脑袋。mask的边界质量直接决定融合效果,用原图的缺陷掩码做形态学腐蚀再放大,比手工画框靠谱。合成样本只进训练集,验证集和本地测试集必须全部用真实样本,否则指标是假的。
比增强更容易翻车的是划分方式。工业缺陷往往是同一批次、同一批次内多个样品带同一种缺陷,按图片随机划分会把同源缺陷同时分到训练和验证两边,本地验证分数虚高十个百分点以上。正确做法是按样品或批次整体划分,宁可比训练集小,也要保证验证集干净。
3.3 模型层:参数量、时延、模型数量的三角约束
单模型要同时覆盖已知和未知缺陷,思路是把任务拆成两半:未知缺陷靠无监督的异常检测拿到「哪里有异常、异常有多强」,已知缺陷靠一个极轻的分类头拿到标签。这样一套主干加两个头,模型数量是一,参数量能压到 5M 以内。
关键参数我一般写成配置常量,改的时候一目了然:
BUDGET = { "backbone": "mobilenet_v3_small", # 约 2.5M 参数,够用且推理快 "input_size": (512, 512), # 缺陷偏小,512 比 224 更稳 "feature_layers": ["stage3", "stage4"], # 浅层抓纹理,深层抓大缺陷 "coreset_ratio": 0.01, # 记忆库采样比例,直接决定 kNN 耗时 "max_params_m": 5.0, # 参数量硬上限 "max_latency_ms": 120, # 单图端到端耗时上限 }feature_layers选两层是有讲究的:只取深层,细划伤这种小目标会丢;只取浅层,大面积多区域缺陷又分不清。coreset_ratio是最灵敏的一个旋钮,从 0.1 降到 0.01,记忆库小十倍、kNN 快十倍,精度通常只掉一到两个点,这个交换在参数量和时延双约束下基本是必做的。max_latency_ms要在目标硬件上实测,不是在你本地的工作站上测。
3.4 交付层:评审能一键跑起来的目录约定
交付目录不需要多漂亮,但必须让人在三分钟内跑通。我固定的结构是:data/放数据说明而不放数据本身,models/放权重,src/放全部源码,根目录一个run.sh加一个README.md。README 里只写三件事:环境怎么装、命令怎么敲、预期输出长什么样。少写背景,多写命令。
还有一处常被忽略:把预处理参数固化进代码或配置文件,别写在文档里靠人记。归一化均值方差、resize 的插值方式、通道顺序,这三项任何一项和训练时不一致,评测分数就会莫名其妙掉一大截。我在src/里单开一个preprocess.py,训练和推理共用同一份实现,从根上消灭这种不一致。
4. 关键模块实现:缺陷检测与稀疏转化预估两条主线
七道题实现细节各不相同,但有两类模块是可以复用的:一类是「异常定位」,缺陷检测、图像质量评估都在用它;一类是「稀疏标签建模」,转化率预估是典型。把这两个模块写扎实,换题的时候只改数据接口。
4.1 单模型覆盖已知与未知:patch 特征记忆库
未知缺陷没法监督训练,只能用正常样本建模,推理时看哪些区域偏离正常分布。做法是从正常图里抽 patch 级特征,压成一个记忆库,推理时对每个 patch 做最近邻检索,距离即异常分数。
import torch, torch.nn.functional as F @torch.no_grad() def build_memory_bank(loader, backbone, layers, ratio=0.01, seed=0): """只用正常样本构建记忆库,推理阶段不再更新""" feats = [] for img, _ in loader: maps = backbone(img, out_layers=layers) # 多层特征对齐到同一分辨率后拼接,兼顾纹理与大尺度缺陷 maps = [F.interpolate(m, size=maps[0].shape[-2:], mode="bilinear") for m in maps] f = torch.cat(maps, dim=1) f = F.avg_pool2d(f, 3, stride=1, padding=1) # 3x3 邻域平滑,抑制噪声 feats.append(f.permute(0, 2, 3, 1).reshape(-1, f.shape[1])) bank = torch.cat(feats, dim=0) g = torch.Generator().manual_seed(seed) idx = torch.randperm(bank.shape[0], generator=g)[: int(bank.shape[0] * ratio)] return F.normalize(bank[idx], dim=1) # 归一化后可用余弦距离avg_pool2d那一步是稳定性的关键,不做邻域平滑,单像素噪声会在异常图上炸出一片假阳性。F.normalize之后用余弦距离,阈值就可以按正常样本分数的分位数来定,换个数据集也不用重调。推理时的异常分数取每个 patch 到记忆库的 top-k 距离均值,k 取 3 到 5 之间比较稳。
这套结构天然能报「未知」:任何偏离正常分布的区域都会被高亮,不需要事先知道缺陷叫什么名字。已知缺陷的分类则交给 4.2 的实例分类头,两条路互不干扰。
4.2 从异常图到分割结果与分类标签
赛题要求同时给出分割结果图和分类标签,中间差一步「异常图转实例」。连通域分析是最省事的做法,但面积过滤一定要做,否则一堆碎片会把 IoU 拖下去。
import cv2, numpy as np def anomaly_to_instances(score_map, threshold, min_area=30): """异常热图 -> 连通域 -> 每个缺陷一个实例,供分类头打标签""" mask = (score_map > threshold).astype("uint8") num, labels, stats, _ = cv2.connectedComponentsWithStats(mask, connectivity=8) insts = [] for i in range(1, num): x, y, w, h, area = stats[i] if area < min_area: # 过滤噪点,避免碎片拉低 IoU continue insts.append({ "box": (x, y, w, h), "area": int(area), "score": float(score_map[labels == i].max()), }) return inststhreshold不要写死,用正常样本异常分数的 99 分位定,这样换产线、换光照都不用改代码。min_area和 IoU 的关系是反直觉的:调大它,召回降一点,但误检掉得更快,整体 IoU 往往反而涨。我一般从 20 开始往上扫,画一条 IoU 随min_area变化的曲线,取顶点。
分类标签的设计要兼顾「已知」和「未知」。已知类别走分类头输出具体名字,分数低于置信阈值的,统一归到「未知-形态描述」这种自造标签下——比如按长宽比和面积分成「未知-线状」「未知-斑状」「未知-多区域」。这样未知样本也有标签,评测方看结果图时能明白你识别到了什么。
可解释性文档就在这一步顺手产出:记忆库检索命中的正常 patch 位置、异常分数在多层特征上的贡献分布、分类头对每个实例的注意力区域,三张图配一段说明,讲清哪一层特征对哪类缺陷起了作用。这件事不能留到最后补,补出来的文档一定是泛泛而谈。
4.3 稀疏样本下的转化率预估:负采样校准与延迟反馈
正负比一万比一,直接训练模型会一路预测零。通行方案是负采样加全空间建模:采样后的预估概率要按采样率反算回去,否则整体偏高,业务侧阈值全废。
import torch, torch.nn.functional as F def esmm_loss(pctr, pcvr, ctr, cvr, delay_w, eps=1e-6, neg_ratio=0.05): """CTR/CVR 联合训练 + 延迟反馈加权,neg_ratio 为负样本采样率""" l_ctr = F.binary_cross_entropy(pctr.clamp(eps, 1 - eps), ctr) # 延迟窗口内未观测到转化的样本降权,缓解假负样本 w = torch.where(cvr > 0.5, torch.ones_like(delay_w), delay_w) l_cvr = F.binary_cross_entropy(pcvr.clamp(eps, 1 - eps), cvr, weight=w) return l_ctr + 0.5 * l_cvr def calibrate(p_s, neg_ratio): """把采样空间下的预估概率还原到全空间""" return p_s / (p_s + (1 - p_s) / neg_ratio)delay_w按「点击到当前的天数」做衰减,窗口越短权重越低,这样模型不会把还没转化的样本当成铁定的负例。calibrate是必须做的一步,缺了它模型在采样空间里是准的,回到全空间就系统性偏高,AUC 好看但业务不可用。联合训练里 CVR 分支的梯度只从点击样本回传,靠的是 pctr × pcvr 这个乘积结构,权重 0.5 是我试下来比较稳的折中,任务偏转化可以调到 0.7。
冷启动那部分,我用类目和素材的 embedding 做先验,新广告的预估往同类目均值收缩,收缩强度随曝光量递减。这个设计写进方案文档里,比堆模型结构更能打动评委。
4.4 评估层:本地复现 IoU / PLCC / SROCC
指标脚本必须和评测口径一致,包括那些容易被忽略的细节:IoU 是逐图平均还是全图汇总、PLCC 之前要不要做非线性拟合、时延是单图还是批处理摊薄。这些差异足以让本地分数和线上分数差出五个点。
import numpy as np from scipy.stats import pearsonr, spearmanr def iou(pred, gt, eps=1e-6): inter = np.logical_and(pred, gt).sum() union = np.logical_or(pred, gt).sum() return float(inter / (union + eps)) def iqa_report(mos, pred, cost_list): """图像质量评估:PLCC 前先做单调映射,SROCC 不需要""" plcc = pearsonr(mos, pred)[0] srocc = spearmanr(mos, pred)[0] return {"PLCC": round(float(plcc), 4), "SROCC": round(float(srocc), 4), "avg_cost_s": round(float(np.mean(cost_list)), 3)}iou逐图算完再取均值,别把所有图拼成一张算,长尾小缺陷会被大图淹没。iqa_report里时延单独统计,因为评分规则里它和相关系数并列;如果规则要求五个维度分别打分,就把它拆成五次调用,每次一个子集的 MOS。整套脚本跑三遍不同随机种子,取中位数写进文档,比报一个最好成绩可信得多。
5. 避坑与排查:五个在提交前一晚才暴露的问题
5.1 本地 IoU 0.8,评测集 0.4
现象是本地验证一路顺畅,提交后分数腰斩。九成原因是预处理不一致:训练用双线性 resize,推理用了默认最近邻;或者归一化用了 ImageNet 均值,训练时其实用的是自定义统计量。解决办法是把预处理抽成单独模块,训练、验证、推理三条路径全部调用同一份实现,并且在推理脚本开头打印一次输入张量的均值和范围,肉眼确认。
5.2 参数量统计口径对不上
现象是本地算出来 48MB,评审那边量出来 62MB,直接被扣分。原因是只统计了主干网络,漏掉分类头、记忆库缓存文件、后处理用到的中间权重。解决办法是提交前用脚本遍历交付目录下所有.pth、.onnx文件累加体积,把记忆库这类非参数但占空间的缓存也算进去。上限 50MB 的题,压到 45MB 再提交,留余量。
5.3 推理时延测出来很好看,实测超一倍
现象是本地测 40ms,评审测 100ms。三个常见原因:本地测的是批处理摊薄后的单图时间,评审是逐图串行;本地算了 GPU 时间,实际部署只有 CPU;首次推理包含模型加载和内存分配,没有剔除预热。解决办法是显式做十次预热、再逐图计时取中位数,并且强制在 CPU 上跑一遍完整流程,把 IO 读取也算进去。
5.4 负采样后概率没校准
现象是离线 AUC 很高,一上线预估转化率整体偏高五到十倍。原因是模型在采样空间里学的是「相对排序」,没做过采样率还原。解决办法就是 4.3 里那个calibrate函数,在推理出口统一做一次反算,并且在文档里写清楚采样率取值。这一条在稀疏场景里几乎必犯,写完代码先自测一遍预估均值是否接近真实正样本比例。
5.5 可解释性文档写成了模型介绍
现象是文档洋洋洒洒十页,评委看完不知道哪些节点对哪些缺陷起了作用。原因是通篇在讲网络结构,没有落到「特征—缺陷形态」的对应关系上。解决办法是提前准备好三张图:正常样本检索命中位置、多层特征的异常贡献热力图、分类头的注意力区域,每张图配一句结论,比如「深层特征对多区域缺陷的响应比浅层高 2.3 倍」。有数据、有对比、有结论,才叫可解释性文档。
6. 验收与答辩:把六成的专家评分变成一份可复现清单
专家评分占大头,且用未公开数据考察泛化,所以答辩现场最有效的一招不是讲模型多新,而是当场证明「换一份数据,我的分数不会崩」。我会准备一份复现清单,逐项过一遍再上场:
| 检查项 | 验证方式 | 通过标准 |
|---|---|---|
| 环境可复现 | 干净容器里按 README 装一遍 | 无手动步骤,一次成功 |
| 推理可复现 | 换机器、换路径、换种子跑三次 | 指标波动 < 0.5 个点 |
| 泛化可验证 | 留出一个未参与训练的批次做盲测 | 掉点幅度写在文档里 |
| 资源达标 | 统计权重大小、逐图计时 | 参数量与时延均留 10% 余量 |
| 文档可对照 | 每个结论都能指到一张图或一张表 | 无孤立的定性描述 |
答辩讲述顺序也有讲究。开头三分钟不要放架构图,直接放一组对比:同一张缺陷图,基线模型的漏检区域和你方案的检出区域并排,配上 IoU 数字。评委的注意力只有前几分钟,先把「解决了什么问题」摆出来,后面再讲怎么做到的。中间讲消融,每一条改动对应一个指标变化,讲不清楚涨在哪的改动就删掉,留着反而会被追问。最后留一页讲失败案例,主动说清哪类缺陷仍然漏检、为什么,比被问出来强得多。
有个细节值得单独说:盲测。自己留一个从未参与训练和调参的批次,跑完把掉点幅度写在文档首页。这件事做了,泛化性这个话题你就掌握了主动权;不做,评委一问「换产线还行吗」就只能靠嘴硬。我一般留 15% 的真实样本做这件事,宁可牺牲一点训练量。
从那以后我每次提交前都强制走一遍「换机器、换路径、换随机种子」的三换测试,跑不通就不提交,跑通了才写文档。这套习惯救过我两次,一次是硬编码的绝对路径,一次是没锁版本的依赖。希望帮到你。
本文还有配套的精品资源,点击获取