Visuals
This commit is contained in:
parent
bae997feab
commit
95c2ff4200
@ -2,8 +2,7 @@ import os
|
|||||||
import time
|
import time
|
||||||
import dill
|
import dill
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
import copy
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
|
|
||||||
class Experiment:
|
class Experiment:
|
||||||
@ -19,7 +18,7 @@ class Experiment:
|
|||||||
self.base_dir = self.experiment_name
|
self.base_dir = self.experiment_name
|
||||||
self.next_iteration = 0
|
self.next_iteration = 0
|
||||||
self.log_messages = []
|
self.log_messages = []
|
||||||
self.data_storage = defaultdict(list)
|
self.historical_particles = dict()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
self.dir = os.path.join(self.base_dir, 'experiments', 'exp-{name}-{id}-{it}'.format(
|
self.dir = os.path.join(self.base_dir, 'experiments', 'exp-{name}-{id}-{it}'.format(
|
||||||
@ -31,7 +30,7 @@ class Experiment:
|
|||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
self.save(experiment=self)
|
self.save(experiment=self.without_particles())
|
||||||
self.save_log()
|
self.save_log()
|
||||||
self.next_iteration += 1
|
self.next_iteration += 1
|
||||||
|
|
||||||
@ -43,14 +42,26 @@ class Experiment:
|
|||||||
with open(os.path.join(self.dir, "{name}.txt".format(name=log_name)), "w") as log_file:
|
with open(os.path.join(self.dir, "{name}.txt".format(name=log_name)), "w") as log_file:
|
||||||
for log_message in self.log_messages:
|
for log_message in self.log_messages:
|
||||||
print(str(log_message), file=log_file)
|
print(str(log_message), file=log_file)
|
||||||
|
|
||||||
|
def __copy__(self):
|
||||||
|
copy_ = Experiment(name=self.experiment_name,)
|
||||||
|
copy_.__dict__ = {attr: self.__dict__[attr] for attr in self.__dict__ if
|
||||||
|
attr not in ['particles', 'historical_particles']}
|
||||||
|
return copy_
|
||||||
|
|
||||||
|
def without_particles(self):
|
||||||
|
self_copy = copy.copy(self)
|
||||||
|
# self_copy.particles = [particle.states for particle in self.particles]
|
||||||
|
self_copy.historical_particles = {key: val.states for key, val in self.historical_particles.items()}
|
||||||
|
return self_copy
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
for name, value in kwargs.items():
|
for name, value in kwargs.items():
|
||||||
with open(os.path.join(self.dir, "{name}.dill".format(name=name)), "wb") as dill_file:
|
with open(os.path.join(self.dir, "{name}.dill".format(name=name)), "wb") as dill_file:
|
||||||
dill.dump(value, dill_file)
|
dill.dump(value, dill_file)
|
||||||
|
|
||||||
def add_trajectory_segment(self, run_id, trajectory):
|
def add_trajectory_segment(self, run_id, trajectory):
|
||||||
self.data_storage[run_id].append(trajectory)
|
self.historical_particles[run_id].append(trajectory)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@ import copy
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from keras.models import Sequential
|
from keras.models import Sequential
|
||||||
|
from keras.callbacks import Callback
|
||||||
from keras.layers import SimpleRNN, Dense
|
from keras.layers import SimpleRNN, Dense
|
||||||
|
import keras.backend as K
|
||||||
|
|
||||||
from util import *
|
from util import *
|
||||||
from experiment import *
|
from experiment import *
|
||||||
@ -12,6 +14,20 @@ from experiment import *
|
|||||||
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
|
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
|
||||||
|
|
||||||
|
|
||||||
|
class SaveStateCallback(Callback):
|
||||||
|
def __init__(self, net, epoch=0):
|
||||||
|
super(SaveStateCallback, self).__init__()
|
||||||
|
self.net = net
|
||||||
|
self.init_epoch = epoch
|
||||||
|
|
||||||
|
def on_epoch_end(self, epoch, logs={}):
|
||||||
|
description = dict(time=epoch+self.init_epoch)
|
||||||
|
description['action'] = 'train_self'
|
||||||
|
description['counterpart'] = None
|
||||||
|
self.net.save_state(**description)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class NeuralNetwork(PrintingObject):
|
class NeuralNetwork(PrintingObject):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -64,6 +80,7 @@ class NeuralNetwork(PrintingObject):
|
|||||||
self.params = dict(epsilon=0.00000000000001)
|
self.params = dict(epsilon=0.00000000000001)
|
||||||
self.params.update(params)
|
self.params.update(params)
|
||||||
self.keras_params = dict(activation='linear', use_bias=False)
|
self.keras_params = dict(activation='linear', use_bias=False)
|
||||||
|
self.states = []
|
||||||
|
|
||||||
def get_model(self):
|
def get_model(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@ -147,6 +164,23 @@ class NeuralNetwork(PrintingObject):
|
|||||||
def print_weights(self, weights=None):
|
def print_weights(self, weights=None):
|
||||||
print(self.repr_weights(weights))
|
print(self.repr_weights(weights))
|
||||||
|
|
||||||
|
def make_state(self, **kwargs):
|
||||||
|
weights = self.get_weights_flat()
|
||||||
|
state = {'class': self.__class__.__name__, 'weights': weights}
|
||||||
|
if any(np.isinf(weights)):
|
||||||
|
return None
|
||||||
|
state.update(kwargs)
|
||||||
|
return state
|
||||||
|
|
||||||
|
def save_state(self, **kwargs):
|
||||||
|
state = self.make_state(**kwargs)
|
||||||
|
if state is not None:
|
||||||
|
self.states += [state]
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
def get_states(self):
|
||||||
|
return self.states
|
||||||
|
|
||||||
|
|
||||||
class WeightwiseNeuralNetwork(NeuralNetwork):
|
class WeightwiseNeuralNetwork(NeuralNetwork):
|
||||||
|
|
||||||
@ -600,10 +634,11 @@ class TrainingNeuralNetworkDecorator():
|
|||||||
self.model_compiled = True
|
self.model_compiled = True
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def train(self, batchsize=1):
|
def train(self, batchsize=1, store_states=True, epoch=0):
|
||||||
self.compiled()
|
self.compiled()
|
||||||
x, y = self.net.compute_samples()
|
x, y = self.net.compute_samples()
|
||||||
history = self.net.model.fit(x=x, y=y, verbose=0, batch_size=batchsize)
|
savestatecallback = SaveStateCallback(net=self.net, epoch=epoch) if store_states else None
|
||||||
|
history = self.net.model.fit(x=x, y=y, verbose=0, batch_size=batchsize, callbacks=[savestatecallback])
|
||||||
return history.history['loss'][-1]
|
return history.history['loss'][-1]
|
||||||
|
|
||||||
def train_other(self, other_network, batchsize=1):
|
def train_other(self, other_network, batchsize=1):
|
||||||
@ -611,6 +646,7 @@ class TrainingNeuralNetworkDecorator():
|
|||||||
other_network.compiled()
|
other_network.compiled()
|
||||||
x, y = other_network.net.compute_samples()
|
x, y = other_network.net.compute_samples()
|
||||||
history = self.net.model.fit(x=x, y=y, verbose=0, batch_size=batchsize)
|
history = self.net.model.fit(x=x, y=y, verbose=0, batch_size=batchsize)
|
||||||
|
|
||||||
return history.history['loss'][-1]
|
return history.history['loss'][-1]
|
||||||
|
|
||||||
|
|
||||||
@ -648,17 +684,21 @@ if __name__ == '__main__':
|
|||||||
if True:
|
if True:
|
||||||
# ok so this works quite realiably
|
# ok so this works quite realiably
|
||||||
with FixpointExperiment() as exp:
|
with FixpointExperiment() as exp:
|
||||||
run_count = 1000
|
for i in range(10):
|
||||||
net = TrainingNeuralNetworkDecorator(WeightwiseNeuralNetwork(width=2, depth=2))\
|
|
||||||
.with_params(epsilon=0.0001).with_keras_params(optimizer='sgd')
|
run_count = 1000
|
||||||
for run_id in tqdm(range(run_count+1)):
|
net = TrainingNeuralNetworkDecorator(WeightwiseNeuralNetwork(width=2, depth=2))\
|
||||||
loss = net.compiled().train()
|
.with_params(epsilon=0.0001).with_keras_params(optimizer='sgd')
|
||||||
if run_id % 100 == 0:
|
for run_id in tqdm(range(run_count+1)):
|
||||||
net.print_weights()
|
loss = net.compiled().train(epoch=run_id)
|
||||||
# print(net.apply_to_network(net))
|
if run_id % 100 == 0:
|
||||||
print("Fixpoint? " + str(net.is_fixpoint()))
|
net.print_weights()
|
||||||
print("Loss " + str(loss))
|
# print(net.apply_to_network(net))
|
||||||
print()
|
print("Fixpoint? " + str(net.is_fixpoint()))
|
||||||
|
print("Loss " + str(loss))
|
||||||
|
print()
|
||||||
|
exp.historical_particles[i] = net
|
||||||
|
K.clear_session()
|
||||||
if False:
|
if False:
|
||||||
# this does not work as the aggregation function screws over the fixpoint computation....
|
# this does not work as the aggregation function screws over the fixpoint computation....
|
||||||
# TODO: check for fixpoint in aggregated space...
|
# TODO: check for fixpoint in aggregated space...
|
||||||
|
29
code/soup.py
29
code/soup.py
@ -57,28 +57,30 @@ class Soup:
|
|||||||
other_particle_id = int(prng() * len(self.particles))
|
other_particle_id = int(prng() * len(self.particles))
|
||||||
other_particle = self.particles[other_particle_id]
|
other_particle = self.particles[other_particle_id]
|
||||||
particle.attack(other_particle)
|
particle.attack(other_particle)
|
||||||
description['attacking'] = other_particle.get_uid()
|
description['action'] = 'attacking'
|
||||||
|
description['counterpart'] = other_particle.get_uid()
|
||||||
if prng() < self.params.get('train_other_rate'):
|
if prng() < self.params.get('train_other_rate'):
|
||||||
other_particle_id = int(prng() * len(self.particles))
|
other_particle_id = int(prng() * len(self.particles))
|
||||||
other_particle = self.particles[other_particle_id]
|
other_particle = self.particles[other_particle_id]
|
||||||
particle.train_other(other_particle)
|
particle.train_other(other_particle)
|
||||||
description['training'] = other_particle.get_uid()
|
description['action'] = 'train_other'
|
||||||
|
description['counterpart'] = other_particle.get_uid()
|
||||||
for _ in range(self.params.get('train', 0)):
|
for _ in range(self.params.get('train', 0)):
|
||||||
loss = particle.compiled().train()
|
loss = particle.compiled().train()
|
||||||
description['fitted'] = self.params.get('train', 0)
|
description['fitted'] = self.params.get('train', 0)
|
||||||
description['loss'] = loss
|
description['loss'] = loss
|
||||||
|
description['action'] = 'train_self'
|
||||||
|
description['counterpart'] = None
|
||||||
if self.params.get('remove_divergent') and particle.is_diverged():
|
if self.params.get('remove_divergent') and particle.is_diverged():
|
||||||
new_particle = self.generate_particle()
|
new_particle = self.generate_particle()
|
||||||
self.particles[particle_id] = new_particle
|
self.particles[particle_id] = new_particle
|
||||||
description['died'] = True
|
description['action'] = 'divergent_dead'
|
||||||
description['cause'] = 'divergent'
|
description['counterpart'] = new_particle.get_uid()
|
||||||
description['substitute'] = new_particle.get_uid()
|
|
||||||
if self.params.get('remove_zero') and particle.is_zero():
|
if self.params.get('remove_zero') and particle.is_zero():
|
||||||
new_particle = self.generate_particle()
|
new_particle = self.generate_particle()
|
||||||
self.particles[particle_id] = new_particle
|
self.particles[particle_id] = new_particle
|
||||||
description['died'] = True
|
description['action'] = 'zweo_dead'
|
||||||
description['cause'] = 'zero'
|
description['counterpart'] = new_particle.get_uid()
|
||||||
description['substitute'] = new_particle.get_uid()
|
|
||||||
particle.save_state(**description)
|
particle.save_state(**description)
|
||||||
|
|
||||||
def count(self):
|
def count(self):
|
||||||
@ -120,15 +122,22 @@ class ParticleDecorator:
|
|||||||
return self.uid
|
return self.uid
|
||||||
|
|
||||||
def make_state(self, **kwargs):
|
def make_state(self, **kwargs):
|
||||||
state = {'class': self.net.__class__.__name__, 'weights': self.net.get_weights()}
|
weights = self.net.get_weights_flat()
|
||||||
|
if any(np.isinf(weights)):
|
||||||
|
return None
|
||||||
|
state = {'class': self.net.__class__.__name__, 'weights': weights}
|
||||||
state.update(kwargs)
|
state.update(kwargs)
|
||||||
return state
|
return state
|
||||||
|
|
||||||
def save_state(self, **kwargs):
|
def save_state(self, **kwargs):
|
||||||
state = self.make_state(**kwargs)
|
state = self.make_state(**kwargs)
|
||||||
self.states += [state]
|
if state is not None:
|
||||||
|
self.states += [state]
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
def update_state(self, number, **kwargs):
|
def update_state(self, number, **kwargs):
|
||||||
|
raise NotImplementedError('Result is vague')
|
||||||
if number < len(self.states):
|
if number < len(self.states):
|
||||||
self.states[number] = self.make_state(**kwargs)
|
self.states[number] = self.make_state(**kwargs)
|
||||||
else:
|
else:
|
||||||
|
@ -24,20 +24,24 @@ def build_args():
|
|||||||
return arg_parser.parse_args()
|
return arg_parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
def build_from_soup(soup):
|
def build_from_soup_or_exp(soup):
|
||||||
particles = soup.historical_particles
|
particles = soup.historical_particles
|
||||||
particle_dict = [dict(trajectory=[timestamp['weights'] for timestamp in particle],
|
particle_list = []
|
||||||
fitted=[timestamp['fitted'] for timestamp in particle],
|
for particle in particles.values():
|
||||||
loss=[timestamp['loss'] for timestamp in particle],
|
particle_dict = dict(
|
||||||
time=[timestamp['time'] for timestamp in particle]) for particle in particles.values()]
|
trajectory=[event['weights'] for event in particle],
|
||||||
return particle_dict
|
time=[event['time'] for event in particle],
|
||||||
|
action=[event['action'] for event in particle],
|
||||||
|
counterpart=[event['counterpart'] for event in particle]
|
||||||
|
)
|
||||||
|
particle_list.append(particle_dict)
|
||||||
|
return particle_list
|
||||||
|
|
||||||
|
|
||||||
def plot_latent_trajectories(soup_or_experiment, filename='latent_trajectory_plot'):
|
def plot_latent_trajectories(soup_or_experiment, filename='latent_trajectory_plot'):
|
||||||
assert isinstance(soup_or_experiment, (Experiment, Soup))
|
assert isinstance(soup_or_experiment, (Experiment, Soup))
|
||||||
bupu = cl.scales['11']['div']['RdYlGn']
|
bupu = cl.scales['11']['div']['RdYlGn']
|
||||||
data_dict = soup_or_experiment.data_storage if isinstance(soup_or_experiment, Experiment) \
|
data_dict = build_from_soup_or_exp(soup_or_experiment)
|
||||||
else build_from_soup(soup_or_experiment)
|
|
||||||
scale = cl.interp(bupu, len(data_dict)+1) # Map color scale to N bins
|
scale = cl.interp(bupu, len(data_dict)+1) # Map color scale to N bins
|
||||||
|
|
||||||
# Fit the mebedding space
|
# Fit the mebedding space
|
||||||
@ -91,25 +95,22 @@ def plot_latent_trajectories_3D(soup_or_experiment, filename='plot'):
|
|||||||
def norm(val, a=0, b=0.25):
|
def norm(val, a=0, b=0.25):
|
||||||
return (val - a) / (b - a)
|
return (val - a) / (b - a)
|
||||||
|
|
||||||
data_dict = soup_or_experiment.data_storage if isinstance(soup_or_experiment, Experiment) \
|
data_list = build_from_soup_or_exp(soup_or_experiment)
|
||||||
else build_from_soup(soup_or_experiment)
|
|
||||||
|
|
||||||
bupu = cl.scales['11']['div']['RdYlGn']
|
bupu = cl.scales['11']['div']['RdYlGn']
|
||||||
scale = cl.interp(bupu, len(data_dict)+1) # Map color scale to N bins
|
scale = cl.interp(bupu, len(data_list)+1) # Map color scale to N bins
|
||||||
|
|
||||||
# Fit the embedding space
|
# Fit the embedding space
|
||||||
transformer = TSNE()
|
transformer = TSNE()
|
||||||
for particle_dict in data_dict:
|
for particle_dict in data_list:
|
||||||
array = np.asarray([np.hstack([x.flatten() for x in timestamp]).flatten()
|
array = np.asarray(particle_dict['trajectory'])
|
||||||
for timestamp in particle_dict['trajectory']])
|
|
||||||
particle_dict['trajectory'] = array
|
|
||||||
transformer.fit(array)
|
transformer.fit(array)
|
||||||
|
|
||||||
# Transform data accordingly and plot it
|
# Transform data accordingly and plot it
|
||||||
data = []
|
data = []
|
||||||
for p_id, particle_dict in enumerate(data_dict):
|
for p_id, particle_dict in enumerate(data_list):
|
||||||
transformed = transformer._fit(particle_dict['trajectory'])
|
transformed = transformer._fit(particle_dict['trajectory'])
|
||||||
trace = go.Scatter3d(
|
line_trace = go.Scatter3d(
|
||||||
x=transformed[:, 0],
|
x=transformed[:, 0],
|
||||||
y=transformed[:, 1],
|
y=transformed[:, 1],
|
||||||
z=np.asarray(particle_dict['time']),
|
z=np.asarray(particle_dict['time']),
|
||||||
@ -120,9 +121,28 @@ def plot_latent_trajectories_3D(soup_or_experiment, filename='plot'):
|
|||||||
# showlegend=True,
|
# showlegend=True,
|
||||||
hoverinfo='text',
|
hoverinfo='text',
|
||||||
mode='lines')
|
mode='lines')
|
||||||
data.append(trace)
|
|
||||||
|
|
||||||
layout = go.Layout(scene=dict(aspectratio=dict(x=2, y=2, z=1),
|
line_start = go.Scatter3d(mode='markers', x=[transformed[0, 0]], y=[transformed[0, 1]],
|
||||||
|
z=np.asarray(particle_dict['time'][0]),
|
||||||
|
marker=dict(
|
||||||
|
color='rgb(255, 0, 0)',
|
||||||
|
size=4
|
||||||
|
),
|
||||||
|
showlegend=False
|
||||||
|
)
|
||||||
|
|
||||||
|
line_end = go.Scatter3d(mode='markers', x=[transformed[-1, 0]], y=[transformed[-1, 1]],
|
||||||
|
z=np.asarray(particle_dict['time'][-1]),
|
||||||
|
marker=dict(
|
||||||
|
color='rgb(0, 0, 0)',
|
||||||
|
size=4
|
||||||
|
),
|
||||||
|
showlegend=False
|
||||||
|
)
|
||||||
|
|
||||||
|
data.extend([line_trace, line_start, line_end])
|
||||||
|
|
||||||
|
layout = go.Layout(scene=dict(aspectratio=dict(x=2, y=2, z=2),
|
||||||
xaxis=dict(tickwidth=1, title='Transformed X'),
|
xaxis=dict(tickwidth=1, title='Transformed X'),
|
||||||
yaxis=dict(tickwidth=1, title='transformed Y'),
|
yaxis=dict(tickwidth=1, title='transformed Y'),
|
||||||
zaxis=dict(tickwidth=1, title='Epoch')),
|
zaxis=dict(tickwidth=1, title='Epoch')),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user