news 2026/9/30 3:57:20

开悟AIArena暑假赛深度学习竞赛:从基线到提分实战复盘

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
开悟AIArena暑假赛深度学习竞赛:从基线到提分实战复盘

1. 先把这场比赛在考什么搞明白

1.1 拆开标题里的三个词

我报名这次暑假赛之前,先花了一个晚上把标题里的三个词拆开看:开悟、AIArena、暑假赛。这三个词各自代表一种约束,理解错了,努力方向就会偏。

开悟是平台属性,意味着它带着明显的教学和引导色彩——官方一般会给任务说明、基线代码、数据说明文档,甚至给一些预备知识清单。这一点跟纯粹的工业比赛不一样,工业比赛常常只给你一堆数据和一句"预测目标值",剩下全靠自己猜。有引导的好处是上手快,坏处是很多人会直接复制官方基线然后原地不动,最后卡在一个不上不下的分数上。

AIArena是竞技属性,核心就是排行榜。排行榜意味着你的模型要在一个你看不见的测试集上跑出分数,也意味着你没法靠"我本地验证集99%"来自我安慰。这个属性直接决定了后面所有的技术选择:必须防过拟合,必须做稳定的验证切分,必须留出提交次数。

暑假赛是时间属性。周期短、集中、连续,通常两三周到一个多月。这个约束最容易被新手忽略,但它其实决定了你的策略应该是"快速迭代多个可复现的实验"而不是"死磕一个模型调到底"。

把这三层想明白之后,我给自己定了一个原则:先保证有一个能稳定提交的基线,再谈提分。这个原则在后面救了我至少三次。

1.2 我的三条线打法:基线线、提分线、认知线

参加这类比赛,最容易出现的问题是"东一榔头西一棒子"——今天看到别人用卷积网络提了分,赶紧换;明天看到有人用数据增强又提了分,又赶紧加。结果是实验记录一团乱,最后连哪个改动有效都说不清。

我给自己划了三条并行的线。

基线线的任务只有一个:跑通。数据能读进来、模型能训起来、结果能提交上去、榜单上有个分数。哪怕这个分数很低,只要流程是通的,基线线的任务就算完成。我在这次比赛里用的基线是一个两层全连接网络,验证集准确率比瞎猜好不了多少,但它让我在开赛第二天就完成了第一次提交。

提分线的任务是找"性价比最高的那几刀"。注意是"性价比最高",不是"效果最好"。有些改动能提0.5个点但要重训八小时,有些改动能提0.3个点只要改三行代码,后者明显更值得先做。我给自己定了个粗略的优先级:数据层面的改动 > 训练策略层面的改动 > 模型结构层面的改动 > 集成层面的改动。

认知线最容易被忽略,但对我个人价值最大。我每天收工前会花十分钟写一句复盘:今天试了什么、结果如何、为什么。这个习惯看着很土,但在比赛后半程,当我需要对十几个实验做取舍的时候,这份记录就是唯一可靠的东西。

1.3 四十天的时间节奏怎么排

时间分配上我踩过坑。第一次参赛的时候我前十天全在"学习理论",等到要写代码了发现手生,又花五天重新捡起来。这次我换了个更实用的排法,把学习和动手交替起来。

阶段大致天数主要目标交付物
热身期第1-5天环境跑通、看完任务说明、跑通官方基线一次成功提交
基线期第6-12天搭自己的训练脚本,固定验证集可复现的训练代码
提分期第13-28天数据增强、结构调整、调参实验记录表
冲刺期第29-38天模型融合、TTA、结果稳定化最终提交方案
复盘期第39-40天整理代码与笔记可复用的项目模板

这张表真正有用的地方不是天数,而是每个阶段都必须有明确交付物。没有交付物的阶段,时间一定会被浪费掉。我个人最看重的是"基线期",因为一个可复现的训练脚本,价值远大于一次偶然的高分。

2. 赛前准备:环境、数学、资料三件事

2.1 环境配置的核心是先算清楚显存

深度学习环境这件事,新手最容易陷入的误区是"先把框架装上再说"。我的建议是先反推:手头有多少算力,再决定用什么框架、什么模型规模。

显存估算有个粗略但好用的公式。以训练为例,显存占用大致等于:

参数量 × 4字节(权重) + 参数量 × 4字节(梯度) + 参数量 × 8字节(Adam的两个动量) + 激活值

也就是说,用Adam训练一个1000万参数的小模型,光优化器相关就要占掉大约160MB,加上激活值往往要到几百MB。这只是保守下限,实际能不能跑起来还要看batch size和输入分辨率。我一般会先把batch size设成8或者16试一次,跑得动再往上加。

环境创建我习惯用conda,隔离得干净,出问题直接删掉重建:

conda create -n kaiwu python=3.10 -y conda activate kaiwu pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install numpy pandas matplotlib scikit-learn tqdm tensorboard

这里有两个细节值得说。第一,Python版本不要追最新,3.10左右是最稳的区间,太新的版本经常遇到某个依赖还没出对应轮子,编译到一半报错。第二,框架和驱动版本要对应,我遇到过驱动版本偏低导致装完框架torch.cuda.is_available()返回False的情况,查了两个小时才发现问题在驱动。

装完之后一定要写三行验证代码:

import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else "CPU only")

这三行的意义在于:在写任何模型代码之前,先把"是环境问题还是代码问题"这个变量排除掉。后面调参调到怀疑人生的时候,你会感谢自己做了这一步。

至于用本地机器还是用平台提供的在线环境,我的判断标准很简单:如果数据集规模在几个GB以内、模型参数量在千万级以下,本地跑就够了;如果数据量很大、或者本地显卡显存不足,就直接用平台环境,别在环境上耗时间。比赛期间时间是最贵的资源。

2.2 数学部分只需要一个"最小必要集"

很多人一提到深度学习的数学就打退堂鼓,其实打比赛用到的数学远比想象中少。我自己总结的最小必要集只有三块:泛化误差、反向传播、偏差方差。

先说自己感受最深的泛化误差。训练集上的误差叫经验误差,测试集上的误差叫泛化误差,两者之间的差距叫泛化间隙。比赛里所有的技术动作,本质上都是在做同一件事:让泛化间隙变小。数据增强是让模型见过更多变化、正则化是限制模型复杂度、早停是防止模型在训练集上跑太远。想明白这一层,就不会再盲目堆技巧了。

反向传播我一开始是被推导过程吓住的,后来发现抓住一句话就够了:它是链式法则的高效实现。前向传播算出预测值和损失,反向就是把损失对每一层参数的偏导从后往前一层层乘回来。真正需要理解的不是公式本身,而是它的两个推论:一是靠近输入的层梯度容易变小,这就是深层网络难训的根源;二是学习率太大时梯度更新会震荡,因为乘出来的梯度链被放大了。

偏差方差这一对概念解释了很多现象。模型太小、容量不足,偏差高,表现是训练集和验证集都差,这叫欠拟合;模型太大、数据太少,方差高,表现是训练集很好但验证集差,这叫过拟合。这两个诊断结论直接决定你下一步该加参数还是该加正则,判断错了会浪费好几天。我在热身期就遇到过这个问题,验证集准确率一直卡在六成左右,我第一反应是模型不够强,加了一层又一层,结果毫无起色。后来把训练集准确率打出来一看,训练集也只有六成多——这明显是欠拟合,该做的是把学习率调大、把训练轮数加够,而不是加层数。

2.3 资料清单和它们的正确打开方式

资料这块我的态度是:不要贪多,但要知道每份资料是干什么用的。

吴恩达的课程适合打地基,讲得慢但清楚,尤其是关于正则化、优化算法、诊断模型的几节,属于看一遍就能用上的内容。缺点是作业偏简单,光看完课不动手,写代码时还是会卡。

《深度学习入门:基于Python的理论与实现》这类书,价值在于从零实现一遍前向和反向。很多人觉得"有框架了为什么还要手写",我的实际体会是:手写一遍之后,你对"张量形状不对"这类报错的敏感度会提升一个档次,因为你知道每一步的形状是怎么来的。

邱锡鹏那本《神经网络与深度学习》更偏理论体系,适合在遇到"为什么这么做"的问题时去查,不适合从头到尾啃。动手深度学习那本更偏工程实践,代码多,适合边看边敲。

