Matplotlib animation not showing (Gradient Descent Test) - python-3.x

I tried to create a matplotlib animation to practice using gradient descent to do linear regression. However I can't get the animation to work.
I managed to get the animation to work by using anim.show() but this caused an AttributeError as the animation class does not have a method. No idea why this actually causes the animation to work
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
def main():
# Initialize Dataset
X = 10*np.random.rand(50)
y = 8*X + 1 + 2.5*np.random.randn(50)
model = LinearRegression()
model.train(X,y)
model.animate(X,y)
class LinearRegression():
# Using Gradient Descent for Linear Regression
def __init__(self, learning_rate=0.001, epochs=100):
self.learning_rate = learning_rate
self.epochs = epochs
self.a_0 = 0
self.a_1 = 0
self.w_list = []
def train(self, X, y):
n = X.shape[0]
for i in range(self.epochs):
self.w_list.append([self.a_0,self.a_1])
y_train = self.a_0 + self.a_1 * X
error = y - y_train # Whether you use y_train - y or y - y_train will make a difference
mse = np.sum(error ** 2) / n
self.a_0 -= -2/n * np.sum(error) * self.learning_rate
self.a_1 -= -2/n * np.sum(error * X) * self.learning_rate
#if i%10 == 0:
# print("MSE",str(i)+":", mse)
self.w_list = np.array(self.w_list)
def animate(self, X, y):
fig, ax = plt.subplots()
ax.scatter(X,y)
plot_range = np.array(range(int(min(X))-1,int(max(X))+3))
a_0,a_1 = self.w_list[0,]
y_plot = plot_range*a_1 + a_0
ln, = ax.plot(plot_range, y_plot, color="red", label="Best Fit")
def animator(frame):
a_0, a_1 = self.w_list[frame,]
y_plot = plot_range * a_1 + a_0
ln.set_data(plot_range,y_plot)
print("Launching Animation")
anim = animation.FuncAnimation(fig,func = animator, frames = self.epochs)
anim.show()
if __name__ == "__main__":
main()

You need to call plt.show() to open the plot window.
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
def main():
# Initialize Dataset
X = 10*np.random.rand(50)
y = 8*X + 1 + 2.5*np.random.randn(50)
model = LinearRegression()
model.train(X,y)
model.animate(X,y)
class LinearRegression():
# Using Gradient Descent for Linear Regression
def __init__(self, learning_rate=0.001, epochs=100):
self.learning_rate = learning_rate
self.epochs = epochs
self.a_0 = 0
self.a_1 = 0
self.w_list = []
def train(self, X, y):
n = X.shape[0]
for i in range(self.epochs):
self.w_list.append([self.a_0,self.a_1])
y_train = self.a_0 + self.a_1 * X
error = y - y_train # Whether you use y_train - y or y - y_train will make a difference
mse = np.sum(error ** 2) / n
self.a_0 -= -2/n * np.sum(error) * self.learning_rate
self.a_1 -= -2/n * np.sum(error * X) * self.learning_rate
#if i%10 == 0:
# print("MSE",str(i)+":", mse)
self.w_list = np.array(self.w_list)
def animate(self, X, y):
fig, ax = plt.subplots()
ax.scatter(X,y)
plot_range = np.array(range(int(min(X))-1,int(max(X))+3))
a_0,a_1 = self.w_list[0,]
y_plot = plot_range*a_1 + a_0
ln, = ax.plot(plot_range, y_plot, color="red", label="Best Fit")
def animator(frame):
a_0, a_1 = self.w_list[frame,]
y_plot = plot_range * a_1 + a_0
ln.set_data(plot_range,y_plot)
print("Launching Animation")
anim = animation.FuncAnimation(fig,func = animator, frames = self.epochs)
plt.show()
if __name__ == "__main__":
main()

Related

Slider is not updating my diagram correctly

