☰
通信理论与深度学习交叉资料库:文献筛选、代码复现与笔记维护方法
2026/11/3 11:47:39 网站建设 项目流程

三年前我的硬盘里堆了四百多篇 PDF,文件名从channel_est_final_v2.pdf到arxiv_2307.xxxxx.pdf什么都有,另外还有几十个 Git 仓库的半成品和一堆写在餐巾纸上的公式。结果真正要用的时候,光是搞清楚"哪篇论文对应哪个仓库、当时为什么放弃了那一版实现"就花掉了两个晚上。后来我下决心把这堆东西整理成一个像样的汇集:文献按问题域归档,代码按可复现性分级,阅读笔记按固定模板写。这份汇集现在成了我和身边几个同学做通信理论与深度学习交叉方向的底稿——论文筛选有判据、代码复现有骨架、笔记翻回去三个月还看得懂。这篇就把这套建立汇集的完整方法和踩过的坑摊开讲清楚,适合刚开始做这个交叉方向、面对满地论文不知道从哪下手的人,也适合已经做过一两个小 Demo、但输出散落各处的朋友。

1. 这个交叉方向为什么值得单独建一份资料库

通信理论和深度学习这两个圈子的行事方式差别大到有点离谱。做通信的人拿到一个问题,先问有没有闭式解、能不能做渐进分析、误码率曲线的斜率是多少;做深度学习的人拿到同一个问题,先看数据规模、损失函数、消融实验,最后给一条平滑下降的曲线。两边都有道理,但两边的论文放到一起读的时候,中间有一层厚厚的翻译成本。我见过不少同学读完一篇深度学习辅助信道估计的论文,代码也跑通了,却说不清这个网络到底在什么信噪比区间才真的优于最小二乘,因为论文里那条曲线用的是 Eb/N0,而他自己算的是 SNR,横坐标差了整整一个编码率的对数量级。

1.1 两边术语和评价指标的真实鸿沟

举个最常见的例子。通信里说"在 10 dB 下误码率降到 1e-3",这个 10 dB 到底是 Es/N0、Eb/N0 还是每比特能量与噪声功率谱密度之比,必须一眼能对上。深度学习那套里说的"在某个噪声水平下准确率",噪声水平往往就是一个随手挑的 σ 值,σ 和上述任何一个指标之间还隔着一层功率归一化的约定。这些约定一旦在汇集里没有统一,后面每一次比较都是在拿苹果比橘子。

我踩的第一个坑就是这种。当初我把两篇论文的误码率曲线画在同一张图上,结论是后者全面碾压前者,兴奋了半天。后来发现前者的星座点平均功率归一化到了 1,后者归一化到了每比特能量为 1,横坐标平移了大约 3 dB,两条曲线立刻就交叉了。这件事之后我给自己定了一条规矩:汇集的每一篇文献笔记里,必须有一行写清楚"该论文的横坐标定义与换算关系",不许含糊。这一行看似小事,省下来的返工时间以天计。

1.2 一份能真正用起来的汇集包含哪四类物料

我把这个汇集拆成四块,缺哪一块都会让整个东西变成摆设。

物料类型存放内容缺失后的后果
文献卡片每篇论文一页,含问题设定、方法、指标、横坐标定义三个月后完全想不起某篇论文做了什么
可运行代码按最小可复现单元拆分的脚本,不是完整工程想验证一个想法得从头搭环境
阅读笔记公式推导、与相邻工作的关系、自己的质疑只剩结论没有推导,无法迁移到新场景
实验记录每次跑实验的配置、随机种子、结果表结果对不上,怀疑人生

这四块里最容易被忽略的是实验记录。很多人觉得跑出来了就是自己的,实际上你三个月后重新跑一遍,换个随机种子,曲线就能差出一个数量级——尤其在信道估计这种对初始化敏感的任务上。我现在每跑一次实验就写一个 YAML 配置文件,把学习率、批大小、信噪比训练区间、信道模型参数、随机种子全部落盘,结果显示文件名直接带上配置文件的哈希前缀。这个做法很土,但它让我能在半年后准确回答"这条曲线是哪个版本跑出来的"。

