Matlab实现BP神经网络K折交叉验证,Kfold寻参案例

先准备点实验数据——直接上Matlab自带的癌症诊断数据集:

load breastcancer
inputs = breastInputs; 
targets = ind2vec(breastTargets');  % 转成one-hot编码

注意这里把标签转成向量形式,这是为了适配后面要用的交叉熵损失函数。顺手做个数据归一化:

inputs = mapminmax(inputs, 0, 1);  % 缩放到[0,1]区间

接下来整个狠活,用cvpartition切分10折数据:

k = 10;
cv = cvpartition(size(inputs,2), 'KFold',k);

这里藏着个细节:cvpartition是按样本索引切分的,而我们的输入数据每个列向量是一个样本,所以用size(inputs,2)获取总样本数。

现在进入重头戏——网格搜索寻找最佳隐藏层节点数。咱们试试8-15个节点的范围:

hiddenLayerSize = 8:15;
avgMSE = zeros(size(hiddenLayerSize));

for i = 1:length(hiddenLayerSize)
    foldLoss = zeros(k,1);
    
    for fold = 1:k
        trainIdx = training(cv,fold);
        testIdx = test(cv,fold);
        
        net = patternnet(hiddenLayerSize(i));
        net.divideFcn = 'dividetrain';  % 关键设置!禁用自动划分
        net = train(net, inputs(:,trainIdx), targets(:,trainIdx));
        
        pred = net(inputs(:,testIdx));
        foldLoss(fold) = crossentropy(pred, targets(:,testIdx));
    end
    
    avgMSE(i) = mean(foldLoss);
end

这段代码有个容易翻车的点:patternnet默认会自己划分验证集,必须通过divideFcn='dividetrain'关掉这个机制,否则交叉验证就白做了。训练时看到命令行蹦出来的epoch进度条没?那是反向传播在实时更新权重呢。

跑完循环后,用个折线图直观看看效果:

plot(hiddenLayerSize, avgMSE, 'bo-')
xlabel('隐藏层节点数')
ylabel('交叉熵损失')
title('K折交叉验证结果')
grid on

如果发现节点数增加到12之后损失不再明显下降,反而开始波动,那就该果断选择12节点——模型复杂度和效果达到最佳平衡点的时候。

最后锁定最优参数训练全量数据:

bestNet = patternnet(12);
bestNet = train(bestNet, inputs, targets);

这时候保存训练好的bestNet对象,就能直接部署到生产环境做预测了。不过得提醒一句,实际项目中可能还要考虑早停策略,或者加入L2正则化防止过拟合。

整个过程跑下来,最耗时的部分肯定是那10×8=80次网络训练。如果数据量大,可以上parfor并行加速,或者改用GPU训练——不过那就是另一个故事了。调参这事儿吧,有时候真得靠耐心和咖啡撑着。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