为什么我的Gradient错了(Coursera,Logistic回归,Julia)?

Ale*_*hin 5 gradient gradient-descent julia logistic-regression

我正试图在朱莉娅的Coursera做Logistic回归,但它不起作用.

用于计算渐变的Julia代码:

sigmoid(z) = 1 / (1 + e ^ -z)

hypotesis(theta, x) = sigmoid(scalar(theta' * x))

function gradient(theta, x, y)
    (m, n) = size(x)
    h = [hypotesis(theta, x[i,:]') for i in 1:m]
    g = Array(Float64, n, 1)
    for j in 1:n
        g[j] = sum([(h[i] - y[i]) * x[i, j] for i in 1:m])
    end
    g
end
Run Code Online (Sandbox Code Playgroud)

如果使用此梯度,则会产生错误的结果.无法弄清楚原因,代码似乎是正确的.

全朱莉娅脚本.在此脚本中,使用我的Gradient Descent实现和使用内置Optim包计算出最佳Theta,结果不同.

Vin*_*ynd 5

渐变是正确的(达到标量倍数,正如@roygvib指出的那样).问题在于梯度下降.

如果你在梯度下降期间查看成本函数的值,你会看到很多NaN,这可能来自指数:降低步长(例如,to 1e-5)将避免溢出,但你必须增加迭代次数很多(也许是10_000_000).

更好(更快)的解决方案是让步长变化.例如,1.1 如果成本函数在一个步骤之后得到改善,那么可以将步长乘以(最佳值仍然在这个方向上看得很远:我们可以走得更快),2如果没有,则将其除以(我们走得太快并且结束了)超过最低限度).

也可以在梯度方向上进行线搜索以找到最佳步长(但这很耗时,可以用近似值代替,例如,Armijo的规则).

重新调整预测变量也有帮助.


roy*_*vib 4

我尝试使用以下例程gradient()将 OP 的代码与 的数值导数(这是最小化的目标函数)进行比较cost_j()

function grad_num( theta, x, y )
    g = zeros( 3 )

    eps = 1.0e-6
    disp = zeros( 3 )

    for k = 1:3
        disp[:] = theta[:]

        disp[ k ]= theta[ k ] + eps
        plus = cost_j( disp, x, y )
        disp[ k ]= theta[ k ] - eps
        minus = cost_j( disp, x, y )

        g[ k ] = ( plus - minus ) / ( 2.0 * eps )
    end
    return g
end
Run Code Online (Sandbox Code Playgroud)

但是从两个例程获得的梯度值似乎不太一致(至少对于最小化的初始阶段)...所以我手动导出 的梯度cost_j( theta, x, y ),从中似乎m缺少除法:

#/ OP's code
# g[j] = sum( [ (h[i] - y[i]) * x[i, j] for i in 1:m ] )

#/ modified code
  g[j] = sum( [ (h[i] - y[i]) * x[i, j] for i in 1:m ] ) / m
Run Code Online (Sandbox Code Playgroud)

因为我不太确定上面的代码和表达式是否真的正确,你可以自己检查一下吗...?

但事实上,无论我使用原始梯度还是校正梯度,程序都会收敛到相同的最小值(0.2034977016,与从 Optim 获得的几乎相同),因为这两个梯度仅相差一个乘法因子!由于收敛速度非常慢,我还alpha按照 Vincent 的建议自适应修改了步长(这里我使用了更适中的加速/减速值):

function gradient_descent(x, y, theta, alpha, n_iterations)
    ... 
    c = cost_j( theta, x, y )

    for i = 1:n_iterations
        c_prev = c
        c = cost_j( theta, x, y )

        if c - c_prev < 0.0
            alpha *= 1.01
        else
            alpha /= 1.05
        end
        theta[:] = theta - alpha * gradient(theta, x, y)
    end
    ...
end
Run Code Online (Sandbox Code Playgroud)

并将这个例程称为

optimal_theta = gradient_descent( x, y, [0 0 0]', 1.5e-3, 10^7 )[ 1 ]
Run Code Online (Sandbox Code Playgroud)

cost_j下图绘制了迭代步骤与变化的关系。在此输入图像描述