关于"最小可复现单元"这个说法,我想多解释一句。很多人整理代码喜欢把整个项目打包丢进去,看着很完整,实际完全没法复用。我现在的做法是把系统拆成几个互相独立的小脚本:一个只做信道生成,一个只做调制映射,一个只做端到端自编码器的最小训练循环,每个脚本自己带if __name__ == "__main__"的示例。想试新想法的时候,把这些脚本 import 进来拼起来就行,比改一个大工程快得多。

2. 文献筛选:从几百篇里压出真正值得复现的那几十篇

这个方向每年新增的论文数量非常可观,光靠"读"是读不完的。我摸索出一套比较粗暴但有效的过滤流程,把一次阅读的时间成本从两三个小时压到二十分钟以内,只对通过初筛的论文投入深读。

2.1 用三个问题做初筛

拿到一篇论文,先不读正文,只读摘要、引言最后一段和实验部分的图表标题,然后回答三个问题:

  • 它替换掉了传统方案里的哪一个模块?信道估计、检测、译码、资源分配,还是整个收发链路?
  • 它相比基线提升了多少,在什么信噪比区间提升,用的是什么指标?
  • 它的复杂度代价怎么报的?参数量、浮点运算次数,还是推理时延?

三个问题里只要有一个答不上来,这篇论文就先放进"待定"目录,不投入深读。这个筛选法听着很武断,但实测下来非常有效:真正扎实的论文,这三个问题的答案在摘要和图表标题里基本都有;答不上来的那些,要么是写法太虚,要么是根本没做公平对比,深读的性价比极低。

我统计过自己某一轮筛选的结果:一百来篇候选里,能顺畅答出三问的只有二十多篇,剩下的里面还有大约三分之一在读完实验部分后发现基线的实现方式明显偏弱。这个比例说明一件事——文献筛选这件事本身值得单独花时间,而不是拿到就啃。

2.2 按问题域和信噪比区间双维度打标签

归档的时候我用两个维度做标签,不是单一的"信道估计"这种粗分类。

第一个维度是问题域,我分成:信道估计与反馈、信号检测、信道编码与译码、调制识别与射频指纹、端到端链路设计、资源分配与调度、语义层面的传输。第二个维度是信噪比区间,分低(0 dB 以下)、中(0 到 15 dB)、高(15 dB 以上)三档。

这个双维度标签的价值在于,它能立刻告诉你某个方法在哪个区间是空白的。比如端到端自编码器这一类工作,大量论文集中在中低信噪比,高信噪比区间的性能往往不如传统方案,因为网络的量化误差和训练分布外推问题在高信噪比下暴露得更明显。这个观察直接影响了我的选题判断——如果一个想法只是在中信噪比上再提升零点几个 dB,价值其实很有限。

标签不要写在文件名的开头,那样文件名会长得没法看。我的做法是用一个纯文本的索引文件,一行一篇,字段用制表符分隔:

id year domain snr_band baseline gap_db repro_status notes_file 0142 2021 channel_estimation mid LS+DFT 0.9 done notes/0142.md 0143 2021 detection high MMSE -0.3 partial notes/0143.md

repro_status这一列是关键,只有done的论文才算真正进了汇集。partial表示代码跑通了但对不上论文的数,todo表示还没动。这个字段逼着我诚实面对"我到底复现了多少",而不是拿"读过"冒充"掌握"。

2.3 那些看起来惊艳却注定复现不出来的工作

有几类论文我现在的处理方式是直接归档不深读,因为它们的时间成本收益比实在太差。

第一类是训练数据不可得或者描述不清的。有些工作用的是自采的实测信道数据,论文里只写了"在某频段采集",没有任何公开渠道,也没有说明采集设备和场景细节。这种工作你复现不了,只能信它的结论,那就不如把时间花在别处。

