反向传播,所有输出趋向于1

我在MATLAB中实现了反向传播算法,但在训练过程中遇到了问题。训练初期,所有输出都趋向于1。我已经对输入数据进行了归一化处理(除了用于生成二进制目标向量的期望类别),将其归一化为[0, 1]区间。我参考了《人工智能:现代方法》一书中Norvig等人的实现方法。

我已经将伪代码与我的代码进行了对比(并研究了该算法一段时间),但未能发现错误。我使用MATLAB的时间并不长,所以在需要时会参考文档。

我还尝试了不同数量的隐藏层节点和不同的学习率(ALPHA)。

目标数据编码如下:例如,当目标是分类为2时,目标向量将是[0,1,0];如果是1,则为[1, 0, 0],依此类推。我还尝试了为目标使用不同的值,例如(对于类别1)使用[0.5, 0, 0]

我注意到一些权重超过了1,导致网络值过大。

%拓扑常量NUM_HIDDEN = 8+1;%写成n+1以明确使用偏置NUM_OUT = 3;%训练常量ALPHA = 0.01;TARG_ERR = 0.01;MAX_EPOCH = 50000;%读取并归一化数据文件。X = normdata(dlmread('iris.data'));X = shuffle(X);%X_test = normdata(dlmread('iris2.data'));%epocherrors = fopen('epocherrors.txt', 'w');%权重矩阵。%特征构成size(X, 2)-1,但大小为(X, 2)以便添加偏置。w_IH = rand(size(X, 2), NUM_HIDDEN)-(0.5*rand(size(X, 2), NUM_HIDDEN)); w_HO = rand(NUM_HIDDEN+1, NUM_OUT)-(0.5*rand(NUM_HIDDEN+1, NUM_OUT));%+1为偏置%层网络net_H = zeros(NUM_HIDDEN, 1);net_O = zeros(NUM_OUT, 1);%层输出out_H = zeros(NUM_HIDDEN, 1);out_O = zeros(NUM_OUT, 1);%层误差d_H = zeros(NUM_HIDDEN, 1);d_O = zeros(NUM_OUT, 1);%控制变量error = inf;epoch = 0;%运行算法。while error > TARG_ERR && epoch < MAX_EPOCH    for n=1:size(X, 1)        x = [X(n, 1:size(X, 2)-1) 1]';%为隐藏层添加偏置并转置为列向量。        o = X(n, size(X, 2));        %前向传播。        net_H = w_IH'*x;%转置的w。        out_H = [sigmoid(net_H); 1]; %为输出添加1作为偏置        net_O = w_HO'*out_H;        out_O = sigmoid(net_O); %再次,转置的w。        %计算输出误差。        d_O = ((targetVec(o, NUM_OUT)-out_O) .* (out_O .* (1-out_O)));        %计算隐藏层误差。        for i=1:size(w_HO, 1);            delta_weight = 0;            for j=1:size(w_HO, 2)                delta_weight = delta_weight + d_O(j)*w_HO(i, j);            end            d_H(i) = (out_H(i)*(1-out_H(i)))*delta_weight;        end        %更新隐藏层-输出层权重        for i=1:size(w_HO, 1)            for j=1:size(w_HO, 2)                w_HO(i, j) = w_HO(i, j) + (ALPHA*out_H(i)*d_O(j));            end        end        %更新输入层-隐藏层权重。        for i=1:size(w_IH, 1)            for j=1:size(w_IH, 2)                w_IH(i, j) = w_IH(i, j) + (ALPHA*x(i)*d_H(j));            end        end        out_O        o        %out_H        %w_IH        %w_HO        %d_O        %d_H    end  endfunction outs = sigmoid(nets)    outs = zeros(size(nets, 1), 1);    for i=1:size(nets, 1)        if nets(i) < -45            outs(i) = 0;        elseif nets(i) > 45            outs(i) = 1;        else            outs(i) = 1/1+exp(-nets(i));        end    endend

回答:

经过讨论,发现问题出在sigmoid函数中:

function outs = sigmoid(nets)%...            outs(i) = 1/1+exp(-nets(i)); % 缺少括号!!!!!!%...end

应该改为:

function outs = sigmoid(nets)%...            outs(i) = 1/(1+exp(-nets(i)));%...end

由于缺少括号,有时sigmoid函数的输出会大于1。这导致梯度计算不正确(因为它不是该函数的梯度)。这使得梯度为负值。这导致输出层的误差大部分时间方向错误。修复后(并正确维护错误变量 – 这在您的代码中似乎缺失),一切似乎都正常工作。


除此之外,该代码还有两个主要问题:

1) 没有偏置。没有偏置,每个神经元只能表示通过原点的直线。如果数据被归一化(即值在0到1之间),某些配置是不可分的。

2) 缺乏对高梯度值的防护(我之前回答中的第一点)。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注