1

当使用标准交叉熵(softmax loss)时,我正在尝试运行(随机或批量)梯度下降:

在此处输入图像描述

当使用径向基函数 (RBF)网络作为模型时(如果需要,您可以在此处观看来自 caltech 的讲座)当扩展到多类分类时(通过简单地将 RBF 网络的输出馈送到 softmax 层来轻松扩展。请注意,P(y=l|x)简单地通过将 RBF 网络的输出传递给每个标签的 softmax 层来计算l,如下所示:

在此处输入图像描述

where\theta_l索引负责对 label 进行预测的参数l

在这方面,我想通过计算参数的导数来优化我的模型。回想一下,径向基函数网络中要优化的参数是c最后一层的权重和t第一层的中心。我已经实现并调试了如何计算关于权重的导数c。代码按预期工作,因为偏导数与数值导数匹配。你可以在这里找到单元测试代码。

我也尝试编写实现关于中心的导数的代码,但我似乎无法使我的导数实现与数值导数相匹配。关于我正在尝试实现J的中心的损失导数方程如下:t_k

在此处输入图像描述

其中h_{\theta_l}对应于负责预测标签的 RBF 的输出l。其实h_{\theta_l}表达起来很简单:

在此处输入图像描述

我的主要问题是计算J相对于t_k(上面的等式)的导数。为此,我实现了以下函数,它天真地计算它而不对其进行矢量化:

function [ dJ_dt ] = compute_dJ_dt(z,x,y,t,c)
%Computes dJ_dc
%   Input:
%       z = (K x 1)
%       x = data point (D, 1)
%       y = labels (1 x 1)
%       t = centers (D x K)
%       c = weights (K x L)
%   Output:
%       dJ_dc = (D x K)
[D,K] = size(t);
[~, L] = size(c);
dJ_dt = zeros(D, K);
for k=1:K
    dJ_dt_k = zeros(D, 1);
    for l=1:L
        c_l = c(:,l);
        dh_dt_l = compute_dh_dt(z,x,t,c_l); %(D x K)
        delta = (y==l);
        dJ_dt_k = dJ_dt_k + dh_dt_l(:,k) * delta;
    end
    dJ_dt(:,k) = -dJ_dt_k;
end
end

并且它与数值导数代码不匹配。

我尝试了不同的方法来检查它是否有效,我将在这里解释它们。如果有人有其他想法,请随时分享,我觉得我已经没有好的新想法来尝试调试了。

  1. 首先一个很好的自然问题是,我试图实现的导数的数学推导是否正确?尽管我没有与某人明确检查数学推导,但我非常有信心它是正确的,因为关于模型ct模型中的偏导数的推导是相同的,您只需将符号更改为\theta您有问题的任何参数。由于我已经实现了关于的导数c并且它通过了我所有的导数测试,我会假设关于t或任何参数的导数的推导\theta应该是正确的。可以在此处的 math.stack exchange中查看我对这个等式的推导。
  2. 一种选择可能是compute_dJ_dt实际上并没有实现我所期望的等式。确实可能是这种情况,并检查我是否独立实现了该代码的稍微矢量化的版本,以查看我是否真的在实现我在纸上写下的方程式。由于方程的两个版本输出相同的导数值,我对他们正在计算非常有信心,实际上是我怀疑的方程(如果有人有办法进一步矢量化这个方程,那就太棒了!我添加的矢量化是如此微不足道,以至于它看起来并不那么有趣或性能提升太多,但是,它确实删除了一个 for 循环)。

由于我在纸上的方程(很有可能)是正确的,并且方程的实现似乎是正确的,因为它的两个版本输出相同的值,所以它让我得出结论,数值导数代码可能有一个错误.

  1. 数字导数代码非常简单,以至于很难检查它到底有什么问题。我唯一想到的可能是错误的可能是我对softmax 成本 J的实现是错误的,但我非常怀疑它,因为......我已经为它编写了一个单元测试!另外,我用它来检查关于 ALWAYS pass 的数值导数cc所以我无法想象J这是错误的。
  2. 要检查的最后一件重要的事情compute_dh_dt是计算是否正确。我已经为 dh_dt 编写了单元测试,并且由于它们在每次运行时都匹配相应的数值导数,所以我怀疑代码是正确的。

在这一点上,我不是 100% 确定还有什么可以尝试的,我希望也许有人有一个好主意,或者指出我正在做的愚蠢的事情?我不确定现在该怎么想。感谢社区的帮助和时间!

4

1 回答 1

0

这是一种反高潮的解决方案,但我想这是意料之中的,因为这段代码似乎是由工作组件构建的,所以它肯定是一个愚蠢的小错误。错误是我粘贴的上面代码中的错误,我应该使用delta标签指示和该标签概率之间的差异,但我忘记减去概率。所以上面的代码是:

    delta = (y==l);

什么时候应该是:

    prob_y_x_h_x = prob_y_x(h_x); % (L x 1)
    ind_y_l = (y==l);
    delta = ind_y_l - prob_y_x_h_x(l);

因此,固定代码现在通过了数值测试,如下所示:

function [ dJ_dt ] = compute_dJ_dt(h_x,z,x,y,t,c)
%Computes dJ_dc
%   Input:
%       z = (K x 1)
%       x = data point (D, 1)
%       y = labels (1 x 1)
%       t = centers (D x K)
%       c = weights (K x L)
%   Output:
%       dJ_dc = (D x K)
[D,K] = size(t);
[~, L] = size(c);
dJ_dt = zeros(D, K);
for k=1:K
    dJ_dt_k = zeros(D, 1);
    for l=1:L
        c_l = c(:,l);
        dh_dt_l = compute_dh_dt(z,x,t,c_l); %(D x K)
        prob_y_x_h_x = prob_y_x(h_x); % (L x 1)
        ind_y_l = (y==l);
        delta = ind_y_l - prob_y_x_h_x(l);
        dJ_dt_k = dJ_dt_k + dh_dt_l(:,k) * delta;
    end
    dJ_dt(:,k) = -dJ_dt_k;
end
end

我仍然不知道如何进一步矢量化上面的代码,所以我仍然很高兴收到关于这部分问题的反馈!这是我到目前为止的矢量化:

function [ dJ_dt ] = compute_dJ_dt_vec(h_x,z,x,y,t,c)
%Computes dJ_dc
%   Input:
%       z = (K x 1)
%       x = data point (D, 1)
%       y = labels (1 x 1)
%       t = centers (D x K)
%       c = weights (K x L)
%   Output:
%       dJ_dc = (D x K)
[D,K] = size(t);
[~, L] = size(c);
dJ_dt = zeros(D, K);
for l=1:L
    c_l = c(:,l);
    dh_dt = compute_dh_dt(z,x,t,c_l); %(D x K)
    ind_y_l = (y==l);
    prob_y_x_h_x = prob_y_x(h_x); % (L x 1)
    dJ_dh = repmat( ind_y_l - prob_y_x_h_x(l) , D, K); %(D x K)
    dJ_dt = dJ_dt + dJ_dh.*dh_dt;
end
dJ_dt = -dJ_dt;
end
于 2015-10-19T23:22:03.833 回答