至于MATLAB那边的神经网络工具箱,我个人的用法是拿它做快速验证。工具箱里拖几个模块就能搭出一个前馈网络,用来验证一个想法值不值得投入时间,比写Python快得多。真要打比赛,长期还是得回到代码里,因为可定制性差太多了。

工业视觉方向还有专门的深度学习工具,比如Halcon的深度学习模块,它的优势是训练和部署一体化,做缺陷检测这类落地项目非常省事。但比赛阶段用它意义不大,因为比赛的评测接口是固定的。我把它列进学习清单,是为将来做工程项目留的后路。

提示:资料看得再多,也不如把一个数据集从头到尾跑三遍。每跑一遍你会注意到之前完全没留意的问题。

3. 网络结构选型:全连接、卷积、循环到底怎么用

3.1 前馈网络和BP:最容易被跳过的那个基线

前馈神经网络,也就是常说的多层感知机,结构简单到一句话能说完:输入层、若干隐藏层、输出层,层与层之间全连接。它的训练靠的就是反向传播加梯度下降。

我建议每个人都用MLP先跑一个基线,理由有两层。第一层是工程上的:MLP的代码最短,出问题的概率最低,跑通它意味着数据管道、训练循环、验证逻辑、提交格式都没问题了。第二层是认知上的:MLP的参数量你算得清楚,因此你知道模型容量到底有多大。

举个具体例子。输入是28×28的灰度图,展平后是784维,接一个256维隐藏层,再输出10类:

  • 第一层参数:784 × 256 + 256 = 200,960
  • 第二层参数:256 × 10 + 10 = 2,570
  • 合计约20.4万

一个20万参数的小网络,在几万条数据上的表现基本就是"能跑但不惊艳"。这个认知很重要,因为它给了你一个参照系:后面换成卷积网络后参数量降到了几万,效果反而更好,你就能直观理解"参数量不等于能力"。

用MLP有几个实操注意点:

  • 输入一定要归一化。像素值从0-255压到0-1,损失曲线会平顺很多,不归一化很容易出现第一轮损失就炸掉的情况。
  • 权重初始化别用全零。全零会导致同一层的神经元梯度完全相同,网络退化成只有几个有效单元。用默认的Kaiming或者Xavier初始化就行。
  • 随机种子要固定。同一份代码两次跑出不同结果,排查起来非常痛苦。

3.2 图像任务里为什么卷积网络能压住全连接

"图像处理为什么用CNN不用前馈网络"这个问题,我一开始的答案很敷衍——书上都说CNN好。后来自己算了一遍参数量,才算真的理解。

还是28×28的输入。如果用全连接,第一层每个神经元都要连784个输入,256个神经元就是20万个参数。而一个3×3的卷积核,即使输出32个通道,参数量也只有3 × 3 × 1 × 32 + 32 = 320个。差了三个数量级。

但参数量少只是表象,真正的差别在归纳偏置。图像有两个天然性质:局部相关和平移不变。相邻像素关系密切,一个特征出现在左上角还是右下角,本质是同一个特征。卷积通过局部连接和权重共享,把这两条先验直接写进了结构里。全连接网络没有这个先验,它必须从数据里学出"左上角的角和右下角的角是同一回事",这需要大量样本。

我用一张表概括一下两者的差别:

维度前馈网络(MLP)卷积网络(CNN)
参数规模随输入尺寸平方增长与输入尺寸基本无关
空间结构展平后丢失邻接关系保留二维邻接关系
平移不变性需要从数据中学结构自带
小数据集表现容易过拟合相对更稳
适合的场景表格数据、低维特征图像、语音谱、时序信号

卷积网络的经典入门结构是LeNet-5这类小网络:两个卷积层加池化,再接全连接分类头。它的层数很浅,但在手写数字这种任务上表现相当好。我建议第一次搭CNN就从这种结构开始,别一上来就堆ResNet,因为你还没建立"每加一层会发生什么"的直觉。

搭CNN时我踩过的坑集中在形状上:

  • 卷积分辨率和通道数要一起看。经过几次下采样后,特征图会变得很小,这时候再加池化可能直接就变成1×1了。
  • 全连接层之前的展平维度一定要算准。我最常犯的错就是这里,解决办法是在展平前打印一次形状。
  • 批归一化的位置。一般放在卷积之后、激活之前,用起来收敛会明显更快。

