hypergan.encoders.uniform_encoder module
import tensorflow as tf
import hyperchamber as hc
import numpy as np
from .base_encoder import BaseEncoder
from ..gan_component import ValidationException
TINY=1e-12
class UniformEncoder(BaseEncoder):
def required(self):
return "z min max".split()
def validate(self):
errors = BaseEncoder.validate(self)
if(self.config.z is not None and int(self.config.z) % 2 != 0):
errors.append("z must be a multiple of 2 (was %2d)" % self.config.z)
return errors
def create(self):
gan = self.gan
ops = self.ops
config = self.config
projections = []
batch_size = self.gan.batch_size()
self.z = tf.random_uniform([batch_size, int(config.z)], config.min or -1, config.max or 1, dtype=ops.dtype)
for projection in config.projections:
projections.append(self.lookup(projection)(config, gan, self.z))
self.sample = tf.concat(axis=1, values=projections)
return self.sample
def lookup(self, projection):
if callable(projection):
return projection
if projection == 'identity':
return identity
if projection == 'sphere':
return sphere
if projection == 'gaussian':
return gaussian
print("Warning: Encoder could not lookup symbol '"+str(projection)+"'")
return None
def identity(config, gan, net):
return net
def sphere(config, gan, net):
net = gaussian(config, gan, net)
spherenet = tf.square(net)
spherenet = tf.reduce_sum(spherenet, 1)
lam = tf.sqrt(spherenet+TINY)
return net/tf.reshape(lam,[int(lam.get_shape()[0]), 1])
def modal(config, gan, net):
net = tf.round(net*float(config.modes))/float(config.modes)
return net
def binary(config, gan, net):
net = tf.greater(net, 0)
net = tf.cast(net, tf.float32)
return net
def modal_gaussian(config, gan, net):
a = modal(config, gan, net)
b = gaussian(config, gan, net)
return a + b * 0.1
def modal_sphere(config, gan, net):
net = gaussian(config, gan, net)
net = modal(config, gan, net)
spherenet = tf.square(net)
spherenet = tf.reduce_sum(spherenet, 1)
lam = tf.sqrt(spherenet+TINY)
return net/tf.reshape(lam,[int(lam.get_shape()[0]), 1])
def modal_sphere_gaussian(config, gan, net):
net = modal_sphere(config, gan, net)
return net + (gaussian(config, gan, net) * 0.01)
# creates normal distribution from uniform values https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
def gaussian(config, gan, net):
z_dim = int(config.z)
net = (net + 1) / 2
za = tf.slice(net, [0,0], [gan.batch_size(), z_dim//2])
zb = tf.slice(net, [0,z_dim//2], [gan.batch_size(), z_dim//2])
pi = np.pi
ra = tf.sqrt(-2 * tf.log(za+TINY))*tf.cos(2*pi*zb)
rb = tf.sqrt(-2 * tf.log(za+TINY))*tf.sin(2*pi*zb)
return tf.reshape(tf.concat(axis=1, values=[ra, rb]), net.get_shape())
def periodic(config, gan, net):
return periodic_triangle_waveform(net, config.periods)
def periodic_gaussian(config, gan, net):
net = periodic_triangle_waveform(net, config.periods)
return gaussian(config, gan, net)
def periodic_triangle_waveform(z, p):
return 2.0 / np.pi * tf.asin(tf.sin(2*np.pi*z/p))
def bounded(net):
minim = -1
maxim = 1
return tf.minimum(tf.maximum(net, minim), maxim)
Module variables
var TINY
Functions
def binary(
config, gan, net)
def binary(config, gan, net):
net = tf.greater(net, 0)
net = tf.cast(net, tf.float32)
return net
def bounded(
net)
def bounded(net):
minim = -1
maxim = 1
return tf.minimum(tf.maximum(net, minim), maxim)
def gaussian(
config, gan, net)
def gaussian(config, gan, net):
z_dim = int(config.z)
net = (net + 1) / 2
za = tf.slice(net, [0,0], [gan.batch_size(), z_dim//2])
zb = tf.slice(net, [0,z_dim//2], [gan.batch_size(), z_dim//2])
pi = np.pi
ra = tf.sqrt(-2 * tf.log(za+TINY))*tf.cos(2*pi*zb)
rb = tf.sqrt(-2 * tf.log(za+TINY))*tf.sin(2*pi*zb)
return tf.reshape(tf.concat(axis=1, values=[ra, rb]), net.get_shape())
def identity(
config, gan, net)
def identity(config, gan, net):
return net
def modal(
config, gan, net)
def modal(config, gan, net):
net = tf.round(net*float(config.modes))/float(config.modes)
return net
def modal_gaussian(
config, gan, net)
def modal_gaussian(config, gan, net):
a = modal(config, gan, net)
b = gaussian(config, gan, net)
return a + b * 0.1
def modal_sphere(
config, gan, net)
def modal_sphere(config, gan, net):
net = gaussian(config, gan, net)
net = modal(config, gan, net)
spherenet = tf.square(net)
spherenet = tf.reduce_sum(spherenet, 1)
lam = tf.sqrt(spherenet+TINY)
return net/tf.reshape(lam,[int(lam.get_shape()[0]), 1])
def modal_sphere_gaussian(
config, gan, net)
def modal_sphere_gaussian(config, gan, net):
net = modal_sphere(config, gan, net)
return net + (gaussian(config, gan, net) * 0.01)
def periodic(
config, gan, net)
def periodic(config, gan, net):
return periodic_triangle_waveform(net, config.periods)
def periodic_gaussian(
config, gan, net)
def periodic_gaussian(config, gan, net):
net = periodic_triangle_waveform(net, config.periods)
return gaussian(config, gan, net)
def periodic_triangle_waveform(
z, p)
def periodic_triangle_waveform(z, p):
return 2.0 / np.pi * tf.asin(tf.sin(2*np.pi*z/p))
def sphere(
config, gan, net)
def sphere(config, gan, net):
net = gaussian(config, gan, net)
spherenet = tf.square(net)
spherenet = tf.reduce_sum(spherenet, 1)
lam = tf.sqrt(spherenet+TINY)
return net/tf.reshape(lam,[int(lam.get_shape()[0]), 1])
Classes
class UniformEncoder
GANComponents are pluggable pieces within a GAN.
GAN objects are also GANComponents.
class UniformEncoder(BaseEncoder):
def required(self):
return "z min max".split()
def validate(self):
errors = BaseEncoder.validate(self)
if(self.config.z is not None and int(self.config.z) % 2 != 0):
errors.append("z must be a multiple of 2 (was %2d)" % self.config.z)
return errors
def create(self):
gan = self.gan
ops = self.ops
config = self.config
projections = []
batch_size = self.gan.batch_size()
self.z = tf.random_uniform([batch_size, int(config.z)], config.min or -1, config.max or 1, dtype=ops.dtype)
for projection in config.projections:
projections.append(self.lookup(projection)(config, gan, self.z))
self.sample = tf.concat(axis=1, values=projections)
return self.sample
def lookup(self, projection):
if callable(projection):
return projection
if projection == 'identity':
return identity
if projection == 'sphere':
return sphere
if projection == 'gaussian':
return gaussian
print("Warning: Encoder could not lookup symbol '"+str(projection)+"'")
return None
Ancestors (in MRO)
- UniformEncoder
- hypergan.encoders.base_encoder.BaseEncoder
- hypergan.gan_component.GANComponent
- builtins.object
Static methods
def __init__(
self, gan, config)
Initializes a gan component based on a gan
and a config
dictionary.
Different components require different config variables.
A ValidationException
is raised if the GAN component configuration fails to validate.
def __init__(self, gan, config):
"""
Initializes a gan component based on a `gan` and a `config` dictionary.
Different components require different config variables.
A `ValidationException` is raised if the GAN component configuration fails to validate.
"""
self.gan = gan
self.config = hc.Config(config)
errors = self.validate()
if errors != []:
raise ValidationException(self.__class__.__name__+": " +"\n".join(errors))
self.create_ops(config)
def biases(
self)
Biases of the GAN component.
def biases(self):
"""
Biases of the GAN component.
"""
return self.ops.biases
def create(
self)
def create(self):
gan = self.gan
ops = self.ops
config = self.config
projections = []
batch_size = self.gan.batch_size()
self.z = tf.random_uniform([batch_size, int(config.z)], config.min or -1, config.max or 1, dtype=ops.dtype)
for projection in config.projections:
projections.append(self.lookup(projection)(config, gan, self.z))
self.sample = tf.concat(axis=1, values=projections)
return self.sample
def create_ops(
self, config)
Create the ops object as self.ops
. Also looks up config
def create_ops(self, config):
"""
Create the ops object as `self.ops`. Also looks up config
"""
if self.gan is None:
return
if self.gan.ops_backend is None:
return
self.ops = self.gan.ops_backend(config=self.config, device=self.gan.device)
self.config = self.gan.ops.lookup(config)
def fully_connected_from_list(
self, nets)
def fully_connected_from_list(self, nets):
results = []
ops = self.ops
for net, net2 in nets:
net = ops.concat([net, net2], axis=3)
shape = ops.shape(net)
bs = shape[0]
net = ops.reshape(net, [bs, -1])
features = ops.shape(net)[1]
net = ops.linear(net, features)
#net = self.layer_regularizer(net)
net = ops.lookup('lrelu')(net)
#net = ops.linear(net, features)
net = ops.reshape(net, shape)
results.append(net)
return results
def layer_regularizer(
self, net)
def layer_regularizer(self, net):
symbol = self.config.layer_regularizer
op = self.gan.ops.lookup(symbol)
if op:
net = op(self, net)
return net
def lookup(
self, projection)
def lookup(self, projection):
if callable(projection):
return projection
if projection == 'identity':
return identity
if projection == 'sphere':
return sphere
if projection == 'gaussian':
return gaussian
print("Warning: Encoder could not lookup symbol '"+str(projection)+"'")
return None
def permute(
self, nets, k)
def permute(self, nets, k):
return list(itertools.permutations(nets, k))
def relation_layer(
self, net)
def relation_layer(self, net):
ops = self.ops
#hack
shape = ops.shape(net)
input_size = shape[1]*shape[2]*shape[3]
netlist = self.split_by_width_height(net)
permutations = self.permute(netlist, 2)
permutations = self.fully_connected_from_list(permutations)
net = ops.concat(permutations, axis=3)
#hack
bs = ops.shape(net)[0]
net = ops.reshape(net, [bs, -1])
net = ops.linear(net, input_size)
net = ops.reshape(net, shape)
return net
def required(
self)
Return a list of required config strings and a ValidationException
will be thrown if any are missing.
Example:
python
class MyComponent(GANComponent):
def required(self):
"learn rate is required"
["learn_rate"]
def required(self):
return "z min max".split()
def reuse(
self, net)
def reuse(self, net):
self.ops.reuse()
net = self.build(net)
self.ops.stop_reuse()
return net
def split_batch(
self, net, count=2)
Discriminators return stacked results (on axis 0).
This splits the results. Returns [d_real, d_fake]
def split_batch(self, net, count=2):
"""
Discriminators return stacked results (on axis 0).
This splits the results. Returns [d_real, d_fake]
"""
ops = self.ops or self.gan.ops
s = ops.shape(net)
bs = s[0]
nets = []
net = ops.reshape(net, [bs, -1])
start = [0 for x in ops.shape(net)]
for i in range(count):
size = [bs//count] + [x for x in ops.shape(net)[1:]]
nets.append(ops.slice(net, start, size))
start[0] += bs//count
return nets
def split_by_width_height(
self, net)
def split_by_width_height(self, net):
elems = []
ops = self.gan.ops
shape = ops.shape(net)
bs = shape[0]
height = shape[1]
width = shape[2]
for i in range(width):
for j in range(height):
elems.append(ops.slice(net, [0, i, j, 0], [bs, 1, 1, -1]))
return elems
def validate(
self)
Validates a GANComponent. Return an array of error messages. Empty array []
means success.
def validate(self):
errors = BaseEncoder.validate(self)
if(self.config.z is not None and int(self.config.z) % 2 != 0):
errors.append("z must be a multiple of 2 (was %2d)" % self.config.z)
return errors
def variables(
self)
All variables associated with this component.
def variables(self):
"""
All variables associated with this component.
"""
return self.ops.variables()
def weights(
self)
The weights of the GAN component.
def weights(self):
"""
The weights of the GAN component.
"""
return self.ops.weights