journal_basins.py debugged

This commit is contained in:
steffen-illium
2021-05-16 11:30:34 +02:00
parent 5074100b71
commit 042188f15a
5 changed files with 89 additions and 75 deletions

View File

@ -0,0 +1,5 @@
from mixed_setting_exp import run_mixed_experiment
from robustness_exp import run_robustness_experiment
from self_application_exp import run_SA_experiment
from self_train_exp import run_ST_experiment
from soup_exp import run_soup_experiment

View File

@ -20,7 +20,6 @@ def add_noise(input_data, epsilon = pow(10, -5)):
return output return output
class RobustnessExperiment: class RobustnessExperiment:
def __init__(self, population_size, log_step_size, net_input_size, net_hidden_size, net_out_size, net_learning_rate, def __init__(self, population_size, log_step_size, net_input_size, net_hidden_size, net_out_size, net_learning_rate,
ST_steps, directory_name) -> None: ST_steps, directory_name) -> None:

View File

@ -1,4 +1,6 @@
import os import os
from pathlib import Path
from tqdm import tqdm from tqdm import tqdm
import random import random
import copy import copy
@ -14,37 +16,41 @@ from sklearn.metrics import mean_squared_error as MSE
def prng(): def prng():
return random.random() return random.random()
def l1 (tup):
def l1(tup):
a, b = tup a, b = tup
return abs(a-b) return abs(a-b)
def mean_invariate_manhattan_distance(X,Y):
def mean_invariate_manhattan_distance(x, y):
# One of these one-liners that might be smart or really dumb. Goal is to find pairwise # One of these one-liners that might be smart or really dumb. Goal is to find pairwise
# distances of ascending values, ie. sum (abs(min1_X-min1_Y), abs(min2_X-min2Y) ...) / mean. # distances of ascending values, ie. sum (abs(min1_X-min1_Y), abs(min2_X-min2Y) ...) / mean.
# Idea was to find weight sets that have same values but just in different positions, that would # Idea was to find weight sets that have same values but just in different positions, that would
# make this distance 0. # make this distance 0.
return np.mean(list(map(l1, zip(sorted(X),sorted(Y))))) return np.mean(list(map(l1, zip(sorted(x), sorted(y)))))
def distance_matrix(nets, distance="MIM", print_it=True): def distance_matrix(nets, distance="MIM", print_it=True):
matrix = [[0 for _ in range(len(nets))] for _ in range(len(nets))] matrix = [[0 for _ in range(len(nets))] for _ in range(len(nets))]
for net in range(len(nets)): for net in range(len(nets)):
weights = nets[net].input_weight_matrix()[:,0] weights = nets[net].input_weight_matrix()[:, 0]
for other_net in range(len(nets)): for other_net in range(len(nets)):
other_weights = nets[other_net].input_weight_matrix()[:,0] other_weights = nets[other_net].input_weight_matrix()[:, 0]
if distance in ["MSE"]: if distance in ["MSE"]:
matrix[net][other_net] = MSE(weights, other_weights) matrix[net][other_net] = MSE(weights, other_weights)
elif distance in ["MAE"]: elif distance in ["MAE"]:
matrix[net][other_net] = MAE(weights, other_weights) matrix[net][other_net] = MAE(weights, other_weights)
elif distance in ["MIM"]: elif distance in ["MIM"]:
matrix[net][other_net] = mean_invariate_manhattan_distance(weights, other_weights) matrix[net][other_net] = mean_invariate_manhattan_distance(weights, other_weights)
if print_it: if print_it:
print(f"\nDistance matrix [{distance}]:") print(f"\nDistance matrix [{distance}]:")
[print(row) for row in matrix] [print(row) for row in matrix]
return matrix return matrix
class SpawnExperiment: class SpawnExperiment:
@staticmethod @staticmethod
def apply_noise(network, noise: int): def apply_noise(network, noise: int):
""" Changing the weights of a network to values + noise """ """ Changing the weights of a network to values + noise """
@ -52,16 +58,16 @@ class SpawnExperiment:
for layer_id, layer_name in enumerate(network.state_dict()): for layer_id, layer_name in enumerate(network.state_dict()):
for line_id, line_values in enumerate(network.state_dict()[layer_name]): for line_id, line_values in enumerate(network.state_dict()[layer_name]):
for weight_id, weight_value in enumerate(network.state_dict()[layer_name][line_id]): for weight_id, weight_value in enumerate(network.state_dict()[layer_name][line_id]):
#network.state_dict()[layer_name][line_id][weight_id] = weight_value + noise # network.state_dict()[layer_name][line_id][weight_id] = weight_value + noise
if prng() < 0.5: if prng() < 0.5:
network.state_dict()[layer_name][line_id][weight_id] = weight_value + noise network.state_dict()[layer_name][line_id][weight_id] = weight_value + noise
else: else:
network.state_dict()[layer_name][line_id][weight_id] = weight_value - noise network.state_dict()[layer_name][line_id][weight_id] = weight_value - noise
return network return network
def __init__(self, population_size, log_step_size, net_input_size, net_hidden_size, net_out_size, net_learning_rate, def __init__(self, population_size, log_step_size, net_input_size, net_hidden_size, net_out_size, net_learning_rate,
epochs, ST_steps, noise, directory_name) -> None: epochs, st_steps, noise, directory_name) -> None:
self.population_size = population_size self.population_size = population_size
self.log_step_size = log_step_size self.log_step_size = log_step_size
self.net_input_size = net_input_size self.net_input_size = net_input_size
@ -69,19 +75,19 @@ class SpawnExperiment:
self.net_out_size = net_out_size self.net_out_size = net_out_size
self.net_learning_rate = net_learning_rate self.net_learning_rate = net_learning_rate
self.epochs = epochs self.epochs = epochs
self.ST_steps = ST_steps self.ST_steps = st_steps
self.loss_history = [] self.loss_history = []
self.nets = [] self.nets = []
self.noise = noise or 10e-5 self.noise = noise or 10e-5
print("\nNOISE:", self.noise) print("\nNOISE:", self.noise)
self.directory_name = directory_name self.directory = Path(directory_name)
os.mkdir(self.directory_name) self.directory.mkdir(parents=True, exist_ok=True)
self.populate_environment() self.populate_environment()
self.spawn_and_continue() self.spawn_and_continue()
self.weights_evolution_3d_experiment() self.weights_evolution_3d_experiment()
#self.visualize_loss() # self.visualize_loss()
distance_matrix(self.nets) distance_matrix(self.nets)
def populate_environment(self): def populate_environment(self):
@ -93,66 +99,67 @@ class SpawnExperiment:
net = Net(self.net_input_size, self.net_hidden_size, self.net_out_size, net_name) net = Net(self.net_input_size, self.net_hidden_size, self.net_out_size, net_name)
for _ in range(self.ST_steps): for _ in range(self.ST_steps):
input_data = net.input_weight_matrix() net.self_train(1, self.log_step_size, self.net_learning_rate)
target_data = net.create_target_weights(input_data)
net.self_train(1, self.log_step_size, self.net_learning_rate, input_data, target_data)
#print(f"\nLast weight matrix (epoch: {self.epochs}):\n{net.input_weight_matrix()}\nLossHistory: {net.loss_history[-10:]}") # print(f"\nLast weight matrix (epoch: {self.epochs}):\n
# {net.input_weight_matrix()}\nLossHistory: {net.loss_history[-10:]}")
self.nets.append(net) self.nets.append(net)
def spawn_and_continue(self, number_spawns: int = 5):
def spawn_and_continue(self, number_spawns:int = 5):
# For every initial net {i} after populating (that is fixpoint after first epoch); # For every initial net {i} after populating (that is fixpoint after first epoch);
for i in range(self.population_size): for i in range(self.population_size):
net = self.nets[i] net = self.nets[i]
net_input_data = net.input_weight_matrix()
net_target_data = net.create_target_weights(net_input_data)
if is_identity_function(net, net_input_data, net_target_data):
print(f"\nNet {i} is fixpoint")
#print("\nNet weights before training\n", target_data)
# Clone the fixpoint x times and add (+-)self.noise to weight-sets randomly; net_input_data = net.input_weight_matrix()
# To plot clones starting after first epoch (z=ST_steps), set that as start_time! net_target_data = net.create_target_weights(net_input_data)
for j in range(number_spawns): if is_identity_function(net):
clone = Net(net.input_size, net.hidden_size, net.out_size, f"ST_net_{str(i)}_clone_{str(j)}", start_time=self.ST_steps) print(f"\nNet {i} is fixpoint")
clone.load_state_dict(copy.deepcopy(net.state_dict())) # print("\nNet weights before training\n", target_data)
rand_noise = prng() * self.noise
clone = self.apply_noise(clone, rand_noise)
# Then finish training each clone {j} (for remaining epoch-1 * ST_steps) and add to nets for plotting; # Clone the fixpoint x times and add (+-)self.noise to weight-sets randomly;
for _ in range(self.epochs - 1): # To plot clones starting after first epoch (z=ST_steps), set that as start_time!
for _ in range(self.ST_steps): for j in range(number_spawns):
input_data = clone.input_weight_matrix() clone = Net(net.input_size, net.hidden_size, net.out_size,
target_data = clone.create_target_weights(input_data) f"ST_net_{str(i)}_clone_{str(j)}",
clone.self_train(1, self.log_step_size, self.net_learning_rate, input_data, target_data) start_time=self.ST_steps)
#print(f"clone {j} last weights: {target_data}, noise {noise}") clone.load_state_dict(copy.deepcopy(net.state_dict()))
if is_identity_function(clone, input_data, target_data): rand_noise = prng() * self.noise
print(f"Clone {j} (of net_{i}) is fixpoint. \nMSE(j,i): {MSE(net_target_data, target_data)}, \nMAE(j,i): {MAE(net_target_data, target_data)}\n") clone = self.apply_noise(clone, rand_noise)
self.nets.append(clone)
# Finally take parent net {i} and finish it's training for comparison to clone development. # Then finish training each clone {j} (for remaining epoch-1 * ST_steps)
for _ in range(self.epochs - 1): # and add to nets for plotting;
for _ in range(self.ST_steps): for _ in range(self.epochs - 1):
input_data = net.input_weight_matrix() for _ in range(self.ST_steps):
target_data = net.create_target_weights(input_data) clone.self_train(1, self.log_step_size, self.net_learning_rate)
net.self_train(1, self.log_step_size, self.net_learning_rate, input_data, target_data) # print(f"clone {j} last weights: {target_data}, noise {noise}")
#print("\nNet weights after training \n", target_data) if is_identity_function(clone):
input_data = clone.input_weight_matrix()
target_data = clone.create_target_weights(input_data)
print(f"Clone {j} (of net_{i}) is fixpoint. \nMSE(j,i): "
f"{MSE(net_target_data, target_data)}, \nMAE(j,i): {MAE(net_target_data, target_data)}\n")
self.nets.append(clone)
# Finally take parent net {i} and finish it's training for comparison to clone development.
for _ in range(self.epochs - 1):
for _ in range(self.ST_steps):
net.self_train(1, self.log_step_size, self.net_learning_rate)
# print("\nNet weights after training \n", target_data)
else: else:
print("No fixpoints found.") print("No fixpoints found.")
def weights_evolution_3d_experiment(self): def weights_evolution_3d_experiment(self):
exp_name = f"ST_{str(len(self.nets))}_nets_3d_weights_PCA" exp_name = f"ST_{str(len(self.nets))}_nets_3d_weights_PCA"
return plot_3d_self_train(self.nets, exp_name, self.directory_name, self.log_step_size) return plot_3d_self_train(self.nets, exp_name, self.directory.name, self.log_step_size)
def visualize_loss(self): def visualize_loss(self):
for i in range(len(self.nets)): for i in range(len(self.nets)):
net_loss_history = self.nets[i].loss_history net_loss_history = self.nets[i].loss_history
self.loss_history.append(net_loss_history) self.loss_history.append(net_loss_history)
plot_loss(self.loss_history, self.directory_name) plot_loss(self.loss_history, self.directory.name)
if __name__=="__main__":
if __name__ == "__main__":
NET_INPUT_SIZE = 4 NET_INPUT_SIZE = 4
NET_OUT_SIZE = 1 NET_OUT_SIZE = 1
@ -180,7 +187,7 @@ if __name__=="__main__":
net_out_size=NET_OUT_SIZE, net_out_size=NET_OUT_SIZE,
net_learning_rate=ST_net_learning_rate, net_learning_rate=ST_net_learning_rate,
epochs=ST_epochs, epochs=ST_epochs,
ST_steps=ST_steps, st_steps=ST_steps,
noise=pow(10,-noise_factor), noise=pow(10, -noise_factor),
directory_name=f"./experiments/spawn_basin/{ST_name_hash}_10e-{noise_factor}" directory_name=f"./experiments/spawn_basin/{ST_name_hash}_10e-{noise_factor}"
) )