I am trying to plot the biffurcation diagram and its equation.
My problem is that I want to put a slider for when I change the rate in the logistic map equation, but I can't seem to understand what I need to code in the update function.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
rate = np.linspace(1, 4, 1000)
N = 1000
x = np.zeros(N) + 0.5
count = np.arange(round(N*0.9), N)
y = np.zeros(N) + 0.5
#t = 1
# Biffurcation
for rs in range(len(rate)):
for n in range(N-1):
x[n+1] = rate[rs] * x[n] * (1-x[n])
u = np.unique(x[count])
r = rate[rs] * np.ones(len(u))
for i in range(N - 1):
y[i + 1] = rate[rs] * y[i] * (1 - y[i])
# plotting
plt.plot(r, u, '.', markersize=2)
plt.ylabel(ylabel='X')
plt.xlabel(xlabel='r')
plt.title('Biffurcation')
# Plotting
fig, ax = plt.subplots()
axes, = ax.plot(y, 'o-')
ax.set_ylabel(ylabel='X')
ax.set_xlabel(xlabel='Time')
ax.set_title('$x_{n+1}$ = r * $x_{n}$ * (1-$x_{n}$)')
# defining axSlider
fig.subplots_adjust(bottom=0.25)
ax_slider = fig.add_axes([0.15, 0.1, 0.65, 0.03])
slider = Slider(ax_slider, label='r', valmin=1, valmax=4, valinit=1, valstep=rate)
# updating the plot
def update(val):
current_v = slider.val
rate[rs] = current_v
axes.set_ydata(rate[rs])
fig.canvas.draw()
slider.on_changed(update)
plt.show()
I tried to update my plot for when I change the rate on my slider, but it is not working properly.
def update(val):
current_v = slider.val
rate[rs] = current_v
axes.set_ydata(rate[rs])
fig.canvas.draw()

REINFORCE for Cartpole: Training Unstable

