Bug Fixes: Taskingsoup now can have n entities per layer, where n is the size of the task input. Entity task input and soup task input need to be of same size.
This commit is contained in:
parent
9bbe5df2b2
commit
de85f45e6b
@ -2,7 +2,7 @@ import os
|
||||
import time
|
||||
import dill
|
||||
from tqdm import tqdm
|
||||
import copy
|
||||
from copy import copy
|
||||
|
||||
from tensorflow.python.keras import backend as K
|
||||
|
||||
@ -33,11 +33,11 @@ class Experiment(ABC):
|
||||
self.params = dict(exp_iterations=100, application_steps=100, prints=True, trains_per_application=100)
|
||||
self.with_params(**kwargs)
|
||||
|
||||
def __copy__(self):
|
||||
|
||||
self_copy = self.__class__(name=self.experiment_name, **self.params)
|
||||
self_copy.__dict__ = {attr: self.__dict__[attr] for attr in self.__dict__ if
|
||||
attr not in ['particles', 'historical_particles']}
|
||||
def __copy__(self, *args, **kwargs):
|
||||
params = self.params
|
||||
params.update(name=self.experiment_name)
|
||||
params.update(**kwargs)
|
||||
self_copy = self.__class__(*args, **params)
|
||||
return self_copy
|
||||
|
||||
def __enter__(self):
|
||||
@ -68,9 +68,14 @@ class Experiment(ABC):
|
||||
print(str(log_message), file=log_file)
|
||||
|
||||
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()}
|
||||
self_copy = copy(self)
|
||||
# Check if attribute exists
|
||||
if hasattr(self, 'historical_particles'):
|
||||
# Check if it is empty.
|
||||
if self.historical_particles:
|
||||
# Do the Update
|
||||
# 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):
|
||||
@ -196,7 +201,7 @@ class TaskExperiment(MixedFixpointExperiment):
|
||||
kwargs['name'] = self.__class__.__name__ if 'name' not in kwargs else kwargs['name']
|
||||
super(TaskExperiment, self).__init__(**kwargs)
|
||||
|
||||
def run_exp(self, network_generator, logging=True, reset_model=False, **kwargs):
|
||||
def run_exp(self, network_generator, reset_model=False, logging=True, **kwargs):
|
||||
kwargs.update(reset_model=False, logging=logging)
|
||||
super(FixpointExperiment, self).run_exp(network_generator, **kwargs)
|
||||
if reset_model:
|
||||
@ -247,10 +252,13 @@ class TaskingSoupExperiment(Experiment):
|
||||
|
||||
def __init__(self, soup_generator, **kwargs):
|
||||
kwargs['name'] = self.__class__.__name__ if 'name' not in kwargs else kwargs['name']
|
||||
self.soup_generator = soup_generator
|
||||
super(TaskingSoupExperiment, self).__init__(**kwargs)
|
||||
self.soup_generator = soup_generator
|
||||
|
||||
def run_exp(self, network_generator, **kwargs):
|
||||
def __copy__(self):
|
||||
super(TaskingSoupExperiment, self).__copy__(self.soup_generator)
|
||||
|
||||
def run_exp(self, **kwargs):
|
||||
for i in range(self.params.get('exp_iterations')):
|
||||
soup = self.soup_generator()
|
||||
soup.seed()
|
||||
@ -263,3 +271,7 @@ class TaskingSoupExperiment(Experiment):
|
||||
def run_net(self, net, **kwargs):
|
||||
raise NotImplementedError()
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pass
|
@ -1,16 +1,17 @@
|
||||
# Librarys
|
||||
import numpy as np
|
||||
from abc import abstractmethod, ABC
|
||||
from typing import List, Union, Tuple
|
||||
from typing import List, Tuple
|
||||
from types import FunctionType
|
||||
import warnings
|
||||
|
||||
import os
|
||||
|
||||
# Functions and Operators
|
||||
from operator import mul
|
||||
from functools import reduce
|
||||
from itertools import accumulate
|
||||
from statistics import mean
|
||||
from random import random as prng
|
||||
from copy import deepcopy
|
||||
|
||||
# Deep learning Framework
|
||||
from tensorflow.python.keras.models import Sequential
|
||||
@ -18,8 +19,8 @@ from tensorflow.python.keras.callbacks import Callback
|
||||
from tensorflow.python.keras.layers import SimpleRNN, Dense
|
||||
|
||||
# Experiment Class
|
||||
from experiment import *
|
||||
from task import *
|
||||
from task import TaskAdditionOfN
|
||||
from experiment import TaskExperiment
|
||||
|
||||
# Supress warnings and info messages
|
||||
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
|
||||
@ -131,8 +132,11 @@ class NeuralNetwork(ABC):
|
||||
def get_amount_of_weights(self):
|
||||
return self.get_weight_amount(self.get_weights())
|
||||
|
||||
def get_model(self):
|
||||
return self.model
|
||||
|
||||
def get_weights(self) -> List[np.ndarray]:
|
||||
return self.model.get_weights()
|
||||
return self.get_model().get_weights()
|
||||
|
||||
def get_weights_flat(self) -> np.ndarray:
|
||||
return self.weights_to_flat_array(self.get_weights())
|
||||
@ -163,7 +167,7 @@ class NeuralNetwork(ABC):
|
||||
assert degree >= 1, "degree must be >= 1"
|
||||
epsilon = epsilon or self.get_params().get('epsilon')
|
||||
|
||||
new_weights = copy.deepcopy(self.get_weights())
|
||||
new_weights = deepcopy(self.get_weights())
|
||||
|
||||
for _ in range(degree):
|
||||
new_weights = self.apply_to_weights(new_weights)
|
||||
@ -277,7 +281,7 @@ class ParticleDecorator:
|
||||
return self
|
||||
|
||||
|
||||
class TaskDecorator(ParticleTaskAdditionOf2):
|
||||
class TaskDecorator(TaskAdditionOfN):
|
||||
|
||||
def __init__(self, network, **kwargs):
|
||||
super(TaskDecorator, self).__init__(**kwargs)
|
||||
@ -299,6 +303,7 @@ class TaskDecorator(ParticleTaskAdditionOf2):
|
||||
|
||||
else:
|
||||
self_x, self_y = self.network.get_samples()
|
||||
# Super class = Task
|
||||
task_x, task_y = super(TaskDecorator, self).get_samples()
|
||||
|
||||
amount_of_weights = self.network.get_amount_of_weights()
|
||||
@ -439,7 +444,7 @@ class AggregatingNeuralNetwork(NeuralNetwork):
|
||||
epsilon = epsilon or self.get_params().get('epsilon')
|
||||
|
||||
old_aggregations, _ = self.get_aggregated_weights()
|
||||
new_weights = copy.deepcopy(self.get_weights())
|
||||
new_weights = deepcopy(self.get_weights())
|
||||
|
||||
for _ in range(degree):
|
||||
new_weights = self.apply_to_weights(new_weights)
|
||||
@ -459,7 +464,7 @@ class RecurrentNeuralNetwork(NeuralNetwork):
|
||||
|
||||
def __init__(self, width, depth, **kwargs):
|
||||
raise NotImplementedError
|
||||
super().__init__(**kwargs)
|
||||
super(RecurrentNeuralNetwork, self).__init__()
|
||||
self.features = 1
|
||||
self.width = width
|
||||
self.depth = depth
|
||||
@ -475,7 +480,7 @@ class RecurrentNeuralNetwork(NeuralNetwork):
|
||||
|
||||
def apply_to_weights(self, old_weights):
|
||||
# build list from old weights
|
||||
new_weights = copy.deepcopy(old_weights)
|
||||
new_weights = deepcopy(old_weights)
|
||||
old_weights_list = []
|
||||
for layer_id, layer in enumerate(old_weights):
|
||||
for cell_id, cell in enumerate(layer):
|
||||
@ -532,7 +537,7 @@ class TrainingNeuralNetworkDecorator:
|
||||
return self
|
||||
|
||||
def compile_model(self, **kwargs):
|
||||
compile_params = copy.deepcopy(self.compile_params)
|
||||
compile_params = deepcopy(self.compile_params)
|
||||
compile_params.update(kwargs)
|
||||
return self.network.model.compile(**compile_params)
|
||||
|
||||
@ -599,7 +604,8 @@ if __name__ == '__main__':
|
||||
# WeightWise Neural Network
|
||||
with TaskExperiment().with_params(application_steps=10, trains_per_application=1000, exp_iterations=30) as exp:
|
||||
net_generator = lambda: TrainingNeuralNetworkDecorator(TaskDecorator(
|
||||
WeightwiseNeuralNetwork(width=4, depth=3))).with_keras_params(activation='linear')
|
||||
WeightwiseNeuralNetwork(width=2, depth=2))
|
||||
).with_keras_params(activation='linear')
|
||||
exp.run_exp(net_generator, reset_model=True)
|
||||
|
||||
if False:
|
||||
|
157
code/soup.py
157
code/soup.py
@ -1,15 +1,55 @@
|
||||
import random
|
||||
from tensorflow.python.keras.layers import Dense, Dropout, BatchNormalization
|
||||
from tensorflow.python.keras.layers import Input, Layer, Concatenate, RepeatVector, Reshape
|
||||
from tensorflow.python.keras.models import Sequential, Model
|
||||
from tensorflow.python.keras import backend as K
|
||||
|
||||
from network import *
|
||||
from typing import List, Tuple
|
||||
|
||||
# Functions and Operators
|
||||
from operator import mul
|
||||
from functools import reduce
|
||||
from itertools import accumulate
|
||||
|
||||
import numpy as np
|
||||
|
||||
from task import Task, TaskAdditionOfN
|
||||
|
||||
from copy import copy, deepcopy
|
||||
|
||||
from network import ParticleDecorator, WeightwiseNeuralNetwork, TrainingNeuralNetworkDecorator, \
|
||||
EarlyStoppingByInfNanLoss
|
||||
|
||||
from experiment import TaskingSoupExperiment
|
||||
|
||||
from math import sqrt
|
||||
|
||||
|
||||
def prng():
|
||||
return random.random()
|
||||
|
||||
|
||||
class SlicingLayer(Layer):
|
||||
|
||||
def __init__(self):
|
||||
self.kernel: None
|
||||
self.inputs: int
|
||||
super(SlicingLayer, self).__init__()
|
||||
|
||||
def build(self, input_shape):
|
||||
# Create a trainable weight variable for this layer.
|
||||
self.kernel = None
|
||||
self.inputs = input_shape[-1]
|
||||
super(SlicingLayer, self).build(input_shape) # Be sure to call this at the end
|
||||
|
||||
def call(self, x, **kwargs):
|
||||
concats = [Concatenate()([x[:, i][..., None]] * self.inputs) for i in range(x.shape[-1].value)]
|
||||
return concats
|
||||
|
||||
def compute_output_shape(self, input_shape):
|
||||
return [Concatenate()([(None, 1)] * 4) for _ in range(input_shape[-1])]
|
||||
|
||||
|
||||
class Soup(object):
|
||||
|
||||
def __init__(self, size, generator, **kwargs):
|
||||
@ -23,6 +63,9 @@ class Soup(object):
|
||||
self.is_seeded = False
|
||||
self.is_compiled = False
|
||||
|
||||
def __len__(self):
|
||||
return len(self.particles)
|
||||
|
||||
def __copy__(self):
|
||||
copy_ = Soup(self.size, self.generator, **self.soup_params)
|
||||
copy_.__dict__ = {attr: self.__dict__[attr] for attr in self.__dict__ if
|
||||
@ -30,7 +73,7 @@ class Soup(object):
|
||||
return copy_
|
||||
|
||||
def without_particles(self):
|
||||
self_copy = copy.copy(self)
|
||||
self_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
|
||||
@ -120,7 +163,7 @@ class Soup(object):
|
||||
print(particle.is_fixpoint())
|
||||
|
||||
|
||||
class SolvingSoup(Soup):
|
||||
class TaskingSoup(Soup):
|
||||
|
||||
@staticmethod
|
||||
def weights_to_flat_array(weights: List[np.ndarray]) -> np.ndarray:
|
||||
@ -138,12 +181,21 @@ class SolvingSoup(Soup):
|
||||
weights = [np.reshape(weight_slice, shape) for weight_slice, shape in zip(slices, shapes)]
|
||||
return weights
|
||||
|
||||
def __init__(self, population_size: int, task: Task, particle_generator, **kwargs):
|
||||
super(SolvingSoup, self).__init__(population_size, particle_generator, **kwargs)
|
||||
def __init__(self, population_size: int, task: Task, particle_generator, sparsity_rate=0.1, use_bias=False,
|
||||
safe=True, **kwargs):
|
||||
|
||||
if safe:
|
||||
input_shape_error_message = f'The population size must be devideable by {task.input_shape[-1]}'
|
||||
assert population_size % task.input_shape[-1] == 0, input_shape_error_message
|
||||
assert population_size % 2 == 0, 'The population size needs to be of even value'
|
||||
|
||||
super(TaskingSoup, self).__init__(population_size, particle_generator, **kwargs)
|
||||
self.task = task
|
||||
self.model: Sequential
|
||||
|
||||
self.network_params = dict(sparsity_rate=0.1, early_nan_stopping=True)
|
||||
self.network_params = dict(sparsity_rate=sparsity_rate, early_nan_stopping=True, use_bias=use_bias,
|
||||
depth=population_size // task.input_shape[-1])
|
||||
self.network_params.update(kwargs.get('network_params', {}))
|
||||
self.compile_params = dict(loss='mse', optimizer='sgd')
|
||||
self.compile_params.update(kwargs.get('compile_params', {}))
|
||||
|
||||
@ -151,25 +203,24 @@ class SolvingSoup(Soup):
|
||||
self.network_params.update(params)
|
||||
|
||||
def _generate_model(self):
|
||||
model = Sequential()
|
||||
weights, last_weights = self.get_total_weight_amount(), 0
|
||||
while weights:
|
||||
n = int(sqrt(weights))
|
||||
this_weights = sqrt(weights / n)
|
||||
if not this_weights:
|
||||
break
|
||||
if not model.layers:
|
||||
# First Input layer
|
||||
model.add(Dense(this_weights, activation='linear', input_shape=self.task.input_shape))
|
||||
else:
|
||||
# Intermediate Layers
|
||||
model.add(Dense(this_weights, activation='linear'))
|
||||
self.model.add(BatchNormalization())
|
||||
self.model.add(Dropout(rate=self.soup_params.get('sparsity_rate')))
|
||||
weights -= this_weights * last_weights
|
||||
last_weights = this_weights
|
||||
# Last Layer
|
||||
model.add(Dense(self.task.output_shape))
|
||||
particle_idx_list = list(range(len(self)))
|
||||
particles_per_layer = len(self) // self.network_params.get('depth')
|
||||
task_input = Input(self.task.input_shape, name='Task_Input')
|
||||
# First layer, which is conected to the input layer and independently trainable / not trainable at all.
|
||||
input_neurons = particles_per_layer * self.task.output_shape
|
||||
x = Dense(input_neurons, use_bias=self.network_params.get('use_bias'))(task_input)
|
||||
x = SlicingLayer()(x)
|
||||
|
||||
for layer_num in range(self.network_params.get('depth')):
|
||||
# This needs to be tensors, because particles come as keras models that applicable
|
||||
x = [self.particles[layer_num*particles_per_layer + i].get_model()(x[i]) for
|
||||
i in range(particles_per_layer)]
|
||||
x = [RepeatVector(particles_per_layer)(x[i]) for i in range(particles_per_layer)]
|
||||
x = [Reshape((particles_per_layer,))(x[i]) for i in range(particles_per_layer)]
|
||||
x = Concatenate()(x)
|
||||
x = Dense(self.task.output_shape, use_bias=self.network_params.get('use_bias'), activation='linear')(x)
|
||||
|
||||
model = Model(inputs=task_input, outputs=x)
|
||||
return model
|
||||
|
||||
def get_weights(self):
|
||||
@ -183,15 +234,19 @@ class SolvingSoup(Soup):
|
||||
all_weights[1:-1] = weights
|
||||
self.set_weights(all_weights)
|
||||
|
||||
def get_intermediate_weights(self):
|
||||
return self.get_weights()[1:-1]
|
||||
|
||||
def seed(self):
|
||||
super(SolvingSoup, self).seed()
|
||||
K.clear_session()
|
||||
self.is_compiled = False
|
||||
super(TaskingSoup, self).seed()
|
||||
self.model = self._generate_model()
|
||||
pass
|
||||
|
||||
def compile_model(self, **kwargs):
|
||||
if not self.is_compiled:
|
||||
compile_params = copy.deepcopy(self.compile_params)
|
||||
compile_params = deepcopy(self.compile_params)
|
||||
compile_params.update(kwargs)
|
||||
return self.model.compile(**compile_params)
|
||||
else:
|
||||
@ -199,7 +254,7 @@ class SolvingSoup(Soup):
|
||||
|
||||
def get_total_weight_amount(self):
|
||||
if self.is_seeded:
|
||||
return sum([x.get_amount_of_weights for x in self.particles])
|
||||
return sum([x.get_amount_of_weights() for x in self.particles])
|
||||
else:
|
||||
return 0
|
||||
|
||||
@ -208,29 +263,37 @@ class SolvingSoup(Soup):
|
||||
|
||||
def get_intermediate_shapes(self):
|
||||
weights = [x.shape for x in self.get_weights()]
|
||||
return weights[1:-1]
|
||||
return weights[2:-2] if self.network_params.get('use_bias') else weights[1:-1]
|
||||
|
||||
def predict(self, x):
|
||||
return self.model.predict(x)
|
||||
|
||||
def evolve(self, **kwargs):
|
||||
super(SolvingSoup, self).evolve(iterations=1)
|
||||
def evolve(self, iterations=1):
|
||||
for iteration in range(iterations):
|
||||
super(TaskingSoup, self).evolve(iterations=1)
|
||||
self.train_particles()
|
||||
|
||||
def get_particle_weights(self):
|
||||
return np.concatenate([x.get_weights_flat() for x in self.particles])
|
||||
|
||||
def get_particle_input_shape(self):
|
||||
if self.is_seeded:
|
||||
return tuple([x if x else -1 for x in self.particles[0].get_model().input_shape])
|
||||
else:
|
||||
return -1
|
||||
|
||||
def set_particle_weights(self, weights):
|
||||
particle_weight_shape = self.particles[0].shapes(self.particles[0].get_weights())
|
||||
sizes = [x.get_amount_of_weights() for x in self.particles]
|
||||
flat_weights = self.weights_to_flat_array(weights)
|
||||
slices = [flat_weights[x: y] for x, y in zip(accumulate([0] + sizes), accumulate(sizes))]
|
||||
for particle, weight in zip((self.particles, slices)):
|
||||
self.reshape_flat_array(weight, particle_weight_shape)
|
||||
for particle, slice in zip(self.particles, slices):
|
||||
new_weights = self.reshape_flat_array(slice, particle_weight_shape)
|
||||
particle.set_weights(new_weights)
|
||||
return True
|
||||
|
||||
def compiled(self, **kwargs):
|
||||
if not self.is_compiled:
|
||||
self.seed()
|
||||
self.compile_model(**kwargs)
|
||||
self.is_compiled = True
|
||||
return self
|
||||
@ -259,27 +322,29 @@ class SolvingSoup(Soup):
|
||||
batch_size=batchsize, callbacks=callbacks)
|
||||
return history.history['loss'][-1]
|
||||
|
||||
def train_at_particle_level(self):
|
||||
def train_particles(self, **kwargs):
|
||||
self.compiled()
|
||||
|
||||
weights = self.get_particle_weights()
|
||||
shaped_weights = self.reshape_flat_array(weights, self.get_intermediate_shapes())
|
||||
self.set_intermediate_weights(shaped_weights)
|
||||
|
||||
_ = self.train(**kwargs) # This returns the loss values
|
||||
new_weights = self.get_intermediate_weights()
|
||||
self.set_particle_weights(new_weights)
|
||||
return
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if True:
|
||||
from task import TaskAdditionOf2
|
||||
soup_generator = SolvingSoup(20, ParticleTaskAdditionOf2(), net_generator)
|
||||
with SoupExperiment(soup_generator, name='solving_soup') as exp:
|
||||
net_generator = lambda: TrainingNeuralNetworkDecorator(
|
||||
WeightwiseNeuralNetwork(2, 2).with_keras_params(activation='linear').with_params()
|
||||
)
|
||||
exp.run_exp(net_generator)
|
||||
from task import TaskAdditionOfN
|
||||
|
||||
if True:
|
||||
net_generator = lambda: TrainingNeuralNetworkDecorator(
|
||||
WeightwiseNeuralNetwork(2, 2).with_keras_params(activation='linear').with_params()
|
||||
)
|
||||
soup_generator = lambda: TaskingSoup(20, TaskAdditionOfN(4), net_generator)
|
||||
with TaskingSoupExperiment(soup_generator, name='solving_soup') as exp:
|
||||
exp.run_exp(reset_model=False)
|
||||
|
||||
if False:
|
||||
soup_generator = lambda: Soup(10, net_generator).with_soup_params(remove_divergent=True, remove_zero=True)
|
||||
with SoupExperiment(soup_generator, name='soup') as exp:
|
||||
net_generator = lambda: TrainingNeuralNetworkDecorator(
|
||||
@ -293,7 +358,7 @@ if __name__ == '__main__':
|
||||
# .with_params(shuffler=AggregatingNeuralNetwork.shuffle_random)
|
||||
# net_generator = lambda: RecurrentNeuralNetwork(2, 2).with_keras_params(activation='linear').with_params()
|
||||
|
||||
if True:
|
||||
if False:
|
||||
soup_generator = lambda: Soup(10, net_generator).with_soup_params(remove_divergent=True, remove_zero=True)
|
||||
with SoupExperiment(soup_generator, name='soup') as exp:
|
||||
net_generator = lambda: TrainingNeuralNetworkDecorator(WeightwiseNeuralNetwork(2, 2)) \
|
||||
|
26
code/task.py
26
code/task.py
@ -1,12 +1,13 @@
|
||||
from abc import ABC, abstractmethod
|
||||
import numpy as np
|
||||
|
||||
from typing import Tuple, List, Union
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
class Task(ABC):
|
||||
|
||||
def __init__(self, input_shape, output_shape, **kwargs):
|
||||
assert any([x not in kwargs.keys() for x in ["input_shape", "output_shape"]]), 'Dublicated arguments were given'
|
||||
self.input_shape = input_shape
|
||||
self.output_shape = output_shape
|
||||
self.batchsize = kwargs.get('batchsize', 100)
|
||||
@ -15,24 +16,17 @@ class Task(ABC):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ParticleTaskAdditionOf2(Task):
|
||||
class TaskAdditionOfN(Task):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(ParticleTaskAdditionOf2, self).__init__(input_shape=(4,), output_shape=(1, ), **kwargs)
|
||||
def __init__(self, n: int, input_shape=(4,), output_shape=1, **kwargs):
|
||||
assert any([x not in kwargs.keys() for x in ["input_shape", "output_shape"]]), 'Dublicated arguments were given'
|
||||
assert n <= input_shape[0], f'You cannot Add more values (n={n}) than your input is long (in={input_shape}).'
|
||||
kwargs.update(input_shape=input_shape, output_shape=output_shape)
|
||||
super(TaskAdditionOfN, self).__init__(**kwargs)
|
||||
self.n = n
|
||||
|
||||
def get_samples(self) -> Tuple[np.ndarray, np.ndarray]:
|
||||
x = np.zeros((self.batchsize, *self.input_shape))
|
||||
x[:, :2] = np.random.standard_normal((self.batchsize, 2)) * 0.5
|
||||
x[:, :self.n] = np.random.standard_normal((self.batchsize, self.n)) * 0.5
|
||||
y = np.sum(x, axis=1)
|
||||
return x, y
|
||||
|
||||
|
||||
class SoupTask(Task):
|
||||
|
||||
def __init__(self, input_shape, output_shape):
|
||||
super(SoupTask, self).__init__(input_shape, output_shape)
|
||||
pass
|
||||
|
||||
def get_samples(self) -> Tuple[np.ndarray, np.ndarray]:
|
||||
raise NotImplementedError
|
||||
# ToDo Hier geht es weiter.
|
Loading…
x
Reference in New Issue
Block a user