Output the result of gradient descent method as matplotlib animation

Introduction

Continuing from Last time [Introduction to mathematics starting from Python](https://www.amazon.co.jp/Python%E3%81%8B%E3% 82% 89% E3% 81% AF% E3% 81% 98% E3% 82% 81% E3% 82% 8B% E6% 95% B0% E5% AD% A6% E5% 85% A5% E9% 96% 80-Amit-Saha / dp / 4873117682) series. This time

Is involved.

In the explanation in the book, the result is plotted with matplotlib and output to an image (still image, of course), but I wanted to see how the gradient descent algorithm works with animation. So this time I tried to output it as a gif animation. The gradient descent method and gradient descent method are only included in the code and will not be explained.

things to do

First, find the minimum value of the function using gradient descent. Next, we will output an animation in gif format to visualize how the value decreases with each step.

This time

f(x) = 3x^2 + 2x

Find the minimum value of the quadratic function.

Source code

gradient_descent.py


from sympy import Derivative, Symbol, sympify, solve
from numpy import arange
import matplotlib.pyplot as plt
import matplotlib.animation as ani


def gradient_descent(x0, f1x, x, epsilon=1e-6, step_size=1e-4):
  # f1x =Find out if it has a solution of 0.
  if not solve(f1x):
    return

  x_old = x0
  x_new = x_old - step_size * f1x.subs({x: x_old}).evalf()
  X_traversed = []

  while abs(x_old - x_new) > epsilon:
    X_traversed.append(x_new)
    x_old = x_new
    x_new = x_old - step_size * f1x.subs({x: x_old}).evalf()

  return x_new, X_traversed


def draw_graph(f, x):
  X = arange(-1, 1, 0.01)
  Y = [f.subs({x: x_val}) for x_val in X]

  plt.plot(X, Y)


def draw_frame(i, x, X, Y):
  plt.clf()
  draw_graph(f, x)
  plt.scatter(X[i], Y[i], s=20, alpha=0.8)


if __name__ == '__main__':
  x = Symbol('x')
  f = 3 * x ** 2 + 2 * x
  var0 = 0.75  #Initial value of gradient descent

  d = Derivative(f, x).doit()

  # gradient_descent()Returns the minimum value obtained by gradient descent and the value of x at each step.
  var_min, X_traversed = gradient_descent(var0, d, x)

  print('Total number of steps: {0}'.format(len(X_traversed)))
  print('minimum value(Gradient descent): {0}'.format(var_min))
  print('minimum value(f1x =0 solution): {0}'.format(float(solve(d)[0])))

  X = X_traversed[::100] # (1)
  Y = [f.subs({x: x_val}) for x_val in X]

  fig = plt.figure(figsize=(6.5, 6.5))

  anim = ani.FuncAnimation(fig, draw_frame, fargs=(x, X, Y), frames=len(X)) # (2)
  anim.save('gradient_descent.gif', writer='imagemagick', fps=10) # (3)

Standard output

Total number of steps: 10792
minimum value(Gradient descent): -0.331667951428822
minimum value(f1x =0 solution): -0.3333333333333333

Commentary

(1) Reduction of array

X = X_traversed[::100]

X_traversed is an array that contains all the values of x at each step of the steepest descent.

The total number of steps len (X_traversed) is 10,792. If you draw a frame at 10fps, or 10 frames per second, it will take about 1,079 seconds to finish the animation. To reduce this to a few seconds of animation, we generate a new array x that takes every 100 elements of the resulting array X_traversed and use it to create the animation.

This method excludes the element stored at the end of X_traversed, that is, the value of x corresponding to the minimum value. However, I am compromising because I think it's okay if I can grasp the atmosphere with animation.

(2) Call FuncAnimation ()

Call FuncAnimation () [matplotlib.animation.Animation](http://matplotlib.org/ api / _as_gen / matplotlib.animation.Animation.html # matplotlib.animation.Animation) Creating an object.

The arguments are as follows.

argument Description
fig The origin of the graphFigureobject.
draw_frame A function called for each frame. draw_The frame number is automatically passed to the first argument of frame.
fargs draw_The value passed after the second argument of frame.
frames The number of frames in the animation.

(3) Call Animation.save ()

Call Animation.save () and actually save the animation.

By specifying ʻimagemagick for the argument writer`, we were able to output a gif animation. However, it is assumed that ImageMagick is installed on your machine. I'm using macOS, but I didn't have ImageMagick installed, so I installed it with Homebrew.

$ brew install imagemagick

No other settings were made.

animation

gradient_descent.gif

** This guy ... works! ** **

It's a lot of fun to visualize how the algorithm works like this: blush :: hearts:

reference

Books

Respect article

If you want to see the stronger and stronger ones, I recommend the article Explanation of what is stochastic gradient descent in Python. Do: + 1: It is upward compatible. I was also strongly motivated to output such an animation. Thank you: pray :: sparkles:

Other

Recommended Posts

Output the result of gradient descent method as matplotlib animation
Output the output result of sklearn.metrics.classification_report as a CSV file
Roughly think about the gradient descent method
The basis of graph theory with matplotlib animation
Gradient descent method list (2020)
A memorandum about the warning of the pylint output result
Set the output destination of the execution result to Vim started as a modeless window
Get the output value of the command (as received by xargs)
Scraping the result of "Schedule-kun"
Change the style of matplotlib
Filter the output of tracemalloc
Save the result of the life game as a gif with python
Feature extraction by TF method using the result of morphological analysis
How to output the output result of the Linux man command to a file
Process the result of% time,% timeit
Machine learning algorithm (gradient descent method)
Extract the TOP command result with USER and output it as CSV
Align the size of the colorbar with matplotlib
Count / verify the number of method calls.
Saddle point search using the gradient method
Flexible animation creation using animation.FuncAnimation of matplotlib
The importance of Lint as Pythonista thinks
Implementation of SVM by stochastic gradient descent
The result of installing python in Anaconda