""" This module contains some example Generative Adversarial Networks for testing. The classes StupidToyPointGan and StupidToyListGan are not really Networks. This classes are used for testing the interface. Hope your actually GAN will perform better than this two. The class SimpleGan is a simple standard Generative Adversarial Network. """ import numpy as np import math from library.interfaces import GanBaseClass def square(x): return (x*x) def fold0(f, xs): if xs == []: return None s = xs[0] for x in xs[1:]: s = f(s, x) return s def fold1(f, s0, xs): if xs == []: return None s = s0 for x in xs: s = f(s, x) return s def dist(x, y): return math.sqrt(fold1(lambda s, a: s + square(a[0] - a[1]), 0, list(zip(x, y)))) def minDistPointToSet(x, setB): return fold0(lambda m,y: min(m,y), [dist(x,y) for y in setB]) def minDistSetToSet(setA, setB): return fold0(lambda m,x: min(m, minDistPointToSet(x,setB)), setA) def normInf(xs): return fold0(lambda m, x: max(m, abs(x)), xs) def norm2Sq(xs): return fold0(lambda s, x: s + (x*x), xs) def norm2(xs): return math.sqrt(norm2Sq(xs)) def minmax(xs): if xs == []: return None (mi, mx) = (xs[0][1], xs[0][1]) for x in xs[1:]: mi = min(mi, x[1]) mx = max(mx, x[1]) return (mi, mx) def createSquare(pointCount, noiseSize): noise = [ [np.random.uniform(-1.0, 1.0) for n in range(noiseSize)] for m in range(pointCount) ] return np.array(noise) def createDisc(pointCount, noiseSize): noise = [] for n in range(pointCount): p = [np.random.uniform(-1.0, 1.0)] for m in range(noiseSize - 1): d = norm2Sq(p) d = math.sqrt(1.0 - d) p.append(np.random.uniform(0.0 - d, d)) noise.append(p) return np.array(noise) class SpheredNoise(GanBaseClass): """ A class for a simple GAN. """ def __init__(self, noiseSize=101): self.isTrained = False self.noiseSize = noiseSize self.disc = [] self.reset() def reset(self, _dataSet): """ Resets the trained GAN to an random state. """ self.pointDists = [] self.nextId = 0 self.numPoints = 0 self.nextDiscPoint = 0 self.minDist = 0.0 def train(self, dataset): majoritySet = dataset.data0 minoritySet = dataset.data1 trainDataSize = minoritySet.shape[0] numOfFeatures = minoritySet.shape[1] print(f"Train {majoritySet.shape[0]}/{trainDataSize} points") if minoritySet.shape[0] <= 0 or majoritySet.shape[0] <= 0: raise AttributeError("Train: Expected each data class to contain at least one point.") if numOfFeatures <= 0: raise AttributeError("Train: Expected at least one feature.") print("-> new disc") self.disc = createDisc(self.noiseSize, minoritySet.shape[1]) print("-> calc distances") self.pointDists = list(filter(lambda x: x[1] > 0.0, [(x, minDistPointToSet(x, majoritySet)) for x in minoritySet])) print("-> statistics") self.nextId = 0 self.numPoints = len(self.pointDists) self.isTrained = True (minD, maxD) = minmax(self.pointDists) self.minDist = minD print(f"trained {trainDataSize} points min:{minD} max:{maxD}") def generateDataPoint(self): (x, d) = self.pointDists[self.nextId] self.nextId = (self.nextId + 1) % self.numPoints disc = (0.5 * self.minDist) * self.disc p = disc[self.nextDiscPoint] self.nextDiscPoint = (self.nextDiscPoint + 1) % disc.shape[0] return p def generateData(self, numOfSamples=1): return np.array([self.generateDataPoint() for n in range(numOfSamples)])