2015-10-19 16 views
2

我試圖運行(隨機或批量)梯度下降,當一個使用標準交叉熵(SOFTMAX虧損):在使用softmax損耗時,如何調試和矢量化徑向基函數網絡的偏導數?

enter image description here

使用作爲模型的Radial Basis Function (RBF)網絡時,(你可以觀看講座的形式caltech here),當擴展到多類分類時(通過簡單地將RBF網絡的輸出饋送到softmax層來容易地擴展)。注意,P(y=l|x)僅通過將RBF網絡的輸出通過每個標記的softmax層來計算l如下:

enter image description here

其中\theta_l索引負責做標籤預測的參數l

在這方面,我想通過計算關於參數的導數來優化我的模型。回想一下,在徑向基函數網絡中優化的參數是最後一層的權重c以及第一層的權重t。我已經實現並調試瞭如何計算權重c的導數。該代碼按預期工作,因爲偏導數與數值導數匹配。你可以找到單元測試代碼是here

我也試過編寫相對於中心來實現派生的代碼,但我似乎無法讓我實現派生匹配的數值導數。損失J相對於中心t_k我試圖實現的導數的計算公式如下:

enter image description here

其中h_{\theta_l}對應於負責預測標籤l的RBF輸出。事實上,h_{\theta_l}是表達很簡單:

enter image description here

我的主要問題是與相對於t_k(上面的方程)計算的J的衍生物。對於這一點,我已經實施了天真地計算它的following function沒有向量化它:

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 

和不匹配the numerical derivatives code

我試過不同的東西來檢查它是否有效,我會在這裏解釋它們。如果任何人有更多的想法,隨時分享,我覺得我用完了新的想法來嘗試調試。

  1. 首先一個很好的自然問題是,我的數學推導導數是否正確?儘管我沒有明確地檢查過某個人的數學推導,但我有很高的信心,因爲對於模型中的ct偏導數的推導是相同的,並且您只將符號\theta更改爲您擁有的任何參數有問題。由於我已經實施了關於c的衍生工具,並且它通過了我所有的衍生工具測試,所以我會假設衍生工具相對於t或任何參數\theta的派生都應該是正確的。可以在math.stack exchange here中看到我對這個公式的推導。
  2. 一個選項可能是compute_dJ_dt實際上並未實現我期待的等式。這確實可能是這種情況,並檢查我是否獨立實施了更多vectorized version of that code以查看我是否實際實施了我在紙面上記錄的公式。由於這個方程的兩個版本輸出相同的微分值,我有很高的信心,他們正在計算,實際上我懷疑的方程(如果有人有進一步矢量化這個方程的方法,那真是太棒了!我添加的矢量化是如此微不足道,以至於它看起來並沒有那麼有趣,或者說在性能上有很大的提升,但它確實會去除一個循環)。

由於我在紙上的方程式(具有高概率)是正確的,並且方程式的實現似乎是正確的,因爲它的兩個版本輸出相同的值,所以它導致我可以得出結論:數值派生代碼有一個錯誤。

  1. numerical derivative code太簡單了,以至於很難檢查地球上會出現什麼問題。我發現的唯一可能是錯誤的是,可能是我的softmax cost J的實現是錯誤的,但我非常懷疑它,因爲......我已經爲它寫了一個單元測試!另外,我用它來檢查數值衍生物相對於cc總是通過,所以我無法想象J是錯誤的。
  2. 要檢查的最後一件不平凡的事是compute_dh_dt正在計算正確。我寫了units tests for dh_dt,並且由於它們在每次運行中都匹配其相應的數值衍生物,所以我會懷疑代碼是正確的。

在這一點上,我不是100%肯定還有什麼其他嘗試我希望也許有人有一個好主意,或者指出我正在做的愚蠢的事情?我不知道現在該怎麼想。感謝幫助和時間社區!

回答

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