第二类是基线实现明显偏弱的。判断方法很朴素:看它对比的传统方案有没有做参数调优。比如对比最小均方误差检测,如果基线用的是没做过任何正则化的朴素版本,而自己的网络调了三轮超参,那这个提升有多少来自方法、多少来自调参,就说不清了。

第三类是只报最优信噪比结果的。一条曲线只画一个点,或者说"在 20 dB 下我们最好",这种报告方式在低信噪比区间往往很难看。我遇到过一篇,读完正文发现它的方法在 0 dB 下直接发散,作者用一句"极端条件下不适用"带过去了。

提示:判断一篇论文值不值得复现,最快的信号是看它有没有公开的配置细节——层数、宽度、学习率、批大小、训练轮数、随机种子。这些写得越细,复现成功率越高;只写"训练至收敛"的,通常要你自己摸索很久。

3. 代码复现:从论文公式到张量形状对上的那一刻

复现这件事,我最大的体会是:论文里最难复现的从来不是那个网络结构,而是它周围那一圈看起来理所当然的工程细节。网络结构在论文里画得清清楚楚,几层、多宽、什么激活函数,抄下来半小时的事;真正让人卡住三天的是功率归一化放在哪一步、复数是拆成两路还是用复数张量、损失函数里要不要加正则项。

3.1 信道建模这一层必须自己写,别用黑盒

我强烈建议汇集里有一份自己写的、看得懂每一行的信道生成代码。原因很简单:几乎所有复现失败最后都追到这一层。别人的信道生成函数里可能默默做了功率归一化,可能对复噪声的方差用了不同的约定,可能对多径做了不同的时延抽取方式,你在上层怎么调都对不上。

最基本的加性高斯白噪声信道,我用的写法是这样的:

import numpy as np def awgn_channel(x, snr_db, rng): """x: 复数数组,平均符号功率归一化为 1 snr_db: 定义为符号功率与噪声功率之比""" snr_linear = 10.0 ** (snr_db / 10.0) noise_power = 1.0 / snr_linear # 总噪声功率 sigma = np.sqrt(noise_power / 2.0) # 每个实维度的标准差 noise = sigma * (rng.standard_normal(x.shape) + 1j * rng.standard_normal(x.shape)) return x + noise

这段代码里最容易被写错的是noise_power / 2.0那一步。复高斯噪声的每一个实维度方差是总方差的一半,漏掉这个 2,整条误码率曲线会平移 3 dB,而且平移的方向还取决于你在哪一步做的归一化,非常隐蔽。我在汇集里专门写了一页笔记讲这个 2 的来历,就是为了防止自己隔一段时间又忘。

衰落信道再多一层。平坦瑞利衰落就是乘一个复高斯系数,注意这个系数的方差要归一化到 1,否则平均接收功率会漂:

def rayleigh_flat(x, snr_db, rng): h = (rng.standard_normal(x.shape) + 1j * rng.standard_normal(x.shape)) / np.sqrt(2.0) y = h * x return awgn_channel(y, snr_db, rng), h

多径信道就要引入时延抽头和功率时延谱,我一般用抽头延迟线模型,抽头功率按指数衰减,抽头间隔取符号周期的整数分之一。这一层的参数一定要在配置文件里显式写出来,因为它直接决定信道的频率选择性强度,而这个强度对深度学习方法的性能影响巨大——有些网络在弱频率选择性下表现很好,抽头功率谱一陡峭就崩了。

3.2 端到端自编码器通信系统的最小骨架

端到端学习收发机这类工作,最小可复现单元其实很小,一百行以内就能跑起来。我把骨架写成这样:

import torch import torch.nn as nn class TxNet(nn.Module): def __init__(self, M, n_real=2, hidden=128): super().__init__() self.enc = nn.Sequential( nn.Linear(M, hidden), nn.ReLU(), nn.Linear(hidden, hidden), nn.ReLU(), nn.Linear(hidden, n_real), ) self.n_real = n_real def forward(self, one_hot): s = self.enc(one_hot) # 关键:按样本做功率归一化,保证平均符号能量为 1 power = (s ** 2).sum(dim=1, keepdim=True) return s / torch.sqrt(power + 1e-8) class RxNet(nn.Module): def __init__(self, M, n_real=2, hidden=128): super().__init__() self.dec = nn.Sequential( nn.Linear(n_real, hidden), nn.ReLU(), nn.Linear(hidden, hidden), nn.ReLU(), nn.Linear(hidden, M), ) def forward(self, y): return self.dec(y)

这段骨架里有三个地方值得单独说。

第一是功率归一化的位置。必须在编码器输出之后、加噪声之前做,而且是按样本做,不是按整个批次做。按批次做的话,批次内每个样本的功率会互相耦合,训练早期梯度会很不稳。

第二是训练用的损失函数和评估用的指标不是一回事。训练用交叉熵,因为它梯度性质好;评估必须换算成误码率,因为读者只认误码率。这两者之间的换算在汇集里要写清楚,尤其当 M 不是 2 的幂、需要做非均匀映射的时候。

第三是信道这一层的可导性。加性高斯白噪声和乘性衰落都是可导的,可以直接放进计算图里端到端训练。但一旦中间插入了量化、硬判决或者实际的编码译码模块,梯度就断了。这时候要么用直通估计器近似,要么把整个链路拆成两段分别训练。这两条路我都试过,前者的实现简单但训练不稳定,后者稳定但需要仔细设计中间接口,取舍要看具体任务。

3.3 神经网络译码器复现时最容易卡住的对齐问题

神经网络辅助的迭代译码是我在这个方向上花时间最多的一块,也是踩坑最密集的一块。核心难点不在网络结构,而在各种索引和符号约定。

按我的经验,卡人的地方按出现频率排下来大概是这些:

问题具体表现排查方法
校验矩阵与生成矩阵不匹配编码后的码字不满足校验关系用H @ c.T % 2 == 0验证
对数似然比的符号约定相反译码完全不收敛,误码率恒定在 0.5 附近全零码字测试,看外部信息符号
打孔位置记错删余码的译码性能差于不删余逐步关闭打孔对照
交织顺序不一致突发错误场景性能异常用单错图样逐位注入验证
边索引与消息更新顺序错位迭代不收敛或收敛到错误码字用香农极限附近的短码手工验证

第一项是最基础的,也是最容易忽略的。有些论文直接给校验矩阵,有些给生成矩阵,有些只给度分布,你得自己构造。构造完之后一定要做一次校验:随便生成几个信息比特,编码,然后验证所有校验方程都成立。这一步省掉的话,后面所有的训练曲线都是错的。

第二项里对数似然比的符号约定,是一个典型的"两边都对但拼起来就错"的问题。有的实现里正数表示比特为 0 更可能,有的表示比特为 1 更可能。这个约定不一致的时候,译码器不会报错,只会安静地把所有比特判反,误码率稳定在 0.5 上下。我第一次遇到这个问题时调了两天才发现。

第三项打孔,是我吃过最大亏的地方。删余卷积码和删余低密度校验码的打孔图样完全不是一回事,我一开始把两者的位置搞混了,结果译码性能比不删余还差,还以为是自己的网络结构有问题,绕了好大一圈。

3.4 随机种子和版本锁定:复现的地基工程

这一条讲起来最不性感,但重要性排第一。我的汇集里有一个env目录,只放两样东西:依赖版本清单和随机种子管理脚本。

依赖版本清单我是用最土的办法,直接pip freeze > requirements.txt,每个能跑通的实验目录各存一份。深度学习框架的版本差异在这个方向上是实打实的坑,同一个模型换个版本,默认的初始化方式可能变了,某个算子的数值实现可能变了,最后曲线就是不一样。