顺便说一下ViT和EfficientNetV2这类相对新的结构。ViT把图像切成patch当作序列处理,在数据量大的时候表现优异,但数据量小的时候往往不如CNN,因为它缺少卷积的那套先验,需要更多数据来补。EfficientNetV2则在精度和速度之间做了比较好的平衡,做图像分类时可以直接拿来当骨干网。我的建议是:比赛初期先用自己搭的小CNN建立基线,中期再考虑换骨干网,因为换骨干会引入一堆新的超参,需要重新调。

3.3 序列任务里的循环网络和它的替代选项

如果任务涉及序列——文本、时序信号、音频帧——那单靠卷积就不太够了,需要能记住"上文"的结构。

循环神经网络的核心思想是维护一个隐藏状态,每一步都把它和当前输入一起送进网络,更新后再传给下一步。它在结构上天然适合变长序列。但基础的RNN有个硬伤:梯度消失。序列一长,反向传播时梯度连乘很多次,很快就趋近于零,模型学不到长距离依赖。

LSTM通过门控机制缓解了这个问题:遗忘门决定丢掉多少旧信息,输入门决定写入多少新信息,输出门决定暴露多少给下一步。这套机制让LSTM在长序列上稳定很多,代价是参数量翻了几倍,训练也更慢。

现在的实际选择通常是这样:

  • 序列不长、追求速度:一维卷积就能做得不错,把序列当一维图像处理。
  • 序列较长、需要长距离依赖:LSTM或者GRU。
  • 数据量大、有充足算力:注意力机制那一类结构,效果通常更好,但对数据和算力要求更高。

还有一个方向值得一提,就是把图结构引进来。如果数据本身带有关系结构(比如节点之间的连接关系),图神经网络会比单纯堆卷积或循环层更合适。我这次比赛没用到,但在看别人的方案时注意到,处理关系型数据的队伍里用图结构的不少。这条线可以作为暑假之后的延伸方向,慢慢啃。

3.4 选型拿不准时看这张表

实战中我基本是靠这张表做第一轮决策的,能省掉大量犹豫时间:

任务形态首选结构备选主要风险
表格/低维特征MLP梯度提升树特征未归一化导致不收敛
二维图像分类小CNN预训练骨干网输入尺寸与下采样不匹配
长序列建模LSTM/GRU一维卷积序列过长导致训练慢
关系型数据图结构网络手工特征+MLP图构造方式不对,白做
数据极少预训练+微调强增强+小模型直接训练必然过拟合

这张表的用法是"先定方向,再调细节"。方向错了,调参调到天亮也没用。

4. 一次完整实操:从读数据到提交榜单

4.1 数据检查:先看,再动手

我现在养成了一个习惯:拿到数据的前半小时不写任何模型代码,只看数据。这一步看起来浪费时间,实际上是最省时间的一步。

要看的东西包括:类别分布是否均衡、图像尺寸是否统一、有没有损坏文件、标签有没有明显错误。我这次就发现训练集里有几十张图尺寸和其他样本不一样,如果直接送进网络,会因为维度不匹配直接报错,排查起来又是半小时。提前发现,统一resize就解决了。

数据划分上,我的做法是先用固定随机种子切出验证集,一般取训练数据的15%到20%。如果类别不均衡,就分层抽样,保证验证集的类别分布和训练集一致。这个细节很重要,因为验证集分布偏了,你会得到错误的反馈信号,据此做的所有调参决策都是错的。

import numpy as np from sklearn.model_selection import train_test_split SEED = 42 X_train, X_val, y_train, y_val = train_test_split( X, y, test_size=0.15, random_state=SEED, stratify=y )

4.2 一个可以反复复用的训练脚本骨架

比赛期间我的经验是:训练脚本要写得"笨"一点,但必须稳定。花哨的写法在调参阶段会变成负担。下面这个骨架我用了整个暑假,改动很少。

