habe ich versuchte gradient()
in der OP-Kodex mit numerischer Ableitung von cost_j()
Vergleich (welche die Zielfunktion der Minimierung ist) unter Verwendung der Routine folgenden
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
Aber die Gradientenwerte von den zwei Routinen erhielten keine scheinen zu stimmen sehr gut (zumindest für die Anfangsphase der Minimierung) ... Also habe ich abgeleitet manuell den Gradienten cost_j(theta, x, y)
, von dem es scheint, dass die Division durch m
fehlt:
#/ 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
Da ich mir nicht sicher bin, ob der obige Code und der Ausdruck wirklich korrekt sind, können Sie sie selbst überprüfen ...?
Aber tatsächlich, unabhängig davon, ob ich die ursprünglichen oder korrigierten Gradienten verwende, konvergiert das Programm zum selben minimalen Wert (0,2034977016, fast der gleiche wie von Optim), weil sich die beiden Gradienten nur durch einen multiplikativen Faktor unterscheiden!Da die Konvergenz sehr langsam war, habe ich verändern auch die Schrittgrßenregister alpha
adaptiv nach dem Vorschlag von Vincent (hier habe ich moderate Werte für die Beschleunigung/Abbremsung):
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
und diese Routine als
optimal_theta = gradient_descent(x, y, [0 0 0]', 1.5e-3, 10^7)[ 1 ]
genannt
Die Variation von cost_j
gegen Iterationsschritte ist unten aufgetragen.
Danke, ja, Sie haben Recht, der Gradient sollte durch 'm' geteilt werden. Das Seltsame ist jedoch, dass in dem ursprünglichen Beispiel, das mit der Oktave gemacht wurde, der Gradient ungefähr 400 Iterationen konvergieren würde. Ich werde den Originalcode nochmal überprüfen, vielleicht benutzen sie ein paar Tricks, um den Code zu beschleunigen. –