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