随机种子管理我用一个简单的上下文管理器:

import contextlib, random import numpy as np import torch @contextlib.contextmanager def fixed_seed(seed=20240101): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False yield

这里cudnn.deterministic = True会让训练慢一点,但能保证同一份代码在同一个机器上跑出完全一致的结果。对于需要对比实验的场合,这点性能损失完全值得。至于benchmark = False,是因为自动调优算法会引入不确定的算子选择,让结果无法严格复现。

注意:随机种子只能保证同一台机器、同一套依赖下结果一致。换了显卡型号,浮点运算顺序可能变化,结果仍然会有微小差异。做论文级别的对比时,最好在同一台机器上一次性跑完所有基线。

4. 阅读笔记:写给三个月后的自己看

笔记这件事,我一开始的写法是"抄摘要 + 抄结论",写了半年发现完全没用——三个月后我打开笔记,看到的是和论文摘要一模一样的一段话,还是不知道这篇论文的方法到底怎么落地。后来改了模板,情况才好转。

4.1 一页纸笔记模板里的固定栏目

现在我的每篇笔记都是一个 Markdown 文件,固定六个栏目,缺一个就标红提醒自己补:

  • 问题设定:输入是什么、输出是什么、约束是什么。不写"针对某某问题提出某某方法",而是写成"输入是导频位置的频域观测,输出是全带宽的信道频响估计,约束是导频开销不超过百分之五"。
  • 核心变换:从输入到输出,中间经过了哪几步张量变换,每一步的维度变化写出来。
  • 训练目标:损失函数具体长什么样,有没有额外的正则项、对抗项、辅助任务。
  • 指标与横坐标:横坐标是 SNR 还是 Eb/N0,换算关系是什么,指标是误码率、归一化均方误差还是准确率。
  • 与相邻工作的关系:它解决了谁没解决的问题,又留下了什么没解决。
  • 我的疑问:读的时候哪里觉得不对劲,哪一步没讲清楚。

最后这个"我的疑问"栏目是价值最高的。我翻回去看,很多有价值的选题都是从这些疑问里长出来的。比如有一篇讲信道反馈的论文,在压缩率很低的时候性能下降很快,作者归因于量化误差,但我怀疑是训练数据分布的问题。后来我把训练集换成信道分布更宽的混合模型,性能确实提升了不少,这就成了一个可以做的点。

4.2 公式推导记到什么颗粒度才够用

这个我摸索了很久。记太少,三个月后看不懂;记太多,抄公式的时间比读论文还长。

我的判断标准是:凡是论文里写"显然""容易得到""经过简单推导"的地方,一定要自己推一遍并写下来。因为作者觉得显然的东西,通常刚好是你不熟的那一块。反过来,论文详细展开的推导,如果是标准流程,记个结论和引用出处就够了。

举个例子,某篇讲展开式迭代检测的论文,中间有一句"将上式对发送符号求偏导并令其为零,即可得到软输出"。这一步我推了快两个小时,原因是我对复数域的求导规则不熟,实部和虚部要不要分开处理搞混了。推导完我把过程写在笔记里,还附了一段数值验证的代码,用有限差分核对解析梯度。这段笔记后来被好几个同学借去看,说明大家卡的是同一个地方。

关于数值验证梯度这件事,我强烈推荐。解析梯度推完之后,用有限差分做一个简单的核对,两行代码的事,能挡掉绝大部分符号错误:

def check_grad(f, x, eps=1e-6): # f 返回标量,x 是 numpy 数组 num = np.zeros_like(x) for i in range(x.size): xp, xm = x.copy(), x.copy() xp.flat[i] += eps xm.flat[i] -= eps num.flat[i] = (f(xp) - f(xm)) / (2 * eps) return num

4.3 用对照表把实验结论钉死

笔记里除了文字和公式,我还强制自己放一张对照表。表头固定是:方法、配置、信噪比区间、指标数值、我的复现结果、差异原因。