I am implementing REINFORCE for Cartpole-V0. However, the training process is very unstable. I have not implemented `early-stopping' for the environment and allow training to continue for a fixed (high) number of episodes. After a few thousand iterations, the training reward seems to go down again. Is this due to overfitting and early-stopping is essential, or have I implemented something incorrectly?
Here is my code:
import gym
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
import os
def running_average(x, n):
N = n
kernel = np.ones(N)
conv_len = x.shape[0]-N
y = np.zeros(conv_len)
for i in range(conv_len):
y[i] = kernel # x[i:i+N] # matrix multiplication operator: np.mul
y[i] /= N
return y
class PolicyNetwork(nn.Module):
def __init__(self, state_dim, n_actions):
super().__init__()
self.n_actions = n_actions
self.model = nn.Sequential(
nn.Linear(state_dim, 64),
nn.ReLU(),
nn.Linear(64, 32),
nn.ReLU(),
nn.Linear(32, n_actions),
nn.Softmax(dim=1)
).float()
def forward(self, X):
return self.model(X)
def train_reinforce_agent(env, episode_length, max_episodes, gamma, visualize_step, learning_rate=0.003):
model = PolicyNetwork(env.observation_space.shape[0], env.action_space.n)
optimizer = optim.Adam(model.parameters(), lr=learning_rate)
EPISODE_LENGTH = episode_length
MAX_EPISODES = max_episodes
GAMMA = gamma
VISUALIZE_STEP = max(1, visualize_step)
score = []
for episode in range(MAX_EPISODES):
curr_state = env.reset()
done = False
all_episode_t = []
score_episode = 0
for t in range(EPISODE_LENGTH):
act_prob = model(torch.from_numpy(curr_state).unsqueeze(0).float())
action = np.random.choice(np.array(list(range(env.action_space.n))), p=act_prob.squeeze(0).data.numpy())
prev_state = curr_state
curr_state, reward, done, info = env.step(action)
score_episode += reward
e_t = {'state': prev_state, 'action':action, 'reward': reward, 'returns':0}
all_episode_t.append(e_t)
if done:
break
score.append(score_episode)
G = 0
max_G = 0
for t in range(len(all_episode_t)-1, -1, -1):
G = GAMMA*G + all_episode_t[t]['reward']
all_episode_t[t]['returns'] = G
if G > max_G:
max_G = G
episode_returns = np.array([all_episode_t[t]['returns'] for t in range(len(all_episode_t))])
# normalize the returns
for t in range(len(all_episode_t)):
all_episode_t[t]['returns'] = (all_episode_t[t]['returns'] - np.mean(episode_returns))/(max_G + 10**(-6))
episode_returns = torch.FloatTensor(episode_returns)
state_batch = torch.Tensor(np.array([all_episode_t[t]['state'] for t in range(len(all_episode_t))]))
action_batch = torch.Tensor(np.array([all_episode_t[t]['action'] for t in range(len(all_episode_t))]))
pred_batch = model(state_batch)
prob_batch = pred_batch.gather(dim=1, index=action_batch.long().view(-1, 1)).squeeze()
loss_tensor = torch.log(prob_batch) * episode_returns
loss = -torch.sum(loss_tensor)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if episode % VISUALIZE_STEP == 0 and episode > 0:
print('Episode {}\tAverage Score: {:.2f}'.format(episode, np.mean(score[-VISUALIZE_STEP:-1])))
# # EARLY-STOPPING: if the average score across last 100 episodes is greater than 195, game is solved
# if np.mean(score[-100:-1]) > 195:
# break
# Training plot
score = np.array(score)
avg_score = running_average(score, visualize_step)
plt.figure(figsize=(15, 7))
plt.ylabel("Episodic Reward", fontsize=12)
plt.xlabel("Training Episodes", fontsize=12)
plt.plot(score, color='gray', linewidth=1)
plt.plot(avg_score, color='blue', linewidth=3)
plt.scatter(np.arange(score.shape[0]), score, color='green', linewidth=0.3)
plt.savefig("cartpole_reinforce_training_plot.pdf")
def main():
env = gym.make('CartPole-v0')
episode_length = 300
n_episodes = 5000
gamma = 0.99
vis_steps = 100
learning_rate = 0.003
train_reinforce_agent(env, episode_length, n_episodes, gamma, vis_steps, learning_rate=learning_rate)
if __name__ == "__main__":
main()

Place and insert plane image along path using matplotlib

My code is a fair bit more advanced, but in simple terms I am looking to place and rotate an image of a plane along a path using matplotlib. Ideally I would be able to select the angle and how far along the path the image should be placed. Any ideas? My ideal output would be something like this (ignoring the coordinates I already fixed that in my real code).
Image of Norway used:
Code
import matplotlib.pyplot as plt
import matplotlib.image as img
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def x2map(x, x_scale):
return x * x_scale
def y2map(y, y_scale):
return (1 - y) * y_scale
if __name__ == "__main__":
image_url = "Norge2.png"
# Obtains the scaling for the figure
map = img.imread(image_url)
fig, ax = plt.subplots()
im = ax.imshow(map)
_, x_scale = plt.xlim()
y_scale, _ = plt.ylim()
# Fixes the axis to 0-1 and 0-1
positions_x = [i * x_scale / 10 for i in range(0, 11)]
positions_y = [i * y_scale / 10 for i in range(0, 11)]
labels = [i / 10 for i in range(0, 11)]
ax.set_xticks(positions_x)
ax.set_xticklabels([i / 10 for i in range(0, 11)])
ax.set_yticks(positions_y)
ax.set_yticklabels([(10 - i) / 10 for i in range(0, 11)])
route_color = "red"
route_ls = "-"
city_marker ="o"
city_color = "red"
A = [x2map(0.125,x_scale), y2map(0.14,y_scale)]
B = [x2map(0.772,x_scale), y2map(0.92,y_scale)]
plt.plot(
[A[0], B[0]], [A[1], B[1]], marker='o', color=route_color, ls=route_ls
)
plt.show()

Numpy implementation for regression using NN

I am implementing my own Neural Network model for regression using only NumPy, and I'm getting really weird results when I'm testing my model on m > 1 samples (for m=1 it works fine).. It seems like the model collapses and predicts only specific values for the whole batch:
Input:
X [[ 7.62316802 -6.12433912]
[ 1.11048966 4.97509421]]
Expected Output:
Y [[16.47952332 12.50288412]]
Model Output
y_hat [[10.42446234 10.42446234]]
Any idea what might cause this issue?
My code:
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# np.seterr(all=None, divide=None, over=None, under=None, invalid=None)
data_x = np.random.uniform(0, 10, size=(2, 1))
data_y = (2 * data_x).sum(axis=0, keepdims=True)
# data_y = data_x[0, :] ** 2 + data_x[1, :] ** 2
# data_y = data_y.reshape((1, -1))
# # fig = plt.figure()
# # ax = fig.add_subplot(111, projection='3d')
# # ax.scatter(data_x[0, :], data_x[1, :], data_y)
# # plt.show()
memory = dict()
nn_architecture = [
{"input_dim": 2, "output_dim": 6, "activation": "sigmoid", "bias": True},
{"input_dim": 6, "output_dim": 4, "activation": "sigmoid", "bias": True},
{"input_dim": 4, "output_dim": 1, "activation": "relu", "bias": True}
]
def init_network_parameters(nn_architecture):
parameters = []
for idx, layer in enumerate(nn_architecture):
layer_params = {}
input_dim, output_dim, activation, bias = layer.values()
W = np.random.uniform(0, 1, (output_dim, input_dim))
B = np.zeros((output_dim, 1))
if bias:
B = np.ones((output_dim, 1))
activation_func = identity
backward_activation_func = identity_backward
if activation is 'sigmoid':
activation_func = sigmoid
backward_activation_func = sigmoid_backward
elif activation is 'relu':
activation_func = relu
backward_activation_func = relu_backward
else:
print(f"Activation function set to identity for layer {idx}")
layer_params[f"W"] = W
layer_params[f"B"] = B
layer_params[f"activation"] = activation_func
layer_params[f"backward_activation"] = backward_activation_func
layer_params[f"bias"] = bias
parameters.append(layer_params)
return parameters
def identity(z):
return z
def sigmoid(z):
return np.clip(1 / (1 + np.exp(-z)), -100, 100)
def relu(z):
output = np.array(z, copy=True)
output[z <= 0] = 0
return output
def identity_backward(z, dA):
return dA
def sigmoid_backward(z, dA):
return np.clip(z * (1-z) * dA, -100, 100)
def relu_backward(z, dA):
output = np.ones(z.shape)
output[z <= 0] = 0
return output * dA
def forward_single_layer(prev_A, parameters, idx):
W = parameters[f"W"]
B = parameters[f"B"]
activation = parameters[f"activation"]
if parameters["bias"]:
curr_Z = W.dot(prev_A) + B
else:
curr_Z = W.dot(prev_A)
curr_A = activation(curr_Z)
memory[f"Z{idx+1}"] = curr_Z
memory[f"A{idx+1}"] = curr_A
return curr_Z, curr_A
def forward(X, parameters):
prev_A = X
memory["A0"] = prev_A
for idx, layer_params in enumerate(parameters):
curr_Z, prev_A = forward_single_layer(prev_A=prev_A, parameters=layer_params, idx=idx)
return prev_A
def criteria(y_hat, y):
assert y_hat.shape == y.shape
n = y_hat.shape[0]
m = y_hat.shape[1]
loss = np.sum(y_hat - y, axis=1) / m
dA = (y_hat - y) / m
return loss, dA
def backward_single_layer(prev_A, dA, curr_W, curr_Z, backward_activation, idx):
m = prev_A.shape[1]
dZ = backward_activation(z=curr_Z, dA=dA)
dW = np.dot(dZ, prev_A.T) / m
dB = np.sum(dZ, axis=1, keepdims=True) / m
dA = np.dot(curr_W.T, dZ)
return dA, dW, dB
def backpropagation(parameters, dA):
grads = {}
for idx in reversed(range(len(parameters))):
layer = parameters[idx]
prev_A = memory[f"A{idx}"]
curr_Z = memory[f"Z{idx+1}"]
curr_W = layer["W"]
backward_activation = layer["backward_activation"]
dA, dW, dB = backward_single_layer(prev_A, dA, curr_W, curr_Z, backward_activation, idx)
grads[f"W{idx}"] = dW
grads[f"B{idx}"] = dB
return grads
def update_params(parameters, grads, lr=0.001):
new_params = []
for idx, layer in enumerate(parameters):
layer["W"] -= lr*grads[f"W{idx}"]
layer["B"] -= lr*grads[f"B{idx}"]
new_params.append(layer)
return new_params
X = np.random.uniform(-10, 10, (2, 2))
Y = 2*X[0, :] + X[1, :] ** 2
Y = Y.reshape((1, X.shape[1]))
parameters = init_network_parameters(nn_architecture)
n_epochs = 1000
lr = 0.01
loss_history = []
for i in range(n_epochs):
y_hat = forward(X, parameters)
loss, dA = criteria(y_hat, Y)
loss_history.append(loss)
grads = backpropagation(parameters, dA)
parameters = update_params(parameters, grads, lr)
if not i % 10:
print(f"Epoch {i}/{n_epochs} loss={loss}")
print("X", X)
print("Y", Y)
print("y_hat", y_hat)
There wasn't a problem with my implementation, just overfitting.
More information can be found here.

TensorFlow, losses after training the model are different than losses printed during the last Epoch of Stochastic Gradient Descent.

I'm trying to do binary classification on two spirals. For testing, I am feeding my neural network the exact spiral data with no noise, and the model seems to work as the losses near 0 during SGD. However, after using my model to infer the exact same data points after SGD has completed, I get completely different losses than what was printed during the last epoch of SGD.
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
np.set_printoptions(threshold=np.nan)
# get the spiral points
t_p = np.linspace(0, 4, 1000)
x1_p = t_p * np.cos(t_p*2*np.pi)
y1_p = t_p * np.sin(t_p*2*np.pi)
x2_p = t_p * np.cos(t_p*2*np.pi + np.pi)
y2_p = t_p * np.sin(t_p*2*np.pi + np.pi)
plt.plot(x1_p, y1_p, x2_p, y2_p)
# generate data points
x1_dat = x1_p
y1_dat = y1_p
x2_dat = x2_p
y2_dat = y2_p
def model_variable(shape, name, initializer):
variable = tf.get_variable(name=name,
dtype=tf.float32,
shape=shape,
initializer=initializer
)
tf.add_to_collection('model_variables', variable)
return variable
class Model():
#layer specifications includes bias nodes
def __init__(self, sess, data, nEpochs, learning_rate, layer_specifications):
self.sess = sess
self.data = data
self.nEpochs = nEpochs
self.learning_rate = learning_rate
if layer_specifications[0] != 2 or layer_specifications[-1] != 1:
raise ValueError('First layer only two nodes, last layer only 1 node')
else:
self.layer_specifications = layer_specifications
self.build_model()
def build_model(self):
# x is the two nodes that will be layer one, will input an x, y coordinate
# and need to classify which spiral is it on, the non phase shifted or the phase
# shifted one.
# y is the output of the model
self.x = tf.placeholder(tf.float32, shape=[2, 1])
self.y = tf.placeholder(tf.float32, shape=[])
self.thetas = []
self.biases = []
for i in range(1, len(self.layer_specifications)):
self.thetas.append(model_variable([self.layer_specifications[i], self.layer_specifications[i-1]], 'theta'+str(i), tf.random_normal_initializer(stddev=0.1)))
self.biases.append(model_variable([self.layer_specifications[i], 1], 'bias'+str(i), tf.constant_initializer()))
#forward propagation
intermediate = self.x
for i in range(0, len(self.layer_specifications)-1):
if i != (len(self.layer_specifications) - 2):
intermediate = tf.nn.elu(tf.add(tf.matmul(self.thetas[i], intermediate), self.biases[i]))
else:
intermediate = tf.add(tf.matmul(self.thetas[i], intermediate), self.biases[i])
self.yhat = tf.squeeze(intermediate)
self.loss = tf.nn.sigmoid_cross_entropy_with_logits(self.yhat, self.y);
def train_init(self):
model_variables = tf.get_collection('model_variables')
self.optim = (
tf.train.GradientDescentOptimizer(learning_rate=self.learning_rate)
.minimize(self.loss, var_list=model_variables)
)
self.check = tf.add_check_numerics_ops()
self.sess.run(tf.initialize_all_variables())
# here is where x and y combine to get just x in tf with shape [2, 1] and where label becomes y in tf
def train_iter(self, x, y):
loss, _, _ = sess.run([self.loss, self.optim, self.check],
feed_dict = {self.x: x, self.y: y})
print('loss: {0} on:{1}'.format(loss, x))
# here x and y are still x and y coordinates, label is separate
def train(self):
for _ in range(self.nEpochs):
for x, y, label in self.data():
print(label)
self.train_iter([[x], [y]], label)
print("NEW ONE:\n")
# here x and y are still x and y coordinates, label is separate
def infer(self, x, y, label):
return self.sess.run((tf.sigmoid(self.yhat), self.loss), feed_dict={self.x : [[x], [y]], self.y : label})
def data():
#so first spiral is label 0, second is label 1
for _ in range(len(x1_dat)-1, -1, -1):
for dat in range(2):
if dat == 0:
yield x1_dat[_], y1_dat[_], 0
else:
yield x2_dat[_], y2_dat[_], 1
layer_specifications = [2, 100, 100, 100, 1]
sess = tf.Session()
model = Model(sess, data, nEpochs=10, learning_rate=1.1e-2, layer_specifications=layer_specifications)
model.train_init()
model.train()
inferrences_1 = []
inferrences_2 = []
losses = 0
for i in range(len(t_p)-1, -1, -1):
infer, loss = model.infer(x1_p[i], y1_p[i], 0)
if infer >= 0.5:
print('loss: {0} on point {1}, {2}'.format(loss, x1_p[i], y1_p[i]))
losses = losses + 1
inferrences_1.append('r')
else:
inferrences_1.append('g')
for i in range(len(t_p)-1, -1, -1):
infer, loss = model.infer(x2_p[i], y2_p[i], 1)
if infer >= 0.5:
inferrences_2.append('r')
else:
print('loss: {0} on point {1}, {2}'.format(loss, x2_p[i], y2_p[i]))
losses = losses + 1
inferrences_2.append('g')
print('total losses: {}'.format(losses))
plt.scatter(x1_p, y1_p, c=inferrences_1)
plt.scatter(x2_p, y2_p, c=inferrences_2)
plt.show()

Resources