Top

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