View File

@ -1,4 +1,4 @@
#from __future__ import annotations # from __future__ import annotations
import copy import copy
from typing import Union from typing import Union

View File

@ -1,7 +1,7 @@
from pathlib import Path
from tokenize import String from tokenize import String
from typing import List, Dict from typing import List, Dict
import numpy
from tqdm import tqdm from tqdm import tqdm
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.patches as mpatches import matplotlib.patches as mpatches
@ -120,14 +120,17 @@ def plot_3d(matrices_weights_history, folder_name, population_size, z_axis_legen
ax.set_ylabel("PCA Y") ax.set_ylabel("PCA Y")
ax.set_zlabel(f"Epochs") ax.set_zlabel(f"Epochs")
filepath = f"./{folder_name}" # FIXME: Replace this kind of operation with pathlib.Path() object interactions
filename = f"{filepath}/{exp_name}{is_trained}.png" folder = Path(folder_name)
if os.path.isfile(filename): folder.mkdir(parents=True, exist_ok=True)
filename = f"{exp_name}{is_trained}.png"
filepath = folder / filename
if filepath.exists():
letters = string.ascii_lowercase letters = string.ascii_lowercase
random_letters = ''.join(random.choice(letters) for _ in range(5)) random_letters = ''.join(random.choice(letters) for _ in range(5))
plt.savefig(f"{filename}_{random_letters}") plt.savefig(f"{filepath.stem}_{random_letters}.png")
else: else:
plt.savefig(f"{filename}") plt.savefig(str(filepath))
plt.show() plt.show()
#plt.clf() #plt.clf()