当使用标准交叉熵(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
并且它与数值导数代码不匹配。
我尝试了不同的方法来检查它是否有效,我将在这里解释它们。如果有人有其他想法,请随时分享,我觉得我已经没有好的新想法来尝试调试了。
- 首先一个很好的自然问题是,我试图实现的导数的数学推导是否正确?尽管我没有与某人明确检查数学推导,但我非常有信心它是正确的,因为关于模型
c
和t
模型中的偏导数的推导是相同的,您只需将符号更改为\theta
您有问题的任何参数。由于我已经实现了关于的导数c
并且它通过了我所有的导数测试,我会假设关于t
或任何参数的导数的推导\theta
应该是正确的。可以在此处的 math.stack exchange中查看我对这个等式的推导。 - 一种选择可能是
compute_dJ_dt
实际上并没有实现我所期望的等式。确实可能是这种情况,并检查我是否独立实现了该代码的稍微矢量化的版本,以查看我是否真的在实现我在纸上写下的方程式。由于方程的两个版本输出相同的导数值,我对他们正在计算非常有信心,实际上是我怀疑的方程(如果有人有办法进一步矢量化这个方程,那就太棒了!我添加的矢量化是如此微不足道,以至于它看起来并不那么有趣或性能提升太多,但是,它确实删除了一个 for 循环)。
由于我在纸上的方程(很有可能)是正确的,并且方程的实现似乎是正确的,因为它的两个版本输出相同的值,所以它让我得出结论,数值导数代码可能有一个错误.
- 数字导数代码非常简单,以至于很难检查它到底有什么问题。我唯一想到的可能是错误的可能是我对softmax 成本 J的实现是错误的,但我非常怀疑它,因为......我已经为它编写了一个单元测试!另外,我用它来检查关于 ALWAYS pass 的数值导数
c
,c
所以我无法想象J
这是错误的。 - 要检查的最后一件重要的事情
compute_dh_dt
是计算是否正确。我已经为 dh_dt 编写了单元测试,并且由于它们在每次运行时都匹配相应的数值导数,所以我怀疑代码是正确的。
在这一点上,我不是 100% 确定还有什么可以尝试的,我希望也许有人有一个好主意,或者指出我正在做的愚蠢的事情?我不确定现在该怎么想。感谢社区的帮助和时间!