Gradient descent in matlab work but in python not work

68 views Asked by At

Matlab version

For the contour plotting

[x1,x2\] = meshgrid(-30:0.5:30, -30:0.5:30);
F = (x1-2).^2 + 2\*(x2 - 3).^2;

figure;
surf(x1,x2,F);
hold on;
contour(x1,x2,F);

figure;
contour(x1,x2,F,20);
hold on;

For initialize the value of the matrix and vector

A = [1 0; 0 2];
AT = A';
b = [4; 12];

Nit = 100; % no of iteration of our GD
tol = 1e-5; % error tolerance
lr  = 0.2; % learning rate
xk = [-20;-20\]; % initial x value
noIterations = 1;
gradErr = [];

The looping for the gradient descent

for k =1:Nit
    
    
    x_old = xk; 
    xk = xk - lr*AT*(A*xk - b); % Main GD step 
    
    gradErr(k) = norm(AT*(A*xk-b),'fro');
    if gradErr(k) < tol
        break;
    end
    
    plot([x_old(1) xk(1)],[x_old(2) xk(2)],'ko-')
    noIterations = noIterations + 1;
end

Python version

Contour plotting part

import numpy as np
import matplotlib.pyplot as plt
x1,x2 = np.meshgrid(np.arange(- 30,30+0.5,0.5),np.arange(- 30,30+0.5,0.5))

F = (x1 - 2) ** 2 + 2 * (x2 - 3) ** 2
fig=plt.figure()
surf=fig.gca(projection='3d')
surf.plot_surface(x1,x2,F)
surf.contour(x1,x2,F)
plt.show()

fig,surf=plt.subplots()
plt.contour(x1,x2,F,20)
plt.show()

Initialize the value of the matrix and vector

A = np.array([[1,0],[0,2]])
AT = np.transpose(A)
b = np.array([[4],[12]])
Nit = 100

tol = 1e-05

lr = 0.2

xk = np.array([[-10],[-10]])

noIterations = 1
gradErr = []

Main problem is here where the looping has the bug cause it cant run the coding

for k in range(Nit):  
    x_old = xk
    xk = xk - lr*np.matmul(AT,np.matmul(A,xk - b))
    gradErr[k] = np.linalg.norm(AT * (A * xk - b),'fro')
    if gradErr[k] < tol:
        break
    plt.plot(np.array([x_old(1),xk(1)]),np.array([x_old(2),xk(2)]),'ko-')
    noIterations = noIterations + 1

May I know what is the problem for my python version in the looping part cant work but in matlab version is work well?

1

There are 1 answers

0
TQCH On

To access k-th element of gradErr, it has to be pre-assign a positive length. In your case, it is initialized as an empty list, which is the cause of IndexError. A simple fix is to use gradErr=np.zeros(Nit) Full code after making proper modification is the following:

import numpy as np
import matplotlib.pyplot as plt
x1,x2 = np.meshgrid(np.arange(-30, 30+0.5, 0.5), np.arange(-30, 30+0.5, 0.5))

F = (x1 - 2) ** 2 + 2 * (x2 - 3) ** 2
fig=plt.figure()
surf = fig.add_subplot(1, 1, 1, projection='3d')
surf.plot_surface(x1,x2,F)
surf.contour(x1,x2,F)
plt.show()

fig, surf=plt.subplots()
plt.contour(x1, x2, F, 20)
plt.show()

A = np.array([[1,0], [0,2]])
AT = np.transpose(A)
b = np.array([[4], [12]])

Nit = 100
tol = 1e-05
lr = 0.2

xk = np.array([[-10], [-10]])

noIterations = 1
gradErr = np.zeros(Nit)

for k in range(Nit):  
    x_old = xk
    xk = xk - lr * np.matmul(AT, np.matmul(A, xk - b))
    gradErr[k] = np.linalg.norm(AT * (A * xk - b),'fro')
    if gradErr[k] < tol:
        break
    plt.plot(np.array([x_old[0], xk[0]]),np.array([x_old[1], xk[1]]),'ko-')
    noIterations = noIterations + 1