Преглед изворни кода

Fixed distance calculation problems.

Kristian Schultz пре 4 година
родитељ
комит
cb4e19887e
1 измењених фајлова са 68 додато и 38 уклоњено
  1. 68 38
      library/SpheredNoise.py

+ 68 - 38
library/SpheredNoise.py

@@ -9,49 +9,78 @@ The class SimpleGan is a simple standard Generative Adversarial Network.
 
 
 import numpy as np
-import tensorflow as tf
+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 tf.sqrt(tf.reduce_sum(tf.square(x - y)))
+    return math.sqrt(fold1(lambda s, a: s + square(a[0] - a[1]), 0, list(zip(x, y))))
 
 def minDistPointToSet(x, setB):
-    m = None
-    for y in setB:
-        d = dist(x,y)
-        if m is None or m > d:
-            m = d
-    return m
+    return fold0(lambda m,y: min(m,y), [dist(x,y) for y in setB])
 
 def minDistSetToSet(setA, setB):
-    m = None
-    for x in setA:
-        d = minDistPointToSet(x,setB)
-        if m is None or m > d:
-            m = d
-    return m
+    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 = []
-    while len(noise) < pointCount:
-        nPointsToAdd = max(100, pointCount - len(noise))
-        noiseDimension = [nPointsToAdd, noiseSize]
-        noise.extend(list(filter(
-            lambda x: tf.reduce_max(tf.square(x)) < 1,
-            np.random.normal(0, 1, noiseDimension))))
-    return np.array(noise[0:pointCount])
+    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 = []
-    while len(noise) < pointCount:
-        nPointsToAdd = max(100, pointCount - len(noise))
-        noiseDimension = [nPointsToAdd, noiseSize]
-        noise.extend(list(filter(
-            lambda x: tf.reduce_sum(tf.square(x)) < 1,
-            np.random.normal(0, 1, noiseDimension))))
-    return np.array(noise[0:pointCount])
+    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):
     """
@@ -71,6 +100,7 @@ class SpheredNoise(GanBaseClass):
         self.nextId = 0
         self.numPoints = 0
         self.nextDiscPoint = 0
+        self.minDist = 0.0
 
     def train(self, dataset):
         majoritySet = dataset.data0
@@ -78,30 +108,30 @@ class SpheredNoise(GanBaseClass):
         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])
-        self.pointDists = [(x, minDistPointToSet(x, majoritySet)) for x in minoritySet]
+        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 = None
-        maxD = None
-        for (x, d) in self.pointDists:
-            if minD is None or minD > d:
-                minD = d
-            if maxD is None or maxD < d:
-                maxD = d
+        (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 * d) * self.disc
+        disc = (0.5 * self.minDist) * self.disc
         p = disc[self.nextDiscPoint]
         self.nextDiscPoint = (self.nextDiscPoint + 1) % disc.shape[0]
         return p