资讯详情

资讯详情

深度学习基础与下一代机器智能算法设计:归纳偏置与表示学习

1. 从标题拆解开始这个方向到底在讲什么“深度学习基础下一代机器智能算法设计一”——这个标题第一次看到的时候我脑子里冒出来的第一个念头不是“又要讲神经网络了”而是“终于有人愿意把基础算法设计和下一代思路放在一起聊了”。为什么这么说因为市面上大部分深度学习的内容要么停留在“调包跑通一个分类任务”要么一上来就堆Transformer的变体结构中间那块“算法到底怎么被设计出来的”几乎没人认真讲。而这个标题里的“基础”和“下一代”两个词放在一起恰恰说明它想做的事情是把经典算法的设计逻辑讲透然后顺着这个逻辑推到下一代机器智能算法可能长什么样。我先把话说在前面这篇不是论文综述也不是教科书式的章节复述。我写的是我自己在带团队做算法预研、给新人做内训、以及反复读经典论文和开源实现之后沉淀下来的一套理解框架。它适合三类人看——第一类是刚学完反向传播和卷积网络、想往算法设计方向走的同学第二类是做工程落地但总觉得“只会调参不会设计”的开发者第三类是对下一代机器智能感兴趣、但被各种新名词绕晕的从业者。你不需要有很深的数学功底但需要对梯度下降、损失函数、网络层这些基本概念有直觉层面的理解。核心关键词其实就几个深度学习基础、算法设计、下一代机器智能、归纳偏置、表示学习、优化目标。这些词后面我会反复用到而且我会尽量用生活化的类比把它们讲清楚。比如“归纳偏置”这个词听起来很唬人其实它就是“你在没见过全部数据之前先入为主地相信世界应该是什么样子”。卷积网络相信“相邻像素关系更紧密”这就是一种归纳偏置Transformer相信“任意位置都可以直接建立联系”这是另一种归纳偏置。算法设计很大程度上就是在选择、组合、甚至发明新的归纳偏置。那为什么标题要加个“一”我的理解是下一代机器智能算法设计这件事太大不可能一篇文章讲完。第一部分应该聚焦在“基础”上——也就是那些从第一代神经网络到现在都没有变过的底层设计原则。把这些原则吃透你再看任何新算法都能一眼看出它到底在哪个维度上做了创新。这也是我写这篇博文的组织逻辑先讲清楚算法设计的底层框架再拆解几个经典设计决策背后的“为什么”然后落到实操层面最后聊下一代可能的方向和常见的坑。2. 算法设计的底层框架先搞清楚你在设计什么2.1 一个被大多数人忽略的事实算法设计不等于网络结构设计很多人一提到“设计深度学习算法”脑子里第一反应就是画网络结构图——几层卷积、几层全连接、要不要加残差连接。这个理解不能说错但太窄了。我自己的经验是一个完整的算法设计至少包含四个层面而且这四个层面的重要性是递减的优化目标的设计 表示形式的设计 网络结构的设计 训练策略的设计。为什么优化目标最重要因为优化目标决定了模型“想变成什么样”。你让模型去最小化交叉熵它就会拼命把正确类别的概率推高你让它去最小化均方误差它就会去拟合数值本身。目标错了结构再花哨也救不回来。我举个真实的例子。之前有个做图像去噪的项目一开始大家把精力全花在堆网络深度上从10层堆到50层PSNR涨了不到0.3dB。后来有人提出把损失函数从单纯的MSE改成MSE加上一个感知损失项同样的网络结构PSNR直接涨了1.2dB而且视觉质量明显更好。这就是优化目标设计的威力。所以我在带新人的时候第一件事就是让他们把损失函数写出来然后问三个问题这个损失函数在鼓励模型做什么它有没有可能被“作弊”绕过它和最终评价指标是不是一致的2.2 归纳偏置算法设计的灵魂如果说优化目标是算法的“目的”那归纳偏置就是算法的“世界观”。我前面说了归纳偏置就是模型在没见过数据之前就相信的东西。这个东西为什么重要因为深度学习模型本质上是在一个巨大的函数空间里搜索如果没有归纳偏置搜索空间太大你根本搜不到有用的解。归纳偏置就是给搜索过程加约束让模型更可能找到“符合数据规律”的函数。我拿卷积网络和全连接网络做个对比。假设你处理一张224x224的RGB图像展平之后是150528维。如果第一层全连接层有1000个神经元那参数量就是1.5亿。而同样处理这张图一个64通道的3x3卷积层参数量只有1792。差了将近十万倍。为什么卷积能这么省参数因为它有两个很强的归纳偏置局部性相邻像素关系更紧密和平移等变性物体换个位置还是同一个物体。这两个假设在自然图像上几乎总是成立的所以卷积网络在图像任务上碾压全连接网络。但如果你把同样的卷积网络用在“用户ID序列”这种数据上局部性和平移等变性就不成立了效果可能还不如一个简单的全连接网络。这就是归纳偏置的适用边界。下一代机器智能算法设计的一个核心议题就是如何让模型自己学习归纳偏置而不是由人手工设计。图神经网络、Transformer、以及各种元学习框架本质上都在做这件事。但“自己学”不代表“没有”只是把选择权交给了数据和优化过程。这一点后面我会展开讲。2.3 表示学习从“人工特征”到“端到端”再到“自监督”深度学习最本质的贡献在我看来不是“更深”而是“表示学习”。传统机器学习需要你手工设计特征——SIFT、HOG、MFCC这些都是人根据领域知识提炼出来的。深度学习把特征提取和分类器放在一起端到端训练让模型自己学表示。这个转变的意义在于人只需要设计“学习的方式”不需要设计“学到的内容”。但端到端监督学习有个致命问题它需要大量标注数据。ImageNet有1400万张标注图片这在很多领域是不可想象的。所以下一代算法设计的另一个核心方向就是自监督学习——让模型从无标注数据中自己构造监督信号。比如掩码语言模型把句子里的某些词遮住让模型预测被遮住的词比如对比学习让模型判断两张图是不是同一个物体的不同视角。这些方法的核心思想都是数据本身的结构就可以提供监督信号不需要人来标注。我自己的体会是自监督学习之所以重要不只是因为它省标注更因为它改变了模型“看世界”的方式。监督学习下模型只关心“输入到标签”的映射标签没覆盖到的信息它一概不学。自监督学习下模型必须理解数据的整体结构才能完成预测任务这迫使它学到更通用、更鲁棒的表示。这也是为什么现在大模型预训练几乎都用自监督然后再用少量标注数据做微调。3. 经典算法设计决策的“为什么”拆解3.1 为什么是反向传播而不是别的反向传播现在看起来理所当然但回到上世纪八十年代它并不是唯一的选择。当时还有遗传算法、模拟退火、甚至随机扰动的方法来训练神经网络。为什么最后是反向传播胜出核心原因是计算效率。反向传播利用链式法则把损失函数对每个参数的梯度计算复杂度降到了和一次前向传播同量级。没有反向传播训练一个哪怕只有几层的网络都需要天文数字的计算量。但反向传播也有它的问题。最典型的就是梯度消失和梯度爆炸。当网络很深的时候梯度在反向传播过程中会连乘很多次。如果每层的梯度都小于1连乘之后就会趋近于0前面的层几乎收不到更新信号如果都大于1就会指数级增长导致训练发散。这个问题困扰了深度学习很多年直到残差连接、批归一化、以及更好的初始化方法出现才缓解。我自己的经验是如果你在训练一个超过20层的网络而且没有用残差连接那梯度消失几乎是必然的。这时候不要急着调学习率先检查你的网络结构有没有给梯度留“高速公路”。3.2 为什么是ReLU而不是Sigmoid激活函数的选择也是一个经典的算法设计决策。早期神经网络用Sigmoid或Tanh因为它们有很好的数学性质——光滑、可导、输出有界。但后来大家发现Sigmoid在输入稍微大一点或小一点的时候梯度就趋近于0这就是所谓的“饱和”问题。ReLURectified Linear Unit在正半轴梯度恒为1完全避免了饱和而且计算极其简单就是max(0, x)。这个看似简单的改变让训练深层网络变得可行。但ReLU也不是没有缺点。它在负半轴梯度为0导致一些神经元可能“死掉”——永远不再更新。所以后来有了Leaky ReLU、ELU、GELU等变体。我自己的实测经验是对于大多数视觉任务ReLU及其变体的差异其实不大真正重要的是初始化和归一化。如果你用He初始化配合ReLU训练稳定性会好很多。如果你用GELU那通常是在Transformer类模型里因为它对负值的处理更平滑适合注意力机制那种需要精细梯度的场景。3.3 为什么是批归一化而不是别的归一化批归一化Batch Normalization是另一个改变游戏规则的设计。它的核心思想很简单在每一层之后把激活值重新归一化到均值为0、方差为1然后再用一个可学习的缩放和平移参数恢复表达能力。为什么这么做有效一个直观的解释是它减少了“内部协变量偏移”——也就是每一层输入分布的变化。没有批归一化的时候前面层的参数更新会导致后面层的输入分布不断变化后面层就得不停地适应新分布训练效率很低。批归一化把分布固定住后面层就可以专心学习真正的模式。但批归一化有个硬伤它依赖批次统计量所以批次大小不能太小否则统计量不准。而且在推理阶段它用的是训练时累积的移动平均如果训练和推理的数据分布差异大效果会打折。所以后来有了Layer Normalization、Instance Normalization、Group Normalization等变体。我自己的选择逻辑是批次大且分布稳定用BatchNorm批次小或序列数据用LayerNorm风格迁移类任务用InstanceNorm。这个选择没有绝对的对错关键看你的数据特性和任务需求。4. 从基础到下一代算法设计的演进逻辑4.1 注意力机制从“固定连接”到“动态连接”如果说卷积网络的核心归纳偏置是“局部性”那注意力机制的核心就是“动态性”。卷积核的权重在训练完之后就固定了不管输入是什么它都用同一套权重去扫描。注意力机制不一样它根据输入本身计算权重——哪些位置重要哪些位置不重要是动态决定的。这个转变的意义在于模型不再被固定的连接模式限制可以根据内容自适应地调整信息流动。我拿机器翻译举个例子。在注意力机制出现之前序列到序列模型把整个源句子压缩成一个固定长度的向量然后解码器从这个向量生成目标句子。句子短的时候还好句子一长固定向量就装不下所有信息了。注意力机制让解码器在生成每个词的时候都能“回头看”源句子的所有位置然后决定重点关注哪些词。这个设计让长句翻译质量大幅提升。后来Transformer干脆把卷积和循环都扔了只用注意力结果在几乎所有序列任务上都取得了突破。但注意力机制也有代价。它的计算复杂度是序列长度的平方序列一长计算量就爆炸。所以后来有了各种稀疏注意力、线性注意力的变体。我自己的判断是注意力机制不是终点它只是“动态连接”这个思想的一种实现。下一代算法可能会找到更高效、更通用的动态连接方式。4.2 图神经网络当数据不再是网格卷积网络假设数据是网格状的——图像是二维网格音频是一维网格。但现实世界里很多数据是图结构的社交网络、分子结构、知识图谱。这些数据没有固定的邻居顺序也没有平移不变性。图神经网络GNN就是为这种数据设计的。它的核心思想是消息传递每个节点从邻居那里收集信息更新自己的表示然后重复这个过程。GNN的设计难点在于图的邻居数量不固定而且不同图的节点数也不同。所以GNN必须设计成可以处理变长输入的。另外GNN的深度不能太深因为每多一层节点就多聚合一次邻居信息几层之后所有节点都变得差不多这叫“过平滑”。我自己的经验是GNN通常2到4层就够了再深反而效果下降。这个和卷积网络动辄几十层形成鲜明对比也说明不同归纳偏置对应的最优深度是不一样的。4.3 元学习与自学习让算法自己设计算法下一代机器智能最让人兴奋的方向在我看来是元学习——让算法自己学习如何学习。传统的算法设计是人来选结构、选损失、选优化器。元学习试图把这些选择也交给模型让模型从大量任务中学习“什么样的算法在新任务上表现好”。这个想法很诱人但实现起来很难。最大的挑战是任务分布的设计——你让模型在什么任务上训练它就倾向于在类似任务上表现好。如果新任务和训练任务差异太大元学习的效果可能还不如手工设计。另一个方向是神经架构搜索NAS让算法自动搜索网络结构。NAS在图像分类上确实找到了比人工设计更好的结构但搜索成本极高需要大量GPU时间。我自己的看法是NAS目前更适合作为“灵感来源”而不是直接部署的方案。它找到的结构往往能揭示一些人工设计忽略的模式但直接拿来用可能过拟合搜索时的任务分布。5. 实操层面的关键细节与避坑指南5.1 损失函数设计的三个实操原则我在前面强调了优化目标的重要性这里展开讲三个我反复验证过的原则。第一损失函数必须和评价指标对齐。如果你最终看的是F1分数但训练用的是交叉熵那模型可能会偏向预测多数类因为交叉熵对类别不平衡不敏感。这时候要么改损失函数比如用Focal Loss要么在采样层面做平衡。第二损失函数要防止“作弊”。比如你让模型最小化两个分布的KL散度如果模型直接把输出设成常数KL散度可能也很小但这显然不是你想要的结果。这时候需要加正则项或者换用其他散度。第三多任务损失要小心权重。多个损失项相加的时候量级差异可能导致某个损失主导训练。我通常的做法是先单独训练每个任务观察各自的损失量级然后按比例缩放让它们在同一个数量级。5.2 学习率调度的经验法则学习率是训练深度学习模型最重要的超参数没有之一。我自己的经验法则是先用一个较大的学习率跑几百步观察损失曲线如果损失震荡或者发散就减小如果损失下降太慢就增大。找到大致范围后再用学习率预热和余弦退火来精细调整。预热就是一开始用很小的学习率慢慢增加到设定值这样可以避免训练初期的不稳定。余弦退火就是让学习率按余弦曲线从大到小变化最后趋近于0。这两个技巧配合使用在大多数任务上都能带来稳定的提升。但要注意学习率调度不是万能的。如果你的模型本身有bug比如梯度计算错了或者数据预处理有问题再好的调度也救不回来。我踩过的一个坑是数据归一化的时候训练集和验证集用了不同的均值方差导致验证损失一直比训练损失高很多我以为是过拟合调了半天正则化最后才发现是数据预处理的问题。所以我的建议是调参之前先确保你的数据管道和梯度计算是正确的。可以用一个小数据集做梯度检查或者用数值梯度对比反向传播的结果。5.3 正则化的选择与组合正则化是防止过拟合的手段但不同的正则化方法作用机制不同不能随便堆。L2正则化让权重趋向于小值适合大多数场景Dropout随机丢弃神经元适合全连接层但在卷积层效果一般批归一化本身就有正则化效果所以用了批归一化之后通常可以减小Dropout比例数据增强是最有效的正则化尤其是图像任务随机裁剪、翻转、颜色抖动几乎总是能带来提升。我自己的组合策略是数据增强打底批归一化稳定训练L2正则化控制权重Dropout只在全连接层用且比例不超过0.5。如果还过拟合优先加数据增强而不是加Dropout因为Dropout太强会导致欠拟合。6. 下一代机器智能算法设计的几个可能方向6.1 从“固定计算”到“自适应计算”现在的深度学习模型不管输入难易计算量都是固定的。一张简单的图片和一张复杂的图片经过的网络层数、每层的计算量完全一样。这显然不高效。下一代算法可能会引入自适应计算——简单样本少算复杂样本多算。这个思想在早期退出Early Exit和条件计算Conditional Computation里已经有雏形。比如在网络的中间层加一个分类器如果中间层的结果已经足够自信就直接输出不再往后算。这样简单样本可以提前退出节省计算。但自适应计算也有挑战。最大的问题是训练不稳定——模型可能会倾向于走捷径在中间层就给出草率的答案。所以需要设计合适的损失函数来平衡准确率和计算量。我自己的实验体会是自适应计算在推理阶段确实能省不少计算但训练阶段的开销会增加而且调参更复杂。它更适合对推理延迟敏感的场景比如移动端或实时系统。6.2 从“单模态”到“多模态融合”人类理解世界从来不是单模态的——我们看到图像、听到声音、读到文字然后在大脑里融合这些信息。现在的深度学习模型大多是单模态的图像模型只看图语言模型只看文字。下一代算法必然会走向多模态融合。多模态的核心难点是对齐——如何让图像里的“猫”和文字里的“猫”在同一个表示空间里对应起来。对比学习是目前最常用的方法让匹配的图像-文本对在表示空间里靠近不匹配的远离。我自己的观察是多模态模型在零样本任务上表现惊人但在需要精细推理的任务上还有很大提升空间。比如你问它“图中的人是在笑还是在哭”它可能答对但你问它“图中的人为什么笑”它可能就答不上来。这说明多模态模型目前更多是在做“模式匹配”而不是真正的“理解”。下一代算法需要在这方面有所突破。6.3 从“静态模型”到“持续学习”现在的模型训练完之后就固定了新数据来了只能重新训练。但现实世界是不断变化的模型需要能够持续学习——在不忘记旧知识的前提下学习新知识。这个问题的难点在于“灾难性遗忘”模型学新任务的时候旧任务的性能会大幅下降。解决思路主要有三种一是正则化方法限制重要权重的变化二是回放方法保留一部分旧数据和新数据一起训练三是参数隔离方法为不同任务分配不同的参数子集。我自己的经验是持续学习目前还没有一个通用的解决方案。回放方法效果最好但需要存储旧数据有隐私和存储成本正则化方法不需要存数据但效果不稳定参数隔离方法扩展性好但任务多了之后参数会爆炸。下一代算法可能需要从更根本的层面解决这个问题比如设计一种“可塑性”和“稳定性”自动平衡的机制。7. 常见问题与排查技巧实录7.1 训练损失不下降我该从哪里查起这是最常见的问题我把它拆成一个排查清单。第一步检查数据。把输入数据可视化出来看看有没有标签错位、归一化错误、数据增强过度。我遇到过好几次标签和图像不对应的情况排查了半天才发现是数据加载器的shuffle逻辑写错了。第二步检查梯度。用一个小批次的数据计算数值梯度和反向传播梯度对比它们是否一致。如果不一致说明反向传播实现有bug。第三步检查学习率。学习率太大导致震荡太小导致下降慢。可以尝试用学习率扫描从1e-6到1e-1每个学习率跑几百步看哪个损失下降最快。第四步检查初始化。如果所有输出都相同可能是初始化导致对称性没有打破。可以尝试不同的初始化方法比如Xavier或He初始化。7.2 验证损失比训练损失低这是怎么回事通常验证损失比训练损失高是过拟合但反过来验证损失更低说明有别的因素在起作用。最常见的原因是训练时用了正则化验证时没用。比如训练时用了Dropout验证时Dropout关闭模型在验证集上的表现自然更好。另一个原因是训练损失是每个批次的平均而验证损失是整个验证集的平均如果训练批次大小小批次间的方差大平均下来可能偏高。还有一种可能是数据分布不同——验证集可能比训练集更简单。我自己的处理方式是先确认正则化在验证时是否正确关闭然后对比训练集和验证集的分布如果分布差异大需要重新划分数据集。7.3 模型在测试集上表现差但在验证集上很好这是典型的过拟合验证集。原因通常是你根据验证集反复调参模型间接“看到了”验证集的信息。解决方法很简单划出一个独立的测试集在最终确定模型之前绝对不要碰它。我自己的习惯是训练集用来训练验证集用来调参和早停测试集只在最后评估一次。如果测试集表现差很多说明调参过度了需要简化模型或者增加正则化。另一个可能的原因是测试集和验证集的分布不同比如测试集包含了验证集没有的类别或场景。这时候需要分析测试集的错误样本看看模型在哪些情况下失败然后针对性地补充训练数据。7.4 训练速度太慢怎么优化训练速度慢可能来自多个环节我按优先级排个序。第一数据加载。如果GPU利用率低很可能是数据加载成了瓶颈。可以用多进程数据加载或者把数据预处理成更高效的格式。第二批次大小。批次太小GPU并行度不够批次太大内存不够。可以尝试梯度累积用小批次模拟大批次。第三混合精度训练。用FP16代替FP32速度可以提升一倍左右而且现在大多数框架都支持自动混合精度几乎不需要改代码。第四模型并行或数据并行。如果单卡放不下模型可以用模型并行如果数据量大可以用数据并行。我自己的经验是混合精度训练是性价比最高的优化几乎总是能带来速度提升而且对精度影响很小。8. 我个人的一些体会写了这么多最后说几句我自己的真实感受。深度学习算法设计这件事看起来是在跟数学和代码打交道但本质上是在跟“假设”打交道。你假设数据是什么结构你假设什么信息重要你假设模型应该怎么学——这些假设决定了算法的上限。下一代机器智能算法不管形式怎么变核心都是在寻找更好的假设或者让模型自己找到更好的假设。我刚开始做算法的时候总想着找到一个“万能”的结构能解决所有问题。后来发现没有万能的结构只有适合特定问题的归纳偏置。卷积适合图像循环适合序列注意力适合长距离依赖图网络适合关系数据。下一代算法可能会打破这些界限但打破的方式不是找到一个万能结构而是让模型能够根据数据自动选择合适的归纳偏置。还有一个体会是不要迷信新方法。我见过太多人一上来就用最新的Transformer变体结果在一个小数据集上过拟合得一塌糊涂还不如一个简单的卷积网络。算法设计的第一原则是匹配问题复杂度。问题简单模型就简单问题复杂再考虑复杂模型。这个原则听起来很朴素但真正能做到的人不多。最后分享一个小技巧。每次设计新算法之前先写一个“最笨”的基线——哪怕就是一个线性分类器或者最近邻。这个基线不仅能给你一个性能下限还能帮你理解数据的难度。如果线性分类器就能达到90%的准确率那你花大力气设计复杂模型可能只为了提升几个百分点性价比很低。如果线性分类器只有50%那说明问题确实需要非线性模型你的复杂设计才有意义。这个习惯帮我省了很多时间也让我对问题的本质有了更清晰的认识。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →