资讯动态

深度信念网络详解:从受限玻尔兹曼机到无监督预训练与微调

发布时间:2026/10/20 16:23:40 来源:尧图企业网站定制
深度信念网络DBN这个名词现在很多深度学习入门教程里已经不太常提了但它仍然是理解整个深度学习演进路线上绕不过去的一站。经典教材往往会把这部分放在第12章这样的后半段位置原因是前面得先把概率图模型、玻尔兹曼机、反向传播这些地基垫好不然很难讲清楚它到底在做什么。不过教材的篇幅有限读者最后经常只记住一堆能量函数和采样公式落到自己的项目里依然不知道从哪下手。这篇我想用做实际模型训练比较直接的口吻把DBN拆开重新过一遍它当年解决了什么问题、受限玻尔兹曼机是怎么当积木用的、逐层贪婪预训练怎么把网络变深、微调阶段模型性质发生了什么变化。如果你在阅读相关经典论文或者想了解除了CNN、Transformer之外的另一条表征学习路线这篇文章配合代码可以帮你少走一些弯路。1. 深度信念网络出现前深层模型卡在哪一步在真正动手复现DBN之前我对它的印象也停留在“很老、已经被新模型替代了”这个层面。跑通一轮之后才发现这个判断太武断了。DBN里藏着的很多思路今天照样活跃在自编码器、生成模型以及各类无监督预训练流程里。1.1 梯度消失之外的另一道坎现在一谈到深度网络训练困难大家第一反应就是梯度消失。这个说法对但不全面。深度信念网络在提出的年代要面对的问题其实分两层。第一层确实是梯度消失。当时主流的非线性激活函数还是S型函数导数在饱和区趋近于零。一个十几层的网络反向传播的梯度信号经过多层相乘传回前几层时基本已经衰减到可以忽略。这直接导致网络前部学不到有效参数整个模型只是名义上“深”实际有效层数不多。第二层是初始化困境。没有可靠的大规模初始化方法时深度模型一开始就落在损失曲面比较糟糕的区域反向传播推很久都推不出来。预训练的价值就体现在这里它先把每一层初始化为一个还不错的特征提取器完全不依赖标签然后从这样更有意义的起点出发去做整体优化。有很多资料把DBN描述成“为了解决梯度消失而生”。这个说法不够准确。它真正解决的问题是让深度网络从一开始就站在一个有结构的数据表示上而不是站在随机权重上硬闯。1.2 无监督预训练为什么一时间被看作通用解法DBN的另一个关键贡献是“无监督预训练”这个操作本身。对于一批图像你完全可以不关心它的类别标签因为数据本身有结构手写数字的笔划粗细、方向、局部曲率都呈现重复出现的模式。用无监督方法先把这些统计规律提取出来后续的有监督训练通常只需要在一个很小的分类头上进行。当时一批工作反复验证过用预训练权重做初始化再去反向传播效果远好于从随机初始化开始硬训。预训练不是锦上添花而是让深度结构能够真正收敛的前提条件。后来随着更好的初始化方法、批归一化、残差结构出现端到端训练也能收敛得很好无监督预训练才从“必需品”退成“可选手段”。但理解它为什么曾经是必需品仍然能帮你理清很多后续模型的动机。2. 核心积木受限玻尔兹曼机深度信念网络不是随便拿几层神经网络叠在一起的纯前馈结构它的地基是受限玻尔兹曼机RBM。RBM本身就是一个带随机变量的概率模型理解它之后DBN的堆叠逻辑才会顺起来。2.1 能量函数从物理中借来的语言RBM是无向概率图模型有一层可见单元v和一层隐藏单元h。名字里“受限”这个词很关键可见层内部没有连接隐藏层内部也没有连接只有可见单元和隐藏单元之间存在权重边。它的能量函数如下 E(v,h) -Σ_i a_i v_i - Σ_j b_j h_j - Σ_i Σ_j v_i W_ij h_ja_i是可见偏置b_j是隐藏偏置W_ij是两层之间的权重。能量取负指数后做归一化就得到联合分布 p(v,h) exp(-E(v,h)) / Z这里的Z是配分函数要对所有可能的(v,h)状态组合做指数级求和几乎不可能精确计算。所以后面所有训练算法本质上都在想办法绕开Z。把能量函数拆开理解会直观很多如果一块输入图像和一组隐藏特征同时出现时能量很低说明这对组合是“舒服”的如果能量很高说明模型认为这种搭配不合理。训练RBM就是调整能量参数让真实数据所在状态能量降下去让随机搭配的状态能量抬起来。2.2 条件分布与吉布斯采样因为RBM层内没有连接给定一层时另一层的条件概率可以因式分解成很简单形式 p(h_j1|v) σ(b_j Σ_i v_i W_ij) p(v_i1|h) σ(a_i Σ_j h_j W_ij)也就是说知道所有可见单元的情况下某个隐藏单元是否激活只取决于自身偏置和可见单元按权重的线性加权和反过来也一样。有了这两个条件概率就可以用两步交替采样根据当前可见状态v算出每个h_j的激活概率按该概率抽样得到隐藏状态h根据当前隐藏状态h算出每个v_i的激活概率按该概率抽样得到新的可见状态v不断重复这个过程。这个流程叫吉布斯采样。理论上交替足够多轮之后采出的(v,h)会趋近模型分布p(v,h)。但真正要去跑那么多轮采样计算开销很大所以后面才有了对比散度算法。2.3 对比散度让负相估计变得可计算训练RBM的方向是最大化数据对数似然log p(v)。对参数求导之后梯度会分成正负两项 ∂log p(v)/∂W_ij E_data[v_i h_j] - E_model[v_i h_j]第一项叫正相表示数据分布下的期望可以用训练样本和隐藏单元后验概率直接估计第二项叫负相表示模型分布下的期望严格来说要等吉布斯采样跑到稳态之后再从模型分布里采样估计。这是训练开销最大的部分也是稳定性最差的部分。对比散度CD做了一个大胆近似既然吉布斯采样的目标是模型分布那就直接从真实数据出发只跑k步吉布斯采样用最终的重建状态来近似模型的负相样本。因为起点离真实数据不远k1通常就够用计算成本一下子降了下来。于是更新规则可以写成 ΔW ε(⟨v^0 h^0^T⟩_data - ⟨v^k h^k^T⟩_recon) Δa ε(⟨v^0⟩_data - ⟨v^k⟩_recon) Δb ε(⟨h^0⟩_data - ⟨h^k⟩_recon)上标0代表原始可见输入k代表跑完k步吉布斯采样后的重建状态。注意这类梯度是带近似误差的所以在实际训练里很难看到平滑下降的loss曲线通常需要靠重建误差、重建图像质量这些信息来监控训练状态。3. 从单体RBM到DBN逐层贪婪预训练单个RBM只学一层隐藏表示已经能做一些有趣的事情但离“深度”还有距离。深度信念网络的核心操作是把多个RBM串起来而且采用逐层贪婪训练每次只训练一层锁住前面的权重再用前面层的输出作为下面一层的输入。3.1 堆叠顺序与新的数据表示具体训练过程拆成四步看会很清楚把原始数据v当作可见层训练第一个RBM得到第一层权重W1用W1把所有样本正向传播成隐藏表示h1。这里可以用概率σ(W1 v b1)也可以按伯努利抽样但下一层训练时一般用概率会稳定一些把h1当作新一层的可见输入训练第二个RBM得到W2重复下去直到覆盖设定好的层数。所以初看DBN会觉得很像普通多层网络但它其实是一个混合概率图模型。最底下的若干层之间是有向的数据从可见层向上传播最上面两层之间是无向的因为它们原本就是同一个RBM里的可见层和隐藏层。顶层这个无向连接非常关键它让DBN在顶层保持了一种“联想记忆”机制可以从中间表示重新生成出看起来合理的输入样本。有个细节经常被人忽略逐层预训练过程中每一层RBM面对的可见层分布并不相同。第一层在原始图像上训练第二层在第一层隐藏概率空间上训练第三层又在第二层的隐藏概率空间上训练。每一层都只负责重新表达它看到的输入找更紧凑的内部表征。这种一层层重新编码的过程才是DBN能够自动学到层次化特征的根本原因。3.2 顶层无向连接意味着什么很多人把DBN简化理解成“很多个RBM直接叠起来”这个说法只对了一半。关键在顶层那几个RBM并不只是作为普通隐藏层安放它还负责生成性质。你可以把DBN理解成一个带记忆底座的生成系统顶层无向结构负责捕捉全局的高阶关联之下的有向层再把这些高阶关联逐层“解释”到可见空间。所以DBN不仅能做判别任务理论上还能从顶层状态出发反向采样出新样本。这一点让它和纯粹判别式的网络结构拉开了距离。后续的有向生成模型比如各种VAE变体基本不再沿用这种顶层无向结构因为无向层训练复杂、采样成本高。但在当时这是少有的能同时把判别路径和生成路径都放进一个深度模型里的做法。3.3 预训练之后模型发生了什么完成预训练时分类器还没影子但模型已经和随机初始化大不一样了。每一层RBM的重建误差在下降说明它已经记住了大量数据中的统计结构。这时把预训练得到的权重作为初值再接一个输出层去做反向传播效果会比随机初始化好不少。原因有两个一是隐藏层已经形成了有意义的中间特征分类头只需要在优质特征上加一层简单决策边界二是初始点所在损失曲面区域相对理想后续反向传播不容易陷进平坦的坏局部极小值。在实际项目里的体感是预训练带来的收益在数据量少、标签稀缺时尤其明显。数据量巨大时反向传播自己也能从零学出特征预训练优势会被稀释。但数据少的时候DBN这套“先用无监督结构垫底、再补监督头”的做法比拿一个小网络硬训要稳定得多。4. 微调阶段从生成式约束到判别式输出预训练完成之后DBN还不能直接做分类或回归需要一步微调把它变成标准前馈判别网络。4.1 网络展开与确定性映射“展开”这个操作听起来抽象其实就两件事。第一把概率采样替换成确定性激活。预训练阶段隐藏单元的激活方式是随机伯努利采样微调阶段直接令h_j σ(...)去掉随机性。第二把层与层之间的权重组成普通前馈路径。展开之后DBN在结构上就等价于一个多层感知机每层是仿射变换加激活输出层按任务换成softmax或线性输出。到这一步顶层原来的无向连接也无需继续保留退化成普通权重矩阵。只需要把它接成前馈图监督信号就能通过反向传播流向所有层。4.2 反向传播微调和权重层级的衔接微调训练用的是最常见的交叉熵损失加反向传播。有一个操作细节特别值得强调微调的学习率往往要比预训练阶段更小优化器也建议从朴素SGD换成带动量版本或自适应方法。复现DBN翻车的原因很多都是预训练权重已经被调到了不错的状态结果刚进入微调阶段梯度较大又沿用预训练的大学习率几步更新就把预训练结构破坏了。这像房间里的家具刚摆放好你用一台大功率吸尘器横扫全屋反而把整齐的摆设撞得乱七八糟。稳妥做法是先用一个比较小的学习率跑几个epoch看验证指标是在上升还是下降再逐步调整。4.3 DBN真正值得保留的技能点单论最终准确率今天的很多任务上DBN确实不占优势。但它的微调流程里藏着一个至今依然好用的通用套路先无监督学习结构再小步慢调做监督对齐。这套流程后来被各种“预训练微调”框架重复了无数次。你在自然语言处理里看到的大规模预训练之后再做下游任务适配在图像领域看到的自监督预训练再finetune本质上和DBN先堆RBM学特征、再反向传播对齐标签是一个思路。所以学DBN最值得带走的其实是这套分工逻辑无监督阶段只管数据内在结构监督阶段只管任务对齐。这个心智模型远比具体网络结构耐用。5. 用自动微分框架实现一个手写数字识别DBN理论说完了落地最要紧。下面给出一套可运行的最小实现思路数据集用手写数字这类公开图像数据。这里我不绑定某个具体深度学习框架的API只保留核心逻辑。RBM没有现成模块所有代码基本都要自己写参数更新。5.1 数据准备与预处理对Bernoulli版本的RBM来说可见单元的输入分布很重要。手写数字图通常是0到255灰度值而毫尔伯努利可见单元假设输入是二值的。实践中最简单的方法是直接把像素归一化到[0,1]训练时按概率处理为0到1之间的浮点值也可以显式二值化把每个像素按阈值切成0/1。两种方式都能用归一化方式一般效果更稳。如果你处理的是连续型数据比如音频特征或高维稠密向量建议换成高斯RBM那是另一套能量函数原理类似但细节不同不要直接照搬Bernoulli版本。5.2 RBM核心类与CD步RBM核心就三部分权重矩阵W、可见偏置v_bias、隐藏偏置h_bias外加一套交替采样逻辑。示意代码如下import math def sigmoid(x): return 1.0 / (1.0 math.exp(-x)) class RBM: def __init__(self, n_vis, n_hid): self.W std_randn((n_vis, n_hid)) * 0.01 self.v_bias zeros(n_vis) self.h_bias zeros(n_hid) def sample_h(self, v): h_prob sigmoid(v self.W self.h_bias) # 按概率采样伯努利值同时返回概率用于后续更新 return h_prob, bernoulli_sample(h_prob) def sample_v(self, h): v_prob sigmoid(h self.W.t() self.v_bias) return v_prob, bernoulli_sample(v_prob) def cd_update(self, v0, k1, lr0.01): h_cur v0 for _ in range(k): h_prob, _ self.sample_h(h_cur) _, h_cur self.sample_v(h_prob) h_prob0 sigmoid(v0 self.W self.h_bias) h_probk sigmoid(h_cur self.W self.h_bias) positive v0.t() h_prob0 negative h_cur.t() h_probk grad_w (positive - negative) / v0.size(0) grad_v mean(v0 - h_cur, dim0) grad_h mean(h_prob0 - h_probk, dim0) self.W lr * grad_w self.v_bias lr * grad_v self.h_bias lr * grad_h这里的std_randn、bernoulli_sample只是示意符号。在用自动微分框架实现时把它们替换成对应的随机初始化和伯努利采样API即可。CD步数k设成1是最常见的起点多数任务上效果已经不错更大的k未必带来更快的收敛。5.3 堆叠为DBN并微调训练完第一层RBM后把所有样本输入到第一层得到隐藏概率h1。然后用h1作为下一层RBM的可见输入继续训练。rbm1 RBM(784, 500) # 用原始特征训练rbm1若干轮得到h1 rbm2 RBM(500, 200) # 用h1训练rbm2若干轮 # 微调把两层展开成784-500-200-10的MLP # 保留rbm1.W、rbm2.W作为初始权重末端接softmax # 使用较小学习率做交叉熵训练看起来和普通多层感知机没什么区别关键差异在初始权重普通MLP直接随机初始化这里用的是经过无监督预训练的权重。微调时只随机初始化最后一层分类权重其它层沿用预训练权重然后用较小学习率跑交叉熵损失。这里有一个实操建议预训练过程中向下一层喂数据时尽量用隐藏概率而不是伯努利样本。采样会放大随机噪声概率版本相当于做了一次平滑训练更平稳。6. 实际使用中的参数权衡与DBN的现代定位能跑通只是第一步真正把DBN调好还要理解几个容易翻车的参数以及它和现代模型之间的关系。6.1 学习率、批大小、CD步数对结果的影响对比散度训练过程里没有平稳的loss曲线最直观的监控指标是重建误差把原始输入送入RBM得到重建结果然后计算两者差的平方和。重建误差在下降说明模型正在捕捉数据分布。学习率是最常见的翻车点。CD梯度本身就是近似量如果学习率太高近似误差会被逐轮放大很快就出现重建误差骤升甚至数值爆炸。我通常把RBM学习率放在0.005到0.05之间手写数字这样的小型数据取0.01比较稳。批大小也影响很大。批次太小时正相和负相估计方差变大CD更新方向不稳定批次太大又会让单次更新变慢整体收敛效率不高。图像数据上128到256是比较常见的选择。至于CD步数CD-1几乎总是首选。更多步数理论上让负相更接近真实模型分布但计算量涨了收敛速度并不会变快。除非你明确要做更好的生成采样器否则不必刻意用更长的链。6.2 和CNN、自动编码器怎么选把DBN放到现在的工具箱里必须承认它既不是最快的解法也不是精度最高的解法。选择哪种模型取决于你的具体任务图像分类且标签量充足直接上CNN或完整的端到端网络。预训练优势会被大量数据稀释没必要额外增加复杂度。想提取无监督表征且数据规模不大自动编码器比DBN更容易训练。DBN有更强的概率生成背景但参数多、调参难度大。输入是高维稀疏向量比如行为日志、点击序列RBM类模型曾经是经典选项今天也可以用分解机或序列模型替代。6.3 适合DBN的场景如果让我给一个当前环境下是否值得投入DBN的判断我会分三种情况第一类是学习和理解深度学习历史那无论如何都值得亲手写一遍RBM和DBN直觉训练会有很大提升。第二类是小样本问题。只有几千条训练样本时无监督预训练提供的初始化价值非常明显。这时候DBN或者类似的预训练加微调流程往往能比从零开始硬训的深层网络表现更好。第三类是明确需要概率模型和不确定性的场景。如果你不只是要特征还要可解释生成过程DBN这类带能量建模的模型仍有参考意义。调了这么多轮DBN我最深的感受是它今天被取代的只是具体结构而不是底层哲学。预训练加微调这个范式或者“先学统计结构再做任务对齐”的思路现在依然在几乎所有主流模型里延续着。如果你想在深度学习里建立更完整的坐标系在第12章这种位置认真停留一下绝对值回票价。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