First, we can update the gradient_descent() function to store all solutions and their score found during the optimization as lists and return them at the end of the search instead of the best solution found.
gradient descent algorithm
def gradient_descent(objective, derivative, bounds, n_iter, step_size):
# track all solutions
solutions, scores = list(), list()
# generate an initial point
solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
# run the gradient descent
for i in range(n_iter):
# calculate gradient
gradient = derivative(solution)
# take a step
solution = solution - step_size * gradient
# evaluate candidate point
solution_eval = objective(solution)
# store solution
solutions.append(solution)
scores.append(solution_eval)
# report progress
print(’>%d f(%s) = %.5f’ % (i, solution, solution_eval))
return [solutions, scores]
gradient descent algorithm
def gradient_descent(objective, derivative, bounds, n_iter, step_size):
# track all solutions
solutions, scores = list(), list()
# generate an initial point
solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
# run the gradient descent
for i in range(n_iter):
# calculate gradient
gradient = derivative(solution)
# take a step
solution = solution - step_size * gradient
# evaluate candidate point
solution_eval = objective(solution)
# store solution
solutions.append(solution)
scores.append(solution_eval)
# report progress
print(’>%d f(%s) = %.5f’ % (i, solution, solution_eval))
return [solutions, scores]
The function can be called and we can get the lists of the solutions and the scores found during the search.
…
perform the gradient descent search
solutions, scores = gradient_descent(objective, derivative, bounds, n_iter, step_size)
…
perform the gradient descent search
solutions, scores = gradient_descent(objective, derivative, bounds, n_iter, step_size)
We can create a line plot of the objective function, as before.
…
sample input range uniformly at 0.1 increments
inputs = arange(bounds[0,0], bounds[0,1]+0.1, 0.1)
compute targets
results = objective(inputs)
create a line plot of input vs result
pyplot.plot(inputs, results)
…
sample input range uniformly at 0.1 increments
inputs = arange(bounds[0,0], bounds[0,1]+0.1, 0.1)
compute targets
results = objective(inputs)
create a line plot of input vs result
pyplot.plot(inputs, results)
Finally, we can plot each solution found as a red dot and connect the dots with a line so we can see how the search moved downhill.
…
plot the solutions found
pyplot.plot(solutions, scores, ‘.-’, color=‘red’)
…
plot the solutions found
pyplot.plot(solutions, scores, ‘.-’, color=‘red’)
Tying this all together, the complete example of plotting the result of the gradient descent search on the one-dimensional test function is listed below.
example of plotting a gradient descent search on a one-dimensional function
from numpy import asarray
from numpy import arange
from numpy.random import rand
from numpy.random import seed
from matplotlib import pyplot
objective function
def objective(x):
return x**2.0
derivative of objective function
def derivative(x):
return x * 2.0
gradient descent algorithm
def gradient_descent(objective, derivative, bounds, n_iter, step_size):
# track all solutions
solutions, scores = list(), list()
# generate an initial point
solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
# run the gradient descent
for i in range(n_iter):
# calculate gradient
gradient = derivative(solution)
# take a step
solution = solution - step_size * gradient
# evaluate candidate point
solution_eval = objective(solution)
# store solution
solutions.append(solution)
scores.append(solution_eval)
# report progress
print(’>%d f(%s) = %.5f’ % (i, solution, solution_eval))
return [solutions, scores]
seed the pseudo random number generator
seed(4)
define range for input
bounds = asarray([[-1.0, 1.0]])
define the total iterations
n_iter = 30
define the step size
step_size = 0.1
perform the gradient descent search
solutions, scores = gradient_descent(objective, derivative, bounds, n_iter, step_size)
sample input range uniformly at 0.1 increments
inputs = arange(bounds[0,0], bounds[0,1]+0.1, 0.1)
compute targets
results = objective(inputs)
create a line plot of input vs result
pyplot.plot(inputs, results)
plot the solutions found
pyplot.plot(solutions, scores, ‘.-’, color=‘red’)
show the plot
pyplot.show()
example of plotting a gradient descent search on a one-dimensional function
from numpy import asarray
from numpy import arange
from numpy.random import rand
from numpy.random import seed
from matplotlib import pyplot
objective function
def objective(x):
return x**2.0
derivative of objective function
def derivative(x):
return x * 2.0
gradient descent algorithm
def gradient_descent(objective, derivative, bounds, n_iter, step_size):
# track all solutions
solutions, scores = list(), list()
# generate an initial point
solution = bounds[:, 0] + rand(len(bounds)) * (bounds[:, 1] - bounds[:, 0])
# run the gradient descent
for i in range(n_iter):
# calculate gradient
gradient = derivative(solution)
# take a step
solution = solution - step_size * gradient
# evaluate candidate point
solution_eval = objective(solution)
# store solution
solutions.append(solution)
scores.append(solution_eval)
# report progress
print(’>%d f(%s) = %.5f’ % (i, solution, solution_eval))
return [solutions, scores]
seed the pseudo random number generator
seed(4)
define range for input
bounds = asarray([[-1.0, 1.0]])
define the total iterations
n_iter = 30
define the step size
step_size = 0.1
perform the gradient descent search
solutions, scores = gradient_descent(objective, derivative, bounds, n_iter, step_size)
sample input range uniformly at 0.1 increments
inputs = arange(bounds[0,0], bounds[0,1]+0.1, 0.1)
compute targets
results = objective(inputs)
create a line plot of input vs result
pyplot.plot(inputs, results)
plot the solutions found
pyplot.plot(solutions, scores, ‘.-’, color=‘red’)
show the plot
pyplot.show()
Running the example performs the gradient descent search on the objective function as before, except in this case, each point found during the search is plotted.
Note: Your results may vary given the stochastic nature of the algorithm or evaluation procedure, or differences in numerical precision. Consider running the example a few times and compare the average outcome.
In this case, we can see that the search started more than halfway up the right part of the function and stepped downhill to the bottom of the basin.
We can see that in the parts of the objective function with the larger curve, the derivative (gradient) is larger, and in turn, larger steps are taken. Similarly, the gradient is smaller as we get closer to the optima, and in turn, smaller steps are taken.