最后两列是重点。只要我的复现结果和论文有差异,就必须在"差异原因"里写一个具体假设,比如"我的导频图样是均匀分布,论文可能是梳状分布"或者"我的训练轮数只有论文的一半"。写不出来就说明我还没真正理解这个实验。

这个习惯帮我抓住过好几个问题。有一次某一格差异一直是空着,我反复看了三天,最后发现论文的基线用的是一种我没注意到的迭代次数设置,把迭代次数对齐之后曲线就吻合了。如果没有这张表逼着我去填"差异原因",我大概率会把这零点几个 dB 的差异归到"实现细节不同"上,然后就永远不知道真相。

5. 汇集过程中反复踩到的几个暗坑

前面讲了不少方法论,这一节专门讲坑。这些坑我几乎每一个都踩过,而且不止一次,写下来是为了在汇集里给它们配上专门的检查项。

5.1 归一化口径不一致,指标根本不可比

这是最高频的问题,没有之一。同一个系统,符号功率归一化到 1 和归一化到星座点平均能量,看起来是一回事,实际上对误码率曲线的横坐标影响可以到几个 dB。

我现在的做法是在配置文件的顶层强制写两个字段:symbol_power_norm和snr_definition。前者只能是unit_average_power或unit_peak_power,后者只能是es_n0、eb_n0或snr。任何实验脚本开头都要读这两个字段,做对应的换算,不允许在中间环节临时改。

换算关系我整理在汇集的一张表里,随时查:

定义表达式与 SNR(dB) 的关系
符号信噪比Es/N0基准量
比特信噪比Eb/N0Eb/N0 = Es/N0 - 10log10(k),k 为每符号信息比特数
采样信噪比符号功率/噪声方差与 Es/N0 在采样率等于符号率时数值相同

那个 k 里包含编码率。举个具体的:调制方式为 16 相正交幅度调制、编码率二分之一,每符号承载 4 个比特,其中 2 个是信息比特,那么 Eb/N0 比 Es/N0 高 3 dB。如果论文里漏写了编码率,这条曲线就没法复现到 dB 级别。

5.2 训练集和测试集的信道分布悄悄泄漏

这个问题比归一化更隐蔽,因为它不会让你的曲线看起来奇怪,只会让你的曲线好看得不真实。

最常见的泄漏方式有三种。第一种是训练和测试用同一个随机种子生成信道,虽然样本不同,但信道的统计特性完全一致,模型实际上记住了这批信道的特征。第二种是用同一个场景的数据划分训练测试,比如同一个用户位置附近的信道样本既有训练又有测试。第三种是训练集覆盖了测试集的信噪比范围,但论文里声称是"跨信噪比泛化"。

我的检查方法是做一个"分布外测试":训练用一组参数生成的信道,测试换一组参数,看性能掉多少。如果掉得厉害,说明模型学到的不是通用的结构而是这批数据的特征。这个测试在汇集里是必做项,结果记在笔记的单独一栏。

还有一种更隐蔽的:数据预处理阶段用全量数据算了归一化统计量,包括测试集。这在小数据集上影响很明显,我见过归一化统计量差异导致的性能差达到百分之十以上的情况。正确做法是只用训练集算统计量,然后应用到测试集。

5.3 高信噪比区间的"虚高"性能

这个坑我在做信号检测的时候踩得最狠。当时一个基于深度学习的检测器在 20 dB 下误码率比传统方案低了快一个数量级,我兴奋了好几天,准备写点东西。后来做消融,把它换成一个简单的线性检测器加上同样的后处理,误码率几乎一样。也就是说,那个提升根本不是网络学出来的,而是后处理里的某一步带来的。

从那以后,我在汇集里给每个实验都配一个"最简基线"。这个基线不是论文里最强的传统方案,而是一个尽可能简单的方案,比如线性最小均方误差、或者干脆就是匹配滤波。如果复杂模型打不过这个最简基线,那就说明提升的来源可疑,得回头查。

