def configurable_param(self, string): self.param_ops = { "decay": self.configurable_params_decay, "on": self.configurable_params_turn_on } if isinstance(string, str): if re.match("^\d+$", string): return int(string) if re.match("^\d+?\.\d+?$", string): return float(string) if "(" not in string: return string method_name, inner = string.split("(") inner = inner.replace(")", "") if method_name not in self.param_ops: raise ValidationException( "configurable param cannot find method: " + method_name + " in string " + string) args, options = self.parse_args(inner.split(" ")) result = self.param_ops[method_name](args, options) if "metric" in options: self.add_metric(options["metric"], result) return result return string
def forward(self, input, context): output = None for layer, layer_name in zip(self.layers, self.layer_names): if layer_name == "self": layer_output = input elif isinstance(layer, hg.Layer): layer_output = layer(input, context) elif layer_name.split(" ")[0] == 'layer': layer_output = context[layer_name.split(" ")[1]] elif layer_name in context: layer_output = context[layer_name] else: layer_output = layer(input) if output is None: output = layer_output else: if self.operation == "+": output = output + layer_output elif self.operation == "*": output = output * layer_output elif self.operation == "cat": output = torch.cat([output, layer_output], 1) else: raise ValidationException("Unknown operation: "+ self.operation) if self.options.mean: output /= len(self.layers) return output
def height(self): if self._height: return self._height if self.inputs == None: raise ValidationException( "gan.height() requested but no inputs provided") return self.ops.shape(self.inputs.x)[1]
def batch_size(self): if self._batch_size: return self._batch_size if self.inputs == None: raise ValidationException( "gan.batch_size() requested but no inputs provided") return self.ops.shape(self.inputs.x)[0]
def channels(self): if self._channels: return self._channels if self.inputs == None: raise ValidationException( "gan.channels() requested but no inputs provided") return self.ops.shape(self.inputs.x)[-1]
def width(self): if self._width: return self._width if self.inputs == None: raise ValidationException( "gan.width() requested but no inputs provided") return self.ops.shape(self.inputs.x)[2]
def create_component(self, defn, *args, **kw_args): if defn == None: return None if defn['class'] == None: raise ValidationException("Component definition is missing '" + name + "'") gan_component = defn['class'](self, defn, *args, **kw_args) self.components.append(gan_component) return gan_component
def new(self): template = self.args.directory + '.json' print("[hypergan] Creating new configuration file '"+template+"' based off of '"+self.config_name+".json'") if os.path.isfile(template): raise ValidationException("File exists: " + template) source_configuration = Configuration.find(self.config_name+".json") shutil.copyfile(source_configuration, template) return
def source(self, name): name = name.replace("+", "").replace("-", "") if name == "mg": return self.gan.generator.sample if name == "mx": return self.gan.inputs.x if name[0:4] == "g(mz": return self.gan.latent.sample raise ValidationException("Unknown rolling type: " + name)
def create(self, directory, channels=3, format='jpg', width=64, height=64, crop=False, resize=False): directories = glob.glob(directory + "/*") directories = [d for d in directories if os.path.isdir(d)] if (len(directories) == 0): directories = [directory] # Create a queue that produces the filenames to read. if (len(directories) == 1): # No subdirectories, use all the images in the passed in path filenames = glob.glob(directory + "/*." + format) else: filenames = glob.glob(directory + "/**/*." + format) if (len(filenames) < self.frame_count): print("Error: Not enough frames in data folder ", directory) self.file_count = len(filenames) filenames = sorted(filenames, key=alphanum_key) if self.file_count == 0: raise ValidationException("No images found in '" + directory + "'") # creates arrays of filenames[:end], filenames[1:end-1], etc for serialized random batching if self.shuffle: frames = [ tf.train.slice_input_producer([filenames], shuffle=True)[0] for i in range(self.frame_count) ] else: input_t = [ filenames[i:i - self.frame_count] for i in range(self.frame_count) ] input_queue = tf.train.slice_input_producer(input_t, shuffle=True) frames = input_queue # Read examples from files in the filename queue. frames = [ self.read_frame(frame, format, crop, resize) for frame in frames ] frames = self._get_data(frames) self.frames = frames x = tf.train.slice_input_producer([filenames], shuffle=True)[0] y = tf.train.slice_input_producer([filenames], shuffle=True)[0] self.x = self.read_frame(x, format, crop, resize) self.y = self.read_frame(y, format, crop, resize) self.x = self._get_data([self.x]) self.y = self._get_data([self.y])
def new(self): if self.args.toml: config_format = '.toml' else: config_format = '.json' template = self.args.directory + config_format print("[hypergan] Creating new configuration file '"+template+"' based off of '"+self.config_name+config_format) if os.path.isfile(template): raise ValidationException("File exists: " + template) source_configuration = Configuration.find(self.config_name+config_format, config_format=config_format, prepackaged=True) shutil.copyfile(source_configuration, template) return
def forward_term(self, term): matching = { "gN(eN(xN))": self.geN, "gN(zN)": self.gzN, "xN": self.xN } for regex, method in matching.items(): regex_subbed = regex.replace("(", '\(').replace(")", '\)').replace("N", "(\d+)?").replace(",options", "([-,=\w\d\.\(\)]+)?") regex = re.compile(regex_subbed) args = re.match(regex, term) if args: return method(*args.groups()) raise ValidationException("Could not match term: " + term)
def forward(self, input, context={}): if self.get_device().index != input.device.index: input = input.to(self.get_device()) for module, parsed, layer_shape in zip(self.net, self.parsed_layers, self.layer_shapes): try: options = parsed.parsed_options args = parsed.args layer_name = parsed.layer_name name = options.name if isinstance(module, hg.Layer): input = module(input, context) elif layer_name == "adaptive_instance_norm": input = module(input, context['w']) elif layer_name == "ez_norm": input = module(input, context['w']) elif layer_name == "split": input = torch.split(input, args[0], options.dim or -1)[args[1]] elif layer_name == "latent": input = self.gan.latent.z #sample() elif layer_name == "modulated_conv2d": input = module(input, context['w']) elif layer_name == "pretrained": in_zero_one = (input + self.const_one) / self.const_two mean = torch.as_tensor([0.485, 0.456, 0.406], device='cuda:0').view(1, 3, 1, 1) std = torch.as_tensor([0.229, 0.224, 0.225], device='cuda:0').view(1, 3, 1, 1) input = module(input.clone().sub_(mean).div_(std)) else: input = module(input) if self.gan.steps == 0: size = LayerShape(*list(input.shape[1:])) if size.squeeze_dims() != layer_shape.squeeze_dims(): print("Error: Size error on", layer_name) print("Error: Expected output size", layer_shape.dims) print("Error: Actual output size", size.dims) raise "Layer size error, cannot continue" else: pass if name is not None: context[name] = input except: raise ValidationException( "Error on " + parsed.layer_defn + " - input size " + ",".join([str(x) for x in input.shape])) self.sample = input return input
def layer_pretrained(self, net, args, options): model = getattr(torchvision.models, args[0])(pretrained=True) model.train(True) if options.layer: layers = list(model.children())[:options.layer] if options.sublayer: layers[-1] = nn.Sequential(*layers[-1][:options.sublayer]) else: layers = [model] print("List of pretrained layers:", layers) raise ValidationException( "layer=-1 required for pretrained, sublayer=-1 optional. Layers outputted above." ) return nn.Sequential(*layers)
def run(self): if self.method == 'train': self.train() elif self.method == 'build': self.gan = hg.GAN(config=self.gan_config, inputs=self.create_input(blank=True)) if not self.gan.load(self.save_file): raise ValidationException("Could not load model: "+ self.save_file) self.build() elif self.method == 'new': self.new() elif self.method == 'sample': self.gan = hg.GAN(config=self.gan_config, inputs=self.create_input(blank=False)) if not self.gan.load(self.save_file): print("Initializing new model") self.sample_forever()
def create(self): config = self.config with tf.device(self.device): self.session = self.ops.new_session(self.ops_config) self.latent = self.create_component(config.z_distribution or config.latent) self.uniform_distribution = self.latent z_shape = self.ops.shape(self.latent.sample) self.android_input = tf.reshape(self.latent.sample, [-1]) direction, slider = self.create_controls( self.ops.shape(self.android_input)) self.slider = slider self.direction = direction z = self.android_input + slider * direction z = tf.maximum(-1., z) z = tf.minimum(1., z) z = tf.reshape(z, z_shape) self.control_z = z self.generator = self.create_component(config.generator, name="generator", input=z) self.autoencoded_x = self.generator.sample x, g = self.inputs.x, self.generator.sample if self.ops.shape(x) == self.ops.shape(g): self.discriminator = self.create_component( config.discriminator, name="discriminator", input=tf.concat([x, g], axis=0)) else: print("X size", self.ops.shape(x)) print("G size", self.ops.shape(g)) raise ValidationException("X and G sizes differ") self.loss = self.create_component(config.loss, discriminator=self.discriminator) self.trainer = self.create_component(config.trainer) self.android_output = tf.reshape(self.generator.sample, [-1]) self.session.run(tf.global_variables_initializer())
def sw(self, var, name): def calculate(dscore): swx = dscore swx = tf.reshape(swx, [-1]) _, swx = tf.nn.top_k(swx, k=(self.config.top_k or 1), sorted=True, name=None) swx = tf.one_hot(swx, self.gan.batch_size(), dtype=tf.float32) swx = tf.reduce_sum(swx, reduction_indices=0) swx = tf.reshape(swx, [self.gan.batch_size(), 1, 1, 1]) return swx def create_disc(var): return self.gan.create_component(self.gan.config.discriminator, name="discriminator", input=tf.concat([var, var], axis=0), features=[self.gan.features], reuse=True) d = create_disc(var) l = self.gan.create_component(self.gan.config.loss, discriminator=d) if name == "mg-": return calculate(-l.d_fake) if name == "mg+": return calculate(l.d_fake) if name == "mx-": return calculate(-l.d_real) if name == "mx+": return calculate(l.d_real) if name == "g(mz-)": return calculate(-l.d_fake) if name == "g(mz+)": return calculate(l.d_fake) raise ValidationException("Unknown rolling type: " + name)
def build_layers(self, component, args, options): options = hc.Config(options) layers = [] layer_names = [] layer_shapes = [] for arg in args: component.current_size = self.size if arg == 'self': layers.append(None) layer_names.append("self") layer_shapes.append(self.size) elif arg == 'noise': layers.append(LearnedNoise()) layer_names.append(None) layer_shapes.append(self.size) elif arg in component.named_layers: layers.append(None) layer_names.append("layer "+arg) layer_shapes.append(component.layer_output_sizes[arg]) elif arg in component.gan.named_layers: layers.append(component.gan.named_layers[arg]) layer_names.append(None) layer_shapes.append(component.layer_output_sizes[arg]) elif arg in component.context_shapes: layers.append(None) layer_names.append(arg) layer_shapes.append(component.context_shapes[arg]) elif type(arg) == pyparsing.ParseResults and type(arg[0]) == hg.parser.Pattern: parsed = arg[0] parsed.parsed_options = hc.Config(parsed.options) layer = component.build_layer(parsed.layer_name, parsed.args, parsed.parsed_options) layers.append(layer) layer_names.append(parsed.layer_name) layer_shapes.append(component.current_size) else: raise ValidationException("Could not parse operation layer '" + arg + "'") return layers, layer_names, layer_shapes
def lazy_create(self): if (self.sampler == None): self.sampler = CLI.sampler_for(self.sampler_name)(self.gan) if (self.sampler == None): raise ValidationException("No sampler found by the name '" + self.sampler_name + "'")
def create(self, directory, channels=3, format='jpg', width=64, height=64, crop=False, resize=False, sequential=False): directories = glob.glob(directory + "/*") directories = [d for d in directories if os.path.isdir(d)] if (len(directories) == 0): directories = [directory] # Create a queue that produces the filenames to read. if (len(directories) == 1): # No subdirectories, use all the images in the passed in path filenames = glob.glob(directory + "/*." + format) else: filenames = glob.glob(directory + "/**/*." + format) filenames = natsorted(filenames) print("[loader] ImageLoader found", len(filenames)) self.file_count = len(filenames) if self.file_count == 0: raise ValidationException("No images found in '" + directory + "'") filenames = tf.convert_to_tensor(filenames, dtype=tf.string) def parse_function(filename): image_string = tf.read_file(filename) if format == 'jpg': image = tf.image.decode_jpeg(image_string, channels=channels) elif format == 'png': image = tf.image.decode_png(image_string, channels=channels) else: print("[loader] Failed to load format", format) image = tf.cast(image, tf.float32) # Image processing for evaluation. # Crop the central [height, width] of the image. if crop: image = hypergan.inputs.resize_image_patch.resize_image_with_crop_or_pad( image, height, width, dynamic_shape=True) elif resize: image = tf.image.resize_images(image, [height, width], 1) image = image / 127.5 - 1. tf.Tensor.set_shape(image, [height, width, channels]) return image # Generate a batch of images and labels by building up a queue of examples. dataset = tf.data.Dataset.from_tensor_slices(filenames) if not sequential: print("Shuffling data") dataset = dataset.shuffle(self.file_count) dataset = dataset.map(parse_function, num_parallel_calls=4) dataset = dataset.batch(self.batch_size, drop_remainder=True) dataset = dataset.repeat() dataset = dataset.prefetch(1) self.dataset = dataset self.iterator = self.dataset.make_one_shot_iterator() self.x = tf.reshape(self.iterator.get_next(), [self.batch_size, height, width, channels])
def apply_gradients(self, grads_and_vars, global_step=None, name=None): d_vars = [] g_vars = [] d_grads = [] g_grads = [] for grad, var in grads_and_vars: if var in self.gan.d_vars(): d_vars += [var] d_grads += [grad] elif var in self.gan.g_vars(): g_vars += [var] g_grads += [grad] else: raise ValidationException( "Couldn't find var in g_vars or d_vars " + var.name) all_grads = d_grads + g_grads var_list = d_vars + g_vars with ops.init_scope(): initial_f1 = [ tf.constant(self.config.initial_constraint or 0.0, shape=self.gan.ops.shape(v)) for v in var_list ] f1 = [ self._get_or_make_slot(v, f, "f", self._name) for f, v in zip(initial_f1, var_list) ] v1 = [ self._get_or_make_slot(v, v, "v1", self._name) for v in var_list ] if self.config.include_slots: for name in self.optimizer.get_slot_names(): for var in self.optimizer.variables(): self._zeros_slot(var, "pm", "pm") self._prepare() f1 = [self.get_slot(v, "f") for v in var_list] v1 = [self.get_slot(v, "v1") for v in var_list] slots_list = [] slots_vars = [] if self.config.include_slots: for name in self.optimizer.get_slot_names(): for var in self.optimizer.variables(): slots_vars += [var] slots_list.append(self._zeros_slot(var, "pm", "pm")) current_vars = var_list + slots_vars tmp_vars = v1 + slots_list diff = [tf.square(v - t) for v, t in zip(current_vars, tmp_vars)] f_accum = [] f_decay = self.gan.configurable_param(self.config.f_decay or 0.95) gradient_scale = self.gan.configurable_param(self.config.gradient_scale or 1.0) for v, f, g in zip(var_list, f1, all_grads): opts = self.gan.layer_options(v) if opts is not None and "ewc_f_decay" in opts: f_decay = self.gan.configurable_param(opts["ewc_f_decay"]) print("Setting f_decay to ", f_decay, " for ", v) if opts is not None and "ewc_gradient_scale" in opts: gradient_scale = self.gan.configurable_param( opts["ewc_gradient_scale"]) print("Setting gradient_scale to ", gradient_scale, " for ", v) f_accum += [f_decay * f + gradient_scale * tf.square(g)] #f_accum = [tf.where(tf.is_nan(_f), tf.zeros_like(_f), _f) for _f in f_accum] #f_accum = [tf.where(tf.is_inf(_f), tf.zeros_like(_f), _f) for _f in f_accum] self.gan.add_metric('f1', tf.reduce_sum([tf.reduce_sum(f) for f in f_accum])) reg = [tf.multiply(f, d) for f, d in zip(f1, diff)] #reg = [tf.where(tf.is_nan(_f), tf.zeros_like(_f), _f) for _f in reg] ewc_loss = self.gan.configurable_param( self.config.lam or 17.5) / 2.0 * tf.reduce_sum( tf.add_n([tf.reduce_sum(r) for r in reg])) self.gan.add_metric('ewc', ewc_loss) save_weights = tf.group(*[ tf.assign(w, v) for w, v in zip(tmp_vars, current_vars) ]) # store variables if isinstance(self.loss, list): if self.config.add_ewc_loss_gradients: newloss = [ewc_loss, ewc_loss] else: newloss = [self.loss[0] + ewc_loss, self.loss[1] + ewc_loss] new_grads = tf.gradients(newloss[0], d_vars) + tf.gradients( newloss[1], g_vars) self.optimizer.loss = [ ewc_loss + self.loss[0], ewc_loss + self.loss[1] ] else: if self.config.add_ewc_loss_gradients: newloss = ewc_loss else: newloss = self.loss + ewc_loss new_grads = tf.gradients(newloss, current_vars) self.optimizer.loss = ewc_loss + self.loss if self.config.add_ewc_loss_gradients: new_grads = [_g + _ng for _g, _ng in zip(all_grads, new_grads)] for g, oldg, v in zip(new_grads, all_grads, current_vars): if (self.gan.ops.shape(g) != self.gan.ops.shape(oldg)): print("[ERROR] Shape change on gradients for", v, g, "old g", oldg) raise "Gradient change error" step = self.optimizer.apply_gradients(list(zip(new_grads, current_vars)).copy(), global_step=global_step, name=name) store_f = tf.group(*[tf.assign(w, v) for w, v in zip(f1, f_accum)]) with tf.get_default_graph().control_dependencies([store_f]): with tf.get_default_graph().control_dependencies([step]): with tf.get_default_graph().control_dependencies( [save_weights]): return tf.no_op()
def _step(self, feed_dict={}): if self.trainer == None: raise ValidationException("gan.trainer is missing. Cannot train.") return self.trainer.step(feed_dict)
def lazy_create(self): if(self.sampler == None): self.sampler = self.gan.sampler_for(self.sampler_name)(self.gan, samples_per_row=self.args.width) if(self.sampler == None): raise ValidationException("No sampler found by the name '"+self.sampler_name+"'")
def validate(self): if(self.sampler == None): raise ValidationException("No sampler found by the name '"+self.sampler_name+"'")
def create(self): raise ValidationException( "BaseGAN.create() called directly. Please override")
def create(self): if self.created: raise ValidationException( "gan.create already called. Cowardly refusing to create graph twice" ) self.created = True
def create(self, directory, channels=3, format='jpg', width=64, height=64, crop=False, resize=False): directories = glob.glob(directory+"/*") directories = [d for d in directories if os.path.isdir(d)] if(len(directories) == 0): directories = [directory] labels,total_labels = self.build_labels(sorted(filter(os.path.isdir, directories))) # Create a queue that produces the filenames to read. if(len(directories) == 1): # No subdirectories, use all the images in the passed in path filenames = glob.glob(directory+"/*."+format) classes = [0 for f in filenames] else: filenames = glob.glob(directory+"/**/*."+format) classes = [labels[f.split('/')[-2]] for f in filenames] print("[loader] ImageLoader found", len(filenames), "images with", total_labels, "different class labels") self.file_count = len(filenames) if self.file_count == 0: raise ValidationException("No images found in '" + directory + "'") filenames = tf.convert_to_tensor(filenames, dtype=tf.string) classes = tf.convert_to_tensor(classes, dtype=tf.int32) input_queue = tf.train.slice_input_producer([filenames, classes]) # Read examples from files in the filename queue. value = tf.read_file(input_queue[0]) if format == 'jpg': img = tf.image.decode_jpeg(value, channels=channels) elif format == 'png': img = tf.image.decode_png(value, channels=channels) else: print("[loader] Failed to load format", format) img = tf.cast(img, tf.float32) label = input_queue[1] # Image processing for evaluation. # Crop the central [height, width] of the image. if crop: resized_image = hypergan.inputs.resize_image_patch.resize_image_with_crop_or_pad(img, height, width, dynamic_shape=True) elif resize: resized_image = tf.image.resize_images(img, [height, width], 1) else: resized_image = img tf.Tensor.set_shape(resized_image, [height,width,channels]) # This moves the image to a range of -1 to 1. float_image = resized_image / 127.5 - 1. # Ensure that the random shuffling has good mixing properties. min_fraction_of_examples_in_queue = 0.4 # Generate a batch of images and labels by building up a queue of examples. x,y = self._get_data(float_image, label) y = tf.cast(y, tf.int64) y = tf.one_hot(y, total_labels, 1.0, 0.0) self.x = x self.y = y return x, y