Visualization of Gradient Descent Optimization

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.