拓冰建站拓冰建站
首页 / 资讯中心 / 正文

DBN多特征分类实战:基于Matlab的RBM预训练与BP微调实现

简介深度置信网络DBN由多层受限玻尔兹曼机RBM堆叠而成通过逐层无监督预训练提取数据分布再结合BP神经网络进行有监督微调有效缓解了传统BP网络在小样本、多特征分类场景下易陷入局部最优的问题。RBM采用对比散度算法近似求解能量模型梯度使得特征学习更加稳健将预训练权重展开为前馈网络后仅需少量迭代即可收敛。本文围绕Matlab实现展开从RBM能量模型与采样机制、DBN结构展开与微调流程到main.m中数据归一化、网络参数设置、分类效果图与混淆矩阵分析完整覆盖了模型训练、调参、保存与批量预测的关键环节。该方法适用于工程中快速构建二分类或多分类模型尤其适合特征维度较高而样本量有限的工业数据场景。1. 为什么多特征分类我会选DBN而不是直接堆BP网络当手上只有一千多条样本、每条样本却带十几个特征时直接堆BP网络容易陷入局部最优训练误差曲线抖得像心跳。DBN先用受限玻尔兹曼机逐层无监督学习特征分布再用BP监督微调相当于先让网络“看懂”数据再学“分类”。这份Matlab源码完整实现了从RBM预训练到反向传播微调的整条链路输入Excel里的多列特征输出单一分类标签二分类、多分类都能跑。它能直接给出分类效果图、迭代优化图和混淆矩阵图特别适合要快速出结果并且想读取DBN内部结构的人。下面按源码的调用顺序拆开讲。2. DBN训练流程与Matlab代码模块的对应关系2.1 RBM预训练从能量模型到对比散度DBN底层是RBM堆叠。RBM定义了一个能量函数[ E(v,h) -\sum_i a_i v_i - \sum_j b_j h_j - \sum_{i,j} v_i W_{ij} h_j ]可见单元 (v) 和隐藏单元 (h) 的联合概率与能量相关训练的目标是让输入数据的似然最大。直接求这个似然梯度需要计算配分函数复杂度指数级所以Hinton引入了对比散度CD-1。操作上就是正反向各采样一次用重构误差近似真实梯度。在源码里面rbmtrain.m就实现了CD-1。核心循环是这样% rbmtrain.m 的CD-1核心循环简化 for i 1 : numepochs % 正向可见层到隐藏层sigmrnd是随机采样 pos_hidden_prob sigmrnd(repmat(rbm.b, size(x,1), 1) x * rbm.W); pos_associations x * pos_hidden_prob; % 反向隐藏层重构可见层再用sigm得到确定概率 neg_visible_prob sigm(repmat(rbm.c, size(x,1), 1) pos_hidden_prob * rbm.W); neg_hidden_prob sigm(repmat(rbm.b, size(x,1), 1) neg_visible_prob * rbm.W); neg_associations neg_visible_prob * neg_hidden_prob; % 更新权重和偏置 rbm.W rbm.W rbm.learning_rate * (pos_associations - neg_associations) / size(x,1); rbm.c rbm.c rbm.learning_rate * sum(pos_hidden_prob - neg_hidden_prob) / size(x,1); end逻辑是先用随机采样得到pos_hidden_prob再通过重构得到neg_visible_prob和二次采样的neg_hidden_prob最后用正负关联矩阵的差乘上学习率更新 (W)。这里用sigmrnd而不是sigm是因为CD要求从概率分布中采样而不是只取确定性概率值否则模型会被困在概率大于0.5的固定路径上起不到对比散度的作用。再看两个辅助函数rbmup.m负责从可见层算隐藏层激活概率rbmdown.m负责从隐藏层采样出可见层。这两个文件都很短通常不超过10行但它们在预训练循环里被反复调用。tanh_opt.m和sigm.m是激活函数tanh_opt是带截断的tanh收敛速度比sigmoid快适合隐藏层sigm用于需要0到1概率的场景。2.2 从RBM堆叠到DBNdbnunfoldtonn展开RBM预训练完成后DBN还只是多个RBM的松散堆叠没法直接拿来做有监督分类。dbnunfoldtonn.m会把每个RBM的权重矩阵转置后填入一个标准BP网络结构体同时把最后一层随机初始化。之所以要转置是因为RBM权重保存的是“可见层-隐藏层”的映射而在BP前向传播中权重矩阵的方向是反的。展开后进入微调段。nnsetup.m建立网络nnff.m做前向传播nnbp.m做反向传播nnapplygrads.m把梯度更新到权重。这四步和普通BP完全一样不同之处是起点DBN的初始权重来自无监督预训练而不是随机高斯。所以即使在样本不多时微调也只需要几十轮就能收敛到一个不错的分类平面。softmax.m在微调阶段的输出层使用它把多个输出节点转换为和为1的概率分布配合交叉熵损失使得多分类训练更稳定。注意这里有个容易误读的地方dbnunfoldtonn.m的最后一个参数不是RBM层数而是输出类的数目填错了网络尺寸就会对不上运行nnff时直接报矩阵维度错误。2.3 源码文件与分工速查表文件作用关键参数dbnsetup.m初始化DBN结构体dbn.sizes各层节点数rbmtrain.m训练单个RBMlearning_rate,numepochsrbmup.m/rbmdown.mRBM向上采样与向下重构无额外参数dbnunfoldtonn.m将RBM展开为NN输出类别数nnsetup.m/nntrain.m初始化并训练BP网络activation_function,output,learningRatennff.m/nnbp.m/nnapplygrads.m前向/反向/梯度更新nn.a,nn.deltasoftmax.m/sigm.m/tanh_opt.m激活函数数据矩阵nnpredict.m预测新样本返回标签main.m串联整个流程数据集路径这张表相当于源码地图。我拿到这类工具箱时会先从main.m找数据读取和参数设定再跳到dbntrain.m和nntrain.m看调用顺序最后根据自己的网络设计修改dbn.sizes。在流程跑通之后再回头细读rbmtrain.m和nnbp.m这样比从头到尾逐行看效率高得多。2.4 预训练质量的快速检查在微调之前可以通过重构误差判断RBM是否学到了特征。rbmtrain.m运行时会在每次迭代后计算一次重构误差但这个值只存在临时变量里脚本结束就丢了。我一般会在main.m里加一段保存重构误差的代码用plot画出来。如果误差在100轮内从0.9降到0.5以下说明预训练有效如果误差始终在1附近波动多半是学习率太大或sigmrnd被误改成了sigm导致随机性被破坏。3. main.m实战从Excel数据到三张分类图3.1 读取数据集.xlsx并进行归一化程序自带“数据集.xlsx”main.m第一步是读数据。我用一个18特征二分类的示例来说明% 读取Excel data readtable(数据集.xlsx); X table2array(data(:, 1:18)); % 前18列为特征 y table2array(data(:, 19)); % 第19列为标签 % mapminmax默认按行归一化所以要转置 [X_norm, ps] mapminmax(X, 0, 1); X_norm X_norm;readtable会把Excel的首行默认作为变量名如果你的表第一行就是数据要加ReadVariableNames, false。特征列换成多少列都行但X和y行数必须一致。归一化时mapminmax把每一行即每个特征映射到0~1这样量纲不同的特征不会在RBM的权重更新中相互压制。ps保存的是每个特征的最大最小值后面预测新样本时必须用同一个ps。如果觉得mapminmax不好理解也可以用zscore做标准化效果类似。只是无论选哪种都要保证训练和测试用同一种变换不能在测试集上重新计算均值方差。我见过不少把测试数据单独mapminmax(X_test)导致模型崩溃的案例问题就在这里。3.2 搭建DBN结构和训练参数main.m中网络搭建一般分成两步先训练RBM堆再展开并微调。参考代码% 设置预训练结构18个输入 - 60 - 30 - 输出层 dbn dbnsetup(dbn, X_norm, y, opts); dbn.sizes [60 30]; dbn dbntrain(dbn, X_norm, opts); % 展开成前馈网络输出层节点数为类别数 nn dbnunfoldtonn(dbn, 2); nn.activation_function sigm; nn.output softmax; nn.learningRate 0.5; nn.numepochs 200; nn.batchsize 32; % 开始有监督微调 nn nntrain(nn, X_norm, y_train, opts);dbn.sizes决定RBM隐藏层宽度这个值可以根据特征数量调整。特征有18个时第一层60个节点是够用的特征上百时可以考虑两倍特征数量起步比如200。dbnsetup会自动把第一层大小设为输入维数但不会改后面的节点数所以dbn.sizes只写隐藏层就行。dbnunfoldtonn第二个参数2代表二分类如果换成unique(y)的数量就变成多分类模型。nn.learningRate是微调阶段的全局学习率0.5在两层隐藏层时通常能收敛但如果你加了第三个隐藏层建议降到0.2以下。nn.numepochs是微调轮数要配合误差下降曲线来判断我先设200轮观察如果曲线在最后还在下降就改成500轮。提示opts里面通常有opts.numepochs和opts.batchsize它们控制的是RBM预训练阶段nn结构体里的同名参数控制微调阶段。改参数时要确认改对位置。配置项对应变量示例取值输入特征维度size(X_norm,2)18隐藏层节点dbn.sizes[60 30]输出类别数dbnunfoldtonn第二参2微调学习率nn.learningRate0.5每批样本数nn.batchsize32这张表就是为了替换数据时方便对照。如果你把特征数从18改成50第一行不用动但要记得把dbn.sizes的首位改成匹配输入规模的节点数否则dbnsetup也会报错。3.3 分类效果图、迭代优化图和混淆矩阵图程序运行结束会弹出三张图对应三种验证手段。迭代优化图看的是训练误差变化可以用nn.train.error直接重画figure; plot(nn.train.error, LineWidth, 1.5); xlabel(迭代轮数); ylabel(误差); title(DBN迭代优化曲线); grid on;分类效果图在二维空间里展示预测和真实类别通常取前两个主成分或前两个特征作为横纵坐标。混淆矩阵可以用plotconfusion自动画但某些Matlab版本没装深度学习工具箱时不可用这时用手写版本pred nnpredict(nn, X_test_norm); cm confusionmat(y_test, pred); disp(混淆矩阵); disp(cm); figure; heatmap(cm, XLabel, 预测标签, YLabel, 真实标签);这里nnpredict返回的行向量是每个样本的类别编号confusionmat会自动按类别排序。多分类时看混淆矩阵要注意类别样本量某个类别样本特别少时就算准确率高也可能在这个类上全错。程序里已经写好了这些图的保存逻辑但我习惯把figure句柄显式指定避免多个图重叠。3.4 替换成自己的数据集时要注意的细节直接替换数据的确可以用但有四个细节必须处理。第一Excel里不要有合并单元格和表头注释readtable会把注释行当作数据读进来造成列数错乱。第二标签列必须是double类型如果Excel里存的是字符串“’是‘/’否‘”程序跑不下去先在Excel里用公式转成1和2。第三样本顺序如果存在时间排序不要用随机划分应该按时间窗口拆训练测试集否则未来信息泄漏会虚高准确率。第四替换数据后最好确认一下每类的样本数二分类里如果某类只占5%DBN会倾向把边界全划给多数类这时应该考虑采样平衡。4. 二分类与多分类的切换、常见坑与调参建议4.1 输出层与标签编码的匹配这套代码沿用Hinton早期DeepLearningToolbox的习惯多分类用softmax输出层二分类也可以直接用softmax只是类别数设置为2。标签编码必须从1开始连续比如三分类只能是1、2、3。如果原始Excel里用0、1、2需要先执行y y 1。另外不要混合使用输出层nn.output softmax之后最终误差函数自动切换为交叉熵如果改成sigm误差会用MSE这时输出概率不再保证和为1多分类效果通常会变差。这个参数不是随便选的它决定你损失函数和梯度末端的形式。4.2 调参策略学习率、动量、批量大小调参顺序很重要。我先固定网络层数[60 30]然后调学习率再调批大小最后才是层数。下面这个表是多轮实验后的经验范围参数推荐范围异常表现RBM预训练学习率0.01 ~ 0.05过大重构误差震荡隐藏层激活几乎全为0或1微调学习率0.1 ~ 0.8过大分类准确率在训练中骤降过小误差曲线下降缓慢动量系数0.5 ~ 0.9过高权重震荡过低后期收敛慢隐藏层数2 ~ 3超过3层小数据集容易过拟合每层节点数20 ~ 100首层一般取输入特征数的2~4倍batchsize16 ~ 64样本少于1000时全批量反而更稳定rbmtrain.m默认没有实现动量需要手动在权重更新语句前加一行rbm.momentum 0.5然后把更新公式替换成带动量版本。我一般不轻易动L2权重衰减因为DBN的预训练本身已有正则化效果再加权重衰减会让首层隐藏单元大量失活。4.3 数据划分与验证的三种方式大多数使用者把Excel直接丢进main.m训练没有划分训练测试集。这样出来的准确率是训练集准确率不能代表真实预测能力。我通常按以下三种方式之一处理随机划分rng(42); idx randperm(size(X_norm,1)); trainNum round(0.7 * length(idx)); trainIdx idx(1:trainNum); testIdx idx(trainNum1:end); X_train X_norm(trainIdx, :); X_test X_norm(testIdx, :); y_train y(trainIdx); y_test y(testIdx);用cvpartition做交叉验证适合数据量较小的场景。按时间或组别划分适合样本之间有依赖关系的时序或面板数据。第4种错误做法是先归一化再划分但因为之前用了ps实际不会导致测试集信息泄漏如果改用zscore就要严格先划分再标准化。4.4 常见报错和定位方法报错信息最常出现在矩阵尺寸不匹配时。例如Error using * ... inner matrix dimensions must agree检查size(X_norm,2)是否等于dbn.sizes(1)。dbnsetup会在数据输入那一行自动适配维度但如果你在读取Excel时把标签列也当成了特征特征数就比实际多一列网络自然对不上。训练误差变成NaN是另一个高频问题。先用sum(isnan(X))检查数据再用逐步下降学习率的方式定位到底是哪一步发散。快速验证代码如下if any(isnan(X(:))) error(输入数据含有NaN); end if any(isnan(nn.W{1}(:))) error(预训练权重出现NaN请降低RBM学习率); end这两个检查可以插入nntrain.m的每次迭代里能最快定位NaN是在预训练阶段还是微调阶段出现。若是预训练阶段把RBM学习率从0.05降到0.01若是微调阶段把nn.learningRate从1降到0.2。4.5 训练轮数多少合适微调的nn.numepochs我一般先设200然后看nn.train.error曲线。如果最后20轮的误差下降幅度小于0.001就认为已经收敛可以提前停止。如果曲线还在稳定下降就加到500轮并观察是否出现过拟合。有一种更稳妥的做法是每次迭代后在验证集上计算准确率保存验证集准确率最高时的模型而不是最后一步的模型。具体做法是在nntrain.m里插一个判断如果当前验证准确率高于历史最优就用bestNn nn保存一份训练结束后取bestNn做预测。这样可以避免在训练末期发生过拟合导致测试准确率倒退。5. 用训练好的DBN对新数据预测保存、加载与批量推理5.1 模型的保存与加载训练结束后nn结构体里已经装了全部分类网络参数可保存为mat文件save(dbn_trained_model.mat, nn, ps);ps必须和模型一起保存否则新数据无法做归一化。5.2 新数据预测的完整命令load(dbn_trained_model.mat); new_X table2array(readtable(new_data.xlsx)); new_X_norm mapminmax(apply, new_X, ps); pred_label nnpredict(nn, new_X_norm);这里关键点在于mapminmax(apply,...)使用的是训练时的最大最小值而不是重新计算。如果new_X是单行mapminmax输出可能变成列向量我一般先复制一行再取第一行。5.3 批量处理多个Excel文件当预测目标不止一个文件时用循环加拼接的方式最省事files dir(batch/*.xlsx); allPred []; for k 1:numel(files) data readtable(fullfile(files(k).folder, files(k).name)); x table2array(data(:, 1:18)); x_norm mapminmax(apply, x, ps); p nnpredict(nn, x_norm); allPred [allPred; p]; enddir支持通配符匹配所以文件命名尽量保持规律比如batch_01.xlsx、batch_02.xlsx。每次循环读取的列数要一致否则table2array会因为列名不同而错位。5.4 获取分类概率并导出nnpredict.m默认只返回类别编号。复制一份为nnpredict_prob.m在函数末尾加入prob nn.a{end};并调整输出顺序。之后就能拿到每个类别的概率[pred, prob] nnpredict_prob(nn, new_X_norm); out table(IDs, pred, prob(:,2), VariableNames, {ID, PredLabel, Confidence}); writetable(out, predict_results.xlsx);nn.a{end}保存的是最后一个前向传播的输出对于softmax层来说就是归一化后的类别概率。这个字段在nnff.m中每一层都会计算不需要额外推理。用这种方式可以在不改变原文件的情况下为业务提供置信度输出。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门