import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset from tqdm import tqdm def set_seed(seed=42): torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) np.random.seed(seed) def train_one_epoch(model, loader, optimizer, criterion, device): model.train() total_loss, correct, total = 0.0, 0, 0 for x, y in tqdm(loader, leave=False): x, y = x.to(device), y.to(device) optimizer.zero_grad() out = model(x) loss = criterion(out, y) loss.backward() optimizer.step() total_loss += loss.item() * x.size(0) correct += (out.argmax(1) == y).sum().item() total += x.size(0) return total_loss / total, correct / total @torch.no_grad() def evaluate(model, loader, criterion, device): model.eval() total_loss, correct, total = 0.0, 0, 0 for x, y in loader: x, y = x.to(device), y.to(device) out = model(x) loss = criterion(out, y) total_loss += loss.item() * x.size(0) correct += (out.argmax(1) == y).sum().item() total += x.size(0) return total_loss / total, correct / total

有了这两个函数,主循环就只剩十几行:每轮训练、每轮验证、记录最好的那一版权重。

关键点在于"保存验证集最优权重",而不是保存最后一轮的。训练轮数给多了以后,模型一定会在某个点之后开始过拟合,保存最后一轮等于主动放弃了前面最好的状态。我这次比赛里,验证集最优出现在第23轮,而我一共训了40轮,如果不做这个保存,分数会低一截。

4.3 超参数的取值逻辑,不是玄学

超参调参我以前是靠感觉,后来发现其实有比较清晰的逻辑链条。

学习率是最关键的一个。它太大,损失会震荡甚至发散;太小,收敛慢到让人绝望。我的做法是先做一次粗略的扫描,取值在1e-1到1e-4之间跨数量级试几个,看哪一段损失下降最快,再在这个区间内细化。经验值是:配合Adam,1e-3是个很稳的起点;用SGD的话,1e-2左右更常见。

批大小跟学习率是联动的。批大小翻倍,学习率大致也可以翻倍,这个缩放关系在多数任务上成立。批大小大的好处是训练稳定、吞吐高,坏处是泛化性有时会略差。小批大小噪声大一些,反而常常能带来更好的泛化。

训练轮数不要靠猜,通过观察验证集曲线来定。我一般会先设一个偏大的值(比如50轮),然后看验证集在第几轮开始不再提升。

参数常见起点表现不对时的信号调整方向
学习率1e-3(Adam)损失震荡或长时间不降先降一个数量级
批大小32/64显存不足或梯度噪声太大结合学习率一起调
权重衰减1e-4训练准确率远高于验证准确率适当加大
训练轮数30-50验证损失开始回升加早停
数据增强强度中等训练准确率上不去减弱增强

早停这个技巧值得单独说。它的实现很简单:记录验证集最优分数,如果连续N轮没有提升就停掉训练。它同时解决了两个问题——省时间和防过拟合。我在比赛后期把早停的容忍轮数设成7轮,效果比较稳。

4.4 提分手段的性价比排序

比赛到中期,你会发现可选的提分手段一大堆,这时候排序就变得非常重要。我的排序大致是这样,从最推荐到最不推荐:

第一档:数据增强和验证集质量。这两件事几乎零成本,收益却很直接。图像任务里,随机裁剪、水平翻转、轻微色彩抖动就能带来一两个点的提升。验证集切分做得干净,你的所有后续判断才有依据。

第二档:训练策略优化。学习率调度(比如余弦退火)、warmup、标签平滑,这些改动通常只要几行代码。

第三档:换更强的模型结构。比如从小CNN换到预训练骨干网。收益可能不小,但代价是重新调参,而且推理时间会变长。

第四档:测试时增强和模型融合。也就是TTA和多模型投票。这类手段能提分,但成本高——TTA会让推理时间翻几倍,多模型融合需要训好几个模型,训练时间成本翻倍。

第五档:伪标签、自训练这类半监督手段。这类方法有一定门槛,做不好反而掉分,建议等前面的都做扎实了再碰。

注意:永远不要同时改两个变量。一次只改一个,跑完看结果,记录,再动下一步。同时改两个,你永远不知道是哪个起了作用。这是我在比赛早期浪费最多时间的地方。

4.5 提交记录表和复盘

排行榜上的分数是最诚实的反馈,但如果不做记录,你很快就会忘记"第7次提交那个0.83是怎么来的"。我用的表格很简单,但收益极大:

序号改动内容验证集分数榜单分数结论
1基线MLP0.710.70跑通流程
2换小CNN0.850.84结构有效
3加随机裁剪0.870.86增强有效
4学习率改1e-30.880.87小幅提升
5换骨干网0.900.89明显提升
6加TTA0.910.91提升有限但值得

这张表最重要的作用是防止重复劳动。人很容易在焦虑的时候反复试已经试过的东西,尤其是隔了几天之后。

5. 踩坑实录和排查速查表

5.1 损失不下降,按这个顺序查

这是我整个暑假遇到最多的问题,后来我固定了一套排查顺序,基本能在半小时内定位。

  1. 先看数据。把一批样本可视化出来,确认图像内容和标签是对应的。我就遇到过标签整体错位一位的情况,这个错很隐蔽,因为模型依然能训出一个看似合理的数字,只是分数上不去。
  2. 确认输入归一化。灰度图像除以255、彩色图像按通道做标准化。归一化没做的时候,损失经常在第一轮就变成nan。
  3. 把学习率降一个数量级。如果损失从稳定变成下降,说明学习率太大。
  4. 检查标签编码。分类任务里,类别标签必须是0到N-1的整数,损失函数要匹配。用交叉熵却传了one-hot标签,会得到一个很小但几乎不变的损失值。
  5. 用一个极小的子集过拟合。拿20条数据训100轮,如果模型不能在训练集上接近100%准确率,那说明代码有结构性问题,跟超参无关。这招非常好用,能在几分钟内区分"模型有问题"和"数据太难"。
  6. 检查是否忘了optimizer.zero_grad()。忘了清零梯度会导致梯度累加,训练直接崩掉。
  7. 检查验证逻辑和训练逻辑是否一致。忘记model.eval()会让批归一化和dropout在验证时行为错误,验证分数会莫名其妙地低。

5.2 过拟合和欠拟合,看两条曲线就够了

这个问题我用一张对比讲清楚。训练集和验证集两条损失曲线,是诊断模型状态最直接的工具。

训练损失下降、验证损失也下降,且两者差距小——健康状态,继续训。 训练损失一直降、验证损失先降后升——典型过拟合。处理方式:加数据增强、加权重衰减、加dropout、减小模型、加早停。 训练损失和验证损失都很高、都降得很慢——欠拟合。处理方式:加大模型容量、提高学习率、延长训练、减少正则强度。

我这次比赛中期就卡在第二种状态上。验证集分数到了一个点就不动了,训练集却还在往上走。当时的应对是加了两项增强:随机旋转和随机擦除,验证集分数又上去了一点。这个经验说明,过拟合不是模型的问题,是数据多样性的问题,从数据侧解决往往比从模型侧解决更有效。

5.3 环境和显存上的坑,都是可以提前规避的

**显存不足(OOM)**是高频问题。我的排查顺序是:先看是不是batch size太大,减半试试;再看是不是验证阶段忘了用torch.no_grad(),验证时也在建计算图,显存会涨得很快;最后看是不是数据加载器积压,把num_workers从0开始试。

训练速度慢有时候不是显卡的问题,而是数据加载成了瓶颈。判断方法很简单:看GPU利用率,如果长期低于50%,瓶颈大概率在数据侧。解决办法是把数据预处理提前做一次,存成numpy数组或者缓存文件,训练时直接读。

随机种子不固定导致结果不可复现,这个坑的代价是巨大的。我现在的做法是在脚本入口处就把torch、numpy、random三个种子全设一遍,并且在训练日志里把种子值打出来。

版本不匹配造成的报错往往很迷惑。我遇到过某个依赖版本升级之后,加载模型权重报键名不匹配的情况。现在我的习惯是:环境跑通之后马上导出依赖清单,后面所有实验都在同一个环境里跑。

pip freeze > requirements_lock.txt

这份锁定的清单,在换机器或者重装环境的时候能省下大量时间。

5.4 报错速查表

现象大概率原因处理方式
损失变成nan学习率过大 / 未归一化 / 除零降学习率,检查数据范围
维度不匹配报错卷积后展平维度算错展平前打印形状
验证分数异常低未调用eval模式验证前加model.eval()
GPU用不上驱动或框架版本不匹配重建环境,跑三行验证代码
训练速度波动大数据加载慢预处理缓存,调整num_workers
多次运行结果不同随机种子未固定统一设置torch/numpy/random种子
提交格式报错列名或行数不符对照样例文件逐列核对

