
1. 先别急着搭模型我这些年对神经网络最深的几个困惑1.1 为什么同一个网络换个人调效果天差地别这些年我见过太多类似的场景两个工程师拿同一份代码、同一个数据集一个人跑出来的模型准确率90%另一个人怎么调都只有85%。代码没变网络结构没变变的只是谁在操作。于是很多人把这种差异归结为玄学说深度学习是炼丹。但我不太认同这个说法。炼丹这个词听起来像运气实际上差的那几个点几乎都藏在那些不起眼的细节里学习率是用固定值还是余弦退火、BatchNorm是放在激活前还是激活后、权重初始化用的是He还是Xavier、数据增强的强度是不是刚好卡在过拟合边缘。这些细节看起来小但它们共同决定了损失曲面上的路径走向。神经网络是个高维非线性系统初始条件和路径选择对终点的印象往往比网络本身有多宽更明显。所以我的第一个思考是我们抱怨模型不稳定的时候常常不是在抱怨数学而是在抱怨自己对超参数空间的感知太粗。真正稳定的人不是运气好而是对每个旋钮的效应都有个大概的模型。哪怕说不清楚理论也知道这个参数调大训练曲线会往哪个方向偏。这是一种手感但手感背后是有逻辑的。1.2 深度学习里的深度到底带来了什么还有一个我反复想的问题深度为什么有效如果只看万能逼近定理一个足够宽的单隐层网络就能逼近任意连续函数那要那么深的层干什么后来我慢慢体会到深不只是为了拟合能力的堆叠更是一种特征的重用与抽象。浅层网络相当于把输入直接映射到输出每一层都在独立地猜一个函数深层网络则默认了一种层级分解的假设——低层先学边缘、纹理中层学部件高层学语义。这个假设在很多感知任务上非常符合自然信号的生成规律所以深度结构相当于把先验知识偷偷塞进了架构里。这也是为什么同样的参数量深而窄的网络往往比浅而宽的网络泛化更好。参数数量相同但深网络把参数花在了特征的逐级抽象上浅网络把参数花在了一个超大矩阵的直接变换上。前者更像在构建知识体系后者更像在死记硬背。当然深度也有代价梯度传播更难、优化更敏感、对数据量的需求更大。这些都是下一步要聊的。1.3 数据、算力、算法三驾马车里哪匹最容易掉链子业内有句老话数据和特征决定上限模型和算法只是逼近这个上限。放到神经网络语境里我觉得同样成立只是特征换成了表征。模型再强数据里没有的信息它学不出来算力再猛也只是把错误的训练更快地跑完。这三者里最容易掉链子的其实是数据质量。算力不够可以等、可以租、可以用小模型替代算法不对可以换结构、换优化器但数据一旦有偏差模型就会忠实地复现这种偏差。比如做数字识别如果训练集里全是规整印刷体数字模型对歪歪扭扭的手写体就很容易懵。这不是模型笨是数据没给它见过足够多的歪。我现在的习惯是拿到任何数据集先不看模型先花两天时间把数据翻个底朝天。统计类别分布、看错误标注、可视化激活前的原始样本、检查有没有重复和泄漏。磨刀不误砍柴工这一步省下来的时间通常比调两周模型还多。2. 网络结构的每一种选择都藏着对世界的假设2.1 前馈网络最简单的顺序假设全连接前馈网络是理解所有深度学习模型的起点。它的假设非常朴素输入是一个固定维度的向量每一层神经元对上一层的所有输出做加权求和然后过一个非线性激活。没有时序、没有空间结构、没有邻居关系所有输入特征在每一层都被一视同仁地混合一遍。这种假设的好处是简单、通用、容易优化坏处是它完全没有利用数据的结构信息。拿一张图片来说把像素拉成一维向量喂给全连接网络意味着网络需要自己从零开始学习相邻像素有关联这件事。它确实能学出来但要付出的参数量和样本量都远超卷积网络。这种由模型从数据中自己发现结构的能力值得尊重但在数据有限的实际项目里往往是种奢侈。所以在思考网络选型时我通常会问一句我的数据里哪些结构是先验的、稳定的、不需要重新学习的如果邻居关系是确定的那就用卷积如果时序顺序是确定的那就用循环网络或Transformer如果什么都没有再用全连接也不迟。先验用得好模型就轻松先验用错模型再深也白搭。2.2 卷积网络把局部性和平移不变性焊死在架构里卷积神经网络最核心的两个思想局部连接和权值共享。局部连接假设离得近的像素关系更紧密权值共享假设同一个特征出现在图片的不同位置应该用同一套参数去检测。这俩假设放在图像上非常合理也正是它们让CNN在参数效率上吊打了全连接网络。但用久了你会发现平移不变性是个双刃剑。数字识别里数字6出现在图片左上角和右下角CNN都能认出来这是好事但有些任务里位置本身就是信息比如医学影像里病灶必须在特定器官区域才有意义这时候过度追求平移不变性反而会损失位置信息。业界用的解决办法是在网络末端加位置编码、或者改用带坐标输入的变体本质上都是在和焊死在架构里的假设做对抗。我的另一个思考是卷积的局部性其实也限制了它的感受野。小卷积核堆叠可以扩大感受野但需要足够的深度空洞卷积能在不增加参数的情况下扩大感受野但可能引入网格伪影。这些都是工程细节但每一个细节背后都是我要让网络相信什么样的世界的权衡。2.3 循环网络与LSTM对时间序列的执念循环神经网络天生为序列而生它假设数据有一个时间方向当前时刻的隐状态依赖于过去所有时刻的信息。这个假设对语音、文本、传感器数据都成立。但RNN有个经典毛病梯度在时间维上连乘很容易指数级衰减或爆炸所以早期RNN根本记不住长距离依赖。LSTM的贡献在于用门控机制绕开了这条死路。输入门、遗忘门、输出门各自控制信息的写入、丢弃和输出让梯度可以在细胞状态这条传送带上长距离流动。我曾经用LSTM做过一段工业传感器的时间序列预测最直观的感受是LSTM对什么时候该忘非常敏感。遗忘门偏置初始化为1、学习率调小一点长程依赖就能稳住反之模型很容易变成只记最近几步的短视鬼。不过我也得说句公道话现在很多序列任务已经被Transformer和注意力机制抢走了。但RNN/LSTM那种按时间步递归处理的归纳偏置在处理流式数据、在线推断、可解释的状态演化时仍然有不可替代的位置。网络没有优劣只有适合的场景这是我反复提醒自己的。2.4 图神经网络当数据不再是规则网格图神经网络解决的问题是数据没有规则网格结构但有明确的拓扑关系时的表征学习。社交网络、分子结构、知识图谱、交通路网全是这类数据。GNN的核心思路是消息传递每个节点聚合邻居的特征更新自己的表示堆叠多层就能捕捉多跳范围的信息。但我对GNN一直保持审慎态度。原因是图数据的邻居定义不是唯一的不同的聚合方式求和、均值、注意力加权对应着不同的假设。GCN用的是归一化邻接矩阵聚合相当于假设每个邻居的贡献和它的度成反比GAT用注意力学习邻居权重假设重要性可以学习。没有一种聚合方式在所有图上都是最优的换句话说GNN比CNN更依赖你对图结构的理解。还有一个常被忽略的问题图数据的噪声比图像大得多。图像像素的噪声是局部的、随机的但图里的一个错误连边可能直接改变消息传递路径造成污染扩散。做节点分类时一个误标注的邻接节点能把整个社区的特征带偏。所以我在图相关的项目里花在边清洗和构建上的时间比调GNN结构的时间多得多。这也是思考神经网络时绕不开的一部分很多问题不是模型不行是你喂给它的关系本身就有问题。2.5 Neural ODE用微分方程重新思考网络的连续化Neural ODE是我最近比较着迷的一个方向。它把网络的残差块看成是欧拉法求解微分方程的一步ht1 ht f(ht)本质上是连续动力系统的离散近似。这样一来网络深度就从层数变成了积分步数前向传播等价于数值积分反向传播也可以通过伴随灵敏度法计算而不必逐层存激活值。这个想法的优雅之处在于它逼着你去思考网络到底在做什么动态变换。残差网络之所以效果好有人从微分方程角度解释为拟合的是恒等映射附近的扰动这种视角比单纯的跳连缓解梯度消失更深刻。Neural ODE还天然适合处理不规则时间序列——你可以把观测时间直接当作积分区间的一部分这也是它在Neural CDE等变体里发光发热的原因。不过实操层面Neural ODE的训练比普通网络慢不少因为积分器需要多次函数估值内存省了但算力贵了。我自己更愿意把它当作一种思考工具当我在设计深度网络时想象每一个残差块是对某个连续过程的离散逼近很多关于要不要加深、残差怎么加的直觉就清晰了。3. 正向传播、反向传播与残差计算从数学到工程的思考3.1 正向传播不只是矩阵乘法是信息压缩正向传播的过程就是把输入数据一层层地线性变换加非线性激活最后得到输出。看起来是矩阵乘法但本质上是一次信息压缩每一层都在把输入重新编码成更抽象、更低维或更高维的表示。为什么最后特征维度常常比输入维度低因为我们需要丢掉无关细节、保留判别信息。这也是为什么中间层常被称为表征而不是中间结果。我很喜欢用一个类比来解释正向传播像公司层层汇报每个中层干部都要把底层信息提炼成自己的语言传到最上面只剩结论。如果所有层都只做线性变换那这个汇报链再长也等价于一次性汇报——因为线性变换的复合还是线性变换。非线性激活函数ReLU、GELU、Sigmoid才是让每一次汇报产生信息取舍的关键。没有非线性的神经网络叠再多层也只是个线性模型这是我刚学时最容易忽略的点。3.2 反向传播链式法则背后的信用分配反向传播解决的核心问题是每个参数对最终损失贡献了多少。它用链式法则把损失对输出的梯度逐层往回传每一层都知道自己放大或缩小了误差的多少倍。这很像公司裁员时做责任追溯先看总部亏损了多少再按各部门在链条上的影响系数把责任拆回去每个环节都分到属于自己的那一份。从数学上讲反向传播的过程就是雅可比矩阵的连乘。这里有个特别值得思考的点梯度在数值上等于局部敏感度乘以路径上所有敏感度的乘积。如果某条路径上的很多雅可比矩阵的特征值小于1梯度就会指数衰减对应的远层参数几乎学不到东西这就是梯度消失。如果特征值大于1梯度爆炸。残差结构的出现等于给梯度提供了一条高速公路——跳跃连接让梯度可以不经过那些容易缩水的非线性层直接传到浅层。3.3 残差计算为什么梯度消失总是盯上深层网络说到残差我不得不聊聊我第一次用几十层网络时的感受。不用残差结构的普通前馈网络超过二十层之后训练误差就很难下降不是因为它不够强而是因为浅层梯度已经被中间层的连乘磨没了。浅层学不动整个网络就变成只有后面几层在干活。残差网络把映射拆成H(x) x F(x)如果F0网络至少能退化成恒等映射。这个设计思路妙在它让什么都不学变成了一种可选项网络不必在每层都做有损变换。训练初期F的输出接近0网络先保住已学到的信息随着训练推进F逐渐承担更精细的修正。这种先保证不退化再逐步优化的思路其实和很多好的系统设计理念相通——优先保证基本盘再谈增量收益。3.4 数值稳定性你看不到的NaN和爆炸理论和结构说完了必须落到数值上。我在实际训练中遇到的最头疼的问题不是模型不收敛而是loss变成NaN。原因通常就几种学习率太大导致梯度爆炸、logits里出现极端值让softmax溢出、或者某一层的权重在初始化时让激活输出进入ReLU的死区。这里有个工程经验给loss加上梯度裁剪gradient clipping几乎是训练RNN和深层网络的标配。用clip_by_norm把梯度整体缩放到一个合理的范数范围能挡住99%的NaN问题。还有一招是盯住每一层的激活值统计量——如果某一层激活的均值和方差训练到后面越来越离谱那多半是数值不稳定在酝酿。把这些监控脚本写成固定工具每次训练前都跑一遍会比等到loss炸了再排查省很多时间。4. 从算法到芯片神经网络跑在硬件上时思考才刚刚开始4.1 为什么通用处理器跑神经网络很憋屈算法侧的思考告一段落接下来聊部署。很多人以为神经网络部署就是把模型存下来、load进内存、跑个forward但真到了端侧或数据中心问题就多了。通用CPU的核心设计目标是低延迟处理各种指令流为此花了大量晶体管在分支预测、乱序执行、缓存一致性上。但神经网络的计算模式非常规律大量矩阵乘法、卷积、激活数据复用度高、控制流简单。用CPU跑算力利用率通常低得可怜。GPU能好很多是因为它把晶体管花在大量并行ALU和高速内存上用SIMT方式同时处理上千个线程。但GPU也不是万能的小 batch 的延迟高、显存带宽是瓶颈、对稀疏计算的支持也不够好。所以通用神经网络处理器NPU这些年才兴起本质上是把矩阵乘法非线性激活池化这些算子固化成专用电路摒弃通用性换效率。4.2 多核调度并行不是万灵药同步才是真问题一旦上了多核NPU或GPU调度问题就来了。刚开始我天真地以为把一个大矩阵乘法切成4块分给4个核速度就能翻4倍。实际跑起来发现加速比经常只有2.5倍卡在哪儿数据同步和内存带宽。多核并行计算里每个核算完自己的分块之后如果有数据依赖必须等其它核算完才能进入下一层。这个同步等待时间就成了隐形的串行瓶颈。更麻烦的是如果切分方式没考虑数据的存储布局核与核之间会产生大量的内存搬运而搬运数据比计算还慢。一个有意思的权衡发生在按batch切分和按层内通道切分之间按batch切分通信少、但要求每个核有完整的模型副本按通道切分负载均衡好、但需要跨核汇总部分和。实际选哪种得看模型大小、核间带宽和片上存储。想到一个问题很多算法工程师会忽略多核调度以为把模型扔给编译器就行。但跑一次profiling你就会发现算子之间的kernel launch开销、多核间的任务分配是否均匀、能不能用异步流水掩盖同步延迟这些对端到端性能的影响常常比网络结构本身的FLOPs还大。4.3 Versal ACAP这类异构平台带来的新思考前几年我接触过Xilinx的Versal ACAP平台现在属于AMD它给我的启发很大。ACAP不是单纯的FPGA或CPU而是在一颗芯片上集成了标量引擎ARM核、适配引擎可编程逻辑和智能引擎AI张量核还带一个片上网络NoC。跑神经网络的时候你可以把预处理放在ARM上把灵活可变的前处理逻辑放到可编程逻辑里把大规模的矩阵乘加放到AI引擎阵列上三个引擎并行跑中间通过NoC传数据。这带来的思考是神经网络部署终于不再被固定指令集框死了。你可以为某条数据通路专门定制一个硬件加速器可以把for循环展开成流水线可以把某个算子融合进相邻算子以减少内存往返。Versal这类平台实际上给了你一个软硬协同的旋钮效率的极限不再由软件堆栈单独决定而在于你能不能把算法映射到合理的异构架构上。但也别高兴太早这样的平台对工程能力要求很高。你得懂点硬件描述看得懂时序和流水线冲突还要会写设备驱动或至少会调HLS级别的工具。我用下来的体会是这类平台适合场景相对固定、量产规模足够大、性能要求极度苛刻的项目比如雷达信号处理、5G基站的波束成形、实时视频智能分析。用在一个简单的数字识别Demo上那是杀鸡用牛刀。4.4 量化与内存带宽被忽略的第二性能曲线最后聊聊性能的隐性瓶颈——内存带宽。神经网络推理时权重和激活都要频繁读写内存。FP32的4字节精度、INT8的1字节精度直接差4倍带宽需求。所以量化不只是为了省存储更是为了降低内存带宽的压力从而提升有效吞吐。我做过一个实验把ResNet50从FP32量化到INT8用校准集做每个通道的scale精度只掉了0.2%但推理速度提升了3倍多。这比我尝试任何网络结构修改都来得立竿见影。更细一层的思考是访存密集算子 vs 计算密集算子。卷积早期层通常是内存密集的因为特征图大深层卷积则是计算密集的因为通道多。真正的高手会把算子重排把内存密集的算子放在一起减少上下文切换时的cache miss。这些经验在通用框架里不一定开箱即用但理解它们能帮你在调优时找到方向。神经网络从来不只是算法题它是一道涉及数学、系统、芯片的综合题。5. 从一个具体的应用出发数字识别与TTS里的模式之思5.1 数字识别为什么MNIST被玩烂了还有价值MNIST手写数字识别可能是人类训练过最多的神经网络任务。很多人觉得它太简单没什么好聊的。但我反而觉得越是简单的任务越适合做思想实验。比如你可以在这个数据集上做一个实验用只有全连接层的网络和用CNN分别把参数量控制在一样看两者的差距有多大。你会发现CNN在很小参数量下就能达到很高准确率而全连接网络要堆很多参数才追得上而且泛化还不一定好。这个实验背后揭示的就是归纳偏置的力量。数字识别的结构先验——笔画是局部连续的、同一个数字可以出现在图片不同位置、旋转和轻微的形变不该改变标签——都完美契合了CNN的平移不变性和局部性。所以MNIST不是拿来刷分的是拿来体会为什么结构假设能帮模型偷懒的。很多新学者一上来就调参刷准确率忽略了在玩具数据上做控制变量的思考实在可惜。5.2 TTS神经网络要学会说话先得学会听语音合成TTS是另一个很有意思的领域。它和数字识别最大的不同在于输出是变长的序列而且包含丰富的韵律和声学细节。早期我们用拼接合成录一堆音频片段再拼起来效果生硬。后来的神经网络TTS比如Tacotron、FastSpeech等本质上是在做一个从文本到声学特征的序列到序列映射。但我思考最多的反而不是生成端而是听这一侧。要让网络学会说话得先让它理解语音里哪些特征是关键的。如果你把音频直接塞给网络常见做法是提取对数梅尔频谱作为输入特征这本身就是一种信号处理假设人耳对频率的感知是非线性的梅尔刻度是对这种非线性的建模。所以TTS的成功一半是神经网络的序列建模能力另一半是经典信号处理知识的支撑。这也让我养成一个习惯做音频相关任务前先把傅里叶变换、滤波器组、语谱图这些老知识复习一遍。5.3 小波Elman网络经典方法没死只是换了个位置很多人看到小波Elman神经网络会觉得这是个老古董。但我在实际项目里确实用过类似组合解决过问题。Elman网络是一种简单的循环网络结构上相当于在隐层加了一个上下文层来记忆上一步的隐状态适合时间序列预测。小波变换则擅长把非平稳信号拆成不同尺度的成分两者结合的基本思路是先用小波分解把原始序列拆成不同频段的子序列再分别用Elman网络去预测每个子序列最后重构结果。这个组合比直接上一个LSTM好在哪好在可解释性。小波分解让你看得见高频细节和低频趋势分别在哪层被建模Elman的上下文记忆让你能追踪预测的依据。不是所有问题都需要LSTM这种复杂门控有时候一个结构清晰的老网络加一个经典信号预处理效果和可解释性都更好。神经网络不是越新越好合适才是好这是我在这类老方法里复习到的思考。5.4 从应用反推网络设计先有问题才有模型数字识别和TTS这两个例子可以提炼出一个通用套路先定义清楚问题的固有结构再选择能匹配这种结构的网络。输入是图像还是序列输出是标签还是向量数据是否有时间依赖是否对位置敏感这些问题的答案直接决定了你该用什么网络。我见过很多失败项目原因不是网络不够强而是用错了假设。比如拿着LSTM去分析没有时序依赖的静态表格效果可能还不如梯度提升树拿着CNN去做分子性质预测却忽略了分子没有规则网格结构最后效果被GNN吊打。模型是为问题服务的不是反过来。每次开工前多花半小时画一张数据结构-网络假设的对照表长期看能省下几个月的试错时间。6. 建立你自己的神经网络观几个可以带走的思考框架6.1 从这叫什么网络到它隐含了什么先验我在带新人的时候会让他们做一个小练习给定一个网络结构不要说它叫什么名字只描述它相信什么。全连接网络相信所有特征平等且无结构CNN相信邻近性和局部性RNN相信时间方向性和状态延续GNN相信拓扑关系比欧氏距离更重要Transformer相信所有位置都可以通过注意力机制建立关系。能把网络翻译成假设才算是真的理解。6.2 从准确率到失败模式准确率是个粗颗粒指标它掩盖了太多信息。我现在的习惯是每次评估模型除了看总体准确率一定看混淆矩阵和分类错误的样本。用数字识别举例如果4和9互相认错可能说明模型对开口方向不敏感如果0和6搞混可能说明它对上半部分的特征不敏感。错误的模式比错误的个数更有价值。TTS也一样只听平均自然度评分没用要听它具体在哪类词上发音不清晰——是爆破音、是韵律边界还是生僻字。6.3 从调参炼丹到假设-验证把调参过程变成科学实验是我的另一个心得。每次改一个变量前先写下预测如果我增大数据增强强度验证集损失应该会先降后升因为实验在过拟合的边缘。然后跑实验看是否符合预测。符合说明你的心智模型是对的不符合说明有些隐含因素你没看到这时候的收获反而更大。这个习惯让我从四处乱试变成了有序逼近。6.4 少看排行榜多看错误样本最后我常提醒自己的是公开数据集和排行榜离真实问题太远了。排行榜上的模型在同一个测试集上卷到小数点后三位但你的业务数据可能连标注标准都不统一。与其追逐SOTA不如把时间花在理解自己的数据、分析自己的失败样本、打磨部署中的数值稳定性上。神经网络的价值不是刷分而是在真实系统里可靠地解决问题。从我自己的经历来看对神经网络的思考是一个长期迭代的过程。每遇到一次意外每踩过一个坑都会刷新一点对假设和工程的理解。结构、训练、部署、应用四个层面环环相扣缺一个视角都容易走偏。这篇东西算不上什么体系更多的是一些阶段性的想法写出来也是想逼自己把模糊的直觉变成清楚的语言。如果你也在摸索这条路希望这些思考能给你哪怕一个值得琢磨的切入点。