另一类虚高来自测试样本数。误码率是很低的量级,1e-4 的误码率意味着至少要几十万个比特才有统计意义。有些实验只跑了一万个比特,出现的几个错误完全是随机波动,画出来的曲线抖动很大,还容易被误读成某个方法的优势区间。我在汇集里给了一个简单的样本量估算表:

目标误码率建议最少比特数期望错误数
1e-21e4100
1e-31e5100
1e-41e6100
1e-51e7100

经验法则是期望错误数至少要一百个,曲线才相对平滑。

提示:跑高信噪比实验时先算一下需要的比特数,再决定跑多久。很多人因为没算这一步,跑了一晚上的结果是完全没有统计意义的。

6. 让这份汇集活过两年的维护办法

整理汇集最大的敌人不是技术难度,是时间。一开始热情很高,一周建了几十个目录,三个月后就荒废了,再打开发现里面全是半成品。我改过三次目录结构,最后定下来的这套用了两年多没动过,关键就在于"别改结构"和"固定入库节奏"这两件事。

6.1 目录结构定死,改动成本要压到最低

现在的结构是这样,非常简单:

corpus/ papers/ # 文献卡片,一个 md 一页 notes/ # 深读笔记与推导 code/ channel/ # 信道生成 modulation/ # 调制映射与解映射 estimators/ # 各类估计器 decoders/ # 译码相关 experiments/ # 每次实验一个目录,含配置与结果 index.tsv # 全局索引

这个结构的核心原则是:任何新内容都能放进已有的某个目录,不需要新建顶层目录。这条原则听起来很约束,但它避免了"目录越建越多、最后自己都记不住东西放哪"的经典困境。

文献卡片和深读笔记我分成两个目录,是因为它们的产出节奏不同。卡片是快速过滤的产物,二十分钟一篇;笔记是深读的产物,可能要花好几天。放一起的话,快速卡片会淹没在深读笔记里,找起来很费劲。

6.2 每周固定一次入库,不攒着

我的做法是每周固定一个时间段做入库,把这一周新增的文献卡片、跑通的代码、实验记录统一整理进汇集。这个节奏的关键是"不攒"。攒上一个月,你会发现有二十多个半成品需要归类,那个工作量足以让你直接放弃。

入库的时候我会做三件事。第一件是更新索引文件,把新条目的repro_status填上。第二件是跑一遍所有done状态的实验的快速验证脚本,确认没有因为环境变化而挂掉。第三件是清理,把todo超过三个月还没动的条目重新评估一遍,要么降级归档,要么删掉。

第三件事最反直觉,但我觉得最重要。汇集的价值不在于它有多大,而在于里面的东西都是活的。一堆三个月没动过的待办条目,除了增加心理负担没有任何作用。

7. 一点个人的使用体会

这套汇集跑了两年多,我最大的感受是它改变了我读论文的方式。以前读论文是"读完就完",现在读之前会先想"这篇读完之后我要往汇集里放什么",这个预设让阅读变得有目标感,也让我更快地判断一篇论文值不值得投入时间。

另外一点是关于代码复现的心态。我以前总觉得复现不出来是自己能力问题,后来发现大部分情况下是论文给的信息本身就不够,需要做合理假设。现在我复现之前会先把所有需要假设的地方列出来,写在笔记里,跑完之后回头看这些假设有没有影响结论。这个习惯让我少了很多"跑出来不对就怀疑自己"的内耗。

最后分享一个小的操作:我给汇集的每个实验目录都放了一个README.md,只写三行——这个实验复现的是哪篇、怎么跑、当前状态。三行字,写起来三十秒,但它让我在任何时候打开任何一个实验目录都能立刻接上上下文。这个习惯是从一次长达两周的断档后养成的,那次我打开一个目录,完全想不起来里面那个脚本在做什么,只能从头看代码。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询