这张表里的每一条我都至少踩过一次。尤其是最后一条,提交格式错误在比赛最后阶段是致命的,因为提交次数往往有限。我的做法是:第一次提交前,先写一个校验脚本,检查行数、列名、取值范围是否与样例一致。这个脚本写一次,后面每次提交前跑一遍,能避免绝大部分低级失误。

5.5 比赛节奏和心态上的两个坑

第一个坑是过早追求高分。开赛第一周就想冲榜,结果基础没打牢,后面反复返工。我现在更认同的顺序是:流程正确优先于分数,分数稳定优先于分数最高。

第二个坑是最后阶段大改方案。我在比赛倒数第二天动过一次模型结构,结果验证集分数上去了,提交之后榜单分数反而掉了。原因很可能是验证集和测试集分布有差异,改动引入了对验证集的过拟合。这个教训让我定了一条规矩:最后三天只做能大幅提升稳定性的改动,比如固定种子多次运行取平均,不做结构性的探索。

如果提交次数有限,我的分配策略是:前期用掉三分之一做探索,中期用掉三分之一做验证,最后留三分之一做保守提交。很多队伍最后发现没有提交次数了,只能眼睁睁看着排名掉下去。

最后再分享一个小技巧。整个比赛期间,我把所有实验目录都按"日期+改动+分数"命名,比如0820_cnn_crop_0887。听起来是很土的习惯,但当你需要对十几个实验做取舍、或者想回头复现某个两周前的实验时,这套命名法就是救命的。

至于这个暑假真正学到了什么,我的答案不是某一项技术,而是一套把想法快速变成可验证实验的工作流:先固定变量,一次只改一个,记录结果,定期复盘。这套流程放在这次比赛里能提分,放在任何需要试错的事情上也一样管用。顺便提一句,这次比赛带出来的代码模板我做了整理,打算拿它去跑几个自己感兴趣的小项目——复现一个数字识别的demo,试试把序列模型迁移到传感器数据上,看看换个数据集之后哪些超参需要重调。这些在比赛期间没时间做的事,正好留到开学后慢慢折腾。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/30 3:57:10

typechecker:轻量级JS模板化类型检查工具,告别手写if堆叠

打字软件里,最让我头疼的就是各种联调场景下的类型问题。后端返回的字段类型说变就变,前端拿着字符串当数组使,页面打开直接白屏;自己写的数据解析逻辑,十几个 if 堆在那里,看到就烦。这种痛点做前端的人多…

作者头像 李华
网站建设 2026/9/30 3:55:43

STM32流水灯寄存器、标准库与HAL库三种实现方式对比

STM32流水灯寄存器、标准库与HAL库三种实现方式对比 一、实验目的 掌握直接操作寄存器的方法,理解GPIO端口的寄存器地址、位域含义与配置参数。掌握STM32标准外设库的工程搭建方法与函数式编程思路。掌握HAL库配合STM32CubeMX的快速开发方式,理解外部中…

作者头像 李华
网站建设 2026/9/30 3:55:10

实验二最近点对分治法:合并细节与C++/Python实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 3:54:44

Transformer输入输出与PyTorch代码实现:张量形状与Mask避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/30 3:54:12

多Agent协作实战:Claude Code与Codex组队,Raven调度与Harness进化

1. 从单兵作战到团队协作:多Agent编排的必然趋势1.1 为什么单个AI助手已经不够用了过去大半年,我几乎把市面上主流的AI编程助手都深度用了一遍。最开始是Claude Code,后来是Codex,再后来各种Agent框架层出不穷。用久了会发现一个很…

作者头像 李华
网站建设 2026/9/30 3:53:20

亚马逊爆单增长闭环:数据化选品到复购的系统实操

行内做亚马逊的都知道,这两年“爆单”这个词已经从惊喜变成了焦虑的代名词。很多卖家还在靠老一套:看哪个类目火就冲进去,Listing抄优秀同行,广告预算拍脑袋定,结果要么是ACOS高得离谱,要么是单量起来之后被…

作者头像 李华